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