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