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