1 /* $NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej 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 __KERNEL_RCSID(0, "$NetBSD: openfirm.c,v 1.33 2021/02/13 01:48:33 thorpej Exp $"); 36 37 #ifdef _KERNEL_OPT 38 #include "opt_multiprocessor.h" 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <machine/psl.h> 47 #include <machine/autoconf.h> 48 49 #include <dev/ofw/openfirm.h> 50 51 char *OF_buf; 52 53 static void ofbcopy(const void *, void *, size_t); 54 55 #ifdef MULTIPROCESSOR 56 void OF_start_cpu(int, u_int, int); 57 58 59 static __cpu_simple_lock_t ofw_mutex = __SIMPLELOCK_UNLOCKED; 60 #endif /* MULTIPROCESSOR */ 61 62 static inline register_t 63 ofw_lock(void) 64 { 65 const register_t s = mfmsr(); 66 67 mtmsr(s & ~(PSL_EE|PSL_RI)); /* disable interrupts */ 68 69 #ifdef MULTIPROCESSOR 70 __cpu_simple_lock(&ofw_mutex); 71 #endif /* MULTIPROCESSOR */ 72 73 return s; 74 } 75 76 static inline void 77 ofw_unlock(register_t s) 78 { 79 #ifdef MULTIPROCESSOR 80 __cpu_simple_unlock(&ofw_mutex); 81 #endif /* MULTIPROCESSOR */ 82 mtmsr(s); 83 } 84 85 int 86 OF_peer(int phandle) 87 { 88 static struct { 89 const char *name; 90 int nargs; 91 int nreturns; 92 int phandle; 93 int sibling; 94 } args = { 95 "peer", 96 1, 97 1, 98 }; 99 100 const register_t s = ofw_lock(); 101 int rv; 102 103 args.phandle = phandle; 104 if (openfirmware(&args) == -1) 105 rv = 0; 106 else 107 rv = args.sibling; 108 109 ofw_unlock(s); 110 return rv; 111 } 112 113 int 114 OF_child(int phandle) 115 { 116 static struct { 117 const char *name; 118 int nargs; 119 int nreturns; 120 int phandle; 121 int child; 122 } args = { 123 "child", 124 1, 125 1, 126 }; 127 128 const register_t s = ofw_lock(); 129 int rv; 130 131 args.phandle = phandle; 132 if (openfirmware(&args) == -1) 133 rv = 0; 134 else 135 rv = args.child; 136 137 ofw_unlock(s); 138 return rv; 139 } 140 141 int 142 OF_parent(int phandle) 143 { 144 static struct { 145 const char *name; 146 int nargs; 147 int nreturns; 148 int phandle; 149 int parent; 150 } args = { 151 "parent", 152 1, 153 1, 154 }; 155 156 const register_t s = ofw_lock(); 157 int rv; 158 159 args.phandle = phandle; 160 if (openfirmware(&args) == -1) 161 rv = 0; 162 else 163 rv = args.parent; 164 165 ofw_unlock(s); 166 return rv; 167 } 168 169 int 170 OF_instance_to_package(int ihandle) 171 { 172 static struct { 173 const char *name; 174 int nargs; 175 int nreturns; 176 int ihandle; 177 int phandle; 178 } args = { 179 "instance-to-package", 180 1, 181 1, 182 }; 183 184 const register_t s = ofw_lock(); 185 int rv; 186 187 args.ihandle = ihandle; 188 if (openfirmware(&args) == -1) 189 rv = -1; 190 else 191 rv = args.phandle; 192 193 ofw_unlock(s); 194 return rv; 195 } 196 197 int 198 OF_getproplen(int handle, const char *prop) 199 { 200 static struct { 201 const char *name; 202 int nargs; 203 int nreturns; 204 int phandle; 205 const char *prop; 206 int proplen; 207 } args = { 208 "getproplen", 209 2, 210 1, 211 }; 212 213 const register_t s = ofw_lock(); 214 int rv; 215 216 strncpy(OF_buf, prop, 32); 217 args.phandle = handle; 218 args.prop = OF_buf; 219 if (openfirmware(&args) == -1) 220 rv = -1; 221 else 222 rv = args.proplen; 223 224 ofw_unlock(s); 225 return rv; 226 } 227 228 int 229 OF_getprop(int handle, const char *prop, void *buf, int buflen) 230 { 231 static struct { 232 const char *name; 233 int nargs; 234 int nreturns; 235 int phandle; 236 const char *prop; 237 void *buf; 238 int buflen; 239 int size; 240 } args = { 241 "getprop", 242 4, 243 1, 244 }; 245 246 if (buflen > PAGE_SIZE) 247 return -1; 248 249 const register_t s = ofw_lock(); 250 int rv; 251 252 strncpy(OF_buf, prop, 32); 253 args.phandle = handle; 254 args.prop = OF_buf; 255 args.buf = &OF_buf[33]; 256 args.buflen = buflen; 257 if (openfirmware(&args) == -1) 258 rv = -1; 259 else { 260 if (args.size > buflen) 261 args.size = buflen; 262 if (args.size > 0) 263 ofbcopy(&OF_buf[33], buf, args.size); 264 rv = args.size; 265 } 266 267 ofw_unlock(s); 268 return rv; 269 } 270 271 int 272 OF_setprop(int handle, const char *prop, const void *buf, int buflen) 273 { 274 struct { 275 const char *name; 276 int nargs; 277 int nreturns; 278 int phandle; 279 const char *prop; 280 const void *buf; 281 int buflen; 282 int size; 283 } args = { 284 "setprop", 285 4, 286 1 287 }; 288 289 if (buflen > PAGE_SIZE) 290 return -1; 291 292 const register_t s = ofw_lock(); 293 int rv; 294 295 ofbcopy(buf, OF_buf, buflen); 296 args.phandle = handle; 297 args.prop = prop; 298 args.buf = OF_buf; 299 args.buflen = buflen; 300 if (openfirmware(&args) == -1) 301 rv = -1; 302 else 303 rv = args.size; 304 305 ofw_unlock(s); 306 return rv; 307 } 308 309 int 310 OF_nextprop(int handle, const char *prop, void *nextprop) 311 { 312 static struct { 313 const char *name; 314 int nargs; 315 int nreturns; 316 int phandle; 317 const char *prop; 318 char *buf; 319 int flag; 320 } args = { 321 "nextprop", 322 3, 323 1, 324 }; 325 326 const register_t s = ofw_lock(); 327 int rv; 328 329 strncpy(OF_buf, prop, 32); 330 args.phandle = handle; 331 args.prop = OF_buf; 332 args.buf = &OF_buf[33]; 333 if (openfirmware(&args) == -1) 334 rv = -1; 335 else { 336 strncpy(nextprop, &OF_buf[33], 32); 337 rv = args.flag; 338 } 339 340 ofw_unlock(s); 341 return rv; 342 } 343 344 int 345 OF_finddevice(const char *name) 346 { 347 static struct { 348 const char *name; 349 int nargs; 350 int nreturns; 351 const char *device; 352 int phandle; 353 } args = { 354 "finddevice", 355 1, 356 1, 357 }; 358 359 const register_t s = ofw_lock(); 360 int rv; 361 362 strncpy(OF_buf, name, NBPG); 363 args.device = OF_buf; 364 if (openfirmware(&args) == -1) 365 rv = -1; 366 else 367 rv = args.phandle; 368 369 ofw_unlock(s); 370 return rv; 371 } 372 373 int 374 OF_instance_to_path(int ihandle, char *buf, int buflen) 375 { 376 static struct { 377 const char *name; 378 int nargs; 379 int nreturns; 380 int ihandle; 381 char *buf; 382 int buflen; 383 int length; 384 } args = { 385 "instance-to-path", 386 3, 387 1, 388 }; 389 390 if (buflen > PAGE_SIZE) 391 return -1; 392 393 const register_t s = ofw_lock(); 394 int rv; 395 396 args.ihandle = ihandle; 397 args.buf = OF_buf; 398 args.buflen = buflen; 399 if (openfirmware(&args) < 0) 400 rv = -1; 401 else { 402 if (args.length > buflen) 403 args.length = buflen; 404 if (args.length > 0) 405 ofbcopy(OF_buf, buf, args.length); 406 rv = args.length; 407 } 408 409 ofw_unlock(s); 410 return rv; 411 } 412 413 int 414 OF_package_to_path(int phandle, char *buf, int buflen) 415 { 416 static struct { 417 const char *name; 418 int nargs; 419 int nreturns; 420 int phandle; 421 char *buf; 422 int buflen; 423 int length; 424 } args = { 425 "package-to-path", 426 3, 427 1, 428 }; 429 430 if (buflen > PAGE_SIZE) 431 return -1; 432 433 const register_t s = ofw_lock(); 434 int rv; 435 436 args.phandle = phandle; 437 args.buf = OF_buf; 438 args.buflen = buflen; 439 if (openfirmware(&args) < 0) 440 rv = -1; 441 else { 442 if (args.length > buflen) 443 args.length = buflen; 444 if (args.length > 0) 445 ofbcopy(OF_buf, buf, args.length); 446 rv = args.length; 447 } 448 449 ofw_unlock(s); 450 return rv; 451 } 452 453 int 454 OF_call_method(const char *method, int ihandle, int nargs, int nreturns, ...) 455 { 456 static struct { 457 const char *name; 458 int nargs; 459 int nreturns; 460 const char *method; 461 int ihandle; 462 int args_n_results[12]; 463 } args = { 464 "call-method", 465 2, 466 1, 467 }; 468 469 if (nargs > 6) 470 return -1; 471 472 va_list ap; 473 int *ip, n; 474 int rv; 475 476 const register_t s = ofw_lock(); 477 478 args.nargs = nargs + 2; 479 args.nreturns = nreturns + 1; 480 args.method = method; 481 args.ihandle = ihandle; 482 483 va_start(ap, nreturns); 484 485 for (ip = args.args_n_results + (n = nargs); --n >= 0;) { 486 *--ip = va_arg(ap, int); 487 } 488 489 if (openfirmware(&args) == -1) { 490 rv = -1; 491 } else if (args.args_n_results[nargs]) { 492 rv = args.args_n_results[nargs]; 493 } else { 494 for (ip = args.args_n_results + nargs + (n = args.nreturns); 495 --n > 0;) { 496 *va_arg(ap, int *) = *--ip; 497 } 498 rv = 0; 499 } 500 501 va_end(ap); 502 503 ofw_unlock(s); 504 return rv; 505 } 506 507 int 508 OF_call_method_1(const char *method, int ihandle, int nargs, ...) 509 { 510 static struct { 511 const char *name; 512 int nargs; 513 int nreturns; 514 const char *method; 515 int ihandle; 516 int args_n_results[8]; 517 } args = { 518 "call-method", 519 2, 520 2, 521 }; 522 523 if (nargs > 6) 524 return -1; 525 526 va_list ap; 527 int *ip, n; 528 int rv; 529 530 const register_t s = ofw_lock(); 531 532 args.nargs = nargs + 2; 533 args.method = method; 534 args.ihandle = ihandle; 535 536 va_start(ap, nargs); 537 for (ip = args.args_n_results + (n = nargs); --n >= 0;) { 538 *--ip = va_arg(ap, int); 539 } 540 va_end(ap); 541 542 if (openfirmware(&args) == -1) 543 rv = -1; 544 else if (args.args_n_results[nargs]) 545 rv = -1; 546 else 547 rv = args.args_n_results[nargs + 1]; 548 549 ofw_unlock(s); 550 return rv; 551 } 552 553 int 554 OF_open(const char *dname) 555 { 556 static struct { 557 const char *name; 558 int nargs; 559 int nreturns; 560 const char *dname; 561 int handle; 562 } args = { 563 "open", 564 1, 565 1, 566 }; 567 int l; 568 569 if ((l = strlen(dname)) >= PAGE_SIZE) 570 return -1; 571 572 const register_t s = ofw_lock(); 573 int rv; 574 575 ofbcopy(dname, OF_buf, l + 1); 576 args.dname = OF_buf; 577 if (openfirmware(&args) == -1) 578 rv = -1; 579 else 580 rv = args.handle; 581 582 ofw_unlock(s); 583 return rv; 584 } 585 586 void 587 OF_close(int handle) 588 { 589 static struct { 590 const char *name; 591 int nargs; 592 int nreturns; 593 int handle; 594 } args = { 595 "close", 596 1, 597 0, 598 }; 599 600 const register_t s = ofw_lock(); 601 602 args.handle = handle; 603 openfirmware(&args); 604 605 ofw_unlock(s); 606 } 607 608 /* 609 * This assumes that character devices don't read in multiples of PAGE_SIZE. 610 */ 611 int 612 OF_read(int handle, void *addr, int len) 613 { 614 static struct { 615 const char *name; 616 int nargs; 617 int nreturns; 618 int ihandle; 619 void *addr; 620 int len; 621 int actual; 622 } args = { 623 "read", 624 3, 625 1, 626 }; 627 int l, act = 0; 628 char *p = addr; 629 630 const register_t s = ofw_lock(); 631 632 args.ihandle = handle; 633 args.addr = OF_buf; 634 for (; len > 0; len -= l, p += l) { 635 l = uimin(PAGE_SIZE, len); 636 args.len = l; 637 if (openfirmware(&args) == -1) { 638 act = -1; 639 goto out; 640 } 641 if (args.actual > 0) { 642 ofbcopy(OF_buf, p, args.actual); 643 act += args.actual; 644 } 645 if (args.actual < l) { 646 if (act == 0) { 647 act = args.actual; 648 } 649 goto out; 650 } 651 } 652 653 out: 654 ofw_unlock(s); 655 return act; 656 } 657 658 int 659 OF_write(int handle, const void *addr, int len) 660 { 661 static struct { 662 const char *name; 663 int nargs; 664 int nreturns; 665 int ihandle; 666 void *addr; 667 int len; 668 int actual; 669 } args = { 670 "write", 671 3, 672 1, 673 }; 674 int l, act = 0; 675 const char *p = addr; 676 677 const register_t s = ofw_lock(); 678 679 args.ihandle = handle; 680 args.addr = OF_buf; 681 for (; len > 0; len -= l, p += l) { 682 l = uimin(PAGE_SIZE, len); 683 ofbcopy(p, OF_buf, l); 684 args.len = l; 685 args.actual = l; /* work around a PIBS bug */ 686 if (openfirmware(&args) == -1) { 687 act = -1; 688 goto out; 689 } 690 l = args.actual; 691 act += l; 692 } 693 694 out: 695 ofw_unlock(s); 696 return act; 697 } 698 699 int 700 OF_seek(int handle, u_quad_t pos) 701 { 702 static struct { 703 const char *name; 704 int nargs; 705 int nreturns; 706 int handle; 707 int poshi; 708 int poslo; 709 int status; 710 } args = { 711 "seek", 712 3, 713 1, 714 }; 715 716 const register_t s = ofw_lock(); 717 int rv; 718 719 args.handle = handle; 720 args.poshi = (int)(pos >> 32); 721 args.poslo = (int)pos; 722 if (openfirmware(&args) == -1) 723 rv = -1; 724 else 725 rv = args.status; 726 727 ofw_unlock(s); 728 return rv; 729 } 730 731 #ifdef MULTIPROCESSOR 732 void 733 OF_start_cpu(int phandle, u_int pc, int arg) 734 { 735 static struct { 736 const char *name; 737 int nargs; 738 int nreturns; 739 int phandle; 740 u_int pc; 741 int arg; 742 } args = { 743 "start-cpu", 744 3, 745 0, 746 }; 747 748 const register_t s = ofw_lock(); 749 bool failed = false; 750 751 args.phandle = phandle; 752 args.pc = pc; 753 args.arg = arg; 754 if (openfirmware(&args) == -1) 755 failed = true; 756 757 ofw_unlock(s); 758 if (failed) { 759 panic("WTF?"); 760 } 761 } 762 #endif 763 764 void 765 OF_boot(const char *bstr) 766 { 767 static struct { 768 const char *name; 769 int nargs; 770 int nreturns; 771 char *bootspec; 772 } args = { 773 "boot", 774 1, 775 0, 776 }; 777 int l; 778 779 if ((l = strlen(bstr)) >= PAGE_SIZE) 780 panic("OF_boot"); 781 782 const register_t s = ofw_lock(); 783 784 ofbcopy(bstr, OF_buf, l + 1); 785 args.bootspec = OF_buf; 786 openfirmware(&args); 787 788 ofw_unlock(s); 789 panic("OF_boot didn't"); 790 } 791 792 void 793 OF_enter(void) 794 { 795 static struct { 796 const char *name; 797 int nargs; 798 int nreturns; 799 } args = { 800 "enter", 801 0, 802 0, 803 }; 804 805 const register_t s = ofw_lock(); 806 807 openfirmware(&args); 808 809 ofw_unlock(s); 810 } 811 812 void 813 OF_exit(void) 814 { 815 static struct { 816 const char *name; 817 int nargs; 818 int nreturns; 819 } args = { 820 "exit", 821 0, 822 0, 823 }; 824 825 const register_t s = ofw_lock(); 826 827 openfirmware(&args); 828 829 ofw_unlock(s); 830 while (1); /* just in case */ 831 } 832 833 void 834 (*OF_set_callback (void (*newfunc)(void *))) (void *) 835 { 836 static struct { 837 const char *name; 838 int nargs; 839 int nreturns; 840 void (*newfunc)(void *); 841 void (*oldfunc)(void *); 842 } args = { 843 "set-callback", 844 1, 845 1, 846 }; 847 848 const register_t s = ofw_lock(); 849 void (*rv)(void *); 850 851 args.newfunc = newfunc; 852 if (openfirmware(&args) == -1) 853 rv = NULL; 854 else 855 rv = args.oldfunc; 856 857 ofw_unlock(s); 858 return rv; 859 } 860 861 int 862 OF_interpret(const char *cmd, int nargs, int nreturns, ...) 863 { 864 static struct { 865 const char *name; 866 uint32_t nargs; 867 uint32_t nreturns; 868 uint32_t slots[16]; 869 } args = { 870 "interpret", 871 1, 872 2, 873 }; 874 875 va_list ap; 876 int i, len; 877 int rv; 878 879 if (nreturns > 8) 880 return -1; 881 if ((len = strlen(cmd)) >= PAGE_SIZE) 882 return -1; 883 884 const register_t s = ofw_lock(); 885 886 ofbcopy(cmd, OF_buf, len + 1); 887 i = 0; 888 args.slots[i] = (uintptr_t)OF_buf; 889 args.nargs = nargs + 1; 890 args.nreturns = nreturns + 1; 891 va_start(ap, nreturns); 892 i++; 893 while (i < args.nargs) { 894 args.slots[i] = (uintptr_t)va_arg(ap, uint32_t *); 895 i++; 896 } 897 898 if (openfirmware(&args) == -1) 899 rv = -1; 900 else { 901 rv = args.slots[i]; 902 i++; 903 904 while (i < args.nargs + args.nreturns) { 905 *va_arg(ap, uint32_t *) = args.slots[i]; 906 i++; 907 } 908 } 909 va_end(ap); 910 911 ofw_unlock(s); 912 return rv; 913 } 914 915 void 916 OF_quiesce(void) 917 { 918 static struct { 919 const char *name; 920 int nargs; 921 int nreturns; 922 } args = { 923 "quiesce", 924 0, 925 0, 926 }; 927 928 const register_t s = ofw_lock(); 929 930 openfirmware(&args); 931 932 ofw_unlock(s); 933 } 934 935 /* 936 * This version of bcopy doesn't work for overlapping regions! 937 */ 938 static void 939 ofbcopy(const void *src, void *dst, size_t len) 940 { 941 const char *sp = src; 942 char *dp = dst; 943 944 if (src == dst) 945 return; 946 947 while (len-- > 0) 948 *dp++ = *sp++; 949 } 950