1 /* $NetBSD: promlib.c,v 1.13 2001/12/07 11:00:39 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Paul Kranenburg. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * OPENPROM functions. These are here mainly to hide the OPENPROM interface 41 * from the rest of the kernel. 42 */ 43 #if defined(_KERNEL_OPT) 44 #include "opt_sparc_arch.h" 45 #endif 46 47 #include <sys/errno.h> 48 #include <sys/param.h> 49 50 #ifdef _STANDALONE 51 #include <lib/libsa/stand.h> 52 #define malloc(s,t,f) alloc(s) 53 #else 54 #include <sys/systm.h> 55 #include <sys/malloc.h> 56 #endif /* _STANDALONE */ 57 58 #include <machine/stdarg.h> 59 #include <machine/oldmon.h> 60 #include <machine/bsd_openprom.h> 61 #include <machine/promlib.h> 62 #include <machine/openfirm.h> 63 64 #define obpvec ((struct promvec *)romp) 65 66 static void notimplemented __P((void)); 67 static void obp_v0_fortheval __P((char *)); 68 static void obp_set_callback __P((void (*)__P((void)))); 69 static int obp_v0_read __P((int, void *, int)); 70 static int obp_v0_write __P((int, void *, int)); 71 static int obp_v2_getchar __P((void)); 72 static int obp_v2_peekchar __P((void)); 73 static void obp_v2_putchar __P((int)); 74 static void obp_v2_putstr __P((char *, int)); 75 static int obp_v2_seek __P((int, u_quad_t)); 76 static char *parse_bootfile __P((char *)); 77 static char *parse_bootargs __P((char *)); 78 static char *obp_v0_getbootpath __P((void)); 79 static char *obp_v0_getbootfile __P((void)); 80 static char *obp_v0_getbootargs __P((void)); 81 static char *obp_v2_getbootpath __P((void)); 82 static char *obp_v2_getbootfile __P((void)); 83 static char *obp_v2_getbootargs __P((void)); 84 static int obp_v2_finddevice __P((char *)); 85 static int obp_ticks __P((void)); 86 87 static int findchosen __P((void)); 88 static char *opf_getbootpath __P((void)); 89 static char *opf_getbootfile __P((void)); 90 static char *opf_getbootargs __P((void)); 91 static int opf_finddevice __P((char *)); 92 static int opf_instance_to_package __P((int)); 93 static char *opf_nextprop __P((int, char *)); 94 95 96 /* 97 * PROM entry points. 98 * Note: only PROM functions we use ar represented here; add as required. 99 */ 100 struct promops promops = { 101 -1, /* version */ 102 -1, /* revision */ 103 -1, /* stdin handle */ 104 -1, /* stdout handle */ 105 NULL, /* bootargs */ 106 107 (void *)notimplemented, /* bootpath */ 108 (void *)notimplemented, /* bootargs */ 109 (void *)notimplemented, /* bootfile */ 110 111 (void *)notimplemented, /* getchar */ 112 (void *)notimplemented, /* peekchar */ 113 (void *)notimplemented, /* putchar */ 114 (void *)notimplemented, /* putstr */ 115 (void *)notimplemented, /* open */ 116 (void *)notimplemented, /* close */ 117 (void *)notimplemented, /* read */ 118 (void *)notimplemented, /* write */ 119 (void *)notimplemented, /* seek */ 120 121 (void *)notimplemented, /* instance_to_package */ 122 123 (void *)notimplemented, /* halt */ 124 (void *)notimplemented, /* boot */ 125 (void *)notimplemented, /* call */ 126 (void *)notimplemented, /* interpret */ 127 (void *)notimplemented, /* callback */ 128 (void *)notimplemented, /* ticks */ 129 NULL, /* ticker data */ 130 131 (void *)notimplemented, /* setcontext */ 132 (void *)notimplemented, /* cpustart */ 133 (void *)notimplemented, /* cpustop */ 134 (void *)notimplemented, /* cpuidle */ 135 (void *)notimplemented, /* cpuresume */ 136 137 (void *)notimplemented, /* firstchild */ 138 (void *)notimplemented, /* nextsibling */ 139 140 (void *)notimplemented, /* getproplen */ 141 (void *)notimplemented, /* getprop */ 142 (void *)notimplemented, /* setprop */ 143 (void *)notimplemented, /* nextprop */ 144 (void *)notimplemented /* finddevice */ 145 }; 146 147 static void 148 notimplemented() 149 { 150 char str[64]; 151 int n; 152 153 n = sprintf(str, "Operation not implemented on ROM version %d\r\n", 154 promops.po_version); 155 156 /* 157 * Use PROM vector directly, in case we're called before prom_init(). 158 */ 159 #if defined(SUN4) 160 if (CPU_ISSUN4) { 161 struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE; 162 (*sun4pvec->fbWriteStr)(str, n); 163 } else 164 #endif 165 if (obpvec->pv_magic == OBP_MAGIC) { 166 if (obpvec->pv_romvec_vers < 2) { 167 (*obpvec->pv_putstr)(str, n); 168 } else { 169 int fd = *obpvec->pv_v2bootargs.v2_fd1; 170 (*obpvec->pv_v2devops.v2_write)(fd, str, n); 171 } 172 } else { /* assume OFW */ 173 static int stdout_node; 174 if (stdout_node == 0) { 175 int chosen = findchosen(); 176 OF_getprop(chosen, "stdout", &stdout_node, sizeof(int)); 177 } 178 OF_write(stdout_node, str, n); 179 } 180 } 181 182 183 /* 184 * PROM_getprop() reads the named property data from a given node. 185 * A buffer for the data may be passed in `*bufp'; if NULL, a 186 * buffer is allocated. The argument `size' specifies the data 187 * element size of the property data. This function checks that 188 * the actual property data length is an integral multiple of 189 * the element size. The number of data elements read into the 190 * buffer is returned into the integer pointed at by `nitem'. 191 */ 192 193 int 194 PROM_getprop(node, name, size, nitem, bufp) 195 int node; 196 char *name; 197 int size; 198 int *nitem; 199 void **bufp; 200 { 201 void *buf; 202 int len; 203 204 len = PROM_getproplen(node, name); 205 if (len <= 0) 206 return (ENOENT); 207 208 if ((len % size) != 0) 209 return (EINVAL); 210 211 buf = *bufp; 212 if (buf == NULL) { 213 /* No storage provided, so we allocate some */ 214 buf = malloc(len, M_DEVBUF, M_NOWAIT); 215 if (buf == NULL) 216 return (ENOMEM); 217 } else { 218 if (size * (*nitem) < len) 219 return (ENOMEM); 220 } 221 222 _prom_getprop(node, name, buf, len); 223 *bufp = buf; 224 *nitem = len / size; 225 return (0); 226 } 227 228 /* 229 * Return a string property. There is a (small) limit on the length; 230 * the string is fetched into a static buffer which is overwritten on 231 * subsequent calls. 232 */ 233 char * 234 PROM_getpropstring(node, name) 235 int node; 236 char *name; 237 { 238 static char stringbuf[32]; 239 240 return (PROM_getpropstringA(node, name, stringbuf, sizeof stringbuf)); 241 } 242 243 /* 244 * Alternative PROM_getpropstring(), where caller provides the buffer 245 */ 246 char * 247 PROM_getpropstringA(node, name, buf, bufsize) 248 int node; 249 char *name; 250 char *buf; 251 size_t bufsize; 252 { 253 int len = bufsize - 1; 254 255 if (PROM_getprop(node, name, 1, &len, (void **)&buf) != 0) 256 len = 0; 257 258 buf[len] = '\0'; /* usually unnecessary */ 259 return (buf); 260 } 261 262 /* 263 * Fetch an integer (or pointer) property. 264 * The return value is the property, or the default if there was none. 265 */ 266 int 267 PROM_getpropint(node, name, deflt) 268 int node; 269 char *name; 270 int deflt; 271 { 272 int intbuf, *ip = &intbuf; 273 int len = 1; 274 275 if (PROM_getprop(node, name, sizeof(int), &len, (void **)&ip) != 0) 276 return (deflt); 277 278 return (*ip); 279 } 280 281 #if 0 282 /* 283 * prom_search() recursively searches a PROM tree for a given node 284 */ 285 int 286 prom_search(rootnode, name) 287 int rootnode; 288 const char *name; 289 { 290 int rtnnode; 291 int node = rootnode; 292 char buf[32]; 293 294 #define GPSA(nm) PROM_getpropstringA(node, nm, buf, sizeof buf) 295 if (node == findroot() || 296 !strcmp("hierarchical", GPSA("device type"))) 297 node = firstchild(node); 298 299 if (node == 0) 300 panic("prom_search: null node"); 301 302 do { 303 if (strcmp(GPSA("name"), name) == 0) 304 return (node); 305 306 if ((strcmp(GPSA("device_type"), "hierarchical") == 0 || 307 strcmp(GPSA("name"), "iommu") == 0) 308 && (rtnnode = prom_search(node, name)) != 0) 309 return (rtnnode); 310 311 } while ((node = nextsibling(node)) != NULL); 312 313 return (0); 314 } 315 #endif 316 317 /* 318 * Find the named device in the PROM device tree. 319 * XXX - currently we discard any qualifiers attached to device component names 320 */ 321 int 322 obp_v2_finddevice(name) 323 char *name; 324 { 325 int node; 326 char component[64]; 327 char c, *startp, *endp, *cp; 328 #define IS_SEP(c) ((c) == '/' || (c) == '@' || (c) == ':') 329 330 if (name == NULL) 331 return (-1); 332 333 node = prom_findroot(); 334 335 for (startp = name; *startp != '\0'; ) { 336 node = prom_firstchild(node); 337 338 /* 339 * Identify next component in pathname 340 */ 341 while (*startp == '/') 342 startp++; 343 344 endp = startp; 345 while ((c = *endp) != '\0' && !IS_SEP(c)) 346 endp++; 347 348 /* Copy component */ 349 for (cp = component; startp != endp;) 350 *cp++ = *startp++; 351 352 /* Zero terminate this component */ 353 *cp = '\0'; 354 355 /* Advance `startp' over any non-slash separators */ 356 while ((c = *startp) != '\0' && c != '/') 357 startp++; 358 359 node = prom_findnode(node, component); 360 if (node == 0) 361 return (-1); 362 } 363 364 return (node); 365 } 366 367 368 /* 369 * Translate device path to node 370 */ 371 int 372 prom_opennode(path) 373 char *path; 374 { 375 int fd; 376 377 if (prom_version() < 2) { 378 printf("WARNING: opennode not valid on PROM version %d\n", 379 promops.po_version); 380 return (0); 381 } 382 fd = prom_open(path); 383 if (fd == 0) 384 return (0); 385 386 return (prom_instance_to_package(fd)); 387 } 388 389 int 390 prom_findroot() 391 { 392 static int rootnode; 393 int node; 394 395 if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0) 396 panic("no PROM root device"); 397 rootnode = node; 398 return (node); 399 } 400 401 /* 402 * Given a `first child' node number, locate the node with the given name. 403 * Return the node number, or 0 if not found. 404 */ 405 int 406 prom_findnode(first, name) 407 int first; 408 const char *name; 409 { 410 int node; 411 char buf[32]; 412 413 for (node = first; node != 0; node = prom_nextsibling(node)) { 414 if (strcmp(PROM_getpropstringA(node, "name", buf, sizeof(buf)), 415 name) == 0) 416 return (node); 417 } 418 return (0); 419 } 420 421 /* 422 * Determine whether a node has the given property. 423 */ 424 int 425 prom_node_has_property(node, prop) 426 int node; 427 const char *prop; 428 { 429 430 return (PROM_getproplen(node, (caddr_t)prop) != -1); 431 } 432 433 434 void 435 prom_halt() 436 { 437 438 prom_setcallback(NULL); 439 _prom_halt(); 440 panic("PROM exit failed"); 441 } 442 443 void 444 prom_boot(str) 445 char *str; 446 { 447 448 prom_setcallback(NULL); 449 _prom_boot(str); 450 panic("PROM boot failed"); 451 } 452 453 454 /* 455 * print debug info to prom. 456 * This is not safe, but then what do you expect? 457 */ 458 void 459 #ifdef __STDC__ 460 prom_printf(const char *fmt, ...) 461 #else 462 prom_printf(fmt, va_alist) 463 char *fmt; 464 va_dcl 465 #endif 466 { 467 static char buf[256]; 468 int i, len; 469 va_list ap; 470 471 va_start(ap, fmt); 472 len = vsnprintf(buf, sizeof(buf), fmt, ap); 473 va_end(ap); 474 475 #if _obp_not_cooked_ 476 (*promops.po_write)(promops.po_stdout, buf, len); 477 #endif 478 479 for (i = 0; i < len; i++) { 480 int c = buf[i]; 481 if (c == '\n') 482 (*promops.po_putchar)('\r'); 483 (*promops.po_putchar)(c); 484 } 485 } 486 487 488 /* 489 * Pass a string to the FORTH PROM to be interpreted. 490 * (Note: may fail silently) 491 */ 492 static void 493 obp_v0_fortheval(s) 494 char *s; 495 { 496 497 obpvec->pv_fortheval.v0_eval(strlen(s), s); 498 } 499 500 int 501 obp_v0_read(fd, buf, len) 502 int fd; 503 void *buf; 504 int len; 505 { 506 if (fd != prom_stdin()) 507 prom_printf("obp_v0_read: unimplemented read from %d\n", fd); 508 return (-1); 509 } 510 511 int 512 obp_v0_write(fd, buf, len) 513 int fd; 514 void *buf; 515 int len; 516 { 517 if (fd != prom_stdout()) 518 prom_printf("obp_v0_write: unimplemented write on %d\n", fd); 519 (*obpvec->pv_putstr)(buf, len); 520 return (-1); 521 } 522 523 __inline__ void 524 obp_v2_putchar(c) 525 int c; 526 { 527 char c0; 528 529 c0 = (c & 0x7f); 530 (*promops.po_write)(promops.po_stdout, &c0, 1); 531 } 532 533 #if 0 534 void 535 obp_v2_putchar_cooked(c) 536 int c; 537 { 538 539 if (c == '\n') 540 obp_v2_putchar('\r'); 541 obp_v2_putchar(c); 542 } 543 #endif 544 545 int 546 obp_v2_getchar() 547 { 548 char c; 549 int n; 550 551 while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1) 552 /*void*/; 553 if (c == '\r') 554 c = '\n'; 555 return (c); 556 } 557 558 int 559 obp_v2_peekchar() 560 { 561 char c; 562 int n; 563 564 n = (*promops.po_read)(promops.po_stdin, &c, 1); 565 if (n < 0) 566 return (-1); 567 568 if (c == '\r') 569 c = '\n'; 570 return (c); 571 } 572 573 int 574 obp_v2_seek(handle, offset) 575 int handle; 576 u_quad_t offset; 577 { 578 u_int32_t hi, lo; 579 580 lo = offset & ((u_int32_t)-1); 581 hi = (offset >> 32) & ((u_int32_t)-1); 582 (*obpvec->pv_v2devops.v2_seek)(handle, hi, lo); 583 return (0); 584 } 585 586 /* 587 * On SS1s (and also IPCs, SLCs), `promvec->pv_v0bootargs->ba_argv[1]' 588 * contains the flags that were given after the boot command. On SS2s 589 * (and ELCs, IPXs, etc. and any sun4m class machine), `pv_v0bootargs' 590 * is NULL but `*promvec->pv_v2bootargs.v2_bootargs' points to 591 * "netbsd -s" or whatever. 592 */ 593 char * 594 obp_v0_getbootpath() 595 { 596 struct v0bootargs *ba = promops.po_bootcookie; 597 return (ba->ba_argv[0]); 598 } 599 600 char * 601 obp_v0_getbootargs() 602 { 603 struct v0bootargs *ba = promops.po_bootcookie; 604 return (ba->ba_argv[1]); 605 } 606 607 char * 608 obp_v0_getbootfile() 609 { 610 struct v0bootargs *ba = promops.po_bootcookie; 611 return (ba->ba_kernel); 612 } 613 614 char * 615 parse_bootargs(args) 616 char *args; 617 { 618 char *cp; 619 620 for (cp = args; *cp != '\0'; cp++) { 621 if (*cp == '-') { 622 int c; 623 /* 624 * Looks like options start here, but check this 625 * `-' is not part of the kernel name. 626 */ 627 if (cp == args) 628 break; 629 if ((c = *(cp-1)) == ' ' || c == '\t') 630 break; 631 } 632 } 633 return (cp); 634 } 635 636 char * 637 obp_v2_getbootpath() 638 { 639 struct v2bootargs *ba = promops.po_bootcookie; 640 return (*ba->v2_bootpath); 641 } 642 643 char * 644 obp_v2_getbootargs() 645 { 646 struct v2bootargs *ba = promops.po_bootcookie; 647 648 return (parse_bootargs(*ba->v2_bootargs)); 649 } 650 651 char * 652 parse_bootfile(args) 653 char *args; 654 { 655 static char storage[128]; 656 char *cp, *dp; 657 658 cp = args; 659 dp = storage; 660 while (*cp != 0 && *cp != ' ' && *cp != '\t') { 661 if (dp >= storage + sizeof(storage) - 1) { 662 prom_printf("v2_bootargs too long\n"); 663 return (NULL); 664 } 665 if (*cp == '-') { 666 int c; 667 /* 668 * If this `-' is most likely the start of boot 669 * options, we're done. 670 */ 671 if (cp == args) 672 break; 673 if ((c = *(cp-1)) == ' ' || c == '\t') 674 break; 675 } 676 *dp++ = *cp++; 677 } 678 *dp = '\0'; 679 return (storage); 680 } 681 682 char * 683 obp_v2_getbootfile() 684 { 685 struct v2bootargs *ba = promops.po_bootcookie; 686 687 return (parse_bootfile(*ba->v2_bootargs)); 688 } 689 690 void 691 obp_v2_putstr(str, len) 692 char *str; 693 int len; 694 { 695 prom_write(prom_stdout(), str, len); 696 } 697 698 void 699 obp_set_callback(f) 700 void (*f)__P((void)); 701 { 702 *obpvec->pv_synchook = f; 703 } 704 705 int 706 obp_ticks() 707 { 708 709 return (*((int *)promops.po_tickdata)); 710 } 711 712 static int 713 findchosen() 714 { 715 static int chosennode; 716 int node; 717 718 if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1) 719 panic("no CHOSEN node"); 720 721 chosennode = node; 722 return (node); 723 } 724 725 static int 726 opf_finddevice(name) 727 char *name; 728 { 729 int phandle = OF_finddevice(name); 730 if (phandle == -1) 731 return (0); 732 else 733 return (phandle); 734 } 735 736 static int 737 opf_instance_to_package(ihandle) 738 int ihandle; 739 { 740 int phandle = OF_instance_to_package(ihandle); 741 if (phandle == -1) 742 return (0); 743 else 744 return (phandle); 745 } 746 747 748 static char * 749 opf_getbootpath() 750 { 751 int node = findchosen(); 752 char *buf = NULL; 753 int blen = 0; 754 755 if (PROM_getprop(node, "bootpath", 1, &blen, (void **)&buf) != 0) 756 return (""); 757 758 return (buf); 759 } 760 761 static char * 762 opf_getbootargs() 763 { 764 int node = findchosen(); 765 char *buf = NULL; 766 int blen = 0; 767 768 if (PROM_getprop(node, "bootargs", 1, &blen, (void **)&buf) != 0) 769 return (""); 770 771 return (parse_bootargs(buf)); 772 } 773 774 static char * 775 opf_getbootfile() 776 { 777 int node = findchosen(); 778 char *buf = NULL; 779 int blen = 0; 780 781 if (PROM_getprop(node, "bootargs", 1, &blen, (void **)&buf) != 0) 782 return (""); 783 784 return (parse_bootfile(buf)); 785 } 786 787 static char * 788 opf_nextprop(node, prop) 789 int node; 790 char *prop; 791 { 792 #define OF_NEXTPROP_BUF_SIZE 32 /* specified by the standard */ 793 static char buf[OF_NEXTPROP_BUF_SIZE]; 794 OF_nextprop(node, prop, buf); 795 return (buf); 796 } 797 798 static void prom_init_oldmon __P((void)); 799 static void prom_init_obp __P((void)); 800 static void prom_init_opf __P((void)); 801 802 static __inline__ void 803 prom_init_oldmon() 804 { 805 struct om_vector *oldpvec = (struct om_vector *)PROM_BASE; 806 extern void sparc_noop __P((void)); 807 808 promops.po_version = PROM_OLDMON; 809 promops.po_revision = oldpvec->monId[0]; /*XXX*/ 810 811 promops.po_stdin = *oldpvec->inSource; 812 promops.po_stdout = *oldpvec->outSink; 813 814 promops.po_bootcookie = *oldpvec->bootParam; /* deref 1 lvl */ 815 promops.po_bootpath = obp_v0_getbootpath; 816 promops.po_bootfile = obp_v0_getbootfile; 817 promops.po_bootargs = obp_v0_getbootargs; 818 819 promops.po_putchar = oldpvec->putChar; 820 promops.po_getchar = oldpvec->getChar; 821 promops.po_peekchar = oldpvec->mayGet; 822 promops.po_putstr = oldpvec->fbWriteStr; 823 promops.po_reboot = oldpvec->reBoot; 824 promops.po_abort = oldpvec->abortEntry; 825 promops.po_halt = oldpvec->exitToMon; 826 promops.po_ticks = obp_ticks; 827 promops.po_tickdata = oldpvec->nmiClock; 828 promops.po_setcallback = (void *)sparc_noop; 829 promops.po_setcontext = oldpvec->setcxsegmap; 830 831 #ifdef SUN4 832 #ifndef _STANDALONE 833 if (oldpvec->romvecVersion >= 2) { 834 extern void oldmon_w_cmd __P((u_long, char *)); 835 *oldpvec->vector_cmd = oldmon_w_cmd; 836 } 837 #endif 838 #endif 839 } 840 841 static __inline__ void 842 prom_init_obp() 843 { 844 struct nodeops *no; 845 846 /* 847 * OBP v0, v2 & v3 848 */ 849 switch (obpvec->pv_romvec_vers) { 850 case 0: 851 promops.po_version = PROM_OBP_V0; 852 break; 853 case 2: 854 promops.po_version = PROM_OBP_V2; 855 break; 856 case 3: 857 promops.po_version = PROM_OBP_V3; 858 break; 859 default: 860 obpvec->pv_halt(); /* What else? */ 861 } 862 863 promops.po_revision = obpvec->pv_printrev; 864 865 promops.po_halt = obpvec->pv_halt; 866 promops.po_reboot = obpvec->pv_reboot; 867 promops.po_abort = obpvec->pv_abort; 868 promops.po_setcontext = obpvec->pv_setctxt; 869 promops.po_setcallback = obp_set_callback; 870 promops.po_ticks = obp_ticks; 871 promops.po_tickdata = obpvec->pv_ticks; 872 873 /* 874 * Remove indirection through `pv_nodeops' while we're here. 875 * Hopefully, the PROM has no need to change this pointer on the fly.. 876 */ 877 no = obpvec->pv_nodeops; 878 promops.po_firstchild = no->no_child; 879 promops.po_nextsibling = no->no_nextnode; 880 promops.po_getproplen = no->no_proplen; 881 /* XXX - silently discard getprop's `len' argument */ 882 promops.po_getprop = (void *)no->no_getprop; 883 promops.po_setprop = no->no_setprop; 884 promops.po_nextprop = no->no_nextprop; 885 886 /* 887 * Next, deal with prom vector differences between versions. 888 */ 889 switch (promops.po_version) { 890 case PROM_OBP_V0: 891 promops.po_stdin = *obpvec->pv_stdin; 892 promops.po_stdout = *obpvec->pv_stdout; 893 promops.po_bootcookie = *obpvec->pv_v0bootargs; /* deref 1 lvl */ 894 promops.po_bootpath = obp_v0_getbootpath; 895 promops.po_bootfile = obp_v0_getbootfile; 896 promops.po_bootargs = obp_v0_getbootargs; 897 promops.po_putchar = obpvec->pv_putchar; 898 promops.po_getchar = obpvec->pv_getchar; 899 promops.po_peekchar = obpvec->pv_nbgetchar; 900 promops.po_putstr = obpvec->pv_putstr; 901 promops.po_open = obpvec->pv_v0devops.v0_open; 902 promops.po_close = (void *)obpvec->pv_v0devops.v0_close; 903 promops.po_read = obp_v0_read; 904 promops.po_write = obp_v0_write; 905 promops.po_interpret = obp_v0_fortheval; 906 break; 907 case PROM_OBP_V3: 908 promops.po_cpustart = obpvec->pv_v3cpustart; 909 promops.po_cpustop = obpvec->pv_v3cpustop; 910 promops.po_cpuidle = obpvec->pv_v3cpuidle; 911 promops.po_cpuresume = obpvec->pv_v3cpuresume; 912 /*FALLTHROUGH*/ 913 case PROM_OBP_V2: 914 /* Deref stdio handles one level */ 915 promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0; 916 promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1; 917 918 promops.po_bootcookie = &obpvec->pv_v2bootargs; 919 promops.po_bootpath = obp_v2_getbootpath; 920 promops.po_bootfile = obp_v2_getbootfile; 921 promops.po_bootargs = obp_v2_getbootargs; 922 923 promops.po_interpret = obpvec->pv_fortheval.v2_eval; 924 925 promops.po_putchar = obp_v2_putchar; 926 promops.po_getchar = obp_v2_getchar; 927 promops.po_peekchar = obp_v2_peekchar; 928 promops.po_putstr = obp_v2_putstr; 929 promops.po_open = obpvec->pv_v2devops.v2_open; 930 promops.po_close = (void *)obpvec->pv_v2devops.v2_close; 931 promops.po_read = obpvec->pv_v2devops.v2_read; 932 promops.po_write = obpvec->pv_v2devops.v2_write; 933 promops.po_seek = obp_v2_seek; 934 promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle; 935 promops.po_finddevice = obp_v2_finddevice; 936 937 #ifndef _STANDALONE 938 prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n", 939 obpvec->pv_romvec_vers, 940 obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff, 941 obpvec->pv_plugin_vers); 942 #endif 943 break; 944 } 945 } 946 947 static __inline__ void 948 prom_init_opf() 949 { 950 int node; 951 952 promops.po_version = PROM_OPENFIRM; 953 954 /* 955 * OpenFirmware ops are mostly straightforward. 956 */ 957 promops.po_halt = OF_exit; 958 promops.po_reboot = OF_boot; 959 promops.po_abort = OF_enter; 960 promops.po_interpret = OF_interpret; 961 promops.po_setcallback = (void *)OF_set_callback; 962 promops.po_ticks = OF_milliseconds; 963 964 promops.po_bootpath = opf_getbootpath; 965 promops.po_bootfile = opf_getbootfile; 966 promops.po_bootargs = opf_getbootargs; 967 968 promops.po_firstchild = OF_child; 969 promops.po_nextsibling = OF_peer; 970 promops.po_getproplen = OF_getproplen; 971 promops.po_getprop = OF_getprop; 972 promops.po_nextprop = opf_nextprop; 973 promops.po_setprop = OF_setprop; 974 975 /* We can re-use OBP v2 emulation */ 976 promops.po_putchar = obp_v2_putchar; 977 promops.po_getchar = obp_v2_getchar; 978 promops.po_peekchar = obp_v2_peekchar; 979 promops.po_putstr = obp_v2_putstr; 980 981 promops.po_open = OF_open; 982 promops.po_close = OF_close; 983 promops.po_read = OF_read; 984 promops.po_write = OF_write; 985 promops.po_seek = OF_seek; 986 promops.po_instance_to_package = opf_instance_to_package; 987 promops.po_finddevice = opf_finddevice; 988 989 /* Retrieve and cache stdio handles */ 990 node = findchosen(); 991 OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int)); 992 OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int)); 993 } 994 995 /* 996 * Initialize our PROM operations vector. 997 */ 998 void 999 prom_init() 1000 { 1001 1002 if (CPU_ISSUN4) { 1003 prom_init_oldmon(); 1004 } else if (obpvec->pv_magic == OBP_MAGIC) { 1005 prom_init_obp(); 1006 } else { 1007 /* 1008 * Assume this is an Openfirm machine. 1009 */ 1010 prom_init_opf(); 1011 } 1012 } 1013