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