1 /* $NetBSD: promlib.c,v 1.53 2025/10/04 01:12:14 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2025 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; and by Jason R. Thorpe. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * OPENPROM functions. These are here mainly to hide the OPENPROM interface 34 * from the rest of the kernel. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: promlib.c,v 1.53 2025/10/04 01:12:14 thorpej Exp $"); 39 40 #if defined(_KERNEL_OPT) 41 #include "opt_sparc_arch.h" 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/kernel.h> 46 #include <sys/device.h> 47 48 #ifdef _STANDALONE 49 #include <lib/libsa/stand.h> 50 #define malloc(s,t,f) alloc(s) 51 #else 52 #include <sys/device_calls.h> 53 #include <sys/systm.h> 54 #include <sys/malloc.h> 55 #include <sys/kmem.h> 56 #endif /* _STANDALONE */ 57 58 #include <machine/oldmon.h> 59 #include <machine/promlib.h> 60 #include <machine/ctlreg.h> 61 62 #include <sparc/sparc/asm.h> 63 #include <sparc/sparc/cache.h> 64 65 #include <lib/libkern/libkern.h> 66 67 #define obpvec ((struct promvec *)romp) 68 69 static void notimplemented(void); 70 static void obp_v0_fortheval(const char *); 71 static void obp_set_callback(void (*)(void)); 72 static int obp_v0_read(int, void *, int); 73 static int obp_v0_write(int, const void *, int); 74 static int obp_v2_getchar(void); 75 static int obp_v2_peekchar(void); 76 static void obp_v2_putchar(int); 77 static void obp_v2_putstr(const char *, int); 78 static int obp_v2_seek(int, u_quad_t); 79 static char *parse_bootfile(char *); 80 static char *parse_bootargs(char *); 81 static const char *obp_v0_getbootpath(void); 82 static const char *obp_v0_getbootfile(void); 83 static const char *obp_v0_getbootargs(void); 84 static const char *obp_v2_getbootpath(void); 85 static const char *obp_v2_getbootfile(void); 86 static const char *obp_v2_getbootargs(void); 87 static int obp_v2_finddevice(const char *); 88 static int obp_ticks(void); 89 90 static int findchosen(void); 91 static const char *opf_getbootpath(void); 92 static const char *opf_getbootfile(void); 93 static const char *opf_getbootargs(void); 94 static int opf_finddevice(const char *); 95 static int opf_instance_to_package(int); 96 static char *opf_nextprop(int, const char *); 97 static void opf_interpret_simple(const char *); 98 99 #ifndef _STANDALONE 100 static devhandle_t 101 null_prom_to_devhandle(int node __unused) 102 { 103 return devhandle_invalid(); 104 } 105 106 static int 107 null_devhandle_to_prom(devhandle_t devhandle __unused) 108 { 109 return 0; 110 } 111 #endif /* ! _STANDALONE */ 112 113 /* 114 * PROM entry points. 115 * Note: only PROM functions we use ar represented here; add as required. 116 */ 117 struct promops promops = { 118 -1, /* version */ 119 -1, /* revision */ 120 -1, /* stdin handle */ 121 -1, /* stdout handle */ 122 NULL, /* bootargs */ 123 124 (void *)notimplemented, /* bootpath */ 125 (void *)notimplemented, /* bootargs */ 126 (void *)notimplemented, /* bootfile */ 127 128 (void *)notimplemented, /* getchar */ 129 (void *)notimplemented, /* peekchar */ 130 (void *)notimplemented, /* putchar */ 131 (void *)notimplemented, /* putstr */ 132 (void *)notimplemented, /* open */ 133 (void *)notimplemented, /* close */ 134 (void *)notimplemented, /* read */ 135 (void *)notimplemented, /* write */ 136 (void *)notimplemented, /* seek */ 137 138 (void *)notimplemented, /* instance_to_package */ 139 140 (void *)notimplemented, /* halt */ 141 (void *)notimplemented, /* boot */ 142 (void *)notimplemented, /* call */ 143 (void *)notimplemented, /* interpret */ 144 (void *)notimplemented, /* callback */ 145 (void *)notimplemented, /* ticks */ 146 NULL, /* ticker data */ 147 148 (void *)notimplemented, /* setcontext */ 149 (void *)notimplemented, /* cpustart */ 150 (void *)notimplemented, /* cpustop */ 151 (void *)notimplemented, /* cpuidle */ 152 (void *)notimplemented, /* cpuresume */ 153 154 (void *)notimplemented, /* firstchild */ 155 (void *)notimplemented, /* nextsibling */ 156 157 (void *)notimplemented, /* getproplen */ 158 (void *)notimplemented, /* getprop */ 159 (void *)notimplemented, /* setprop */ 160 (void *)notimplemented, /* nextprop */ 161 (void *)notimplemented, /* finddevice */ 162 163 /* 164 * These should never be called in the STANDALONE environment, 165 * but when we're in the kernel environment, it's not really 166 * invalid to do so. 167 */ 168 #ifdef STANDALONE 169 (void *)notimplemented, /* node_to_devhandle */ 170 (void *)notimplemented, /* devhandle_to_node */ 171 #else 172 (void *)null_prom_to_devhandle, /* node_to_devhandle */ 173 (void *)null_devhandle_to_prom, /* devhandle_to_node */ 174 #endif /* STANDALONE */ 175 }; 176 177 static void 178 notimplemented(void) 179 { 180 char str[64]; 181 int n; 182 183 n = snprintf(str, sizeof(str), 184 "Operation not implemented on ROM version %d\r\n", 185 promops.po_version); 186 187 /* 188 * Use PROM vector directly, in case we're called before prom_init(). 189 */ 190 #if defined(SUN4) 191 if (CPU_ISSUN4) { 192 struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE; 193 (*sun4pvec->fbWriteStr)(str, n); 194 } else 195 #endif 196 if (obpvec->pv_magic == OBP_MAGIC) { 197 if (obpvec->pv_romvec_vers < 2) { 198 (*obpvec->pv_putstr)(str, n); 199 } else { 200 int fd = *obpvec->pv_v2bootargs.v2_fd1; 201 (*obpvec->pv_v2devops.v2_write)(fd, str, n); 202 } 203 } else { /* assume OFW */ 204 static int stdout_node; 205 if (stdout_node == 0) { 206 int chosen = findchosen(); 207 OF_getprop(chosen, "stdout", &stdout_node, sizeof(int)); 208 } 209 OF_write(stdout_node, str, n); 210 } 211 } 212 213 #ifndef _STANDALONE 214 /* 215 * OBP device handle support. We subsume v0-v3 into a single implementation 216 * and use promops to handle differences. 217 * 218 * On 32-bit SPARC, the OpenFirmware variant also gets redirected here. 219 * See prom_init_opf(). 220 */ 221 222 static device_call_t 223 obp_devhandle_lookup_device_call(devhandle_t handle, const char *name, 224 devhandle_t *call_handlep) 225 { 226 __link_set_decl(obp_device_calls, struct device_call_descriptor); 227 struct device_call_descriptor * const *desc; 228 229 __link_set_foreach(desc, obp_device_calls) { 230 if (strcmp((*desc)->name, name) == 0) { 231 return (*desc)->call; 232 } 233 } 234 return NULL; 235 } 236 237 static const struct devhandle_impl obp_devhandle_impl = { 238 .type = DEVHANDLE_TYPE_OPENBOOT, 239 .lookup_device_call = obp_devhandle_lookup_device_call, 240 }; 241 242 static devhandle_t 243 devhandle_from_obp(devhandle_t super_handle, int node) 244 { 245 devhandle_type_t super_type = devhandle_type(super_handle); 246 devhandle_t handle = { 0 }; 247 248 if (super_type == DEVHANDLE_TYPE_OPENBOOT) { 249 handle.impl = super_handle.impl; 250 } else { 251 KASSERT(super_type == DEVHANDLE_TYPE_INVALID); 252 handle.impl = &obp_devhandle_impl; 253 } 254 handle.integer = node; 255 256 return handle; 257 } 258 259 static int 260 devhandle_to_obp(devhandle_t const handle) 261 { 262 KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_OPENBOOT); 263 264 return handle.integer; 265 } 266 267 static int 268 obp_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v) 269 { 270 struct device_enumerate_children_args *args = v; 271 int node = devhandle_to_obp(call_handle); 272 273 for (node = prom_firstchild(node); node != 0; 274 node = prom_nextsibling(node)) { 275 if (!args->callback(dev, devhandle_from_obp(call_handle, node), 276 args->callback_arg)) { 277 break; 278 } 279 } 280 281 return 0; 282 } 283 OBP_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR, 284 obp_device_enumerate_children) 285 286 static bool 287 obp_is_bool_prop(const char *prop __unused, char *propval, int propsize, 288 bool *valp) 289 { 290 /* 291 * Alas, while this is the convention (mainly in the /options 292 * node), apparently it is not universal, so we'll be liberal 293 * in what we accept. 294 */ 295 #if 0 296 /* 297 * Naming convention is "propname?" is a boolean property 298 * with a "true" or "false" value. 299 */ 300 if (prop[strlen(prop) - 1] != '?') { 301 return false; 302 } 303 #endif 304 305 if (propsize >= 4 && memcmp(propval, "true", 4) == 0) { 306 *valp = true; 307 return true; 308 } 309 if (propsize >= 5 && memcmp(propval, "false", 5) == 0) { 310 *valp = false; 311 return true; 312 } 313 return false; 314 } 315 316 static int 317 obp_device_get_property(device_t dev, devhandle_t call_handle, void *v) 318 { 319 struct device_get_property_args *args = v; 320 int node = devhandle_to_obp(call_handle); 321 int propsize, error = 0; 322 char *propval = NULL; 323 bool boolval = true; 324 prop_type_t proptype = PROP_TYPE_UNKNOWN; 325 326 propsize = prom_getproplen(node, args->prop); 327 if (propsize < 0) { 328 return ENOENT; 329 } 330 331 if (propsize == 0) { 332 goto done; 333 } 334 335 /* 336 * OpenBoot's getprop method doesn't actually have a buffer 337 * size argument (the one provided here gets silently dropped), 338 * so if we want to introspect the property in any way, we have 339 * to allocate a buffer for the whole thing. 340 */ 341 propval = kmem_alloc(propsize, KM_SLEEP); 342 _prom_getprop(node, args->prop, propval, propsize); 343 344 /* 345 * Check for the boolean property naming convention, and 346 * cache the value while we're at it. 347 */ 348 if (obp_is_bool_prop(args->prop, propval, propsize, &boolval)) { 349 proptype = PROP_TYPE_BOOL; 350 } 351 352 if (args->buf == NULL) { 353 goto done; 354 } 355 KASSERT(args->buflen != 0); 356 357 switch (args->reqtype) { 358 case PROP_TYPE_NUMBER: 359 KASSERT(args->buflen == sizeof(uint64_t)); 360 if (propsize == sizeof(uint32_t)) { 361 *(uint64_t *)args->buf = *(uint32_t *)propval; 362 } else if (propsize == sizeof(uint64_t)) { 363 *(uint64_t *)args->buf = *(uint64_t *)propval; 364 } else { 365 error = EFTYPE; 366 } 367 break; 368 369 case PROP_TYPE_STRING: 370 memset(args->buf, 0, args->buflen); 371 /* FALLTHROUGH */ 372 373 case PROP_TYPE_DATA: 374 if (args->buflen < propsize) { 375 error = EFBIG; 376 goto done; 377 } 378 memcpy(args->buf, propval, propsize); 379 if (args->reqtype == PROP_TYPE_STRING) { 380 /* 381 * Per the old code: "usually unnecessary." 382 */ 383 ((char *)args->buf)[args->buflen - 1] = '\0'; 384 } 385 break; 386 387 case PROP_TYPE_BOOL: 388 KASSERT(args->buflen == sizeof(bool)); 389 /* 390 * If we noticed the boolean property naming convention, 391 * use the cached value from earlier. 392 */ 393 if (proptype == PROP_TYPE_BOOL) { 394 *(bool *)args->buf = boolval; 395 } else { 396 error = EFTYPE; 397 } 398 break; 399 400 default: 401 error = EFTYPE; 402 break; 403 } 404 405 done: 406 if (propval != NULL) { 407 KASSERT(propsize > 0); 408 kmem_free(propval, propsize); 409 } 410 args->propsize = propsize; 411 args->encoding = _BYTE_ORDER; /* i.e. _BIG_ENDIAN */ 412 args->type = proptype; 413 return error; 414 } 415 OBP_DEVICE_CALL_REGISTER(DEVICE_GET_PROPERTY_STR, 416 obp_device_get_property) 417 #endif /* ! _STANDALONE */ 418 419 /* 420 * prom_getprop() reads the named property data from a given node. 421 * A buffer for the data may be passed in `*bufp'; if NULL, a 422 * buffer is allocated. The argument `size' specifies the data 423 * element size of the property data. This function checks that 424 * the actual property data length is an integral multiple of 425 * the element size. The number of data elements read into the 426 * buffer is returned into the integer pointed at by `nitem'. 427 */ 428 429 int 430 prom_getprop(int node, const char *name, size_t size, int *nitem, void *bufp) 431 { 432 void *buf; 433 int len; 434 435 len = prom_getproplen(node, name); 436 if (len <= 0) 437 return (ENOENT); 438 439 if ((len % size) != 0) 440 return (EINVAL); 441 442 buf = *(void **)bufp; 443 if (buf == NULL) { 444 /* No storage provided, so we allocate some */ 445 buf = malloc(len, M_DEVBUF, M_NOWAIT); 446 if (buf == NULL) 447 return (ENOMEM); 448 } else { 449 if (size * (*nitem) < len) 450 return (ENOMEM); 451 } 452 453 _prom_getprop(node, name, buf, len); 454 *(void **)bufp = buf; 455 *nitem = len / size; 456 return (0); 457 } 458 459 /* 460 * Return a string property. There is a (small) limit on the length; 461 * the string is fetched into a static buffer which is overwritten on 462 * subsequent calls. 463 */ 464 char * 465 prom_getpropstring(int node, const char *name) 466 { 467 static char stringbuf[32]; 468 469 return (prom_getpropstringA(node, name, stringbuf, sizeof stringbuf)); 470 } 471 472 /* 473 * Alternative prom_getpropstring(), where caller provides the buffer 474 */ 475 char * 476 prom_getpropstringA(int node, const char *name, char *buf, size_t bufsize) 477 { 478 int len = bufsize - 1; 479 480 if (prom_getprop(node, name, 1, &len, &buf) != 0) 481 len = 0; 482 483 buf[len] = '\0'; /* usually unnecessary */ 484 return (buf); 485 } 486 487 /* 488 * Fetch an integer (or pointer) property. 489 * The return value is the property, or the default if there was none. 490 */ 491 int 492 prom_getpropint(int node, const char *name, int deflt) 493 { 494 int intbuf, *ip = &intbuf; 495 int len = 1; 496 497 if (prom_getprop(node, name, sizeof(int), &len, &ip) != 0) 498 return (deflt); 499 500 return (*ip); 501 } 502 503 /* 504 * Fetch an unsigned 64-bit integer (or pointer) property. 505 * The return value is the property, or the default if there was none. 506 */ 507 uint64_t 508 prom_getpropuint64(int node, const char *name, uint64_t deflt) 509 { 510 uint64_t uint64buf, *uint64p = &uint64buf; 511 int len = 2; 512 513 if (prom_getprop(node, name, sizeof(uint64_t), &len, &uint64p) != 0) 514 return deflt; 515 516 return uint64buf; 517 } 518 519 /* 520 * Node Name Matching per IEEE 1275, section 4.3.6. 521 */ 522 static int 523 prom_matchname(int node, const char *name) 524 { 525 char buf[32], *cp; 526 527 prom_getpropstringA(node, "name", buf, sizeof buf); 528 if (strcmp(buf, name) == 0) 529 /* Exact match */ 530 return (1); 531 532 /* If name has a comma, an exact match is required */ 533 if (strchr(name, ',')) 534 return (0); 535 536 /* 537 * Otherwise, if the node's name contains a comma, we can match 538 * against the trailing string defined by the first comma. 539 */ 540 if ((cp = strchr(buf, ',')) != NULL) { 541 if (strcmp(cp + 1, name) == 0) 542 return (1); 543 } 544 545 return (0); 546 } 547 548 /* 549 * Translate device path to node 550 */ 551 int 552 prom_opennode(const char *path) 553 { 554 int fd; 555 556 if (prom_version() < 2) { 557 printf("WARNING: opennode not valid on PROM version %d\n", 558 promops.po_version); 559 return (0); 560 } 561 fd = prom_open(path); 562 if (fd == 0) 563 return (0); 564 565 return (prom_instance_to_package(fd)); 566 } 567 568 int 569 prom_findroot(void) 570 { 571 static int rootnode; 572 int node; 573 574 if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0) 575 panic("no PROM root device"); 576 rootnode = node; 577 return (node); 578 } 579 580 /* 581 * Given a `first child' node number, locate the node with the given name. 582 * Return the node number, or 0 if not found. 583 */ 584 int 585 prom_findnode(int first, const char *name) 586 { 587 int node; 588 589 for (node = first; node != 0; node = prom_nextsibling(node)) { 590 if (prom_matchname(node, name)) 591 return (node); 592 } 593 return (0); 594 } 595 596 /* 597 * Determine whether a node has the given property. 598 */ 599 int 600 prom_node_has_property(int node, const char *prop) 601 { 602 603 return (prom_getproplen(node, prop) != -1); 604 } 605 606 /* 607 * prom_search() recursively searches a PROM subtree for a given node name 608 * See IEEE 1275 `Search for matching child node', section 4.3.3. 609 */ 610 int 611 prom_search(int node, const char *name) 612 { 613 614 if (node == 0) 615 node = prom_findroot(); 616 617 if (prom_matchname(node, name)) 618 return (node); 619 620 for (node = prom_firstchild(node); node != 0; 621 node = prom_nextsibling(node)) { 622 int cnode; 623 if ((cnode = prom_search(node, name)) != 0) 624 return (cnode); 625 } 626 627 return (0); 628 } 629 630 /* 631 * Find the named device in the PROM device tree. 632 * XXX - currently we discard any qualifiers attached to device component names 633 */ 634 int 635 obp_v2_finddevice(const char *path) 636 { 637 int node; 638 char component[64]; 639 char c, *cp; 640 const char *startp, *endp; 641 #define IS_SEP(c) ((c) == '/' || (c) == '@' || (c) == ':') 642 643 if (path == NULL) 644 return (-1); 645 646 node = prom_findroot(); 647 648 for (startp = path; *startp != '\0'; ) { 649 /* 650 * Identify next component in path 651 */ 652 while (*startp == '/') 653 startp++; 654 655 endp = startp; 656 while ((c = *endp) != '\0' && !IS_SEP(c)) 657 endp++; 658 659 /* Copy component */ 660 for (cp = component; startp != endp;) { 661 /* Check component bounds */ 662 if (cp > component + sizeof component - 1) 663 return (-1); 664 *cp++ = *startp++; 665 } 666 667 /* Zero terminate this component */ 668 *cp = '\0'; 669 670 /* Advance `startp' over any non-slash separators */ 671 while ((c = *startp) != '\0' && c != '/') 672 startp++; 673 674 node = prom_findnode(prom_firstchild(node), component); 675 if (node == 0) 676 return (-1); 677 } 678 679 return (node); 680 } 681 682 683 /* 684 * Get the global "options" node Id. 685 */ 686 int prom_getoptionsnode(void) 687 { 688 static int optionsnode; 689 690 if (optionsnode == 0) { 691 optionsnode = prom_findnode(prom_firstchild(prom_findroot()), 692 "options"); 693 } 694 return optionsnode; 695 } 696 697 /* 698 * Return a property string value from the global "options" node. 699 */ 700 int prom_getoption(const char *name, char *buf, int buflen) 701 { 702 int node = prom_getoptionsnode(); 703 int error, len; 704 705 if (buflen == 0) 706 return (EINVAL); 707 708 if (node == 0) 709 return (ENOENT); 710 711 len = buflen - 1; 712 if ((error = prom_getprop(node, name, 1, &len, &buf)) != 0) 713 return error; 714 715 buf[len] = '\0'; 716 return (0); 717 } 718 719 void 720 prom_halt(void) 721 { 722 723 prom_setcallback(NULL); 724 _prom_halt(); 725 panic("PROM exit failed"); 726 } 727 728 void 729 prom_boot(char *str) 730 { 731 732 prom_setcallback(NULL); 733 _prom_boot(str); 734 panic("PROM boot failed"); 735 } 736 737 738 /* 739 * print debug info to prom. 740 * This is not safe, but then what do you expect? 741 */ 742 void 743 prom_printf(const char *fmt, ...) 744 { 745 static char buf[256]; 746 int i, len; 747 va_list ap; 748 749 va_start(ap, fmt); 750 len = vsnprintf(buf, sizeof(buf), fmt, ap); 751 va_end(ap); 752 753 #if _obp_not_cooked_ 754 (*promops.po_write)(promops.po_stdout, buf, len); 755 #endif 756 757 for (i = 0; i < len; i++) { 758 int c = buf[i]; 759 if (c == '\n') 760 (*promops.po_putchar)('\r'); 761 (*promops.po_putchar)(c); 762 } 763 } 764 765 766 /* 767 * Pass a string to the FORTH PROM to be interpreted. 768 * (Note: may fail silently) 769 */ 770 static void 771 obp_v0_fortheval(const char *s) 772 { 773 774 obpvec->pv_fortheval.v0_eval(strlen(s), s); 775 } 776 777 int 778 obp_v0_read(int fd, void *buf, int len) 779 { 780 if (fd != prom_stdin()) 781 prom_printf("obp_v0_read: unimplemented read from %d\n", fd); 782 return (-1); 783 } 784 785 int 786 obp_v0_write(int fd, const void *buf, int len) 787 { 788 if (fd != prom_stdout()) 789 prom_printf("obp_v0_write: unimplemented write on %d\n", fd); 790 (*obpvec->pv_putstr)(buf, len); 791 return (-1); 792 } 793 794 inline void 795 obp_v2_putchar(int c) 796 { 797 char c0; 798 799 c0 = (c & 0x7f); 800 (*promops.po_write)(promops.po_stdout, &c0, 1); 801 } 802 803 #if 0 804 void 805 obp_v2_putchar_cooked(int c) 806 { 807 808 if (c == '\n') 809 obp_v2_putchar('\r'); 810 obp_v2_putchar(c); 811 } 812 #endif 813 814 int 815 obp_v2_getchar(void) 816 { 817 char c; 818 int n; 819 820 while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1) 821 /*void*/; 822 if (c == '\r') 823 c = '\n'; 824 return (c); 825 } 826 827 int 828 obp_v2_peekchar(void) 829 { 830 char c; 831 int n; 832 833 n = (*promops.po_read)(promops.po_stdin, &c, 1); 834 if (n < 0) 835 return (-1); 836 837 if (c == '\r') 838 c = '\n'; 839 return (c); 840 } 841 842 int 843 obp_v2_seek(int handle, u_quad_t offset) 844 { 845 uint32_t hi, lo; 846 847 lo = offset & ((uint32_t)-1); 848 hi = (offset >> 32) & ((uint32_t)-1); 849 (*obpvec->pv_v2devops.v2_seek)(handle, hi, lo); 850 return (0); 851 } 852 853 /* 854 * On SS1s (and also IPCs, SLCs), `promvec->pv_v0bootargs->ba_argv[1]' 855 * contains the flags that were given after the boot command. On SS2s 856 * (and ELCs, IPXs, etc. and any sun4m class machine), `pv_v0bootargs' 857 * is NULL but `*promvec->pv_v2bootargs.v2_bootargs' points to 858 * "netbsd -s" or whatever. 859 */ 860 const char * 861 obp_v0_getbootpath(void) 862 { 863 struct v0bootargs *ba = promops.po_bootcookie; 864 return (ba->ba_argv[0]); 865 } 866 867 const char * 868 obp_v0_getbootargs(void) 869 { 870 struct v0bootargs *ba = promops.po_bootcookie; 871 return (ba->ba_argv[1]); 872 } 873 874 const char * 875 obp_v0_getbootfile(void) 876 { 877 struct v0bootargs *ba = promops.po_bootcookie; 878 return (ba->ba_kernel); 879 } 880 881 char * 882 parse_bootargs(char *args) 883 { 884 char *cp; 885 886 for (cp = args; *cp != '\0'; cp++) { 887 if (*cp == '-') { 888 int c; 889 /* 890 * Looks like options start here, but check this 891 * `-' is not part of the kernel name. 892 */ 893 if (cp == args) 894 break; 895 if ((c = *(cp-1)) == ' ' || c == '\t') 896 break; 897 } 898 } 899 return (cp); 900 } 901 902 const char * 903 obp_v2_getbootpath(void) 904 { 905 struct v2bootargs *ba = promops.po_bootcookie; 906 return (*ba->v2_bootpath); 907 } 908 909 const char * 910 obp_v2_getbootargs(void) 911 { 912 struct v2bootargs *ba = promops.po_bootcookie; 913 914 return (parse_bootargs(*ba->v2_bootargs)); 915 } 916 917 /* 918 * Static storage shared by prom_getbootfile(), prom_getbootargs() and 919 * prom_getbootpath(). 920 * Overwritten on each call! 921 */ 922 static char storage[128]; 923 924 char * 925 parse_bootfile(char *args) 926 { 927 char *cp, *dp; 928 929 cp = args; 930 dp = storage; 931 while (*cp != 0 && *cp != ' ' && *cp != '\t') { 932 if (dp >= storage + sizeof(storage) - 1) { 933 prom_printf("v2_bootargs too long\n"); 934 return (NULL); 935 } 936 if (*cp == '-') { 937 int c; 938 /* 939 * If this `-' is most likely the start of boot 940 * options, we're done. 941 */ 942 if (cp == args) 943 break; 944 if ((c = *(cp-1)) == ' ' || c == '\t') 945 break; 946 } 947 *dp++ = *cp++; 948 } 949 *dp = '\0'; 950 return (storage); 951 } 952 953 const char * 954 obp_v2_getbootfile(void) 955 { 956 struct v2bootargs *ba = promops.po_bootcookie; 957 char *kernel = parse_bootfile(*ba->v2_bootargs); 958 char buf[4+1]; 959 const char *prop; 960 961 if (kernel[0] != '\0') 962 return kernel; 963 964 /* 965 * The PROM does not insert the `boot-file' variable if any argument 966 * was given to the `boot' command (e.g `boot -s'). If we determine 967 * in parse_bootfile() above, that boot args contain only switches 968 * then get the `boot-file' value (if any) ourselves. 969 * If the `diag-switch?' PROM variable is set to true, we use 970 * `diag-file' instead. 971 */ 972 prop = (prom_getoption("diag-switch?", buf, sizeof buf) != 0 || 973 strcmp(buf, "true") != 0) 974 ? "diag-file" 975 : "boot-file"; 976 977 if (prom_getoption(prop, storage, sizeof storage) != 0) 978 return (NULL); 979 980 return (storage); 981 } 982 983 void 984 obp_v2_putstr(const char *str, int len) 985 { 986 prom_write(prom_stdout(), str, len); 987 } 988 989 void 990 obp_set_callback(void (*f)(void)) 991 { 992 *obpvec->pv_synchook = f; 993 } 994 995 int 996 obp_ticks(void) 997 { 998 999 return (*((int *)promops.po_tickdata)); 1000 } 1001 1002 static int 1003 findchosen(void) 1004 { 1005 static int chosennode; 1006 int node; 1007 1008 if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1) 1009 panic("no CHOSEN node"); 1010 1011 chosennode = node; 1012 return (node); 1013 } 1014 1015 static int 1016 opf_finddevice(const char *name) 1017 { 1018 int phandle = OF_finddevice(name); 1019 if (phandle == -1) 1020 return (0); 1021 else 1022 return (phandle); 1023 } 1024 1025 static int 1026 opf_instance_to_package(int ihandle) 1027 { 1028 int phandle = OF_instance_to_package(ihandle); 1029 if (phandle == -1) 1030 return (0); 1031 else 1032 return (phandle); 1033 } 1034 1035 1036 static const char * 1037 opf_getbootpath(void) 1038 { 1039 int node = findchosen(); 1040 char *buf = storage; 1041 int blen = sizeof storage; 1042 1043 if (prom_getprop(node, "bootpath", 1, &blen, &buf) != 0) 1044 return (""); 1045 1046 return (buf); 1047 } 1048 1049 static const char * 1050 opf_getbootargs(void) 1051 { 1052 int node = findchosen(); 1053 char *buf = storage; 1054 int blen = sizeof storage; 1055 1056 if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0) 1057 return (""); 1058 1059 return (parse_bootargs(buf)); 1060 } 1061 1062 static const char * 1063 opf_getbootfile(void) 1064 { 1065 int node = findchosen(); 1066 char *buf = storage; 1067 int blen = sizeof storage; 1068 1069 if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0) 1070 return (""); 1071 1072 return (parse_bootfile(buf)); 1073 } 1074 1075 static char * 1076 opf_nextprop(int node, const char *prop) 1077 { 1078 #define OF_NEXTPROP_BUF_SIZE 32 /* specified by the standard */ 1079 static char buf[OF_NEXTPROP_BUF_SIZE]; 1080 OF_nextprop(node, prop, buf); 1081 return (buf); 1082 } 1083 1084 void 1085 opf_interpret_simple(const char *s) 1086 { 1087 (void)OF_interpret(s, 0, 0); 1088 } 1089 1090 /* 1091 * Retrieve physical memory information from the PROM. 1092 * If ap is NULL, return the required length of the array. 1093 */ 1094 int 1095 prom_makememarr(struct memarr *ap, int xmax, int which) 1096 { 1097 struct v0mlist *mp; 1098 int node, n; 1099 const char *prop; 1100 1101 if (which != MEMARR_AVAILPHYS && which != MEMARR_TOTALPHYS) 1102 panic("makememarr"); 1103 1104 /* 1105 * `struct memarr' is in V2 memory property format. 1106 * On previous ROM versions we must convert. 1107 */ 1108 switch (prom_version()) { 1109 struct promvec *promvec; 1110 struct om_vector *oldpvec; 1111 case PROM_OLDMON: 1112 oldpvec = (struct om_vector *)PROM_BASE; 1113 n = 1; 1114 if (ap != NULL) { 1115 ap[0].zero = 0; 1116 ap[0].addr = 0; 1117 ap[0].len = (which == MEMARR_AVAILPHYS) 1118 ? *oldpvec->memoryAvail 1119 : *oldpvec->memorySize; 1120 } 1121 break; 1122 1123 case PROM_OBP_V0: 1124 /* 1125 * Version 0 PROMs use a linked list to describe these 1126 * guys. 1127 */ 1128 promvec = romp; 1129 mp = (which == MEMARR_AVAILPHYS) 1130 ? *promvec->pv_v0mem.v0_physavail 1131 : *promvec->pv_v0mem.v0_phystot; 1132 for (n = 0; mp != NULL; mp = mp->next, n++) { 1133 if (ap == NULL) 1134 continue; 1135 if (n >= xmax) { 1136 printf("makememarr: WARNING: lost some memory\n"); 1137 break; 1138 } 1139 ap->zero = 0; 1140 ap->addr = (u_long)mp->addr; 1141 ap->len = mp->nbytes; 1142 ap++; 1143 } 1144 break; 1145 1146 default: 1147 printf("makememarr: hope version %d PROM is like version 2\n", 1148 prom_version()); 1149 /* FALLTHROUGH */ 1150 1151 case PROM_OBP_V3: 1152 case PROM_OBP_V2: 1153 /* 1154 * Version 2 PROMs use a property array to describe them. 1155 */ 1156 1157 /* Consider emulating `OF_finddevice' */ 1158 node = findnode(firstchild(findroot()), "memory"); 1159 goto case_common; 1160 1161 case PROM_OPENFIRM: 1162 node = OF_finddevice("/memory"); 1163 if (node == -1) 1164 node = 0; 1165 1166 case_common: 1167 if (node == 0) 1168 panic("makememarr: cannot find \"memory\" node"); 1169 1170 prop = (which == MEMARR_AVAILPHYS) ? "available" : "reg"; 1171 if (ap == NULL) { 1172 n = prom_getproplen(node, prop); 1173 } else { 1174 n = xmax; 1175 if (prom_getprop(node, prop, sizeof(struct memarr), 1176 &n, &ap) != 0) 1177 panic("makememarr: cannot get property"); 1178 } 1179 break; 1180 } 1181 1182 if (n <= 0) 1183 panic("makememarr: no memory found"); 1184 /* 1185 * Success! (Hooray) 1186 */ 1187 return (n); 1188 } 1189 1190 static struct idprom idprom; 1191 #ifdef _STANDALONE 1192 long hostid; 1193 #endif 1194 1195 struct idprom * 1196 prom_getidprom(void) 1197 { 1198 int node, len; 1199 u_long h; 1200 u_char *dst; 1201 1202 if (idprom.idp_format != 0) 1203 /* Already got it */ 1204 return (&idprom); 1205 1206 dst = (u_char *)&idprom; 1207 len = sizeof(struct idprom); 1208 1209 switch (prom_version()) { 1210 case PROM_OLDMON: 1211 #ifdef AC_IDPROM 1212 { 1213 u_char *src = (u_char *)AC_IDPROM; 1214 do { 1215 *dst++ = lduba(src++, ASI_CONTROL); 1216 } while (--len > 0); 1217 } 1218 #endif 1219 break; 1220 1221 /* 1222 * Fetch the `idprom' property at the root node. 1223 */ 1224 case PROM_OBP_V0: 1225 case PROM_OBP_V2: 1226 case PROM_OPENFIRM: 1227 case PROM_OBP_V3: 1228 node = prom_findroot(); 1229 if (prom_getprop(node, "idprom", 1, &len, &dst) != 0) { 1230 printf("`idprom' property cannot be read: " 1231 "cannot get ethernet address"); 1232 } 1233 break; 1234 } 1235 1236 /* Establish hostid */ 1237 h = (u_int)idprom.idp_machtype << 24; 1238 h |= idprom.idp_serialnum[0] << 16; 1239 h |= idprom.idp_serialnum[1] << 8; 1240 h |= idprom.idp_serialnum[2]; 1241 hostid = h; 1242 1243 return (&idprom); 1244 } 1245 1246 void prom_getether(int node, u_char *cp) 1247 { 1248 struct idprom *idp; 1249 1250 if (prom_get_node_ether(node, cp)) 1251 return; 1252 1253 /* Fall back on the machine's global ethernet address */ 1254 idp = prom_getidprom(); 1255 memcpy(cp, idp->idp_etheraddr, 6); 1256 } 1257 1258 bool 1259 prom_get_node_ether(int node, u_char *cp) 1260 { 1261 char buf[6+1], *bp; 1262 int nitem; 1263 1264 if (node == 0) 1265 return false; 1266 1267 /* 1268 * First, try the node's "mac-address" property. 1269 * This property is set by the adapter's firmware if the 1270 * device has already been opened for traffic, e.g. for 1271 * net booting. Its value might be `0-terminated', probably 1272 * because the Forth ROMs uses `xdrstring' instead of `xdrbytes' 1273 * to construct the property. 1274 */ 1275 nitem = 6+1; 1276 bp = buf; 1277 if (prom_getprop(node, "mac-address", 1, &nitem, &bp) == 0 && 1278 nitem >= 6) { 1279 memcpy(cp, bp, 6); 1280 return true; 1281 } 1282 1283 /* 1284 * Next, check the global "local-mac-address?" switch to see 1285 * if we should try to extract the node's "local-mac-address" 1286 * property. 1287 */ 1288 if (prom_getoption("local-mac-address?", buf, sizeof buf) != 0 || 1289 strcmp(buf, "true") != 0) 1290 return false; 1291 1292 /* Retrieve the node's "local-mac-address" property, if any */ 1293 nitem = 6; 1294 if (prom_getprop(node, "local-mac-address", 1, &nitem, &cp) == 0 && 1295 nitem == 6) 1296 return true; 1297 1298 return false; 1299 } 1300 1301 /* 1302 * The integer property "get-unum" on the root device is the address 1303 * of a callable function in the PROM that takes a physical address 1304 * (in lo/hipart format) and returns a string identifying the chip 1305 * location of the corresponding memory cell. 1306 */ 1307 const char * 1308 prom_pa_location(u_int phys_lo, u_int phys_hi) 1309 { 1310 static char *(*unum)(u_int, u_int); 1311 char *str; 1312 const char *unk = "<Unknown>"; 1313 1314 switch (prom_version()) { 1315 case PROM_OLDMON: 1316 case PROM_OPENFIRM: 1317 /* to do */ 1318 default: 1319 break; 1320 case PROM_OBP_V0: 1321 case PROM_OBP_V2: 1322 case PROM_OBP_V3: 1323 if (unum == NULL) 1324 unum = (char *(*)(u_int,u_int))(u_long) 1325 prom_getpropint(prom_findroot(), "get-unum", 0); 1326 1327 if (unum == NULL || (str = unum(phys_lo, phys_hi)) == NULL) 1328 break; 1329 1330 return (str); 1331 } 1332 1333 return (unk); 1334 } 1335 1336 static void prom_init_oldmon(void); 1337 static void prom_init_obp(void); 1338 static void prom_init_opf(void); 1339 1340 static inline void 1341 prom_init_oldmon(void) 1342 { 1343 struct om_vector *oldpvec = (struct om_vector *)PROM_BASE; 1344 1345 promops.po_version = PROM_OLDMON; 1346 promops.po_revision = oldpvec->monId[0]; /*XXX*/ 1347 1348 promops.po_stdin = *oldpvec->inSource; 1349 promops.po_stdout = *oldpvec->outSink; 1350 1351 promops.po_bootcookie = *oldpvec->bootParam; /* deref 1 lvl */ 1352 promops.po_bootpath = obp_v0_getbootpath; 1353 promops.po_bootfile = obp_v0_getbootfile; 1354 promops.po_bootargs = obp_v0_getbootargs; 1355 1356 promops.po_putchar = oldpvec->putChar; 1357 promops.po_getchar = oldpvec->getChar; 1358 promops.po_peekchar = oldpvec->mayGet; 1359 promops.po_putstr = oldpvec->fbWriteStr; 1360 promops.po_reboot = oldpvec->reBoot; 1361 promops.po_abort = oldpvec->abortEntry; 1362 promops.po_halt = oldpvec->exitToMon; 1363 promops.po_ticks = obp_ticks; 1364 promops.po_tickdata = oldpvec->nmiClock; 1365 promops.po_setcallback = (void *)sparc_noop; 1366 promops.po_setcontext = oldpvec->setcxsegmap; 1367 1368 #ifdef SUN4 1369 #ifndef _STANDALONE 1370 if (oldpvec->romvecVersion >= 2) { 1371 *oldpvec->vector_cmd = oldmon_w_cmd; 1372 } 1373 #endif 1374 #endif 1375 } 1376 1377 static inline void 1378 prom_init_obp(void) 1379 { 1380 struct nodeops *no; 1381 1382 /* 1383 * OBP v0, v2 & v3 1384 */ 1385 switch (obpvec->pv_romvec_vers) { 1386 case 0: 1387 promops.po_version = PROM_OBP_V0; 1388 break; 1389 case 2: 1390 promops.po_version = PROM_OBP_V2; 1391 break; 1392 case 3: 1393 promops.po_version = PROM_OBP_V3; 1394 break; 1395 default: 1396 obpvec->pv_halt(); /* What else? */ 1397 } 1398 1399 promops.po_revision = obpvec->pv_printrev; 1400 1401 promops.po_halt = obpvec->pv_halt; 1402 promops.po_reboot = obpvec->pv_reboot; 1403 promops.po_abort = obpvec->pv_abort; 1404 promops.po_setcontext = obpvec->pv_setctxt; 1405 promops.po_setcallback = obp_set_callback; 1406 promops.po_ticks = obp_ticks; 1407 promops.po_tickdata = obpvec->pv_ticks; 1408 1409 /* 1410 * Remove indirection through `pv_nodeops' while we're here. 1411 * Hopefully, the PROM has no need to change this pointer on the fly.. 1412 */ 1413 no = obpvec->pv_nodeops; 1414 promops.po_firstchild = no->no_child; 1415 promops.po_nextsibling = no->no_nextnode; 1416 promops.po_getproplen = no->no_proplen; 1417 /* XXX - silently discard getprop's `len' argument */ 1418 promops.po_getprop = (void *)no->no_getprop; 1419 promops.po_setprop = no->no_setprop; 1420 promops.po_nextprop = no->no_nextprop; 1421 1422 #ifndef _STANDALONE 1423 promops.po_node_to_devhandle = devhandle_from_obp; 1424 promops.po_devhandle_to_node = devhandle_to_obp; 1425 #endif /* _STANDALONE */ 1426 1427 /* 1428 * Next, deal with prom vector differences between versions. 1429 */ 1430 switch (promops.po_version) { 1431 case PROM_OBP_V0: 1432 promops.po_stdin = *obpvec->pv_stdin; 1433 promops.po_stdout = *obpvec->pv_stdout; 1434 promops.po_bootcookie = *obpvec->pv_v0bootargs; /* deref 1 lvl */ 1435 promops.po_bootpath = obp_v0_getbootpath; 1436 promops.po_bootfile = obp_v0_getbootfile; 1437 promops.po_bootargs = obp_v0_getbootargs; 1438 promops.po_putchar = obpvec->pv_putchar; 1439 promops.po_getchar = obpvec->pv_getchar; 1440 promops.po_peekchar = obpvec->pv_nbgetchar; 1441 promops.po_putstr = obpvec->pv_putstr; 1442 promops.po_open = obpvec->pv_v0devops.v0_open; 1443 promops.po_close = (void *)obpvec->pv_v0devops.v0_close; 1444 promops.po_read = obp_v0_read; 1445 promops.po_write = obp_v0_write; 1446 promops.po_interpret = obp_v0_fortheval; 1447 break; 1448 case PROM_OBP_V3: 1449 promops.po_cpustart = obpvec->pv_v3cpustart; 1450 promops.po_cpustop = obpvec->pv_v3cpustop; 1451 promops.po_cpuidle = obpvec->pv_v3cpuidle; 1452 promops.po_cpuresume = obpvec->pv_v3cpuresume; 1453 /*FALLTHROUGH*/ 1454 case PROM_OBP_V2: 1455 /* Deref stdio handles one level */ 1456 promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0; 1457 promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1; 1458 1459 promops.po_bootcookie = &obpvec->pv_v2bootargs; 1460 promops.po_bootpath = obp_v2_getbootpath; 1461 promops.po_bootfile = obp_v2_getbootfile; 1462 promops.po_bootargs = obp_v2_getbootargs; 1463 1464 promops.po_interpret = obpvec->pv_fortheval.v2_eval; 1465 1466 promops.po_putchar = obp_v2_putchar; 1467 promops.po_getchar = obp_v2_getchar; 1468 promops.po_peekchar = obp_v2_peekchar; 1469 promops.po_putstr = obp_v2_putstr; 1470 promops.po_open = obpvec->pv_v2devops.v2_open; 1471 promops.po_close = (void *)obpvec->pv_v2devops.v2_close; 1472 promops.po_read = obpvec->pv_v2devops.v2_read; 1473 promops.po_write = obpvec->pv_v2devops.v2_write; 1474 promops.po_seek = obp_v2_seek; 1475 promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle; 1476 promops.po_finddevice = obp_v2_finddevice; 1477 1478 #ifndef _STANDALONE 1479 prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n", 1480 obpvec->pv_romvec_vers, 1481 obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff, 1482 obpvec->pv_plugin_vers); 1483 #endif 1484 break; 1485 } 1486 } 1487 1488 static inline void 1489 prom_init_opf(void) 1490 { 1491 int node; 1492 1493 promops.po_version = PROM_OPENFIRM; 1494 1495 /* 1496 * OpenFirmware ops are mostly straightforward. 1497 */ 1498 promops.po_halt = OF_exit; 1499 promops.po_reboot = OF_boot; 1500 promops.po_abort = OF_enter; 1501 promops.po_interpret = opf_interpret_simple; 1502 promops.po_setcallback = (void *)OF_set_callback; 1503 promops.po_ticks = OF_milliseconds; 1504 1505 promops.po_bootpath = opf_getbootpath; 1506 promops.po_bootfile = opf_getbootfile; 1507 promops.po_bootargs = opf_getbootargs; 1508 1509 promops.po_firstchild = OF_child; 1510 promops.po_nextsibling = OF_peer; 1511 promops.po_getproplen = OF_getproplen; 1512 promops.po_getprop = OF_getprop; 1513 promops.po_nextprop = opf_nextprop; 1514 promops.po_setprop = OF_setprop; 1515 1516 /* We can re-use OBP v2 emulation */ 1517 promops.po_putchar = obp_v2_putchar; 1518 promops.po_getchar = obp_v2_getchar; 1519 promops.po_peekchar = obp_v2_peekchar; 1520 promops.po_putstr = obp_v2_putstr; 1521 1522 promops.po_open = OF_open; 1523 promops.po_close = OF_close; 1524 promops.po_read = OF_read; 1525 promops.po_write = OF_write; 1526 promops.po_seek = OF_seek; 1527 promops.po_instance_to_package = opf_instance_to_package; 1528 promops.po_finddevice = opf_finddevice; 1529 1530 #ifndef _STANDALONE 1531 #ifdef __sparc64__ 1532 promops.po_node_to_devhandle = devhandle_from_of; 1533 promops.po_devhandle_to_node = devhandle_to_of; 1534 #else 1535 /* 1536 * For 32-bit SPARC, pretend this is OpenBoot for now. 1537 * The differences will be hidden behind the promops 1538 * anyway. We do this because this platform doesn't 1539 * pull in all of the OpenFirmware support code that 1540 * 64-bit SPARC does. 1541 */ 1542 promops.po_node_to_devhandle = devhandle_from_obp; 1543 promops.po_devhandle_to_node = devhandle_to_obp; 1544 #endif /* __sparc64__ */ 1545 #endif /* _STANDALONE */ 1546 1547 /* Retrieve and cache stdio handles */ 1548 node = findchosen(); 1549 OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int)); 1550 OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int)); 1551 1552 OF_init(); 1553 } 1554 1555 /* 1556 * Initialize our PROM operations vector. 1557 */ 1558 void 1559 prom_init(void) 1560 { 1561 #ifdef _STANDALONE 1562 int node; 1563 char *cp; 1564 #endif 1565 1566 if (CPU_ISSUN4) { 1567 prom_init_oldmon(); 1568 } else if (obpvec->pv_magic == OBP_MAGIC) { 1569 prom_init_obp(); 1570 } else { 1571 /* 1572 * Assume this is an Openfirm machine. 1573 */ 1574 prom_init_opf(); 1575 } 1576 1577 #ifdef _STANDALONE 1578 /* 1579 * Find out what type of machine we're running on. 1580 * 1581 * This process is actually started in srt0.S, which has discovered 1582 * the minimal set of machine specific parameters for the 1st-level 1583 * boot program (bootxx) to run. The page size has already been set 1584 * and the CPU type is either CPU_SUN4, CPU_SUN4C or CPU_SUN4M. 1585 */ 1586 1587 if (cputyp == CPU_SUN4 || cputyp == CPU_SUN4M) 1588 return; 1589 1590 /* 1591 * We have SUN4C, SUN4M or SUN4D. 1592 * Use the PROM `compatible' property to determine which. 1593 * Absence of the `compatible' property means `sun4c'. 1594 */ 1595 1596 node = prom_findroot(); 1597 cp = prom_getpropstring(node, "compatible"); 1598 if (*cp == '\0' || strcmp(cp, "sun4c") == 0) 1599 cputyp = CPU_SUN4C; 1600 else if (strcmp(cp, "sun4m") == 0) 1601 cputyp = CPU_SUN4M; 1602 else if (strcmp(cp, "sun4d") == 0) 1603 cputyp = CPU_SUN4D; 1604 else 1605 printf("Unknown CPU type (compatible=`%s')\n", cp); 1606 #endif /* _STANDALONE */ 1607 } 1608