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