openfirm.c revision 256938
1275072Semaste/* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ 2275072Semaste 3275072Semaste/*- 4275072Semaste * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5275072Semaste * Copyright (C) 1995, 1996 TooLs GmbH. 6275072Semaste * All rights reserved. 7275072Semaste * 8275072Semaste * Redistribution and use in source and binary forms, with or without 9275072Semaste * modification, are permitted provided that the following conditions 10275072Semaste * are met: 11275072Semaste * 1. Redistributions of source code must retain the above copyright 12275072Semaste * notice, this list of conditions and the following disclaimer. 13344779Sdim * 2. Redistributions in binary form must reproduce the above copyright 14275072Semaste * notice, this list of conditions and the following disclaimer in the 15341825Sdim * documentation and/or other materials provided with the distribution. 16275072Semaste * 3. All advertising materials mentioning features or use of this software 17275072Semaste * must display the following acknowledgement: 18275072Semaste * This product includes software developed by TooLs GmbH. 19275072Semaste * 4. The name of TooLs GmbH may not be used to endorse or promote products 20275072Semaste * derived from this software without specific prior written permission. 21314564Sdim * 22314564Sdim * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23275072Semaste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24275072Semaste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25275072Semaste * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26341825Sdim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27275072Semaste * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28275072Semaste * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29341825Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30341825Sdim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31341825Sdim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32314564Sdim */ 33275072Semaste/*- 34314564Sdim * Copyright (C) 2000 Benno Rice. 35314564Sdim * All rights reserved. 36314564Sdim * 37314564Sdim * Redistribution and use in source and binary forms, with or without 38314564Sdim * modification, are permitted provided that the following conditions 39314564Sdim * are met: 40314564Sdim * 1. Redistributions of source code must retain the above copyright 41314564Sdim * notice, this list of conditions and the following disclaimer. 42314564Sdim * 2. Redistributions in binary form must reproduce the above copyright 43314564Sdim * notice, this list of conditions and the following disclaimer in the 44275072Semaste * documentation and/or other materials provided with the distribution. 45314564Sdim * 46314564Sdim * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47314564Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48314564Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49275072Semaste * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50275072Semaste * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51314564Sdim * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52314564Sdim * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53314564Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54314564Sdim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55314564Sdim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56314564Sdim */ 57314564Sdim 58314564Sdim#include <sys/cdefs.h> 59314564Sdim__FBSDID("$FreeBSD: head/sys/dev/ofw/openfirm.c 256938 2013-10-22 21:20:05Z nwhitehorn $"); 60275072Semaste 61314564Sdim#include "opt_platform.h" 62275072Semaste 63314564Sdim#include <sys/param.h> 64314564Sdim#include <sys/kernel.h> 65314564Sdim#include <sys/malloc.h> 66314564Sdim#include <sys/systm.h> 67314564Sdim#include <sys/endian.h> 68314564Sdim 69314564Sdim#include <machine/stdarg.h> 70314564Sdim 71314564Sdim#include <dev/ofw/ofwvar.h> 72314564Sdim#include <dev/ofw/openfirm.h> 73275072Semaste 74314564Sdim#include "ofw_if.h" 75314564Sdim 76314564Sdimstatic void OF_putchar(int c, void *arg); 77275072Semaste 78314564SdimMALLOC_DEFINE(M_OFWPROP, "openfirm", "Open Firmware properties"); 79314564Sdim 80314564Sdimstatic ihandle_t stdout; 81275072Semaste 82314564Sdimstatic ofw_def_t *ofw_def_impl = NULL; 83314564Sdimstatic ofw_t ofw_obj; 84275072Semastestatic struct ofw_kobj ofw_kernel_obj; 85314564Sdimstatic struct kobj_ops ofw_kernel_kops; 86314564Sdim 87275072Semaste/* 88314564Sdim * OFW install routines. Highest priority wins, equal priority also 89314564Sdim * overrides allowing last-set to win. 90314564Sdim */ 91275072SemasteSET_DECLARE(ofw_set, ofw_def_t); 92314564Sdim 93314564Sdimboolean_t 94314564SdimOF_install(char *name, int prio) 95314564Sdim{ 96314564Sdim ofw_def_t *ofwp, **ofwpp; 97314564Sdim static int curr_prio = 0; 98314564Sdim 99314564Sdim /* 100275072Semaste * Try and locate the OFW kobj corresponding to the name. 101314564Sdim */ 102314564Sdim SET_FOREACH(ofwpp, ofw_set) { 103314564Sdim ofwp = *ofwpp; 104314564Sdim 105275072Semaste if (ofwp->name && 106314564Sdim !strcmp(ofwp->name, name) && 107314564Sdim prio >= curr_prio) { 108275072Semaste curr_prio = prio; 109314564Sdim ofw_def_impl = ofwp; 110314564Sdim return (TRUE); 111314564Sdim } 112275072Semaste } 113314564Sdim 114314564Sdim return (FALSE); 115275072Semaste} 116314564Sdim 117314564Sdim/* Initializer */ 118314564Sdimint 119275072SemasteOF_init(void *cookie) 120314564Sdim{ 121314564Sdim phandle_t chosen; 122314564Sdim int rv; 123275072Semaste 124314564Sdim if (ofw_def_impl == NULL) 125275072Semaste return (-1); 126341825Sdim 127314564Sdim ofw_obj = &ofw_kernel_obj; 128314564Sdim /* 129314564Sdim * Take care of compiling the selected class, and 130314564Sdim * then statically initialize the OFW object. 131314564Sdim */ 132314564Sdim kobj_class_compile_static(ofw_def_impl, &ofw_kernel_kops); 133314564Sdim kobj_init_static((kobj_t)ofw_obj, ofw_def_impl); 134275072Semaste 135341825Sdim rv = OFW_INIT(ofw_obj, cookie); 136341825Sdim 137314564Sdim if ((chosen = OF_finddevice("/chosen")) != -1) 138314564Sdim if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) 139314564Sdim stdout = -1; 140314564Sdim 141314564Sdim return (rv); 142314564Sdim} 143314564Sdim 144314564Sdimstatic void 145314564SdimOF_putchar(int c, void *arg __unused) 146314564Sdim{ 147314564Sdim char cbuf; 148275072Semaste 149314564Sdim if (c == '\n') { 150275072Semaste cbuf = '\r'; 151314564Sdim OF_write(stdout, &cbuf, 1); 152275072Semaste } 153314564Sdim 154314564Sdim cbuf = c; 155314564Sdim OF_write(stdout, &cbuf, 1); 156314564Sdim} 157314564Sdim 158314564Sdimvoid 159314564SdimOF_printf(const char *fmt, ...) 160314564Sdim{ 161314564Sdim va_list va; 162314564Sdim 163314564Sdim va_start(va, fmt); 164275072Semaste (void)kvprintf(fmt, OF_putchar, NULL, 10, va); 165314564Sdim va_end(va); 166275072Semaste} 167275072Semaste 168314564Sdim/* 169275072Semaste * Generic functions 170314564Sdim */ 171314564Sdim 172314564Sdim/* Test to see if a service exists. */ 173275072Semasteint 174314564SdimOF_test(const char *name) 175314564Sdim{ 176314564Sdim 177314564Sdim if (ofw_def_impl == NULL) 178275072Semaste return (-1); 179314564Sdim 180314564Sdim return (OFW_TEST(ofw_obj, name)); 181314564Sdim} 182314564Sdim 183314564Sdimint 184275072SemasteOF_interpret(const char *cmd, int nreturns, ...) 185314564Sdim{ 186275072Semaste va_list ap; 187314564Sdim cell_t slots[16]; 188314564Sdim int i = 0; 189275072Semaste int status; 190314564Sdim 191314564Sdim if (ofw_def_impl == NULL) 192275072Semaste return (-1); 193314564Sdim 194314564Sdim status = OFW_INTERPRET(ofw_obj, cmd, nreturns, slots); 195314564Sdim if (status == -1) 196275072Semaste return (status); 197314564Sdim 198314564Sdim va_start(ap, nreturns); 199275072Semaste while (i < nreturns) 200341825Sdim *va_arg(ap, cell_t *) = slots[i++]; 201341825Sdim va_end(ap); 202314564Sdim 203275072Semaste return (status); 204314564Sdim} 205314564Sdim 206314564Sdim/* 207275072Semaste * Device tree functions 208314564Sdim */ 209314564Sdim 210275072Semaste/* Return the next sibling of this node or 0. */ 211314564Sdimphandle_t 212314564SdimOF_peer(phandle_t node) 213314564Sdim{ 214314564Sdim 215314564Sdim if (ofw_def_impl == NULL) 216275072Semaste return (0); 217314564Sdim 218314564Sdim return (OFW_PEER(ofw_obj, node)); 219314564Sdim} 220314564Sdim 221314564Sdim/* Return the first child of this node or 0. */ 222275072Semastephandle_t 223314564SdimOF_child(phandle_t node) 224314564Sdim{ 225314564Sdim 226275072Semaste if (ofw_def_impl == NULL) 227314564Sdim return (0); 228314564Sdim 229275072Semaste return (OFW_CHILD(ofw_obj, node)); 230314564Sdim} 231314564Sdim 232314564Sdim/* Return the parent of this node or 0. */ 233275072Semastephandle_t 234314564SdimOF_parent(phandle_t node) 235275072Semaste{ 236314564Sdim 237275072Semaste if (ofw_def_impl == NULL) 238314564Sdim return (0); 239314564Sdim 240314564Sdim return (OFW_PARENT(ofw_obj, node)); 241275072Semaste} 242314564Sdim 243275072Semaste/* Return the package handle that corresponds to an instance handle. */ 244314564Sdimphandle_t 245275072SemasteOF_instance_to_package(ihandle_t instance) 246275072Semaste{ 247275072Semaste 248 if (ofw_def_impl == NULL) 249 return (-1); 250 251 return (OFW_INSTANCE_TO_PACKAGE(ofw_obj, instance)); 252} 253 254/* Get the length of a property of a package. */ 255ssize_t 256OF_getproplen(phandle_t package, const char *propname) 257{ 258 259 if (ofw_def_impl == NULL) 260 return (-1); 261 262 return (OFW_GETPROPLEN(ofw_obj, package, propname)); 263} 264 265/* Check existence of a property of a package. */ 266int 267OF_hasprop(phandle_t package, const char *propname) 268{ 269 270 return (OF_getproplen(package, propname) >= 0 ? 1 : 0); 271} 272 273/* Get the value of a property of a package. */ 274ssize_t 275OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen) 276{ 277 278 if (ofw_def_impl == NULL) 279 return (-1); 280 281 return (OFW_GETPROP(ofw_obj, package, propname, buf, buflen)); 282} 283 284ssize_t 285OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len) 286{ 287 ssize_t retval; 288 int i; 289 290 KASSERT(len % 4 == 0, "Need a multiple of 4 bytes"); 291 292 retval = OF_getprop(node, propname, buf, len); 293 for (i = 0; i < len/4; i++) 294 buf[i] = be32toh(buf[i]); 295 296 return (retval); 297} 298 299/* 300 * Recursively search the node and its parent for the given property, working 301 * downward from the node to the device tree root. Returns the value of the 302 * first match. 303 */ 304ssize_t 305OF_searchprop(phandle_t node, const char *propname, void *buf, size_t len) 306{ 307 ssize_t rv; 308 309 for (; node != 0; node = OF_parent(node)) 310 if ((rv = OF_getprop(node, propname, buf, len)) != -1) 311 return (rv); 312 return (-1); 313} 314 315ssize_t 316OF_searchencprop(phandle_t node, const char *propname, void *buf, size_t len) 317{ 318 ssize_t rv; 319 320 for (; node != 0; node = OF_parent(node)) 321 if ((rv = OF_getencprop(node, propname, buf, len)) != -1) 322 return (rv); 323 return (-1); 324} 325 326/* 327 * Store the value of a property of a package into newly allocated memory 328 * (using the M_OFWPROP malloc pool and M_WAITOK). elsz is the size of a 329 * single element, the number of elements is return in number. 330 */ 331ssize_t 332OF_getprop_alloc(phandle_t package, const char *propname, int elsz, void **buf) 333{ 334 int len; 335 336 *buf = NULL; 337 if ((len = OF_getproplen(package, propname)) == -1 || 338 len % elsz != 0) 339 return (-1); 340 341 *buf = malloc(len, M_OFWPROP, M_WAITOK); 342 if (OF_getprop(package, propname, *buf, len) == -1) { 343 free(*buf, M_OFWPROP); 344 *buf = NULL; 345 return (-1); 346 } 347 return (len / elsz); 348} 349 350ssize_t 351OF_getencprop_alloc(phandle_t package, const char *name, int elsz, void **buf) 352{ 353 ssize_t retval; 354 pcell_t *cell; 355 int i; 356 357 KASSERT(elsz % 4 == 0, "Need a multiple of 4 bytes"); 358 359 retval = OF_getprop_alloc(package, name, elsz, buf); 360 if (retval == -1) 361 return (retval); 362 363 cell = *buf; 364 for (i = 0; i < retval*elsz/4; i++) 365 cell[i] = be32toh(cell[i]); 366 367 return (retval); 368} 369 370/* Get the next property of a package. */ 371int 372OF_nextprop(phandle_t package, const char *previous, char *buf, size_t size) 373{ 374 375 if (ofw_def_impl == NULL) 376 return (-1); 377 378 return (OFW_NEXTPROP(ofw_obj, package, previous, buf, size)); 379} 380 381/* Set the value of a property of a package. */ 382int 383OF_setprop(phandle_t package, const char *propname, const void *buf, size_t len) 384{ 385 386 if (ofw_def_impl == NULL) 387 return (-1); 388 389 return (OFW_SETPROP(ofw_obj, package, propname, buf,len)); 390} 391 392/* Convert a device specifier to a fully qualified pathname. */ 393ssize_t 394OF_canon(const char *device, char *buf, size_t len) 395{ 396 397 if (ofw_def_impl == NULL) 398 return (-1); 399 400 return (OFW_CANON(ofw_obj, device, buf, len)); 401} 402 403/* Return a package handle for the specified device. */ 404phandle_t 405OF_finddevice(const char *device) 406{ 407 408 if (ofw_def_impl == NULL) 409 return (-1); 410 411 return (OFW_FINDDEVICE(ofw_obj, device)); 412} 413 414/* Return the fully qualified pathname corresponding to an instance. */ 415ssize_t 416OF_instance_to_path(ihandle_t instance, char *buf, size_t len) 417{ 418 419 if (ofw_def_impl == NULL) 420 return (-1); 421 422 return (OFW_INSTANCE_TO_PATH(ofw_obj, instance, buf, len)); 423} 424 425/* Return the fully qualified pathname corresponding to a package. */ 426ssize_t 427OF_package_to_path(phandle_t package, char *buf, size_t len) 428{ 429 430 if (ofw_def_impl == NULL) 431 return (-1); 432 433 return (OFW_PACKAGE_TO_PATH(ofw_obj, package, buf, len)); 434} 435 436/* Look up effective phandle (see FDT/PAPR spec) */ 437static phandle_t 438OF_child_xref_phandle(phandle_t parent, phandle_t xref) 439{ 440 phandle_t child, rxref; 441 442 /* 443 * Recursively descend from parent, looking for a node with a property 444 * named either "phandle", "ibm,phandle", or "linux,phandle" that 445 * matches the xref we are looking for. 446 */ 447 448 for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 449 rxref = OF_child_xref_phandle(child, xref); 450 if (rxref != -1) 451 return (rxref); 452 453 if (OF_getprop(child, "phandle", &rxref, sizeof(rxref)) == -1 && 454 OF_getprop(child, "ibm,phandle", &rxref, 455 sizeof(rxref)) == -1 && OF_getprop(child, 456 "linux,phandle", &rxref, sizeof(rxref)) == -1) 457 continue; 458 459 if (rxref == xref) 460 return (child); 461 } 462 463 return (-1); 464} 465 466phandle_t 467OF_xref_phandle(phandle_t xref) 468{ 469 phandle_t node; 470 471 node = OF_child_xref_phandle(OF_peer(0), xref); 472 if (node == -1) 473 return (xref); 474 475 return (node); 476} 477 478/* Call the method in the scope of a given instance. */ 479int 480OF_call_method(const char *method, ihandle_t instance, int nargs, int nreturns, 481 ...) 482{ 483 va_list ap; 484 cell_t args_n_results[12]; 485 int n, status; 486 487 if (nargs > 6 || ofw_def_impl == NULL) 488 return (-1); 489 va_start(ap, nreturns); 490 for (n = 0; n < nargs; n++) 491 args_n_results[n] = va_arg(ap, cell_t); 492 493 status = OFW_CALL_METHOD(ofw_obj, instance, method, nargs, nreturns, 494 args_n_results); 495 if (status != 0) 496 return (status); 497 498 for (; n < nargs + nreturns; n++) 499 *va_arg(ap, cell_t *) = args_n_results[n]; 500 va_end(ap); 501 return (0); 502} 503 504/* 505 * Device I/O functions 506 */ 507 508/* Open an instance for a device. */ 509ihandle_t 510OF_open(const char *device) 511{ 512 513 if (ofw_def_impl == NULL) 514 return (0); 515 516 return (OFW_OPEN(ofw_obj, device)); 517} 518 519/* Close an instance. */ 520void 521OF_close(ihandle_t instance) 522{ 523 524 if (ofw_def_impl == NULL) 525 return; 526 527 OFW_CLOSE(ofw_obj, instance); 528} 529 530/* Read from an instance. */ 531ssize_t 532OF_read(ihandle_t instance, void *addr, size_t len) 533{ 534 535 if (ofw_def_impl == NULL) 536 return (-1); 537 538 return (OFW_READ(ofw_obj, instance, addr, len)); 539} 540 541/* Write to an instance. */ 542ssize_t 543OF_write(ihandle_t instance, const void *addr, size_t len) 544{ 545 546 if (ofw_def_impl == NULL) 547 return (-1); 548 549 return (OFW_WRITE(ofw_obj, instance, addr, len)); 550} 551 552/* Seek to a position. */ 553int 554OF_seek(ihandle_t instance, uint64_t pos) 555{ 556 557 if (ofw_def_impl == NULL) 558 return (-1); 559 560 return (OFW_SEEK(ofw_obj, instance, pos)); 561} 562 563/* 564 * Memory functions 565 */ 566 567/* Claim an area of memory. */ 568void * 569OF_claim(void *virt, size_t size, u_int align) 570{ 571 572 if (ofw_def_impl == NULL) 573 return ((void *)-1); 574 575 return (OFW_CLAIM(ofw_obj, virt, size, align)); 576} 577 578/* Release an area of memory. */ 579void 580OF_release(void *virt, size_t size) 581{ 582 583 if (ofw_def_impl == NULL) 584 return; 585 586 OFW_RELEASE(ofw_obj, virt, size); 587} 588 589/* 590 * Control transfer functions 591 */ 592 593/* Suspend and drop back to the Open Firmware interface. */ 594void 595OF_enter() 596{ 597 598 if (ofw_def_impl == NULL) 599 return; 600 601 OFW_ENTER(ofw_obj); 602} 603 604/* Shut down and drop back to the Open Firmware interface. */ 605void 606OF_exit() 607{ 608 609 if (ofw_def_impl == NULL) 610 panic("OF_exit: Open Firmware not available"); 611 612 /* Should not return */ 613 OFW_EXIT(ofw_obj); 614 615 for (;;) /* just in case */ 616 ; 617} 618