1/* $NetBSD: promlib.c,v 1.42 2010/01/21 11:40:01 martin 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 * 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.42 2010/01/21 11:40:01 martin 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 47#ifdef _STANDALONE 48#include <lib/libsa/stand.h> 49#define malloc(s,t,f) alloc(s) 50#else 51#include <sys/systm.h> 52#include <sys/malloc.h> 53#endif /* _STANDALONE */ 54 55#include <machine/oldmon.h> 56#include <machine/promlib.h> 57#include <machine/ctlreg.h> 58#include <sparc/sparc/asm.h> 59 60#include <lib/libkern/libkern.h> 61 62#define obpvec ((struct promvec *)romp) 63 64static void notimplemented(void); 65static void obp_v0_fortheval(const char *); 66static void obp_set_callback(void (*)(void)); 67static int obp_v0_read(int, void *, int); 68static int obp_v0_write(int, const void *, int); 69static int obp_v2_getchar(void); 70static int obp_v2_peekchar(void); 71static void obp_v2_putchar(int); 72static void obp_v2_putstr(const char *, int); 73static int obp_v2_seek(int, u_quad_t); 74static char *parse_bootfile(char *); 75static char *parse_bootargs(char *); 76static const char *obp_v0_getbootpath(void); 77static const char *obp_v0_getbootfile(void); 78static const char *obp_v0_getbootargs(void); 79static const char *obp_v2_getbootpath(void); 80static const char *obp_v2_getbootfile(void); 81static const char *obp_v2_getbootargs(void); 82static int obp_v2_finddevice(const char *); 83static int obp_ticks(void); 84 85static int findchosen(void); 86static const char *opf_getbootpath(void); 87static const char *opf_getbootfile(void); 88static const char *opf_getbootargs(void); 89static int opf_finddevice(const char *); 90static int opf_instance_to_package(int); 91static char *opf_nextprop(int, const char *); 92static void opf_interpret_simple(const char *); 93 94 95/* 96 * PROM entry points. 97 * Note: only PROM functions we use ar represented here; add as required. 98 */ 99struct promops promops = { 100 -1, /* version */ 101 -1, /* revision */ 102 -1, /* stdin handle */ 103 -1, /* stdout handle */ 104 NULL, /* bootargs */ 105 106 (void *)notimplemented, /* bootpath */ 107 (void *)notimplemented, /* bootargs */ 108 (void *)notimplemented, /* bootfile */ 109 110 (void *)notimplemented, /* getchar */ 111 (void *)notimplemented, /* peekchar */ 112 (void *)notimplemented, /* putchar */ 113 (void *)notimplemented, /* putstr */ 114 (void *)notimplemented, /* open */ 115 (void *)notimplemented, /* close */ 116 (void *)notimplemented, /* read */ 117 (void *)notimplemented, /* write */ 118 (void *)notimplemented, /* seek */ 119 120 (void *)notimplemented, /* instance_to_package */ 121 122 (void *)notimplemented, /* halt */ 123 (void *)notimplemented, /* boot */ 124 (void *)notimplemented, /* call */ 125 (void *)notimplemented, /* interpret */ 126 (void *)notimplemented, /* callback */ 127 (void *)notimplemented, /* ticks */ 128 NULL, /* ticker data */ 129 130 (void *)notimplemented, /* setcontext */ 131 (void *)notimplemented, /* cpustart */ 132 (void *)notimplemented, /* cpustop */ 133 (void *)notimplemented, /* cpuidle */ 134 (void *)notimplemented, /* cpuresume */ 135 136 (void *)notimplemented, /* firstchild */ 137 (void *)notimplemented, /* nextsibling */ 138 139 (void *)notimplemented, /* getproplen */ 140 (void *)notimplemented, /* getprop */ 141 (void *)notimplemented, /* setprop */ 142 (void *)notimplemented, /* nextprop */ 143 (void *)notimplemented /* finddevice */ 144}; 145 146static void 147notimplemented(void) 148{ 149 char str[64]; 150 int n; 151 152 n = sprintf(str, "Operation not implemented on ROM version %d\r\n", 153 promops.po_version); 154 155 /* 156 * Use PROM vector directly, in case we're called before prom_init(). 157 */ 158#if defined(SUN4) 159 if (CPU_ISSUN4) { 160 struct om_vector *sun4pvec = (struct om_vector *)PROM_BASE; 161 (*sun4pvec->fbWriteStr)(str, n); 162 } else 163#endif 164 if (obpvec->pv_magic == OBP_MAGIC) { 165 if (obpvec->pv_romvec_vers < 2) { 166 (*obpvec->pv_putstr)(str, n); 167 } else { 168 int fd = *obpvec->pv_v2bootargs.v2_fd1; 169 (*obpvec->pv_v2devops.v2_write)(fd, str, n); 170 } 171 } else { /* assume OFW */ 172 static int stdout_node; 173 if (stdout_node == 0) { 174 int chosen = findchosen(); 175 OF_getprop(chosen, "stdout", &stdout_node, sizeof(int)); 176 } 177 OF_write(stdout_node, str, n); 178 } 179} 180 181 182/* 183 * prom_getprop() reads the named property data from a given node. 184 * A buffer for the data may be passed in `*bufp'; if NULL, a 185 * buffer is allocated. The argument `size' specifies the data 186 * element size of the property data. This function checks that 187 * the actual property data length is an integral multiple of 188 * the element size. The number of data elements read into the 189 * buffer is returned into the integer pointed at by `nitem'. 190 */ 191 192int 193prom_getprop(int node, const char *name, size_t size, int *nitem, void *bufp) 194{ 195 void *buf; 196 int len; 197 198 len = prom_getproplen(node, name); 199 if (len <= 0) 200 return (ENOENT); 201 202 if ((len % size) != 0) 203 return (EINVAL); 204 205 buf = *(void **)bufp; 206 if (buf == NULL) { 207 /* No storage provided, so we allocate some */ 208 buf = malloc(len, M_DEVBUF, M_NOWAIT); 209 if (buf == NULL) 210 return (ENOMEM); 211 } else { 212 if (size * (*nitem) < len) 213 return (ENOMEM); 214 } 215 216 _prom_getprop(node, name, buf, len); 217 *(void **)bufp = buf; 218 *nitem = len / size; 219 return (0); 220} 221 222/* 223 * Return a string property. There is a (small) limit on the length; 224 * the string is fetched into a static buffer which is overwritten on 225 * subsequent calls. 226 */ 227char * 228prom_getpropstring(int node, const char *name) 229{ 230 static char stringbuf[32]; 231 232 return (prom_getpropstringA(node, name, stringbuf, sizeof stringbuf)); 233} 234 235/* 236 * Alternative prom_getpropstring(), where caller provides the buffer 237 */ 238char * 239prom_getpropstringA(int node, const char *name, char *buf, size_t bufsize) 240{ 241 int len = bufsize - 1; 242 243 if (prom_getprop(node, name, 1, &len, &buf) != 0) 244 len = 0; 245 246 buf[len] = '\0'; /* usually unnecessary */ 247 return (buf); 248} 249 250/* 251 * Fetch an integer (or pointer) property. 252 * The return value is the property, or the default if there was none. 253 */ 254int 255prom_getpropint(int node, const char *name, int deflt) 256{ 257 int intbuf, *ip = &intbuf; 258 int len = 1; 259 260 if (prom_getprop(node, name, sizeof(int), &len, &ip) != 0) 261 return (deflt); 262 263 return (*ip); 264} 265 266/* 267 * Node Name Matching per IEEE 1275, section 4.3.6. 268 */ 269static int 270prom_matchname(int node, const char *name) 271{ 272 char buf[32], *cp; 273 274 prom_getpropstringA(node, "name", buf, sizeof buf); 275 if (strcmp(buf, name) == 0) 276 /* Exact match */ 277 return (1); 278 279 /* If name has a comma, an exact match is required */ 280 if (strchr(name, ',')) 281 return (0); 282 283 /* 284 * Otherwise, if the node's name contains a comma, we can match 285 * against the trailing string defined by the first comma. 286 */ 287 if ((cp = strchr(buf, ',')) != NULL) { 288 if (strcmp(cp + 1, name) == 0) 289 return (1); 290 } 291 292 return (0); 293} 294 295/* 296 * Translate device path to node 297 */ 298int 299prom_opennode(const char *path) 300{ 301 int fd; 302 303 if (prom_version() < 2) { 304 printf("WARNING: opennode not valid on PROM version %d\n", 305 promops.po_version); 306 return (0); 307 } 308 fd = prom_open(path); 309 if (fd == 0) 310 return (0); 311 312 return (prom_instance_to_package(fd)); 313} 314 315int 316prom_findroot(void) 317{ 318 static int rootnode; 319 int node; 320 321 if ((node = rootnode) == 0 && (node = prom_nextsibling(0)) == 0) 322 panic("no PROM root device"); 323 rootnode = node; 324 return (node); 325} 326 327/* 328 * Given a `first child' node number, locate the node with the given name. 329 * Return the node number, or 0 if not found. 330 */ 331int 332prom_findnode(int first, const char *name) 333{ 334 int node; 335 336 for (node = first; node != 0; node = prom_nextsibling(node)) { 337 if (prom_matchname(node, name)) 338 return (node); 339 } 340 return (0); 341} 342 343/* 344 * Determine whether a node has the given property. 345 */ 346int 347prom_node_has_property(int node, const char *prop) 348{ 349 350 return (prom_getproplen(node, prop) != -1); 351} 352 353/* 354 * prom_search() recursively searches a PROM subtree for a given node name 355 * See IEEE 1275 `Search for matching child node', section 4.3.3. 356 */ 357int 358prom_search(int node, const char *name) 359{ 360 361 if (node == 0) 362 node = prom_findroot(); 363 364 if (prom_matchname(node, name)) 365 return (node); 366 367 for (node = prom_firstchild(node); node != 0; 368 node = prom_nextsibling(node)) { 369 int cnode; 370 if ((cnode = prom_search(node, name)) != 0) 371 return (cnode); 372 } 373 374 return (0); 375} 376 377/* 378 * Find the named device in the PROM device tree. 379 * XXX - currently we discard any qualifiers attached to device component names 380 */ 381int 382obp_v2_finddevice(const char *path) 383{ 384 int node; 385 char component[64]; 386 char c, *cp; 387 const char *startp, *endp; 388#define IS_SEP(c) ((c) == '/' || (c) == '@' || (c) == ':') 389 390 if (path == NULL) 391 return (-1); 392 393 node = prom_findroot(); 394 395 for (startp = path; *startp != '\0'; ) { 396 /* 397 * Identify next component in path 398 */ 399 while (*startp == '/') 400 startp++; 401 402 endp = startp; 403 while ((c = *endp) != '\0' && !IS_SEP(c)) 404 endp++; 405 406 /* Copy component */ 407 for (cp = component; startp != endp;) { 408 /* Check component bounds */ 409 if (cp > component + sizeof component - 1) 410 return (-1); 411 *cp++ = *startp++; 412 } 413 414 /* Zero terminate this component */ 415 *cp = '\0'; 416 417 /* Advance `startp' over any non-slash separators */ 418 while ((c = *startp) != '\0' && c != '/') 419 startp++; 420 421 node = prom_findnode(prom_firstchild(node), component); 422 if (node == 0) 423 return (-1); 424 } 425 426 return (node); 427} 428 429 430/* 431 * Get the global "options" node Id. 432 */ 433int prom_getoptionsnode(void) 434{ 435static int optionsnode; 436 437 if (optionsnode == 0) { 438 optionsnode = prom_findnode(prom_firstchild(prom_findroot()), 439 "options"); 440 } 441 return optionsnode; 442} 443 444/* 445 * Return a property string value from the global "options" node. 446 */ 447int prom_getoption(const char *name, char *buf, int buflen) 448{ 449 int node = prom_getoptionsnode(); 450 int error, len; 451 452 if (buflen == 0) 453 return (EINVAL); 454 455 if (node == 0) 456 return (ENOENT); 457 458 len = buflen - 1; 459 if ((error = prom_getprop(node, name, 1, &len, &buf)) != 0) 460 return error; 461 462 buf[len] = '\0'; 463 return (0); 464} 465 466void 467prom_halt(void) 468{ 469 470 prom_setcallback(NULL); 471 _prom_halt(); 472 panic("PROM exit failed"); 473} 474 475void 476prom_boot(char *str) 477{ 478 479 prom_setcallback(NULL); 480 _prom_boot(str); 481 panic("PROM boot failed"); 482} 483 484 485/* 486 * print debug info to prom. 487 * This is not safe, but then what do you expect? 488 */ 489void 490prom_printf(const char *fmt, ...) 491{ 492static char buf[256]; 493 int i, len; 494 va_list ap; 495 496 va_start(ap, fmt); 497 len = vsnprintf(buf, sizeof(buf), fmt, ap); 498 va_end(ap); 499 500#if _obp_not_cooked_ 501 (*promops.po_write)(promops.po_stdout, buf, len); 502#endif 503 504 for (i = 0; i < len; i++) { 505 int c = buf[i]; 506 if (c == '\n') 507 (*promops.po_putchar)('\r'); 508 (*promops.po_putchar)(c); 509 } 510} 511 512 513/* 514 * Pass a string to the FORTH PROM to be interpreted. 515 * (Note: may fail silently) 516 */ 517static void 518obp_v0_fortheval(const char *s) 519{ 520 521 obpvec->pv_fortheval.v0_eval(strlen(s), s); 522} 523 524int 525obp_v0_read(int fd, void *buf, int len) 526{ 527 if (fd != prom_stdin()) 528 prom_printf("obp_v0_read: unimplemented read from %d\n", fd); 529 return (-1); 530} 531 532int 533obp_v0_write(int fd, const void *buf, int len) 534{ 535 if (fd != prom_stdout()) 536 prom_printf("obp_v0_write: unimplemented write on %d\n", fd); 537 (*obpvec->pv_putstr)(buf, len); 538 return (-1); 539} 540 541inline void 542obp_v2_putchar(int c) 543{ 544 char c0; 545 546 c0 = (c & 0x7f); 547 (*promops.po_write)(promops.po_stdout, &c0, 1); 548} 549 550#if 0 551void 552obp_v2_putchar_cooked(int c) 553{ 554 555 if (c == '\n') 556 obp_v2_putchar('\r'); 557 obp_v2_putchar(c); 558} 559#endif 560 561int 562obp_v2_getchar(void) 563{ 564 char c; 565 int n; 566 567 while ((n = (*promops.po_read)(promops.po_stdin, &c, 1)) != 1) 568 /*void*/; 569 if (c == '\r') 570 c = '\n'; 571 return (c); 572} 573 574int 575obp_v2_peekchar(void) 576{ 577 char c; 578 int n; 579 580 n = (*promops.po_read)(promops.po_stdin, &c, 1); 581 if (n < 0) 582 return (-1); 583 584 if (c == '\r') 585 c = '\n'; 586 return (c); 587} 588 589int 590obp_v2_seek(int handle, u_quad_t offset) 591{ 592 uint32_t hi, lo; 593 594 lo = offset & ((uint32_t)-1); 595 hi = (offset >> 32) & ((uint32_t)-1); 596 (*obpvec->pv_v2devops.v2_seek)(handle, hi, lo); 597 return (0); 598} 599 600/* 601 * On SS1s (and also IPCs, SLCs), `promvec->pv_v0bootargs->ba_argv[1]' 602 * contains the flags that were given after the boot command. On SS2s 603 * (and ELCs, IPXs, etc. and any sun4m class machine), `pv_v0bootargs' 604 * is NULL but `*promvec->pv_v2bootargs.v2_bootargs' points to 605 * "netbsd -s" or whatever. 606 */ 607const char * 608obp_v0_getbootpath(void) 609{ 610 struct v0bootargs *ba = promops.po_bootcookie; 611 return (ba->ba_argv[0]); 612} 613 614const char * 615obp_v0_getbootargs(void) 616{ 617 struct v0bootargs *ba = promops.po_bootcookie; 618 return (ba->ba_argv[1]); 619} 620 621const char * 622obp_v0_getbootfile(void) 623{ 624 struct v0bootargs *ba = promops.po_bootcookie; 625 return (ba->ba_kernel); 626} 627 628char * 629parse_bootargs(char *args) 630{ 631 char *cp; 632 633 for (cp = args; *cp != '\0'; cp++) { 634 if (*cp == '-') { 635 int c; 636 /* 637 * Looks like options start here, but check this 638 * `-' is not part of the kernel name. 639 */ 640 if (cp == args) 641 break; 642 if ((c = *(cp-1)) == ' ' || c == '\t') 643 break; 644 } 645 } 646 return (cp); 647} 648 649const char * 650obp_v2_getbootpath(void) 651{ 652 struct v2bootargs *ba = promops.po_bootcookie; 653 return (*ba->v2_bootpath); 654} 655 656const char * 657obp_v2_getbootargs(void) 658{ 659 struct v2bootargs *ba = promops.po_bootcookie; 660 661 return (parse_bootargs(*ba->v2_bootargs)); 662} 663 664/* 665 * Static storage shared by prom_getbootfile(), prom_getbootargs() and 666 * prom_getbootpath(). 667 * Overwritten on each call! 668 */ 669static char storage[128]; 670 671char * 672parse_bootfile(char *args) 673{ 674 char *cp, *dp; 675 676 cp = args; 677 dp = storage; 678 while (*cp != 0 && *cp != ' ' && *cp != '\t') { 679 if (dp >= storage + sizeof(storage) - 1) { 680 prom_printf("v2_bootargs too long\n"); 681 return (NULL); 682 } 683 if (*cp == '-') { 684 int c; 685 /* 686 * If this `-' is most likely the start of boot 687 * options, we're done. 688 */ 689 if (cp == args) 690 break; 691 if ((c = *(cp-1)) == ' ' || c == '\t') 692 break; 693 } 694 *dp++ = *cp++; 695 } 696 *dp = '\0'; 697 return (storage); 698} 699 700const char * 701obp_v2_getbootfile(void) 702{ 703 struct v2bootargs *ba = promops.po_bootcookie; 704 char *kernel = parse_bootfile(*ba->v2_bootargs); 705 char buf[4+1]; 706 const char *prop; 707 708 if (kernel[0] != '\0') 709 return kernel; 710 711 /* 712 * The PROM does not insert the `boot-file' variable if any argument 713 * was given to the `boot' command (e.g `boot -s'). If we determine 714 * in parse_bootfile() above, that boot args contain only switches 715 * then get the `boot-file' value (if any) ourselves. 716 * If the `diag-switch?' PROM variable is set to true, we use 717 * `diag-file' instead. 718 */ 719 prop = (prom_getoption("diag-switch?", buf, sizeof buf) != 0 || 720 strcmp(buf, "true") != 0) 721 ? "diag-file" 722 : "boot-file"; 723 724 if (prom_getoption(prop, storage, sizeof storage) != 0) 725 return (NULL); 726 727 return (storage); 728} 729 730void 731obp_v2_putstr(const char *str, int len) 732{ 733 prom_write(prom_stdout(), str, len); 734} 735 736void 737obp_set_callback(void (*f)(void)) 738{ 739 *obpvec->pv_synchook = f; 740} 741 742int 743obp_ticks(void) 744{ 745 746 return (*((int *)promops.po_tickdata)); 747} 748 749static int 750findchosen(void) 751{ 752static int chosennode; 753 int node; 754 755 if ((node = chosennode) == 0 && (node = OF_finddevice("/chosen")) == -1) 756 panic("no CHOSEN node"); 757 758 chosennode = node; 759 return (node); 760} 761 762static int 763opf_finddevice(const char *name) 764{ 765 int phandle = OF_finddevice(name); 766 if (phandle == -1) 767 return (0); 768 else 769 return (phandle); 770} 771 772static int 773opf_instance_to_package(int ihandle) 774{ 775 int phandle = OF_instance_to_package(ihandle); 776 if (phandle == -1) 777 return (0); 778 else 779 return (phandle); 780} 781 782 783static const char * 784opf_getbootpath(void) 785{ 786 int node = findchosen(); 787 char *buf = storage; 788 int blen = sizeof storage; 789 790 if (prom_getprop(node, "bootpath", 1, &blen, &buf) != 0) 791 return (""); 792 793 return (buf); 794} 795 796static const char * 797opf_getbootargs(void) 798{ 799 int node = findchosen(); 800 char *buf = storage; 801 int blen = sizeof storage; 802 803 if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0) 804 return (""); 805 806 return (parse_bootargs(buf)); 807} 808 809static const char * 810opf_getbootfile(void) 811{ 812 int node = findchosen(); 813 char *buf = storage; 814 int blen = sizeof storage; 815 816 if (prom_getprop(node, "bootargs", 1, &blen, &buf) != 0) 817 return (""); 818 819 return (parse_bootfile(buf)); 820} 821 822static char * 823opf_nextprop(int node, const char *prop) 824{ 825#define OF_NEXTPROP_BUF_SIZE 32 /* specified by the standard */ 826 static char buf[OF_NEXTPROP_BUF_SIZE]; 827 OF_nextprop(node, prop, buf); 828 return (buf); 829} 830 831void 832opf_interpret_simple(const char *s) 833{ 834 (void)OF_interpret(s, 0, 0); 835} 836 837/* 838 * Retrieve physical memory information from the PROM. 839 * If ap is NULL, return the required length of the array. 840 */ 841int 842prom_makememarr(struct memarr *ap, int xmax, int which) 843{ 844 struct v0mlist *mp; 845 int node, n; 846 const char *prop; 847 848 if (which != MEMARR_AVAILPHYS && which != MEMARR_TOTALPHYS) 849 panic("makememarr"); 850 851 /* 852 * `struct memarr' is in V2 memory property format. 853 * On previous ROM versions we must convert. 854 */ 855 switch (prom_version()) { 856 struct promvec *promvec; 857 struct om_vector *oldpvec; 858 case PROM_OLDMON: 859 oldpvec = (struct om_vector *)PROM_BASE; 860 n = 1; 861 if (ap != NULL) { 862 ap[0].zero = 0; 863 ap[0].addr = 0; 864 ap[0].len = (which == MEMARR_AVAILPHYS) 865 ? *oldpvec->memoryAvail 866 : *oldpvec->memorySize; 867 } 868 break; 869 870 case PROM_OBP_V0: 871 /* 872 * Version 0 PROMs use a linked list to describe these 873 * guys. 874 */ 875 promvec = romp; 876 mp = (which == MEMARR_AVAILPHYS) 877 ? *promvec->pv_v0mem.v0_physavail 878 : *promvec->pv_v0mem.v0_phystot; 879 for (n = 0; mp != NULL; mp = mp->next, n++) { 880 if (ap == NULL) 881 continue; 882 if (n >= xmax) { 883 printf("makememarr: WARNING: lost some memory\n"); 884 break; 885 } 886 ap->zero = 0; 887 ap->addr = (u_long)mp->addr; 888 ap->len = mp->nbytes; 889 ap++; 890 } 891 break; 892 893 default: 894 printf("makememarr: hope version %d PROM is like version 2\n", 895 prom_version()); 896 /* FALLTHROUGH */ 897 898 case PROM_OBP_V3: 899 case PROM_OBP_V2: 900 /* 901 * Version 2 PROMs use a property array to describe them. 902 */ 903 904 /* Consider emulating `OF_finddevice' */ 905 node = findnode(firstchild(findroot()), "memory"); 906 goto case_common; 907 908 case PROM_OPENFIRM: 909 node = OF_finddevice("/memory"); 910 if (node == -1) 911 node = 0; 912 913 case_common: 914 if (node == 0) 915 panic("makememarr: cannot find \"memory\" node"); 916 917 prop = (which == MEMARR_AVAILPHYS) ? "available" : "reg"; 918 if (ap == NULL) { 919 n = prom_getproplen(node, prop); 920 } else { 921 n = xmax; 922 if (prom_getprop(node, prop, sizeof(struct memarr), 923 &n, &ap) != 0) 924 panic("makememarr: cannot get property"); 925 } 926 break; 927 } 928 929 if (n <= 0) 930 panic("makememarr: no memory found"); 931 /* 932 * Success! (Hooray) 933 */ 934 return (n); 935} 936 937static struct idprom idprom; 938#ifdef _STANDALONE 939long hostid; 940#endif 941 942struct idprom * 943prom_getidprom(void) 944{ 945 int node, len; 946 u_long h; 947 u_char *dst; 948 949 if (idprom.idp_format != 0) 950 /* Already got it */ 951 return (&idprom); 952 953 dst = (u_char *)&idprom; 954 len = sizeof(struct idprom); 955 956 switch (prom_version()) { 957 case PROM_OLDMON: 958#ifdef AC_IDPROM 959 { 960 u_char *src = (u_char *)AC_IDPROM; 961 do { 962 *dst++ = lduba(src++, ASI_CONTROL); 963 } while (--len > 0); 964 } 965#endif 966 break; 967 968 /* 969 * Fetch the `idprom' property at the root node. 970 */ 971 case PROM_OBP_V0: 972 case PROM_OBP_V2: 973 case PROM_OPENFIRM: 974 case PROM_OBP_V3: 975 node = prom_findroot(); 976 if (prom_getprop(node, "idprom", 1, &len, &dst) != 0) { 977 printf("`idprom' property cannot be read: " 978 "cannot get ethernet address"); 979 } 980 break; 981 } 982 983 /* Establish hostid */ 984 h = (u_int)idprom.idp_machtype << 24; 985 h |= idprom.idp_serialnum[0] << 16; 986 h |= idprom.idp_serialnum[1] << 8; 987 h |= idprom.idp_serialnum[2]; 988 hostid = h; 989 990 return (&idprom); 991} 992 993void prom_getether(int node, u_char *cp) 994{ 995 struct idprom *idp; 996 997 if (prom_get_node_ether(node, cp)) 998 return; 999 1000 /* Fall back on the machine's global ethernet address */ 1001 idp = prom_getidprom(); 1002 memcpy(cp, idp->idp_etheraddr, 6); 1003} 1004 1005bool 1006prom_get_node_ether(int node, u_char *cp) 1007{ 1008 char buf[6+1], *bp; 1009 int nitem; 1010 1011 if (node == 0) 1012 return false; 1013 1014 /* 1015 * First, try the node's "mac-address" property. 1016 * This property is set by the adapter's firmware if the 1017 * device has already been opened for traffic, e.g. for 1018 * net booting. Its value might be `0-terminated', probably 1019 * because the Forth ROMs uses `xdrstring' instead of `xdrbytes' 1020 * to construct the property. 1021 */ 1022 nitem = 6+1; 1023 bp = buf; 1024 if (prom_getprop(node, "mac-address", 1, &nitem, &bp) == 0 && 1025 nitem >= 6) { 1026 memcpy(cp, bp, 6); 1027 return true; 1028 } 1029 1030 /* 1031 * Next, check the global "local-mac-address?" switch to see 1032 * if we should try to extract the node's "local-mac-address" 1033 * property. 1034 */ 1035 if (prom_getoption("local-mac-address?", buf, sizeof buf) != 0 || 1036 strcmp(buf, "true") != 0) 1037 return false; 1038 1039 /* Retrieve the node's "local-mac-address" property, if any */ 1040 nitem = 6; 1041 if (prom_getprop(node, "local-mac-address", 1, &nitem, &cp) == 0 && 1042 nitem == 6) 1043 return true; 1044 1045 return false; 1046} 1047 1048/* 1049 * The integer property "get-unum" on the root device is the address 1050 * of a callable function in the PROM that takes a physical address 1051 * (in lo/hipart format) and returns a string identifying the chip 1052 * location of the corresponding memory cell. 1053 */ 1054const char * 1055prom_pa_location(u_int phys_lo, u_int phys_hi) 1056{ 1057 static char *(*unum)(u_int, u_int); 1058 char *str; 1059 const char *unk = "<Unknown>"; 1060 1061 switch (prom_version()) { 1062 case PROM_OLDMON: 1063 case PROM_OPENFIRM: 1064 /* to do */ 1065 default: 1066 break; 1067 case PROM_OBP_V0: 1068 case PROM_OBP_V2: 1069 case PROM_OBP_V3: 1070 if (unum == NULL) 1071 unum = (char *(*)(u_int,u_int))(u_long) 1072 prom_getpropint(prom_findroot(), "get-unum", 0); 1073 1074 if (unum == NULL || (str = unum(phys_lo, phys_hi)) == NULL) 1075 break; 1076 1077 return (str); 1078 } 1079 1080 return (unk); 1081} 1082 1083static void prom_init_oldmon(void); 1084static void prom_init_obp(void); 1085static void prom_init_opf(void); 1086 1087static inline void 1088prom_init_oldmon(void) 1089{ 1090 struct om_vector *oldpvec = (struct om_vector *)PROM_BASE; 1091 extern void sparc_noop(void); 1092 1093 promops.po_version = PROM_OLDMON; 1094 promops.po_revision = oldpvec->monId[0]; /*XXX*/ 1095 1096 promops.po_stdin = *oldpvec->inSource; 1097 promops.po_stdout = *oldpvec->outSink; 1098 1099 promops.po_bootcookie = *oldpvec->bootParam; /* deref 1 lvl */ 1100 promops.po_bootpath = obp_v0_getbootpath; 1101 promops.po_bootfile = obp_v0_getbootfile; 1102 promops.po_bootargs = obp_v0_getbootargs; 1103 1104 promops.po_putchar = oldpvec->putChar; 1105 promops.po_getchar = oldpvec->getChar; 1106 promops.po_peekchar = oldpvec->mayGet; 1107 promops.po_putstr = oldpvec->fbWriteStr; 1108 promops.po_reboot = oldpvec->reBoot; 1109 promops.po_abort = oldpvec->abortEntry; 1110 promops.po_halt = oldpvec->exitToMon; 1111 promops.po_ticks = obp_ticks; 1112 promops.po_tickdata = oldpvec->nmiClock; 1113 promops.po_setcallback = (void *)sparc_noop; 1114 promops.po_setcontext = oldpvec->setcxsegmap; 1115 1116#ifdef SUN4 1117#ifndef _STANDALONE 1118 if (oldpvec->romvecVersion >= 2) { 1119 extern void oldmon_w_cmd(u_long, char *); 1120 *oldpvec->vector_cmd = oldmon_w_cmd; 1121 } 1122#endif 1123#endif 1124} 1125 1126static inline void 1127prom_init_obp(void) 1128{ 1129 struct nodeops *no; 1130 1131 /* 1132 * OBP v0, v2 & v3 1133 */ 1134 switch (obpvec->pv_romvec_vers) { 1135 case 0: 1136 promops.po_version = PROM_OBP_V0; 1137 break; 1138 case 2: 1139 promops.po_version = PROM_OBP_V2; 1140 break; 1141 case 3: 1142 promops.po_version = PROM_OBP_V3; 1143 break; 1144 default: 1145 obpvec->pv_halt(); /* What else? */ 1146 } 1147 1148 promops.po_revision = obpvec->pv_printrev; 1149 1150 promops.po_halt = obpvec->pv_halt; 1151 promops.po_reboot = obpvec->pv_reboot; 1152 promops.po_abort = obpvec->pv_abort; 1153 promops.po_setcontext = obpvec->pv_setctxt; 1154 promops.po_setcallback = obp_set_callback; 1155 promops.po_ticks = obp_ticks; 1156 promops.po_tickdata = obpvec->pv_ticks; 1157 1158 /* 1159 * Remove indirection through `pv_nodeops' while we're here. 1160 * Hopefully, the PROM has no need to change this pointer on the fly.. 1161 */ 1162 no = obpvec->pv_nodeops; 1163 promops.po_firstchild = no->no_child; 1164 promops.po_nextsibling = no->no_nextnode; 1165 promops.po_getproplen = no->no_proplen; 1166 /* XXX - silently discard getprop's `len' argument */ 1167 promops.po_getprop = (void *)no->no_getprop; 1168 promops.po_setprop = no->no_setprop; 1169 promops.po_nextprop = no->no_nextprop; 1170 1171 /* 1172 * Next, deal with prom vector differences between versions. 1173 */ 1174 switch (promops.po_version) { 1175 case PROM_OBP_V0: 1176 promops.po_stdin = *obpvec->pv_stdin; 1177 promops.po_stdout = *obpvec->pv_stdout; 1178 promops.po_bootcookie = *obpvec->pv_v0bootargs; /* deref 1 lvl */ 1179 promops.po_bootpath = obp_v0_getbootpath; 1180 promops.po_bootfile = obp_v0_getbootfile; 1181 promops.po_bootargs = obp_v0_getbootargs; 1182 promops.po_putchar = obpvec->pv_putchar; 1183 promops.po_getchar = obpvec->pv_getchar; 1184 promops.po_peekchar = obpvec->pv_nbgetchar; 1185 promops.po_putstr = obpvec->pv_putstr; 1186 promops.po_open = obpvec->pv_v0devops.v0_open; 1187 promops.po_close = (void *)obpvec->pv_v0devops.v0_close; 1188 promops.po_read = obp_v0_read; 1189 promops.po_write = obp_v0_write; 1190 promops.po_interpret = obp_v0_fortheval; 1191 break; 1192 case PROM_OBP_V3: 1193 promops.po_cpustart = obpvec->pv_v3cpustart; 1194 promops.po_cpustop = obpvec->pv_v3cpustop; 1195 promops.po_cpuidle = obpvec->pv_v3cpuidle; 1196 promops.po_cpuresume = obpvec->pv_v3cpuresume; 1197 /*FALLTHROUGH*/ 1198 case PROM_OBP_V2: 1199 /* Deref stdio handles one level */ 1200 promops.po_stdin = *obpvec->pv_v2bootargs.v2_fd0; 1201 promops.po_stdout = *obpvec->pv_v2bootargs.v2_fd1; 1202 1203 promops.po_bootcookie = &obpvec->pv_v2bootargs; 1204 promops.po_bootpath = obp_v2_getbootpath; 1205 promops.po_bootfile = obp_v2_getbootfile; 1206 promops.po_bootargs = obp_v2_getbootargs; 1207 1208 promops.po_interpret = obpvec->pv_fortheval.v2_eval; 1209 1210 promops.po_putchar = obp_v2_putchar; 1211 promops.po_getchar = obp_v2_getchar; 1212 promops.po_peekchar = obp_v2_peekchar; 1213 promops.po_putstr = obp_v2_putstr; 1214 promops.po_open = obpvec->pv_v2devops.v2_open; 1215 promops.po_close = (void *)obpvec->pv_v2devops.v2_close; 1216 promops.po_read = obpvec->pv_v2devops.v2_read; 1217 promops.po_write = obpvec->pv_v2devops.v2_write; 1218 promops.po_seek = obp_v2_seek; 1219 promops.po_instance_to_package = obpvec->pv_v2devops.v2_fd_phandle; 1220 promops.po_finddevice = obp_v2_finddevice; 1221 1222#ifndef _STANDALONE 1223 prom_printf("OBP version %d, revision %d.%d (plugin rev %x)\n", 1224 obpvec->pv_romvec_vers, 1225 obpvec->pv_printrev >> 16, obpvec->pv_printrev & 0xffff, 1226 obpvec->pv_plugin_vers); 1227#endif 1228 break; 1229 } 1230} 1231 1232static inline void 1233prom_init_opf(void) 1234{ 1235 int node; 1236 1237 promops.po_version = PROM_OPENFIRM; 1238 1239 /* 1240 * OpenFirmware ops are mostly straightforward. 1241 */ 1242 promops.po_halt = OF_exit; 1243 promops.po_reboot = OF_boot; 1244 promops.po_abort = OF_enter; 1245 promops.po_interpret = opf_interpret_simple; 1246 promops.po_setcallback = (void *)OF_set_callback; 1247 promops.po_ticks = OF_milliseconds; 1248 1249 promops.po_bootpath = opf_getbootpath; 1250 promops.po_bootfile = opf_getbootfile; 1251 promops.po_bootargs = opf_getbootargs; 1252 1253 promops.po_firstchild = OF_child; 1254 promops.po_nextsibling = OF_peer; 1255 promops.po_getproplen = OF_getproplen; 1256 promops.po_getprop = OF_getprop; 1257 promops.po_nextprop = opf_nextprop; 1258 promops.po_setprop = OF_setprop; 1259 1260 /* We can re-use OBP v2 emulation */ 1261 promops.po_putchar = obp_v2_putchar; 1262 promops.po_getchar = obp_v2_getchar; 1263 promops.po_peekchar = obp_v2_peekchar; 1264 promops.po_putstr = obp_v2_putstr; 1265 1266 promops.po_open = OF_open; 1267 promops.po_close = OF_close; 1268 promops.po_read = OF_read; 1269 promops.po_write = OF_write; 1270 promops.po_seek = OF_seek; 1271 promops.po_instance_to_package = opf_instance_to_package; 1272 promops.po_finddevice = opf_finddevice; 1273 1274 /* Retrieve and cache stdio handles */ 1275 node = findchosen(); 1276 OF_getprop(node, "stdin", &promops.po_stdin, sizeof(int)); 1277 OF_getprop(node, "stdout", &promops.po_stdout, sizeof(int)); 1278} 1279 1280/* 1281 * Initialize our PROM operations vector. 1282 */ 1283void 1284prom_init(void) 1285{ 1286#ifdef _STANDALONE 1287 int node; 1288 char *cp; 1289#endif 1290 1291 if (CPU_ISSUN4) { 1292 prom_init_oldmon(); 1293 } else if (obpvec->pv_magic == OBP_MAGIC) { 1294 prom_init_obp(); 1295 } else { 1296 /* 1297 * Assume this is an Openfirm machine. 1298 */ 1299 prom_init_opf(); 1300 } 1301 1302#ifdef _STANDALONE 1303 /* 1304 * Find out what type of machine we're running on. 1305 * 1306 * This process is actually started in srt0.S, which has discovered 1307 * the minimal set of machine specific parameters for the 1st-level 1308 * boot program (bootxx) to run. The page size has already been set 1309 * and the CPU type is either CPU_SUN4, CPU_SUN4C or CPU_SUN4M. 1310 */ 1311 1312 if (cputyp == CPU_SUN4 || cputyp == CPU_SUN4M) 1313 return; 1314 1315 /* 1316 * We have SUN4C, SUN4M or SUN4D. 1317 * Use the PROM `compatible' property to determine which. 1318 * Absence of the `compatible' property means `sun4c'. 1319 */ 1320 1321 node = prom_findroot(); 1322 cp = prom_getpropstring(node, "compatible"); 1323 if (*cp == '\0' || strcmp(cp, "sun4c") == 0) 1324 cputyp = CPU_SUN4C; 1325 else if (strcmp(cp, "sun4m") == 0) 1326 cputyp = CPU_SUN4M; 1327 else if (strcmp(cp, "sun4d") == 0) 1328 cputyp = CPU_SUN4D; 1329 else 1330 printf("Unknown CPU type (compatible=`%s')\n", cp); 1331#endif /* _STANDALONE */ 1332} 1333