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