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