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