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