1 /* $NetBSD: Locore.c,v 1.7 2000/08/20 07:04:59 tsubai Exp $ */ 2 3 /*- 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /*- 34 * Copyright (C) 2000 Benno Rice. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 #include <sys/cdefs.h> 59 __FBSDID("$FreeBSD$"); 60 61 #include <sys/endian.h> 62 63 #include <machine/stdarg.h> 64 65 #include <stand.h> 66 67 #include "openfirm.h" 68 69 int (*openfirmware)(void *); 70 71 phandle_t chosen; 72 ihandle_t mmu; 73 ihandle_t memory; 74 int real_mode = 0; 75 76 #define IN(x) htobe32((cell_t)x) 77 #define OUT(x) be32toh(x) 78 #define SETUP(a, b, c, d) \ 79 a.name = IN( (b) ); \ 80 a.nargs = IN( (c) ); \ 81 a.nreturns = IN( (d) ); 82 83 /* Initialiser */ 84 85 void 86 OF_init(int (*openfirm)(void *)) 87 { 88 phandle_t options; 89 char mode[sizeof("true")]; 90 91 openfirmware = openfirm; 92 93 if ((chosen = OF_finddevice("/chosen")) == -1) 94 OF_exit(); 95 if (OF_getprop(chosen, "memory", &memory, sizeof(memory)) == -1) { 96 memory = OF_open("/memory"); 97 if (memory == -1) 98 memory = OF_open("/memory@0"); 99 if (memory == -1) 100 OF_exit(); 101 } 102 if (OF_getprop(chosen, "mmu", &mmu, sizeof(mmu)) == -1) 103 OF_exit(); 104 105 /* 106 * Check if we run in real mode. If so, we do not need to map 107 * memory later on. 108 */ 109 options = OF_finddevice("/options"); 110 if (OF_getprop(options, "real-mode?", mode, sizeof(mode)) > 0 && 111 strcmp(mode, "true") == 0) 112 real_mode = 1; 113 } 114 115 /* 116 * Generic functions 117 */ 118 119 /* Test to see if a service exists. */ 120 int 121 OF_test(char *name) 122 { 123 static struct { 124 cell_t name; 125 cell_t nargs; 126 cell_t nreturns; 127 cell_t service; 128 cell_t missing; 129 } args = {}; 130 SETUP(args, "test", 1, 1); 131 132 args.service = IN(name); 133 if (openfirmware(&args) == -1) 134 return (-1); 135 return (OUT(args.missing)); 136 } 137 138 /* Return firmware millisecond count. */ 139 int 140 OF_milliseconds() 141 { 142 static struct { 143 cell_t name; 144 cell_t nargs; 145 cell_t nreturns; 146 cell_t ms; 147 } args = {}; 148 SETUP(args, "milliseconds", 0, 1); 149 150 openfirmware(&args); 151 return (OUT(args.ms)); 152 } 153 154 /* 155 * Device tree functions 156 */ 157 158 /* Return the next sibling of this node or 0. */ 159 phandle_t 160 OF_peer(phandle_t node) 161 { 162 static struct { 163 cell_t name; 164 cell_t nargs; 165 cell_t nreturns; 166 cell_t node; 167 cell_t next; 168 } args = {}; 169 SETUP(args, "peer", 1, 1); 170 171 args.node = node; 172 if (openfirmware(&args) == -1) 173 return (-1); 174 return (args.next); 175 } 176 177 /* Return the first child of this node or 0. */ 178 phandle_t 179 OF_child(phandle_t node) 180 { 181 static struct { 182 cell_t name; 183 cell_t nargs; 184 cell_t nreturns; 185 cell_t node; 186 cell_t child; 187 } args = {}; 188 SETUP(args, "child", 1, 1); 189 190 args.node = node; 191 if (openfirmware(&args) == -1) 192 return (-1); 193 return (args.child); 194 } 195 196 /* Return the parent of this node or 0. */ 197 phandle_t 198 OF_parent(phandle_t node) 199 { 200 static struct { 201 cell_t name; 202 cell_t nargs; 203 cell_t nreturns; 204 cell_t node; 205 cell_t parent; 206 } args = {}; 207 SETUP(args, "parent", 1, 1); 208 209 args.node = node; 210 if (openfirmware(&args) == -1) 211 return (-1); 212 return (args.parent); 213 } 214 215 /* Return the package handle that corresponds to an instance handle. */ 216 phandle_t 217 OF_instance_to_package(ihandle_t instance) 218 { 219 static struct { 220 cell_t name; 221 cell_t nargs; 222 cell_t nreturns; 223 cell_t instance; 224 cell_t package; 225 } args = {}; 226 SETUP(args, "instance-to-package", 1, 1); 227 228 args.instance = instance; 229 if (openfirmware(&args) == -1) 230 return (-1); 231 return (args.package); 232 } 233 234 /* Get the length of a property of a package. */ 235 int 236 OF_getproplen(phandle_t package, const char *propname) 237 { 238 static struct { 239 cell_t name; 240 cell_t nargs; 241 cell_t nreturns; 242 cell_t package; 243 cell_t propname; 244 cell_t proplen; 245 } args = {}; 246 SETUP(args, "getproplen", 2, 1); 247 248 args.package = package; 249 args.propname = IN(propname); 250 if (openfirmware(&args) == -1) 251 return (-1); 252 return (OUT(args.proplen)); 253 } 254 255 /* Get the value of a property of a package. */ 256 int 257 OF_getprop(phandle_t package, const char *propname, void *buf, int buflen) 258 { 259 static struct { 260 cell_t name; 261 cell_t nargs; 262 cell_t nreturns; 263 cell_t package; 264 cell_t propname; 265 cell_t buf; 266 cell_t buflen; 267 cell_t size; 268 } args = {}; 269 SETUP(args, "getprop", 4, 1); 270 271 args.package = package; 272 args.propname = IN(propname); 273 args.buf = IN(buf); 274 args.buflen = IN(buflen); 275 if (openfirmware(&args) == -1) 276 return (-1); 277 return (OUT(args.size)); 278 } 279 280 /* Decode a binary property from a package. */ 281 int 282 OF_getencprop(phandle_t package, const char *propname, cell_t *buf, int buflen) 283 { 284 int retval, i; 285 retval = OF_getprop(package, propname, buf, buflen); 286 if (retval == -1) 287 return (retval); 288 289 for (i = 0; i < buflen/4; i++) 290 buf[i] = be32toh((uint32_t)buf[i]); 291 292 return (retval); 293 } 294 295 /* Get the next property of a package. */ 296 int 297 OF_nextprop(phandle_t package, const char *previous, char *buf) 298 { 299 static struct { 300 cell_t name; 301 cell_t nargs; 302 cell_t nreturns; 303 cell_t package; 304 cell_t previous; 305 cell_t buf; 306 cell_t flag; 307 } args = {}; 308 SETUP(args, "nextprop", 3, 1); 309 310 args.package = package; 311 args.previous = IN(previous); 312 args.buf = IN(buf); 313 if (openfirmware(&args) == -1) 314 return (-1); 315 return (OUT(args.flag)); 316 } 317 318 /* Set the value of a property of a package. */ 319 /* XXX Has a bug on FirePower */ 320 int 321 OF_setprop(phandle_t package, const char *propname, void *buf, int len) 322 { 323 static struct { 324 cell_t name; 325 cell_t nargs; 326 cell_t nreturns; 327 cell_t package; 328 cell_t propname; 329 cell_t buf; 330 cell_t len; 331 cell_t size; 332 } args = {}; 333 SETUP(args, "setprop", 4, 1); 334 335 args.package = package; 336 args.propname = IN(propname); 337 args.buf = IN(buf); 338 args.len = IN(len); 339 if (openfirmware(&args) == -1) 340 return (-1); 341 return (OUT(args.size)); 342 } 343 344 /* Convert a device specifier to a fully qualified pathname. */ 345 int 346 OF_canon(const char *device, char *buf, int len) 347 { 348 static struct { 349 cell_t name; 350 cell_t nargs; 351 cell_t nreturns; 352 cell_t device; 353 cell_t buf; 354 cell_t len; 355 cell_t size; 356 } args = {}; 357 SETUP(args, "canon", 3, 1); 358 359 args.device = IN(device); 360 args.buf = IN(buf); 361 args.len = IN(len); 362 if (openfirmware(&args) == -1) 363 return (-1); 364 return (OUT(args.size)); 365 } 366 367 /* Return a package handle for the specified device. */ 368 phandle_t 369 OF_finddevice(const char *device) 370 { 371 static struct { 372 cell_t name; 373 cell_t nargs; 374 cell_t nreturns; 375 cell_t device; 376 cell_t package; 377 } args = {}; 378 SETUP(args, "finddevice", 1, 1); 379 380 args.device = IN(device); 381 if (openfirmware(&args) == -1) 382 return (-1); 383 return (args.package); 384 } 385 386 /* Return the fully qualified pathname corresponding to an instance. */ 387 int 388 OF_instance_to_path(ihandle_t instance, char *buf, int len) 389 { 390 static struct { 391 cell_t name; 392 cell_t nargs; 393 cell_t nreturns; 394 cell_t instance; 395 cell_t buf; 396 cell_t len; 397 cell_t size; 398 } args = {}; 399 SETUP(args, "instance-to-path", 3, 1); 400 401 args.instance = instance; 402 args.buf = IN(buf); 403 args.len = IN(len); 404 if (openfirmware(&args) == -1) 405 return (-1); 406 return (OUT(args.size)); 407 } 408 409 /* Return the fully qualified pathname corresponding to a package. */ 410 int 411 OF_package_to_path(phandle_t package, char *buf, int len) 412 { 413 static struct { 414 cell_t name; 415 cell_t nargs; 416 cell_t nreturns; 417 cell_t package; 418 cell_t buf; 419 cell_t len; 420 cell_t size; 421 } args = {}; 422 SETUP(args, "package-to-path", 3, 1); 423 424 args.package = package; 425 args.buf = IN(buf); 426 args.len = IN(len); 427 if (openfirmware(&args) == -1) 428 return (-1); 429 return (OUT(args.size)); 430 } 431 432 /* Call the method in the scope of a given instance. */ 433 int 434 OF_call_method(char *method, ihandle_t instance, int nargs, int nreturns, ...) 435 { 436 va_list ap; 437 static struct { 438 cell_t name; 439 cell_t nargs; 440 cell_t nreturns; 441 cell_t method; 442 cell_t instance; 443 cell_t args_n_results[12]; 444 } args = {}; 445 SETUP(args, "call-method", nargs + 2, nreturns + 1); 446 cell_t *cp; 447 int n; 448 449 if (nargs > 6) 450 return (-1); 451 args.method = IN(method); 452 args.instance = instance; 453 va_start(ap, nreturns); 454 for (cp = (cell_t *)(args.args_n_results + (n = nargs)); --n >= 0;) 455 *--cp = IN(va_arg(ap, cell_t)); 456 if (openfirmware(&args) == -1) 457 return (-1); 458 if (args.args_n_results[nargs]) 459 return (OUT(args.args_n_results[nargs])); 460 /* XXX what if ihandles or phandles are returned */ 461 for (cp = (cell_t *)(args.args_n_results + nargs + 462 (n = be32toh(args.nreturns))); --n > 0;) 463 *va_arg(ap, cell_t *) = OUT(*--cp); 464 va_end(ap); 465 return (0); 466 } 467 468 /* 469 * Device I/O functions 470 */ 471 472 /* Open an instance for a device. */ 473 ihandle_t 474 OF_open(char *device) 475 { 476 static struct { 477 cell_t name; 478 cell_t nargs; 479 cell_t nreturns; 480 cell_t device; 481 cell_t instance; 482 } args = {}; 483 SETUP(args, "open", 1, 1); 484 485 args.device = IN(device); 486 if (openfirmware(&args) == -1 || args.instance == 0) { 487 return (-1); 488 } 489 return (args.instance); 490 } 491 492 /* Close an instance. */ 493 void 494 OF_close(ihandle_t instance) 495 { 496 static struct { 497 cell_t name; 498 cell_t nargs; 499 cell_t nreturns; 500 cell_t instance; 501 } args = {}; 502 SETUP(args, "close", 1, 0); 503 504 args.instance = instance; 505 openfirmware(&args); 506 } 507 508 /* Read from an instance. */ 509 int 510 OF_read(ihandle_t instance, void *addr, int len) 511 { 512 static struct { 513 cell_t name; 514 cell_t nargs; 515 cell_t nreturns; 516 cell_t instance; 517 cell_t addr; 518 cell_t len; 519 cell_t actual; 520 } args = {}; 521 SETUP(args, "read", 3, 1); 522 523 args.instance = instance; 524 args.addr = IN(addr); 525 args.len = IN(len); 526 527 #if defined(OPENFIRM_DEBUG) 528 printf("OF_read: called with instance=%08x, addr=%p, len=%d\n", 529 instance, addr, len); 530 #endif 531 532 if (openfirmware(&args) == -1) 533 return (-1); 534 535 #if defined(OPENFIRM_DEBUG) 536 printf("OF_read: returning instance=%d, addr=%p, len=%d, actual=%d\n", 537 args.instance, OUT(args.addr), OUT(args.len), OUT(args.actual)); 538 #endif 539 540 return (OUT(args.actual)); 541 } 542 543 /* Write to an instance. */ 544 int 545 OF_write(ihandle_t instance, void *addr, int len) 546 { 547 static struct { 548 cell_t name; 549 cell_t nargs; 550 cell_t nreturns; 551 cell_t instance; 552 cell_t addr; 553 cell_t len; 554 cell_t actual; 555 } args = {}; 556 SETUP(args, "write", 3, 1); 557 558 args.instance = instance; 559 args.addr = IN(addr); 560 args.len = IN(len); 561 if (openfirmware(&args) == -1) 562 return (-1); 563 return (OUT(args.actual)); 564 } 565 566 /* Seek to a position. */ 567 int 568 OF_seek(ihandle_t instance, uint64_t pos) 569 { 570 static struct { 571 cell_t name; 572 cell_t nargs; 573 cell_t nreturns; 574 cell_t instance; 575 cell_t poshi; 576 cell_t poslo; 577 cell_t status; 578 } args = {}; 579 SETUP(args, "seek", 3, 1); 580 581 args.instance = instance; 582 args.poshi = IN(((uint64_t)pos >> 32)); 583 args.poslo = IN(pos); 584 if (openfirmware(&args) == -1) 585 return (-1); 586 return (OUT(args.status)); 587 } 588 589 /* Blocks. */ 590 unsigned int 591 OF_blocks(ihandle_t instance) 592 { 593 static struct { 594 cell_t name; 595 cell_t nargs; 596 cell_t nreturns; 597 cell_t instance; 598 cell_t result; 599 cell_t blocks; 600 } args = {}; 601 SETUP(args, "#blocks", 2, 1); 602 603 args.instance = instance; 604 if (openfirmware(&args) == -1) 605 return ((unsigned int)-1); 606 return (OUT(args.blocks)); 607 } 608 609 /* Block size. */ 610 int 611 OF_block_size(ihandle_t instance) 612 { 613 static struct { 614 cell_t name; 615 cell_t nargs; 616 cell_t nreturns; 617 cell_t instance; 618 cell_t result; 619 cell_t size; 620 } args = {}; 621 SETUP(args, "block-size", 2, 1); 622 623 args.instance = instance; 624 if (openfirmware(&args) == -1) 625 return (512); 626 return (OUT(args.size)); 627 } 628 629 /* 630 * Memory functions 631 */ 632 633 /* Claim an area of memory. */ 634 void * 635 OF_claim(void *virt, u_int size, u_int align) 636 { 637 static struct { 638 cell_t name; 639 cell_t nargs; 640 cell_t nreturns; 641 cell_t virt; 642 cell_t size; 643 cell_t align; 644 cell_t baseaddr; 645 } args = {}; 646 SETUP(args, "claim", 3, 1); 647 648 args.virt = IN(virt); 649 args.size = IN(size); 650 args.align = IN(align); 651 if (openfirmware(&args) == -1) 652 return ((void *)-1); 653 return ((void *)OUT(args.baseaddr)); 654 } 655 656 /* Release an area of memory. */ 657 void 658 OF_release(void *virt, u_int size) 659 { 660 static struct { 661 cell_t name; 662 cell_t nargs; 663 cell_t nreturns; 664 cell_t virt; 665 cell_t size; 666 } args = {}; 667 SETUP(args, "release", 2, 0); 668 669 args.virt = IN(virt); 670 args.size = IN(size); 671 openfirmware(&args); 672 } 673 674 /* 675 * Control transfer functions 676 */ 677 678 /* Reset the system and call "boot <bootspec>". */ 679 void 680 OF_boot(char *bootspec) 681 { 682 static struct { 683 cell_t name; 684 cell_t nargs; 685 cell_t nreturns; 686 cell_t bootspec; 687 } args = {}; 688 SETUP(args, "boot", 1, 0); 689 690 args.bootspec = IN(bootspec); 691 openfirmware(&args); 692 for (;;) /* just in case */ 693 ; 694 } 695 696 /* Suspend and drop back to the Open Firmware interface. */ 697 void 698 OF_enter() 699 { 700 static struct { 701 cell_t name; 702 cell_t nargs; 703 cell_t nreturns; 704 } args = {}; 705 SETUP(args, "enter", 0, 0); 706 707 openfirmware(&args); 708 /* We may come back. */ 709 } 710 711 /* Shut down and drop back to the Open Firmware interface. */ 712 void 713 OF_exit() 714 { 715 static struct { 716 cell_t name; 717 cell_t nargs; 718 cell_t nreturns; 719 } args = {}; 720 SETUP(args, "exit", 0, 0); 721 722 openfirmware(&args); 723 for (;;) /* just in case */ 724 ; 725 } 726 727 void 728 OF_quiesce() 729 { 730 static struct { 731 cell_t name; 732 cell_t nargs; 733 cell_t nreturns; 734 } args = {}; 735 SETUP(args, "quiesce", 0, 0); 736 737 openfirmware(&args); 738 } 739 740 /* Free <size> bytes starting at <virt>, then call <entry> with <arg>. */ 741 #if 0 742 void 743 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) 744 { 745 static struct { 746 cell_t name; 747 cell_t nargs; 748 cell_t nreturns; 749 cell_t virt; 750 cell_t size; 751 cell_t entry; 752 cell_t arg; 753 cell_t len; 754 } args = {}; 755 SETUP(args, "chain", 5, 0); 756 757 args.virt = IN(virt); 758 args.size = IN(size); 759 args.entry = IN(entry); 760 args.arg = IN(arg); 761 args.len = IN(len); 762 openfirmware(&args); 763 } 764 #else 765 void 766 OF_chain(void *virt, u_int size, void (*entry)(), void *arg, u_int len) 767 { 768 /* 769 * This is a REALLY dirty hack till the firmware gets this going 770 */ 771 #if 0 772 if (size > 0) 773 OF_release(virt, size); 774 #endif 775 entry(0, 0, openfirmware, arg, len); 776 } 777 #endif 778