1 /* $OpenBSD: openfirm.c,v 1.19 2016/05/19 09:15:28 kettenis Exp $ */ 2 /* $NetBSD: openfirm.c,v 1.13 2001/06/21 00:08:02 eeh Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 6 * Copyright (C) 1995, 1996 TooLs GmbH. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/stdarg.h> 37 #include <machine/psl.h> 38 39 #include <machine/openfirm.h> 40 41 #define min(x,y) ((x<y)?(x):(y)) 42 43 int 44 OF_peer(phandle) 45 int phandle; 46 { 47 struct { 48 cell_t name; 49 cell_t nargs; 50 cell_t nreturns; 51 cell_t phandle; 52 cell_t sibling; 53 } args; 54 55 args.name = ADR2CELL("peer"); 56 args.nargs = 1; 57 args.nreturns = 1; 58 args.phandle = HDL2CELL(phandle); 59 if (openfirmware(&args) == -1) 60 return 0; 61 return args.sibling; 62 } 63 64 int 65 OF_child(phandle) 66 int phandle; 67 { 68 struct { 69 cell_t name; 70 cell_t nargs; 71 cell_t nreturns; 72 cell_t phandle; 73 cell_t child; 74 } args; 75 76 args.name = ADR2CELL("child"); 77 args.nargs = 1; 78 args.nreturns = 1; 79 args.phandle = HDL2CELL(phandle); 80 if (openfirmware(&args) == -1) 81 return 0; 82 return args.child; 83 } 84 85 int 86 OF_parent(phandle) 87 int phandle; 88 { 89 struct { 90 cell_t name; 91 cell_t nargs; 92 cell_t nreturns; 93 cell_t phandle; 94 cell_t parent; 95 } args; 96 97 args.name = ADR2CELL("parent"); 98 args.nargs = 1; 99 args.nreturns = 1; 100 args.phandle = HDL2CELL(phandle); 101 if (openfirmware(&args) == -1) 102 return 0; 103 return args.parent; 104 } 105 106 int 107 OF_instance_to_package(ihandle) 108 int ihandle; 109 { 110 static struct { 111 cell_t name; 112 cell_t nargs; 113 cell_t nreturns; 114 cell_t ihandle; 115 cell_t phandle; 116 } args; 117 118 args.name = ADR2CELL("instance-to-package"); 119 args.nargs = 1; 120 args.nreturns = 1; 121 args.ihandle = HDL2CELL(ihandle); 122 if (openfirmware(&args) == -1) 123 return -1; 124 return args.phandle; 125 } 126 127 /* Should really return a `long' */ 128 int 129 OF_getproplen(handle, prop) 130 int handle; 131 char *prop; 132 { 133 struct { 134 cell_t name; 135 cell_t nargs; 136 cell_t nreturns; 137 cell_t phandle; 138 cell_t prop; 139 cell_t size; 140 } args; 141 142 args.name = ADR2CELL("getproplen"); 143 args.nargs = 2; 144 args.nreturns = 1; 145 args.phandle = HDL2CELL(handle); 146 args.prop = ADR2CELL(prop); 147 if (openfirmware(&args) == -1) 148 return -1; 149 return args.size; 150 } 151 152 int 153 OF_getprop(handle, prop, buf, buflen) 154 int handle; 155 char *prop; 156 void *buf; 157 int buflen; 158 { 159 struct { 160 cell_t name; 161 cell_t nargs; 162 cell_t nreturns; 163 cell_t phandle; 164 cell_t prop; 165 cell_t buf; 166 cell_t buflen; 167 cell_t size; 168 } args; 169 170 if (buflen > NBPG) 171 return -1; 172 args.name = ADR2CELL("getprop"); 173 args.nargs = 4; 174 args.nreturns = 1; 175 args.phandle = HDL2CELL(handle); 176 args.prop = ADR2CELL(prop); 177 args.buf = ADR2CELL(buf); 178 args.buflen = buflen; 179 if (openfirmware(&args) == -1) 180 return -1; 181 return args.size; 182 } 183 184 int 185 OF_setprop(handle, prop, buf, buflen) 186 int handle; 187 char *prop; 188 const void *buf; 189 int buflen; 190 { 191 struct { 192 cell_t name; 193 cell_t nargs; 194 cell_t nreturns; 195 cell_t phandle; 196 cell_t prop; 197 cell_t buf; 198 cell_t buflen; 199 cell_t size; 200 } args; 201 202 if (buflen > NBPG) 203 return -1; 204 args.name = ADR2CELL("setprop"); 205 args.nargs = 4; 206 args.nreturns = 1; 207 args.phandle = HDL2CELL(handle); 208 args.prop = ADR2CELL(prop); 209 args.buf = ADR2CELL(buf); 210 args.buflen = buflen; 211 if (openfirmware(&args) == -1) 212 return -1; 213 return args.size; 214 } 215 216 int 217 OF_nextprop(handle, prop, buf) 218 int handle; 219 char *prop; 220 void *buf; 221 { 222 struct { 223 cell_t name; 224 cell_t nargs; 225 cell_t nreturns; 226 cell_t phandle; 227 cell_t prev; 228 cell_t buf; 229 cell_t next; 230 } args; 231 232 args.name = ADR2CELL("nextprop"); 233 args.nargs = 3; 234 args.nreturns = 1; 235 args.phandle = HDL2CELL(handle); 236 args.prev = ADR2CELL(prop); 237 args.buf = ADR2CELL(buf); 238 if (openfirmware(&args) == -1) 239 return -1; 240 return args.next; 241 } 242 243 int 244 OF_finddevice(name) 245 char *name; 246 { 247 struct { 248 cell_t name; 249 cell_t nargs; 250 cell_t nreturns; 251 cell_t device; 252 cell_t phandle; 253 } args; 254 255 args.name = ADR2CELL("finddevice"); 256 args.nargs = 1; 257 args.nreturns = 1; 258 args.device = ADR2CELL(name); 259 if (openfirmware(&args) == -1) 260 return -1; 261 return args.phandle; 262 } 263 264 int 265 OF_instance_to_path(ihandle, buf, buflen) 266 int ihandle; 267 char *buf; 268 int buflen; 269 { 270 struct { 271 cell_t name; 272 cell_t nargs; 273 cell_t nreturns; 274 cell_t ihandle; 275 cell_t buf; 276 cell_t buflen; 277 cell_t length; 278 } args; 279 280 if (buflen > NBPG) 281 return -1; 282 args.name = ADR2CELL("instance-to-path"); 283 args.nargs = 3; 284 args.nreturns = 1; 285 args.ihandle = HDL2CELL(ihandle); 286 args.buf = ADR2CELL(buf); 287 args.buflen = buflen; 288 if (openfirmware(&args) < 0) 289 return -1; 290 return args.length; 291 } 292 293 int 294 OF_package_to_path(phandle, buf, buflen) 295 int phandle; 296 char *buf; 297 int buflen; 298 { 299 struct { 300 cell_t name; 301 cell_t nargs; 302 cell_t nreturns; 303 cell_t phandle; 304 cell_t buf; 305 cell_t buflen; 306 cell_t length; 307 } args; 308 309 if (buflen > NBPG) 310 return -1; 311 args.name = ADR2CELL("package-to-path"); 312 args.nargs = 3; 313 args.nreturns = 1; 314 args.phandle = HDL2CELL(phandle); 315 args.buf = ADR2CELL(buf); 316 args.buflen = buflen; 317 if (openfirmware(&args) < 0) 318 return -1; 319 return args.length; 320 } 321 322 /* 323 * The following two functions may need to be re-worked to be 64-bit clean. 324 */ 325 int 326 OF_call_method(char *method, int ihandle, int nargs, int nreturns, ...) 327 { 328 va_list ap; 329 struct { 330 cell_t name; 331 cell_t nargs; 332 cell_t nreturns; 333 cell_t method; 334 cell_t ihandle; 335 cell_t args_n_results[12]; 336 } args; 337 long *ip, n; 338 339 if (nargs > 6) 340 return -1; 341 args.name = ADR2CELL("call-method"); 342 args.nargs = nargs + 2; 343 args.nreturns = nreturns + 1; 344 args.method = ADR2CELL(method); 345 args.ihandle = HDL2CELL(ihandle); 346 va_start(ap, nreturns); 347 for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;) 348 *--ip = va_arg(ap, unsigned long); 349 if (openfirmware(&args) == -1) { 350 va_end(ap); 351 return -1; 352 } 353 if (args.args_n_results[nargs]) { 354 va_end(ap); 355 return args.args_n_results[nargs]; 356 } 357 for (ip = (long *)(args.args_n_results + nargs + (n = args.nreturns)); --n > 0;) 358 *va_arg(ap, unsigned long *) = *--ip; 359 va_end(ap); 360 return 0; 361 } 362 363 int 364 OF_call_method_1(char *method, int ihandle, int nargs, ...) 365 { 366 va_list ap; 367 struct { 368 cell_t name; 369 cell_t nargs; 370 cell_t nreturns; 371 cell_t method; 372 cell_t ihandle; 373 cell_t args_n_results[16]; 374 } args; 375 long *ip, n; 376 377 if (nargs > 6) 378 return -1; 379 args.name = ADR2CELL("call-method"); 380 args.nargs = nargs + 2; 381 args.nreturns = 1; 382 args.method = ADR2CELL(method); 383 args.ihandle = HDL2CELL(ihandle); 384 va_start(ap, nargs); 385 for (ip = (long *)(args.args_n_results + (n = nargs)); --n >= 0;) 386 *--ip = va_arg(ap, unsigned long); 387 va_end(ap); 388 if (openfirmware(&args) == -1) 389 return -1; 390 if (args.args_n_results[nargs]) 391 return -1; 392 return args.args_n_results[nargs + 1]; 393 } 394 395 int 396 OF_open(dname) 397 char *dname; 398 { 399 struct { 400 cell_t name; 401 cell_t nargs; 402 cell_t nreturns; 403 cell_t dname; 404 cell_t handle; 405 } args; 406 int l; 407 408 if ((l = strlen(dname)) >= NBPG) 409 return -1; 410 args.name = ADR2CELL("open"); 411 args.nargs = 1; 412 args.nreturns = 1; 413 args.dname = ADR2CELL(dname); 414 if (openfirmware(&args) == -1) 415 return -1; 416 return args.handle; 417 } 418 419 void 420 OF_close(handle) 421 int handle; 422 { 423 struct { 424 cell_t name; 425 cell_t nargs; 426 cell_t nreturns; 427 cell_t handle; 428 } args; 429 430 args.name = ADR2CELL("close"); 431 args.nargs = 1; 432 args.nreturns = 0; 433 args.handle = HDL2CELL(handle); 434 openfirmware(&args); 435 } 436 437 int 438 OF_test(service) 439 char *service; 440 { 441 struct { 442 cell_t name; 443 cell_t nargs; 444 cell_t nreturns; 445 cell_t service; 446 cell_t status; 447 } args; 448 449 args.name = ADR2CELL("test"); 450 args.nargs = 1; 451 args.nreturns = 1; 452 args.service = ADR2CELL(service); 453 if (openfirmware(&args) == -1) 454 return -1; 455 return args.status; 456 } 457 458 int 459 OF_test_method(service, method) 460 int service; 461 char *method; 462 { 463 struct { 464 cell_t name; 465 cell_t nargs; 466 cell_t nreturns; 467 cell_t service; 468 cell_t method; 469 cell_t status; 470 } args; 471 472 args.name = ADR2CELL("test-method"); 473 args.nargs = 2; 474 args.nreturns = 1; 475 args.service = HDL2CELL(service); 476 args.method = ADR2CELL(method); 477 if (openfirmware(&args) == -1) 478 return -1; 479 return args.status; 480 } 481 482 483 /* 484 * This assumes that character devices don't read in multiples of NBPG. 485 */ 486 int 487 OF_read(handle, addr, len) 488 int handle; 489 void *addr; 490 int len; 491 { 492 struct { 493 cell_t name; 494 cell_t nargs; 495 cell_t nreturns; 496 cell_t ihandle; 497 cell_t addr; 498 cell_t len; 499 cell_t actual; 500 } args; 501 int l, act = 0; 502 503 args.name = ADR2CELL("read"); 504 args.nargs = 3; 505 args.nreturns = 1; 506 args.ihandle = HDL2CELL(handle); 507 args.addr = ADR2CELL(addr); 508 for (; len > 0; len -= l) { 509 l = min(NBPG, len); 510 args.len = l; 511 if (openfirmware(&args) == -1) 512 return -1; 513 if (args.actual > 0) { 514 act += args.actual; 515 } 516 if (args.actual < l) { 517 if (act) 518 return act; 519 else 520 return args.actual; 521 } 522 } 523 return act; 524 } 525 526 void prom_printf(const char *fmt, ...); /* XXX for below */ 527 528 int 529 OF_write(handle, addr, len) 530 int handle; 531 void *addr; 532 int len; 533 { 534 struct { 535 cell_t name; 536 cell_t nargs; 537 cell_t nreturns; 538 cell_t ihandle; 539 cell_t addr; 540 cell_t len; 541 cell_t actual; 542 } args; 543 int l, act = 0; 544 545 if (len > 1024) { 546 panic("OF_write(len=%d)", len); 547 } 548 args.name = ADR2CELL("write"); 549 args.nargs = 3; 550 args.nreturns = 1; 551 args.ihandle = HDL2CELL(handle); 552 args.addr = ADR2CELL(addr); 553 for (; len > 0; len -= l) { 554 l = min(NBPG, len); 555 args.len = l; 556 if (openfirmware(&args) == -1) 557 return -1; 558 l = args.actual; 559 act += l; 560 } 561 return act; 562 } 563 564 565 int 566 OF_seek(handle, pos) 567 int handle; 568 u_quad_t pos; 569 { 570 struct { 571 cell_t name; 572 cell_t nargs; 573 cell_t nreturns; 574 cell_t handle; 575 cell_t poshi; 576 cell_t poslo; 577 cell_t status; 578 } args; 579 580 args.name = ADR2CELL("seek"); 581 args.nargs = 3; 582 args.nreturns = 1; 583 args.handle = HDL2CELL(handle); 584 args.poshi = HDQ2CELL_HI(pos); 585 args.poslo = HDQ2CELL_LO(pos); 586 if (openfirmware(&args) == -1) 587 return -1; 588 return args.status; 589 } 590 591 void 592 OF_boot(bootspec) 593 char *bootspec; 594 { 595 struct { 596 cell_t name; 597 cell_t nargs; 598 cell_t nreturns; 599 cell_t bootspec; 600 } args; 601 int l; 602 603 if ((l = strlen(bootspec)) >= NBPG) 604 panic("OF_boot"); 605 args.name = ADR2CELL("boot"); 606 args.nargs = 1; 607 args.nreturns = 0; 608 args.bootspec = ADR2CELL(bootspec); 609 openfirmware(&args); 610 panic("OF_boot failed"); 611 } 612 613 void 614 OF_enter(void) 615 { 616 struct { 617 cell_t name; 618 cell_t nargs; 619 cell_t nreturns; 620 } args; 621 622 args.name = ADR2CELL("enter"); 623 args.nargs = 0; 624 args.nreturns = 0; 625 openfirmware(&args); 626 } 627 628 void 629 OF_exit(void) 630 { 631 struct { 632 cell_t name; 633 cell_t nargs; 634 cell_t nreturns; 635 } args; 636 637 args.name = ADR2CELL("exit"); 638 args.nargs = 0; 639 args.nreturns = 0; 640 openfirmware(&args); 641 panic("OF_exit failed"); 642 } 643 644 void 645 OF_poweroff(void) 646 { 647 struct { 648 cell_t name; 649 cell_t nargs; 650 cell_t nreturns; 651 } args; 652 653 args.name = ADR2CELL("SUNW,power-off"); 654 args.nargs = 0; 655 args.nreturns = 0; 656 openfirmware(&args); 657 } 658 659 void 660 (*OF_set_callback(newfunc))(void *) 661 void (*newfunc)(void *); 662 { 663 struct { 664 cell_t name; 665 cell_t nargs; 666 cell_t nreturns; 667 cell_t newfunc; 668 cell_t oldfunc; 669 } args; 670 671 args.name = ADR2CELL("set-callback"); 672 args.nargs = 1; 673 args.nreturns = 1; 674 args.newfunc = ADR2CELL(newfunc); 675 if (openfirmware(&args) == -1) 676 return (void *)(long)-1; 677 return (void *)(long)args.oldfunc; 678 } 679 680 void 681 OF_set_symbol_lookup(s2v, v2s) 682 void (*s2v)(void *); 683 void (*v2s)(void *); 684 { 685 struct { 686 cell_t name; 687 cell_t nargs; 688 cell_t nreturns; 689 cell_t sym2val; 690 cell_t val2sym; 691 } args; 692 693 args.name = ADR2CELL("set-symbol-lookup"); 694 args.nargs = 2; 695 args.nreturns = 0; 696 args.sym2val = ADR2CELL(s2v); 697 args.val2sym = ADR2CELL(v2s); 698 699 (void)openfirmware(&args); 700 } 701 702 int 703 OF_interpret(char *cmd, int nreturns, ...) 704 { 705 va_list ap; 706 struct { 707 cell_t name; 708 cell_t nargs; 709 cell_t nreturns; 710 cell_t slot[16]; 711 } args; 712 cell_t status; 713 int i = 0; 714 715 args.name = ADR2CELL("interpret"); 716 args.nargs = 1; 717 args.nreturns = ++nreturns; 718 args.slot[i++] = ADR2CELL(cmd); 719 va_start(ap, nreturns); 720 while (i < 1) 721 args.slot[i++] = va_arg(ap, cell_t); 722 if (openfirmware(&args) == -1) { 723 va_end(ap); 724 return (-1); 725 } 726 status = args.slot[i++]; 727 while (i < 1 + nreturns) 728 *va_arg(ap, cell_t *) = args.slot[i++]; 729 va_end(ap); 730 return (status); 731 } 732 733 int 734 OF_milliseconds(void) 735 { 736 struct { 737 cell_t name; 738 cell_t nargs; 739 cell_t nreturns; 740 cell_t nticks; 741 } args; 742 743 args.name = ADR2CELL("milliseconds"); 744 args.nargs = 0; 745 args.nreturns = 1; 746 if (openfirmware(&args) == -1) 747 return -1; 748 return (args.nticks); 749 } 750 751 #ifdef DDB 752 #include <machine/db_machdep.h> 753 #include <ddb/db_sym.h> 754 #include <ddb/db_extern.h> 755 756 int obp_symbol_debug = 0; 757 758 void OF_sym2val(cells) 759 void *cells; 760 { 761 struct args { 762 cell_t service; 763 cell_t nargs; 764 cell_t nreturns; 765 cell_t symbol; 766 cell_t result; 767 cell_t value; 768 } *args = (struct args*)cells; 769 char *symbol; 770 db_expr_t value; 771 772 /* Set data segment pointer */ 773 __asm volatile("clr %%g4" : :); 774 775 /* No args? Nothing to do. */ 776 if (!args->nargs || 777 !args->nreturns) return; 778 779 /* Do we have a place for the value? */ 780 if (args->nreturns != 2) { 781 args->nreturns = 1; 782 args->result = -1; 783 return; 784 } 785 symbol = (char *)(u_long)args->symbol; 786 if (obp_symbol_debug) 787 prom_printf("looking up symbol %s\r\n", symbol); 788 args->result = (db_value_of_name(symbol, &value) == TRUE) ? 0 : -1; 789 if (obp_symbol_debug) 790 prom_printf("%s is %lx\r\n", symbol, value); 791 args->value = ADR2CELL(value); 792 } 793 794 void OF_val2sym(cells) 795 void *cells; 796 { 797 struct args { 798 cell_t service; 799 cell_t nargs; 800 cell_t nreturns; 801 cell_t value; 802 cell_t offset; 803 cell_t symbol; 804 } *args = (struct args*)cells; 805 db_sym_t symbol; 806 db_expr_t value; 807 db_expr_t offset; 808 809 /* Set data segment pointer */ 810 __asm volatile("clr %%g4" : :); 811 812 if (obp_symbol_debug) 813 prom_printf("OF_val2sym: nargs %lx nreturns %lx\r\n", 814 args->nargs, args->nreturns); 815 /* No args? Nothing to do. */ 816 if (!args->nargs || 817 !args->nreturns) return; 818 819 /* Do we have a place for the value? */ 820 if (args->nreturns != 2) { 821 args->nreturns = 1; 822 args->offset = -1; 823 return; 824 } 825 826 value = args->value; 827 if (obp_symbol_debug) 828 prom_printf("looking up value %ld\r\n", value); 829 symbol = db_search_symbol(value, 0, &offset); 830 if (symbol == NULL) { 831 if (obp_symbol_debug) 832 prom_printf("OF_val2sym: not found\r\n"); 833 args->nreturns = 1; 834 args->offset = -1; 835 return; 836 } 837 args->offset = offset; 838 args->symbol = ADR2CELL(symbol); 839 840 } 841 #endif 842 843 int 844 OF_is_compatible(int handle, const char *name) 845 { 846 char compat[256]; 847 char *str; 848 int len; 849 850 len = OF_getprop(handle, "compatible", &compat, sizeof(compat)); 851 if (len <= 0) 852 return 0; 853 854 /* Guarantee that the buffer is null-terminated. */ 855 compat[sizeof(compat) - 1] = 0; 856 857 str = compat; 858 while (len > 0) { 859 if (strcmp(str, name) == 0) 860 return 1; 861 len -= strlen(str) + 1; 862 str += strlen(str) + 1; 863 } 864 865 return 0; 866 } 867