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 81static int ofw_real_init(ofw_t, void *openfirm); 82static int ofw_real_test(ofw_t, const char *name); 83static phandle_t ofw_real_peer(ofw_t, phandle_t node); 84static phandle_t ofw_real_child(ofw_t, phandle_t node); 85static phandle_t ofw_real_parent(ofw_t, phandle_t node); 86static phandle_t ofw_real_instance_to_package(ofw_t, ihandle_t instance); 87static ssize_t ofw_real_getproplen(ofw_t, phandle_t package, 88 const char *propname); 89static ssize_t ofw_real_getprop(ofw_t, phandle_t package, const char *propname, 90 void *buf, size_t buflen); 91static int ofw_real_nextprop(ofw_t, phandle_t package, const char *previous, 92 char *buf, size_t); 93static int ofw_real_setprop(ofw_t, phandle_t package, const char *propname, 94 const void *buf, size_t len); 95static ssize_t ofw_real_canon(ofw_t, const char *device, char *buf, size_t len); 96static phandle_t ofw_real_finddevice(ofw_t, const char *device); 97static ssize_t ofw_real_instance_to_path(ofw_t, ihandle_t instance, char *buf, 98 size_t len); 99static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf, 100 size_t len); 101static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method, 102 int nargs, int nreturns, cell_t *args_and_returns); 103static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, 104 cell_t *returns); 105static ihandle_t ofw_real_open(ofw_t, const char *device); 106static void ofw_real_close(ofw_t, ihandle_t instance); 107static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len); 108static ssize_t ofw_real_write(ofw_t, ihandle_t instance, const void *addr, 109 size_t len); 110static int ofw_real_seek(ofw_t, ihandle_t instance, u_int64_t pos); 111static caddr_t ofw_real_claim(ofw_t, void *virt, size_t size, u_int align); 112static void ofw_real_release(ofw_t, void *virt, size_t size); 113static void ofw_real_enter(ofw_t); 114static void ofw_real_exit(ofw_t); 115 116static 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 146static ofw_def_t ofw_real = { 147 OFW_STD_REAL, 148 ofw_real_methods, 149 0 150}; 151OFW_DEF(ofw_real); 152 153static ofw_def_t ofw_32bit = { 154 OFW_STD_32BIT, 155 ofw_real_methods, 156 0 157}; 158OFW_DEF(ofw_32bit); 159 160static MALLOC_DEFINE(M_OFWREAL, "ofwreal", 161 "Open Firmware Real Mode Bounce Page"); 162 163static int (*openfirmware)(void *); 164 165static vm_offset_t of_bounce_phys; 166static caddr_t of_bounce_virt; 167static off_t of_bounce_offset; 168static 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 206static struct mtx of_bounce_mtx; 207static struct mtx of_spin_mtx; 208static struct mtx *of_real_mtx; 209static void (*of_mtx_lock)(void); 210static void (*of_mtx_unlock)(void); 211 212extern int ofw_real_mode; 213 214/* 215 * After the VM is up, allocate a wired, low memory bounce page. 216 */ 217 218static void ofw_real_bounce_alloc(void *); 219 220SYSINIT(ofw_real_bounce_alloc, SI_SUB_KMEM, SI_ORDER_ANY, 221 ofw_real_bounce_alloc, NULL); 222 223static void 224ofw_real_mtx_lock_spin(void) 225{ 226 mtx_lock_spin(of_real_mtx); 227} 228 229static void 230ofw_real_mtx_lock(void) 231{ 232 mtx_lock(of_real_mtx); 233} 234 235static void 236ofw_real_mtx_unlock_spin(void) 237{ 238 mtx_unlock_spin(of_real_mtx); 239} 240 241static void 242ofw_real_mtx_unlock(void) 243{ 244 mtx_unlock(of_real_mtx); 245} 246 247static void 248ofw_real_start(void) 249{ 250 (*of_mtx_lock)(); 251 of_bounce_offset = 0; 252} 253 254static void 255ofw_real_stop(void) 256{ 257 (*of_mtx_unlock)(); 258} 259 260static void 261ofw_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 300static cell_t 301ofw_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 353static void 354ofw_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 369static int 370ofw_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. */ 399static int 400ofw_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. */ 433static phandle_t 434ofw_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. */ 462static phandle_t 463ofw_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. */ 491static phandle_t 492ofw_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. */ 520static phandle_t 521ofw_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. */ 549static ssize_t 550ofw_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. */ 581static ssize_t 582ofw_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. */ 621static int 622ofw_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 */ 659static int 660ofw_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. */ 697static ssize_t 698ofw_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. */ 734static phandle_t 735ofw_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. */ 765static ssize_t 766ofw_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. */ 802static ssize_t 803ofw_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. */ 839static int 840ofw_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 886static int 887ofw_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. */ 923static ihandle_t 924ofw_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. */ 954static void 955ofw_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. */ 976static ssize_t 977ofw_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. */ 1012static ssize_t 1013ofw_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. */ 1046static int 1047ofw_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. */ 1083static caddr_t 1084ofw_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. */ 1116static void 1117ofw_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. */ 1145static void 1146ofw_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. */ 1167static void 1168ofw_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