1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier:BSD-4-Clause AND BSD-2-Clause-FreeBSD 5 * 6 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 7 * Copyright (C) 1995, 1996 TooLs GmbH. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /*- 36 * Copyright (C) 2000 Benno Rice. 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 51 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 53 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 54 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 56 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 57 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 58 */ 59 60 #include <sys/cdefs.h> 61 __FBSDID("$FreeBSD$"); 62 63 #include <sys/param.h> 64 #include <sys/kernel.h> 65 #include <sys/lock.h> 66 #include <sys/mutex.h> 67 #include <sys/systm.h> 68 69 #include <vm/vm.h> 70 #include <vm/vm_page.h> 71 #include <vm/pmap.h> 72 73 #include <machine/bus.h> 74 #include <machine/md_var.h> 75 #include <machine/ofw_machdep.h> 76 #include <machine/stdarg.h> 77 78 #include <dev/ofw/openfirm.h> 79 #include <dev/ofw/ofwvar.h> 80 #include "ofw_if.h" 81 82 static int ofw_real_init(ofw_t, void *openfirm); 83 static int ofw_real_test(ofw_t, const char *name); 84 static phandle_t ofw_real_peer(ofw_t, phandle_t node); 85 static phandle_t ofw_real_child(ofw_t, phandle_t node); 86 static phandle_t ofw_real_parent(ofw_t, phandle_t node); 87 static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance); 88 static ssize_t ofw_real_getproplen(ofw_t, phandle_t package, 89 const char *propname); 90 static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname, 91 void *buf, size_t buflen); 92 static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous, 93 char *buf, size_t); 94 static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname, 95 const void *buf, size_t len); 96 static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len); 97 static phandle_t ofw_real_finddevice(ofw_t, const char *device); 98 static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf, 99 size_t len); 100 static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf, 101 size_t len); 102 static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method, 103 int nargs, int nreturns, cell_t *args_and_returns); 104 static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, 105 cell_t *returns); 106 static ihandle_t ofw_real_open(ofw_t, const char *device); 107 static void ofw_real_close(ofw_t, ihandle_t instance); 108 static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len); 109 static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr, 110 size_t len); 111 static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos); 112 static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align); 113 static void ofw_real_release(ofw_t, void *virt, size_t size); 114 static void ofw_real_enter(ofw_t); 115 static void ofw_real_exit(ofw_t); 116 117 static ofw_method_t ofw_real_methods[] = { 118 OFWMETHOD(ofw_init, ofw_real_init), 119 OFWMETHOD(ofw_peer, ofw_real_peer), 120 OFWMETHOD(ofw_child, ofw_real_child), 121 OFWMETHOD(ofw_parent, ofw_real_parent), 122 OFWMETHOD(ofw_instance_to_package, ofw_real_instance_to_package), 123 OFWMETHOD(ofw_getproplen, ofw_real_getproplen), 124 OFWMETHOD(ofw_getprop, ofw_real_getprop), 125 OFWMETHOD(ofw_nextprop, ofw_real_nextprop), 126 OFWMETHOD(ofw_setprop, ofw_real_setprop), 127 OFWMETHOD(ofw_canon, ofw_real_canon), 128 OFWMETHOD(ofw_finddevice, ofw_real_finddevice), 129 OFWMETHOD(ofw_instance_to_path, ofw_real_instance_to_path), 130 OFWMETHOD(ofw_package_to_path, ofw_real_package_to_path), 131 132 OFWMETHOD(ofw_test, ofw_real_test), 133 OFWMETHOD(ofw_call_method, ofw_real_call_method), 134 OFWMETHOD(ofw_interpret, ofw_real_interpret), 135 OFWMETHOD(ofw_open, ofw_real_open), 136 OFWMETHOD(ofw_close, ofw_real_close), 137 OFWMETHOD(ofw_read, ofw_real_read), 138 OFWMETHOD(ofw_write, ofw_real_write), 139 OFWMETHOD(ofw_seek, ofw_real_seek), 140 OFWMETHOD(ofw_claim, ofw_real_claim), 141 OFWMETHOD(ofw_release, ofw_real_release), 142 OFWMETHOD(ofw_enter, ofw_real_enter), 143 OFWMETHOD(ofw_exit, ofw_real_exit), 144 { 0, 0 } 145 }; 146 147 static ofw_def_t ofw_real = { 148 OFW_STD_REAL, 149 ofw_real_methods, 150 0 151 }; 152 OFW_DEF(ofw_real); 153 154 static ofw_def_t ofw_32bit = { 155 OFW_STD_32BIT, 156 ofw_real_methods, 157 0 158 }; 159 OFW_DEF(ofw_32bit); 160 161 static MALLOC_DEFINE(M_OFWREAL, "ofwreal", 162 "Open Firmware Real Mode Bounce Page"); 163 164 static int (*openfirmware)(void *); 165 166 static vm_offset_t of_bounce_phys; 167 static caddr_t of_bounce_virt; 168 static off_t of_bounce_offset; 169 static size_t of_bounce_size; 170 171 /* 172 * To be able to use OFW console on PPC, that requires real mode OFW, 173 * the mutex that guards the mapping/unmapping of virtual to physical 174 * buffers (of_real_mtx) must be of SPIN type. This is needed because 175 * kernel console first locks a SPIN mutex before calling OFW real. 176 * By default, of_real_mtx is a sleepable mutex. To make it of SPIN 177 * type, use the following tunnable: 178 * machdep.ofw.mtx_spin=1 179 * 180 * Besides that, a few more tunables are needed to select and use the 181 * OFW console with real mode OFW. 182 * 183 * In order to disable the use of OFW FrameBuffer and fallback to the 184 * OFW console, use: 185 * hw.ofwfb.disable=1 186 * 187 * To disable the use of FDT (that doesn't support OFW read/write methods) 188 * and use real OFW instead, unset the following loader variable: 189 * unset usefdt 190 * 191 * OFW is put in quiesce state in early kernel boot, which usually disables 192 * OFW read/write capabilities (in QEMU write continue to work, but 193 * read doesn't). To avoid OFW quiesce, use: 194 * debug.quiesce_ofw=0 195 * 196 * Note that disabling OFW quiesce can cause conflicts between kernel and 197 * OFW trying to control the same hardware. Thus, it must be used with care. 198 * Some conflicts can be avoided by disabling kernel drivers with hints. 199 * For instance, to disable a xhci controller and an USB keyboard connected 200 * to it, that may be already being used for input by OFW, use: 201 * hint.xhci.0.disabled=1 202 */ 203 204 static struct mtx of_bounce_mtx; 205 static struct mtx of_spin_mtx; 206 static struct mtx *of_real_mtx; 207 static void (*of_mtx_lock)(void); 208 static void (*of_mtx_unlock)(void); 209 210 extern int ofw_real_mode; 211 212 /* 213 * After the VM is up, allocate a wired, low memory bounce page. 214 */ 215 216 static void ofw_real_bounce_alloc(void *); 217 218 SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY, 219 ofw_real_bounce_alloc, NULL); 220 221 static void 222 ofw_real_mtx_lock_spin(void) 223 { 224 mtx_lock_spin(of_real_mtx); 225 } 226 227 static void 228 ofw_real_mtx_lock(void) 229 { 230 mtx_lock(of_real_mtx); 231 } 232 233 static void 234 ofw_real_mtx_unlock_spin(void) 235 { 236 mtx_unlock_spin(of_real_mtx); 237 } 238 239 static void 240 ofw_real_mtx_unlock(void) 241 { 242 mtx_unlock(of_real_mtx); 243 } 244 245 static void 246 ofw_real_start(void) 247 { 248 (*of_mtx_lock)(); 249 of_bounce_offset = 0; 250 } 251 252 static void 253 ofw_real_stop(void) 254 { 255 (*of_mtx_unlock)(); 256 } 257 258 static void 259 ofw_real_bounce_alloc(void *junk) 260 { 261 caddr_t temp; 262 263 /* 264 * Check that ofw_real is actually in use before allocating wads 265 * of memory. Do this by checking if our mutex has been set up. 266 */ 267 if (!mtx_initialized(&of_bounce_mtx)) 268 return; 269 270 /* 271 * Allocate a page of contiguous, wired physical memory that can 272 * fit into a 32-bit address space and accessed from real mode. 273 */ 274 temp = contigmalloc(4 * PAGE_SIZE, M_OFWREAL, 0, 0, 275 ulmin(platform_real_maxaddr(), BUS_SPACE_MAXADDR_32BIT), PAGE_SIZE, 276 4 * PAGE_SIZE); 277 if (temp == NULL) 278 panic("%s: Not able to allocated contiguous memory\n", __func__); 279 280 mtx_lock(&of_bounce_mtx); 281 282 of_bounce_virt = temp; 283 284 of_bounce_phys = vtophys(of_bounce_virt); 285 of_bounce_size = 4 * PAGE_SIZE; 286 287 /* 288 * For virtual-mode OF, direct map this physical address so that 289 * we have a 32-bit virtual address to give OF. 290 */ 291 292 if (!ofw_real_mode && (!hw_direct_map || DMAP_BASE_ADDRESS != 0)) 293 pmap_kenter(of_bounce_phys, of_bounce_phys); 294 295 mtx_unlock(&of_bounce_mtx); 296 } 297 298 static cell_t 299 ofw_real_map(const void *buf, size_t len) 300 { 301 static char emergency_buffer[255]; 302 cell_t phys; 303 304 mtx_assert(of_real_mtx, MA_OWNED); 305 306 if (of_bounce_virt == NULL) { 307 /* 308 * If we haven't set up the MMU, then buf is guaranteed 309 * to be accessible to OF, because the only memory we 310 * can use right now is memory mapped by firmware. 311 */ 312 if (!pmap_bootstrapped) 313 return (cell_t)((uintptr_t)buf & ~DMAP_BASE_ADDRESS); 314 315 /* 316 * XXX: It is possible for us to get called before the VM has 317 * come online, but after the MMU is up. We don't have the 318 * bounce buffer yet, but can no longer presume a 1:1 mapping. 319 * Copy into the emergency buffer, and reset at the end. 320 */ 321 of_bounce_virt = emergency_buffer; 322 of_bounce_phys = (vm_offset_t)of_bounce_virt & 323 ~DMAP_BASE_ADDRESS; 324 of_bounce_size = sizeof(emergency_buffer); 325 } 326 327 /* 328 * Make sure the bounce page offset satisfies any reasonable 329 * alignment constraint. 330 */ 331 of_bounce_offset += sizeof(register_t) - 332 (of_bounce_offset % sizeof(register_t)); 333 334 if (of_bounce_offset + len > of_bounce_size) { 335 panic("Oversize Open Firmware call!"); 336 return 0; 337 } 338 339 if (buf != NULL) 340 memcpy(of_bounce_virt + of_bounce_offset, buf, len); 341 else 342 return (0); 343 344 phys = of_bounce_phys + of_bounce_offset; 345 346 of_bounce_offset += len; 347 348 return (phys); 349 } 350 351 static void 352 ofw_real_unmap(cell_t physaddr, void *buf, size_t len) 353 { 354 mtx_assert(of_real_mtx, MA_OWNED); 355 356 if (of_bounce_virt == NULL) 357 return; 358 359 if (physaddr == 0) 360 return; 361 362 memcpy(buf,of_bounce_virt + (physaddr - of_bounce_phys),len); 363 } 364 365 /* Initialiser */ 366 367 static int 368 ofw_real_init(ofw_t ofw, void *openfirm) 369 { 370 int mtx_spin; 371 372 openfirmware = (int (*)(void *))openfirm; 373 mtx_init(&of_bounce_mtx, "OF Bounce Page", NULL, MTX_DEF); 374 375 mtx_spin = 0; 376 TUNABLE_INT_FETCH("machdep.ofw.mtx_spin", &mtx_spin); 377 if (mtx_spin) { 378 mtx_init(&of_spin_mtx, "OF Real", NULL, MTX_SPIN); 379 of_real_mtx = &of_spin_mtx; 380 of_mtx_lock = ofw_real_mtx_lock_spin; 381 of_mtx_unlock = ofw_real_mtx_unlock_spin; 382 } else { 383 of_real_mtx = &of_bounce_mtx; 384 of_mtx_lock = ofw_real_mtx_lock; 385 of_mtx_unlock = ofw_real_mtx_unlock; 386 } 387 388 of_bounce_virt = NULL; 389 return (0); 390 } 391 392 /* 393 * Generic functions 394 */ 395 396 /* Test to see if a service exists. */ 397 static int 398 ofw_real_test(ofw_t ofw, const char *name) 399 { 400 vm_offset_t argsptr; 401 struct { 402 cell_t name; 403 cell_t nargs; 404 cell_t nreturns; 405 cell_t service; 406 cell_t missing; 407 } args; 408 409 args.name = (cell_t)(uintptr_t)"test"; 410 args.nargs = 1; 411 args.nreturns = 1; 412 413 ofw_real_start(); 414 415 args.service = ofw_real_map(name, strlen(name) + 1); 416 argsptr = ofw_real_map(&args, sizeof(args)); 417 if (args.service == 0 || openfirmware((void *)argsptr) == -1) { 418 ofw_real_stop(); 419 return (-1); 420 } 421 ofw_real_unmap(argsptr, &args, sizeof(args)); 422 ofw_real_stop(); 423 return (args.missing); 424 } 425 426 /* 427 * Device tree functions 428 */ 429 430 /* Return the next sibling of this node or 0. */ 431 static phandle_t 432 ofw_real_peer(ofw_t ofw, phandle_t node) 433 { 434 vm_offset_t argsptr; 435 struct { 436 cell_t name; 437 cell_t nargs; 438 cell_t nreturns; 439 cell_t node; 440 cell_t next; 441 } args; 442 443 args.name = (cell_t)(uintptr_t)"peer"; 444 args.nargs = 1; 445 args.nreturns = 1; 446 447 args.node = node; 448 ofw_real_start(); 449 argsptr = ofw_real_map(&args, sizeof(args)); 450 if (openfirmware((void *)argsptr) == -1) { 451 ofw_real_stop(); 452 return (0); 453 } 454 ofw_real_unmap(argsptr, &args, sizeof(args)); 455 ofw_real_stop(); 456 return (args.next); 457 } 458 459 /* Return the first child of this node or 0. */ 460 static phandle_t 461 ofw_real_child(ofw_t ofw, phandle_t node) 462 { 463 vm_offset_t argsptr; 464 struct { 465 cell_t name; 466 cell_t nargs; 467 cell_t nreturns; 468 cell_t node; 469 cell_t child; 470 } args; 471 472 args.name = (cell_t)(uintptr_t)"child"; 473 args.nargs = 1; 474 args.nreturns = 1; 475 476 args.node = node; 477 ofw_real_start(); 478 argsptr = ofw_real_map(&args, sizeof(args)); 479 if (openfirmware((void *)argsptr) == -1) { 480 ofw_real_stop(); 481 return (0); 482 } 483 ofw_real_unmap(argsptr, &args, sizeof(args)); 484 ofw_real_stop(); 485 return (args.child); 486 } 487 488 /* Return the parent of this node or 0. */ 489 static phandle_t 490 ofw_real_parent(ofw_t ofw, phandle_t node) 491 { 492 vm_offset_t argsptr; 493 struct { 494 cell_t name; 495 cell_t nargs; 496 cell_t nreturns; 497 cell_t node; 498 cell_t parent; 499 } args; 500 501 args.name = (cell_t)(uintptr_t)"parent"; 502 args.nargs = 1; 503 args.nreturns = 1; 504 505 args.node = node; 506 ofw_real_start(); 507 argsptr = ofw_real_map(&args, sizeof(args)); 508 if (openfirmware((void *)argsptr) == -1) { 509 ofw_real_stop(); 510 return (0); 511 } 512 ofw_real_unmap(argsptr, &args, sizeof(args)); 513 ofw_real_stop(); 514 return (args.parent); 515 } 516 517 /* Return the package handle that corresponds to an instance handle. */ 518 static phandle_t 519 ofw_real_instance_to_package(ofw_t ofw, ihandle_t instance) 520 { 521 vm_offset_t argsptr; 522 struct { 523 cell_t name; 524 cell_t nargs; 525 cell_t nreturns; 526 cell_t instance; 527 cell_t package; 528 } args; 529 530 args.name = (cell_t)(uintptr_t)"instance-to-package"; 531 args.nargs = 1; 532 args.nreturns = 1; 533 534 args.instance = instance; 535 ofw_real_start(); 536 argsptr = ofw_real_map(&args, sizeof(args)); 537 if (openfirmware((void *)argsptr) == -1) { 538 ofw_real_stop(); 539 return (-1); 540 } 541 ofw_real_unmap(argsptr, &args, sizeof(args)); 542 ofw_real_stop(); 543 return (args.package); 544 } 545 546 /* Get the length of a property of a package. */ 547 static ssize_t 548 ofw_real_getproplen(ofw_t ofw, phandle_t package, const char *propname) 549 { 550 vm_offset_t argsptr; 551 struct { 552 cell_t name; 553 cell_t nargs; 554 cell_t nreturns; 555 cell_t package; 556 cell_t propname; 557 int32_t proplen; 558 } args; 559 560 args.name = (cell_t)(uintptr_t)"getproplen"; 561 args.nargs = 2; 562 args.nreturns = 1; 563 564 ofw_real_start(); 565 566 args.package = package; 567 args.propname = ofw_real_map(propname, strlen(propname) + 1); 568 argsptr = ofw_real_map(&args, sizeof(args)); 569 if (args.propname == 0 || openfirmware((void *)argsptr) == -1) { 570 ofw_real_stop(); 571 return (-1); 572 } 573 ofw_real_unmap(argsptr, &args, sizeof(args)); 574 ofw_real_stop(); 575 return (args.proplen); 576 } 577 578 /* Get the value of a property of a package. */ 579 static ssize_t 580 ofw_real_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, 581 size_t buflen) 582 { 583 vm_offset_t argsptr; 584 struct { 585 cell_t name; 586 cell_t nargs; 587 cell_t nreturns; 588 cell_t package; 589 cell_t propname; 590 cell_t buf; 591 cell_t buflen; 592 int32_t size; 593 } args; 594 595 args.name = (cell_t)(uintptr_t)"getprop"; 596 args.nargs = 4; 597 args.nreturns = 1; 598 599 ofw_real_start(); 600 601 args.package = package; 602 args.propname = ofw_real_map(propname, strlen(propname) + 1); 603 args.buf = ofw_real_map(buf, buflen); 604 args.buflen = buflen; 605 argsptr = ofw_real_map(&args, sizeof(args)); 606 if (args.propname == 0 || args.buf == 0 || 607 openfirmware((void *)argsptr) == -1) { 608 ofw_real_stop(); 609 return (-1); 610 } 611 ofw_real_unmap(argsptr, &args, sizeof(args)); 612 ofw_real_unmap(args.buf, buf, buflen); 613 614 ofw_real_stop(); 615 return (args.size); 616 } 617 618 /* Get the next property of a package. */ 619 static int 620 ofw_real_nextprop(ofw_t ofw, phandle_t package, const char *previous, 621 char *buf, size_t size) 622 { 623 vm_offset_t argsptr; 624 struct { 625 cell_t name; 626 cell_t nargs; 627 cell_t nreturns; 628 cell_t package; 629 cell_t previous; 630 cell_t buf; 631 cell_t flag; 632 } args; 633 634 args.name = (cell_t)(uintptr_t)"nextprop"; 635 args.nargs = 3; 636 args.nreturns = 1; 637 638 ofw_real_start(); 639 640 args.package = package; 641 args.previous = ofw_real_map(previous, (previous != NULL) ? (strlen(previous) + 1) : 0); 642 args.buf = ofw_real_map(buf, size); 643 argsptr = ofw_real_map(&args, sizeof(args)); 644 if (args.buf == 0 || openfirmware((void *)argsptr) == -1) { 645 ofw_real_stop(); 646 return (-1); 647 } 648 ofw_real_unmap(argsptr, &args, sizeof(args)); 649 ofw_real_unmap(args.buf, buf, size); 650 651 ofw_real_stop(); 652 return (args.flag); 653 } 654 655 /* Set the value of a property of a package. */ 656 /* XXX Has a bug on FirePower */ 657 static int 658 ofw_real_setprop(ofw_t ofw, phandle_t package, const char *propname, 659 const void *buf, size_t len) 660 { 661 vm_offset_t argsptr; 662 struct { 663 cell_t name; 664 cell_t nargs; 665 cell_t nreturns; 666 cell_t package; 667 cell_t propname; 668 cell_t buf; 669 cell_t len; 670 cell_t size; 671 } args; 672 673 args.name = (cell_t)(uintptr_t)"setprop"; 674 args.nargs = 4; 675 args.nreturns = 1; 676 677 ofw_real_start(); 678 679 args.package = package; 680 args.propname = ofw_real_map(propname, strlen(propname) + 1); 681 args.buf = ofw_real_map(buf, len); 682 args.len = len; 683 argsptr = ofw_real_map(&args, sizeof(args)); 684 if (args.propname == 0 || args.buf == 0 || 685 openfirmware((void *)argsptr) == -1) { 686 ofw_real_stop(); 687 return (-1); 688 } 689 ofw_real_unmap(argsptr, &args, sizeof(args)); 690 ofw_real_stop(); 691 return (args.size); 692 } 693 694 /* Convert a device specifier to a fully qualified pathname. */ 695 static ssize_t 696 ofw_real_canon(ofw_t ofw, const char *device, char *buf, size_t len) 697 { 698 vm_offset_t argsptr; 699 struct { 700 cell_t name; 701 cell_t nargs; 702 cell_t nreturns; 703 cell_t device; 704 cell_t buf; 705 cell_t len; 706 int32_t size; 707 } args; 708 709 args.name = (cell_t)(uintptr_t)"canon"; 710 args.nargs = 3; 711 args.nreturns = 1; 712 713 ofw_real_start(); 714 715 args.device = ofw_real_map(device, strlen(device) + 1); 716 args.buf = ofw_real_map(buf, len); 717 args.len = len; 718 argsptr = ofw_real_map(&args, sizeof(args)); 719 if (args.device == 0 || args.buf == 0 || 720 openfirmware((void *)argsptr) == -1) { 721 ofw_real_stop(); 722 return (-1); 723 } 724 ofw_real_unmap(argsptr, &args, sizeof(args)); 725 ofw_real_unmap(args.buf, buf, len); 726 727 ofw_real_stop(); 728 return (args.size); 729 } 730 731 /* Return a package handle for the specified device. */ 732 static phandle_t 733 ofw_real_finddevice(ofw_t ofw, const char *device) 734 { 735 vm_offset_t argsptr; 736 struct { 737 cell_t name; 738 cell_t nargs; 739 cell_t nreturns; 740 cell_t device; 741 cell_t package; 742 } args; 743 744 args.name = (cell_t)(uintptr_t)"finddevice"; 745 args.nargs = 1; 746 args.nreturns = 1; 747 748 ofw_real_start(); 749 750 args.device = ofw_real_map(device, strlen(device) + 1); 751 argsptr = ofw_real_map(&args, sizeof(args)); 752 if (args.device == 0 || 753 openfirmware((void *)argsptr) == -1) { 754 ofw_real_stop(); 755 return (-1); 756 } 757 ofw_real_unmap(argsptr, &args, sizeof(args)); 758 ofw_real_stop(); 759 return (args.package); 760 } 761 762 /* Return the fully qualified pathname corresponding to an instance. */ 763 static ssize_t 764 ofw_real_instance_to_path(ofw_t ofw, ihandle_t instance, char *buf, size_t len) 765 { 766 vm_offset_t argsptr; 767 struct { 768 cell_t name; 769 cell_t nargs; 770 cell_t nreturns; 771 cell_t instance; 772 cell_t buf; 773 cell_t len; 774 int32_t size; 775 } args; 776 777 args.name = (cell_t)(uintptr_t)"instance-to-path"; 778 args.nargs = 3; 779 args.nreturns = 1; 780 781 ofw_real_start(); 782 783 args.instance = instance; 784 args.buf = ofw_real_map(buf, len); 785 args.len = len; 786 argsptr = ofw_real_map(&args, sizeof(args)); 787 if (args.buf == 0 || 788 openfirmware((void *)argsptr) == -1) { 789 ofw_real_stop(); 790 return (-1); 791 } 792 ofw_real_unmap(argsptr, &args, sizeof(args)); 793 ofw_real_unmap(args.buf, buf, len); 794 795 ofw_real_stop(); 796 return (args.size); 797 } 798 799 /* Return the fully qualified pathname corresponding to a package. */ 800 static ssize_t 801 ofw_real_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len) 802 { 803 vm_offset_t argsptr; 804 struct { 805 cell_t name; 806 cell_t nargs; 807 cell_t nreturns; 808 cell_t package; 809 cell_t buf; 810 cell_t len; 811 int32_t size; 812 } args; 813 814 args.name = (cell_t)(uintptr_t)"package-to-path"; 815 args.nargs = 3; 816 args.nreturns = 1; 817 818 ofw_real_start(); 819 820 args.package = package; 821 args.buf = ofw_real_map(buf, len); 822 args.len = len; 823 argsptr = ofw_real_map(&args, sizeof(args)); 824 if (args.buf == 0 || 825 openfirmware((void *)argsptr) == -1) { 826 ofw_real_stop(); 827 return (-1); 828 } 829 ofw_real_unmap(argsptr, &args, sizeof(args)); 830 ofw_real_unmap(args.buf, buf, len); 831 832 ofw_real_stop(); 833 return (args.size); 834 } 835 836 /* Call the method in the scope of a given instance. */ 837 static int 838 ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method, 839 int nargs, int nreturns, cell_t *args_and_returns) 840 { 841 vm_offset_t argsptr; 842 struct { 843 cell_t name; 844 cell_t nargs; 845 cell_t nreturns; 846 cell_t method; 847 cell_t instance; 848 cell_t args_n_results[12]; 849 } args; 850 cell_t *ap, *cp; 851 int n; 852 853 args.name = (cell_t)(uintptr_t)"call-method"; 854 args.nargs = 2; 855 args.nreturns = 1; 856 857 if (nargs > 6) 858 return (-1); 859 860 ofw_real_start(); 861 args.nargs = nargs + 2; 862 args.nreturns = nreturns + 1; 863 args.method = ofw_real_map(method, strlen(method) + 1); 864 args.instance = instance; 865 866 ap = args_and_returns; 867 for (cp = args.args_n_results + (n = nargs); --n >= 0;) 868 *--cp = *(ap++); 869 argsptr = ofw_real_map(&args, sizeof(args)); 870 if (args.method == 0 || 871 openfirmware((void *)argsptr) == -1) { 872 ofw_real_stop(); 873 return (-1); 874 } 875 ofw_real_unmap(argsptr, &args, sizeof(args)); 876 ofw_real_stop(); 877 if (args.args_n_results[nargs]) 878 return (args.args_n_results[nargs]); 879 for (cp = args.args_n_results + nargs + (n = args.nreturns); --n > 0;) 880 *(ap++) = *--cp; 881 return (0); 882 } 883 884 static int 885 ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns) 886 { 887 vm_offset_t argsptr; 888 struct { 889 cell_t name; 890 cell_t nargs; 891 cell_t nreturns; 892 cell_t slot[16]; 893 } args; 894 cell_t status; 895 int i = 0, j = 0; 896 897 args.name = (cell_t)(uintptr_t)"interpret"; 898 args.nargs = 1; 899 900 ofw_real_start(); 901 args.nreturns = ++nreturns; 902 args.slot[i++] = ofw_real_map(cmd, strlen(cmd) + 1); 903 argsptr = ofw_real_map(&args, sizeof(args)); 904 if (openfirmware((void *)argsptr) == -1) { 905 ofw_real_stop(); 906 return (-1); 907 } 908 ofw_real_unmap(argsptr, &args, sizeof(args)); 909 ofw_real_stop(); 910 status = args.slot[i++]; 911 while (i < 1 + nreturns) 912 returns[j++] = args.slot[i++]; 913 return (status); 914 } 915 916 /* 917 * Device I/O functions 918 */ 919 920 /* Open an instance for a device. */ 921 static ihandle_t 922 ofw_real_open(ofw_t ofw, const char *device) 923 { 924 vm_offset_t argsptr; 925 struct { 926 cell_t name; 927 cell_t nargs; 928 cell_t nreturns; 929 cell_t device; 930 cell_t instance; 931 } args; 932 933 args.name = (cell_t)(uintptr_t)"open"; 934 args.nargs = 1; 935 args.nreturns = 1; 936 937 ofw_real_start(); 938 939 args.device = ofw_real_map(device, strlen(device) + 1); 940 argsptr = ofw_real_map(&args, sizeof(args)); 941 if (args.device == 0 || openfirmware((void *)argsptr) == -1 942 || args.instance == 0) { 943 ofw_real_stop(); 944 return (-1); 945 } 946 ofw_real_unmap(argsptr, &args, sizeof(args)); 947 ofw_real_stop(); 948 return (args.instance); 949 } 950 951 /* Close an instance. */ 952 static void 953 ofw_real_close(ofw_t ofw, ihandle_t instance) 954 { 955 vm_offset_t argsptr; 956 struct { 957 cell_t name; 958 cell_t nargs; 959 cell_t nreturns; 960 cell_t instance; 961 } args; 962 963 args.name = (cell_t)(uintptr_t)"close"; 964 args.nargs = 1; 965 args.nreturns = 0; 966 args.instance = instance; 967 ofw_real_start(); 968 argsptr = ofw_real_map(&args, sizeof(args)); 969 openfirmware((void *)argsptr); 970 ofw_real_stop(); 971 } 972 973 /* Read from an instance. */ 974 static ssize_t 975 ofw_real_read(ofw_t ofw, ihandle_t instance, void *addr, size_t len) 976 { 977 vm_offset_t argsptr; 978 struct { 979 cell_t name; 980 cell_t nargs; 981 cell_t nreturns; 982 cell_t instance; 983 cell_t addr; 984 cell_t len; 985 int32_t actual; 986 } args; 987 988 args.name = (cell_t)(uintptr_t)"read"; 989 args.nargs = 3; 990 args.nreturns = 1; 991 992 ofw_real_start(); 993 994 args.instance = instance; 995 args.addr = ofw_real_map(addr, len); 996 args.len = len; 997 argsptr = ofw_real_map(&args, sizeof(args)); 998 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) { 999 ofw_real_stop(); 1000 return (-1); 1001 } 1002 ofw_real_unmap(argsptr, &args, sizeof(args)); 1003 ofw_real_unmap(args.addr, addr, len); 1004 1005 ofw_real_stop(); 1006 return (args.actual); 1007 } 1008 1009 /* Write to an instance. */ 1010 static ssize_t 1011 ofw_real_write(ofw_t ofw, ihandle_t instance, const void *addr, size_t len) 1012 { 1013 vm_offset_t argsptr; 1014 struct { 1015 cell_t name; 1016 cell_t nargs; 1017 cell_t nreturns; 1018 cell_t instance; 1019 cell_t addr; 1020 cell_t len; 1021 int32_t actual; 1022 } args; 1023 1024 args.name = (cell_t)(uintptr_t)"write"; 1025 args.nargs = 3; 1026 args.nreturns = 1; 1027 1028 ofw_real_start(); 1029 1030 args.instance = instance; 1031 args.addr = ofw_real_map(addr, len); 1032 args.len = len; 1033 argsptr = ofw_real_map(&args, sizeof(args)); 1034 if (args.addr == 0 || openfirmware((void *)argsptr) == -1) { 1035 ofw_real_stop(); 1036 return (-1); 1037 } 1038 ofw_real_unmap(argsptr, &args, sizeof(args)); 1039 ofw_real_stop(); 1040 return (args.actual); 1041 } 1042 1043 /* Seek to a position. */ 1044 static int 1045 ofw_real_seek(ofw_t ofw, ihandle_t instance, u_int64_t pos) 1046 { 1047 vm_offset_t argsptr; 1048 struct { 1049 cell_t name; 1050 cell_t nargs; 1051 cell_t nreturns; 1052 cell_t instance; 1053 cell_t poshi; 1054 cell_t poslo; 1055 cell_t status; 1056 } args; 1057 1058 args.name = (cell_t)(uintptr_t)"seek"; 1059 args.nargs = 3; 1060 args.nreturns = 1; 1061 1062 args.instance = instance; 1063 args.poshi = pos >> 32; 1064 args.poslo = pos; 1065 ofw_real_start(); 1066 argsptr = ofw_real_map(&args, sizeof(args)); 1067 if (openfirmware((void *)argsptr) == -1) { 1068 ofw_real_stop(); 1069 return (-1); 1070 } 1071 ofw_real_unmap(argsptr, &args, sizeof(args)); 1072 ofw_real_stop(); 1073 return (args.status); 1074 } 1075 1076 /* 1077 * Memory functions 1078 */ 1079 1080 /* Claim an area of memory. */ 1081 static caddr_t 1082 ofw_real_claim(ofw_t ofw, void *virt, size_t size, u_int align) 1083 { 1084 vm_offset_t argsptr; 1085 struct { 1086 cell_t name; 1087 cell_t nargs; 1088 cell_t nreturns; 1089 cell_t virt; 1090 cell_t size; 1091 cell_t align; 1092 cell_t baseaddr; 1093 } args; 1094 1095 args.name = (cell_t)(uintptr_t)"claim"; 1096 args.nargs = 3; 1097 args.nreturns = 1; 1098 1099 args.virt = (cell_t)(uintptr_t)virt; 1100 args.size = size; 1101 args.align = align; 1102 ofw_real_start(); 1103 argsptr = ofw_real_map(&args, sizeof(args)); 1104 if (openfirmware((void *)argsptr) == -1) { 1105 ofw_real_stop(); 1106 return ((void *)-1); 1107 } 1108 ofw_real_unmap(argsptr, &args, sizeof(args)); 1109 ofw_real_stop(); 1110 return ((void *)(uintptr_t)args.baseaddr); 1111 } 1112 1113 /* Release an area of memory. */ 1114 static void 1115 ofw_real_release(ofw_t ofw, void *virt, size_t size) 1116 { 1117 vm_offset_t argsptr; 1118 struct { 1119 cell_t name; 1120 cell_t nargs; 1121 cell_t nreturns; 1122 cell_t virt; 1123 cell_t size; 1124 } args; 1125 1126 args.name = (cell_t)(uintptr_t)"release"; 1127 args.nargs = 2; 1128 args.nreturns = 0; 1129 1130 args.virt = (cell_t)(uintptr_t)virt; 1131 args.size = size; 1132 ofw_real_start(); 1133 argsptr = ofw_real_map(&args, sizeof(args)); 1134 openfirmware((void *)argsptr); 1135 ofw_real_stop(); 1136 } 1137 1138 /* 1139 * Control transfer functions 1140 */ 1141 1142 /* Suspend and drop back to the Open Firmware interface. */ 1143 static void 1144 ofw_real_enter(ofw_t ofw) 1145 { 1146 vm_offset_t argsptr; 1147 struct { 1148 cell_t name; 1149 cell_t nargs; 1150 cell_t nreturns; 1151 } args; 1152 1153 args.name = (cell_t)(uintptr_t)"enter"; 1154 args.nargs = 0; 1155 args.nreturns = 0; 1156 1157 ofw_real_start(); 1158 argsptr = ofw_real_map(&args, sizeof(args)); 1159 openfirmware((void *)argsptr); 1160 /* We may come back. */ 1161 ofw_real_stop(); 1162 } 1163 1164 /* Shut down and drop back to the Open Firmware interface. */ 1165 static void 1166 ofw_real_exit(ofw_t ofw) 1167 { 1168 vm_offset_t argsptr; 1169 struct { 1170 cell_t name; 1171 cell_t nargs; 1172 cell_t nreturns; 1173 } args; 1174 1175 args.name = (cell_t)(uintptr_t)"exit"; 1176 args.nargs = 0; 1177 args.nreturns = 0; 1178 1179 ofw_real_start(); 1180 argsptr = ofw_real_map(&args, sizeof(args)); 1181 openfirmware((void *)argsptr); 1182 for (;;) /* just in case */ 1183 ; 1184 ofw_real_stop(); 1185 } 1186