1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)autoconf.c 8.4 (Berkeley) 10/01/93 17 * 18 * from: $Header: autoconf.c,v 1.38 93/10/01 21:24:51 torek Exp $ (LBL) 19 */ 20 21 #include <sys/param.h> 22 #include <sys/map.h> 23 #include <sys/buf.h> 24 #include <sys/disklabel.h> 25 #include <sys/device.h> 26 #include <sys/disk.h> 27 #include <sys/dkstat.h> 28 #include <sys/conf.h> 29 #include <sys/dmap.h> 30 #include <sys/reboot.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 34 #include <net/if.h> 35 36 #include <machine/autoconf.h> 37 #include <machine/bsd_openprom.h> 38 #include <machine/cpu.h> 39 40 /* 41 * The following several variables are related to 42 * the configuration process, and are used in initializing 43 * the machine. 44 */ 45 int cold; /* if 1, still working on cold-start */ 46 int dkn; /* number of iostat dk numbers assigned so far */ 47 int fbnode; /* node ID of ROM's console frame buffer */ 48 int optionsnode; /* node ID of ROM's options */ 49 50 extern struct promvec *promvec; 51 52 static int rootnode; 53 int findroot __P((void)); 54 void setroot __P((void)); 55 static int getstr __P((char *, int)); 56 static int findblkmajor __P((struct dkdevice *)); 57 static struct device *getdisk __P((char *, int, int, dev_t *)); 58 59 struct bootpath bootpath[8]; 60 61 /* 62 * Most configuration on the SPARC is done by matching OPENPROM Forth 63 * device names with our internal names. 64 */ 65 int 66 matchbyname(parent, cf, aux) 67 struct device *parent; 68 struct cfdata *cf; 69 void *aux; 70 { 71 72 return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0); 73 } 74 75 /* 76 * Convert hex ASCII string to a value. Returns updated pointer. 77 * Depends on ASCII order (this *is* machine-dependent code, you know). 78 */ 79 static char * 80 str2hex(str, vp) 81 register char *str; 82 register int *vp; 83 { 84 register int v, c; 85 86 for (v = 0;; v = v * 16 + c, str++) { 87 c = *(u_char *)str; 88 if (c <= '9') { 89 if ((c -= '0') < 0) 90 break; 91 } else if (c <= 'F') { 92 if ((c -= 'A' - 10) < 10) 93 break; 94 } else if (c <= 'f') { 95 if ((c -= 'a' - 10) < 10) 96 break; 97 } else 98 break; 99 } 100 *vp = v; 101 return (str); 102 } 103 104 /* 105 * locore.s code calls bootstrap() just before calling main(), after double 106 * mapping the kernel to high memory and setting up the trap base register. 107 * We must finish mapping the kernel properly and glean any bootstrap info. 108 */ 109 void 110 bootstrap() 111 { 112 register char *cp, *pp; 113 register struct bootpath *bp; 114 int v0val[3]; 115 int nmmu, ncontext, node; 116 #ifdef KGDB 117 extern int kgdb_debug_panic; 118 #endif 119 120 node = findroot(); 121 nmmu = getpropint(node, "mmu-npmg", 128); 122 ncontext = getpropint(node, "mmu-nctx", 8); 123 pmap_bootstrap(nmmu, ncontext); 124 #ifdef KGDB 125 zs_kgdb_init(); /* XXX */ 126 #endif 127 /* 128 * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags 129 * that were given after the boot command. On SS2s, pv_v0bootargs 130 * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to 131 * "vmunix -s" or whatever. 132 * ### DO THIS BEFORE pmap_boostrap? 133 */ 134 bp = bootpath; 135 if (promvec->pv_romvec_vers < 2) { 136 /* Grab boot device name and values. */ 137 cp = (*promvec->pv_v0bootargs)->ba_argv[0]; 138 if (cp != NULL) { 139 /* Kludge something up */ 140 pp = cp + 2; 141 v0val[0] = v0val[1] = v0val[2] = 0; 142 if (*pp == '(' && 143 *(pp = str2hex(++pp, &v0val[0])) == ',' && 144 *(pp = str2hex(++pp, &v0val[1])) == ',') 145 (void)str2hex(++pp, &v0val[2]); 146 147 /* Assume sbus0 */ 148 strcpy(bp->name, "sbus"); 149 bp->val[0] = 0; 150 ++bp; 151 152 if (cp[0] == 'l' && cp[1] == 'e') { 153 /* le */ 154 strcpy(bp->name, "le"); 155 bp->val[0] = -1; 156 bp->val[1] = v0val[0]; 157 } else { 158 /* sd or maybe st; assume espN */ 159 strcpy(bp->name, "esp"); 160 bp->val[0] = -1; 161 bp->val[1] = v0val[0]; 162 163 /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */ 164 #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v)) 165 166 ++bp; 167 bp->name[0] = cp[0]; 168 bp->name[1] = cp[1]; 169 bp->name[2] = '\0'; 170 bp->val[0] = CRAZYMAP(v0val[1]); 171 bp->val[1] = v0val[2]; 172 } 173 } 174 175 /* Setup pointer to boot flags */ 176 cp = (*promvec->pv_v0bootargs)->ba_argv[1]; 177 if (cp == NULL || *cp != '-') 178 return; 179 } else { 180 /* Grab boot path */ 181 cp = *promvec->pv_v2bootargs.v2_bootpath; 182 while (cp != NULL && *cp == '/') { 183 /* Step over '/' */ 184 ++cp; 185 /* Extract name */ 186 pp = bp->name; 187 while (*cp != '@' && *cp != '/' && *cp != '\0') 188 *pp++ = *cp++; 189 *pp = '\0'; 190 191 if (*cp == '@') { 192 cp = str2hex(++cp, &bp->val[0]); 193 if (*cp == ',') 194 cp = str2hex(++cp, &bp->val[1]); 195 } 196 ++bp; 197 } 198 199 /* Setup pointer to boot flags */ 200 cp = *promvec->pv_v2bootargs.v2_bootargs; 201 if (cp == NULL) 202 return; 203 while (*cp != '-') 204 if (*cp++ == '\0') 205 return; 206 } 207 for (;;) { 208 switch (*++cp) { 209 210 case '\0': 211 return; 212 213 case 'a': 214 boothowto |= RB_ASKNAME; 215 break; 216 217 case 'b': 218 boothowto |= RB_DFLTROOT; 219 break; 220 221 case 'd': /* kgdb - always on zs XXX */ 222 #ifdef KGDB 223 boothowto |= RB_KDB; /* XXX unused */ 224 kgdb_debug_panic = 1; 225 kgdb_connect(1); 226 #else 227 printf("kernel not compiled with KGDB\n"); 228 #endif 229 break; 230 231 case 's': 232 boothowto |= RB_SINGLE; 233 break; 234 } 235 } 236 } 237 238 /* 239 * Determine mass storage and memory configuration for a machine. 240 * We get the PROM's root device and make sure we understand it, then 241 * attach it as `mainbus0'. We also set up to handle the PROM `sync' 242 * command. 243 */ 244 configure() 245 { 246 register int node; 247 register char *cp; 248 struct romaux ra; 249 void sync_crash(); 250 251 node = findroot(); 252 cp = getpropstring(node, "device_type"); 253 if (strcmp(cp, "cpu") != 0) { 254 printf("PROM root device type = %s\n", cp); 255 panic("need CPU as root"); 256 } 257 *promvec->pv_synchook = sync_crash; 258 ra.ra_node = node; 259 ra.ra_name = cp = "mainbus"; 260 if (!config_rootfound(cp, (void *)&ra)) 261 panic("mainbus not configured"); 262 (void)spl0(); 263 if (bootdv) 264 printf("Found boot device %s\n", bootdv->dv_xname); 265 cold = 0; 266 setroot(); 267 swapconf(); 268 dumpconf(); 269 } 270 271 /* 272 * Console `sync' command. SunOS just does a `panic: zero' so I guess 273 * no one really wants anything fancy... 274 */ 275 void 276 sync_crash() 277 { 278 279 panic("PROM sync command"); 280 } 281 282 char * 283 clockfreq(freq) 284 register int freq; 285 { 286 register char *p; 287 static char buf[10]; 288 289 freq /= 1000; 290 sprintf(buf, "%d", freq / 1000); 291 freq %= 1000; 292 if (freq) { 293 freq += 1000; /* now in 1000..1999 */ 294 p = buf + strlen(buf); 295 sprintf(p, "%d", freq); 296 *p = '.'; /* now buf = %d.%3d */ 297 } 298 return (buf); 299 } 300 301 /* ARGSUSED */ 302 static int 303 mbprint(aux, name) 304 void *aux; 305 char *name; 306 { 307 register struct romaux *ra = aux; 308 309 if (name) 310 printf("%s at %s", ra->ra_name, name); 311 if (ra->ra_paddr) 312 printf(" %saddr 0x%x", ra->ra_iospace ? "io" : "", 313 (int)ra->ra_paddr); 314 return (UNCONF); 315 } 316 317 int 318 findroot() 319 { 320 register int node; 321 322 if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0) 323 panic("no PROM root device"); 324 rootnode = node; 325 return (node); 326 } 327 328 /* 329 * Given a `first child' node number, locate the node with the given name. 330 * Return the node number, or 0 if not found. 331 */ 332 int 333 findnode(first, name) 334 int first; 335 register char *name; 336 { 337 register int node; 338 339 for (node = first; node; node = nextsibling(node)) 340 if (strcmp(getpropstring(node, "name"), name) == 0) 341 return (node); 342 return (0); 343 } 344 345 /* 346 * Fill in a romaux. Returns 1 on success, 0 if the register property 347 * was not the right size. 348 */ 349 int 350 romprop(rp, cp, node) 351 register struct romaux *rp; 352 const char *cp; 353 register int node; 354 { 355 register int len; 356 union { char regbuf[64]; int ireg[3]; } u; 357 static const char pl[] = "property length"; 358 359 len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf); 360 if (len < 12) { 361 printf("%s \"reg\" %s = %d (need 12)\n", cp, pl, len); 362 return (0); 363 } 364 if (len > 12) 365 printf("warning: %s \"reg\" %s %d > 12, excess ignored\n", 366 cp, pl, len); 367 rp->ra_node = node; 368 rp->ra_name = cp; 369 rp->ra_iospace = u.ireg[0]; 370 rp->ra_paddr = (caddr_t)u.ireg[1]; 371 rp->ra_len = u.ireg[2]; 372 rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0); 373 len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr); 374 if (len == -1) 375 len = 0; 376 if (len & 7) { 377 printf("%s \"intr\" %s = %d (need multiple of 8)\n", 378 cp, pl, len); 379 len = 0; 380 } 381 rp->ra_nintr = len >>= 3; 382 /* SPARCstation interrupts are not hardware-vectored */ 383 while (--len >= 0) { 384 if (rp->ra_intr[len].int_vec) { 385 printf("WARNING: %s interrupt %d has nonzero vector\n", 386 cp, len); 387 break; 388 } 389 } 390 return (1); 391 } 392 393 /* 394 * Attach the mainbus. 395 * 396 * Our main job is to attach the CPU (the root node we got in configure()) 397 * and iterate down the list of `mainbus devices' (children of that node). 398 * We also record the `node id' of the default frame buffer, if any. 399 */ 400 static void 401 mainbus_attach(parent, dev, aux) 402 struct device *parent, *dev; 403 void *aux; 404 { 405 register int node0, node; 406 register const char *cp, *const *ssp, *sp; 407 #define L1A_HACK /* XXX hack to allow L1-A during autoconf */ 408 #ifdef L1A_HACK 409 int nzs = 0, audio = 0; 410 #endif 411 struct romaux ra; 412 static const char *const special[] = { 413 /* find these first (end with empty string) */ 414 "memory-error", /* as early as convenient, in case of error */ 415 "eeprom", 416 "counter-timer", 417 "", 418 419 /* ignore these (end with NULL) */ 420 "aliases", 421 "interrupt-enable", 422 "memory", 423 "openprom", 424 "options", 425 "packages", 426 "virtual-memory", 427 NULL 428 }; 429 430 printf("\n"); 431 432 /* configure the cpu */ 433 node = ((struct romaux *)aux)->ra_node; 434 ra.ra_node = node; 435 ra.ra_name = cp = "cpu"; 436 ra.ra_paddr = 0; 437 config_found(dev, (void *)&ra, mbprint); 438 439 /* remember which frame buffer, if any, is to be /dev/fb */ 440 fbnode = getpropint(node, "fb", 0); 441 442 /* Find the "options" node */ 443 node0 = firstchild(node); 444 optionsnode = findnode(node0, "options"); 445 if (optionsnode == 0) 446 panic("no options in OPENPROM"); 447 448 /* Start at the beginning of the bootpath */ 449 ra.ra_bp = bootpath; 450 451 /* 452 * Locate and configure the ``early'' devices. These must be 453 * configured before we can do the rest. For instance, the 454 * EEPROM contains the Ethernet address for the LANCE chip. 455 * If the device cannot be located or configured, panic. 456 */ 457 for (ssp = special; *(sp = *ssp) != 0; ssp++) { 458 if ((node = findnode(node0, sp)) == 0) { 459 printf("could not find %s in OPENPROM\n", sp); 460 panic(sp); 461 } 462 if (!romprop(&ra, sp, node) || 463 !config_found(dev, (void *)&ra, mbprint)) 464 panic(sp); 465 } 466 467 /* 468 * Configure the rest of the devices, in PROM order. Skip 469 * PROM entries that are not for devices, or which must be 470 * done before we get here. 471 */ 472 for (node = node0; node; node = nextsibling(node)) { 473 cp = getpropstring(node, "name"); 474 for (ssp = special; (sp = *ssp) != NULL; ssp++) 475 if (strcmp(cp, sp) == 0) 476 break; 477 if (sp == NULL && romprop(&ra, cp, node)) { 478 #ifdef L1A_HACK 479 if (strcmp(cp, "audio") == 0) 480 audio = 1; 481 if (strcmp(cp, "zs") == 0) 482 nzs++; 483 if (audio && nzs >= 2) 484 (void) splx(11 << 8); /* XXX */ 485 #endif 486 (void) config_found(dev, (void *)&ra, mbprint); 487 } 488 } 489 } 490 491 struct cfdriver mainbuscd = 492 { NULL, "mainbus", matchbyname, mainbus_attach, 493 DV_DULL, sizeof(struct device) }; 494 495 /* 496 * findzs() is called from the zs driver (which is, at least in theory, 497 * generic to any machine with a Zilog ZSCC chip). It should return the 498 * address of the corresponding zs channel. It may not fail, and it 499 * may be called before the VM code can be used. Here we count on the 500 * FORTH PROM to map in the required zs chips. 501 */ 502 void * 503 findzs(zs) 504 int zs; 505 { 506 register int node, addr; 507 508 node = firstchild(findroot()); 509 while ((node = findnode(node, "zs")) != 0) { 510 if (getpropint(node, "slave", -1) == zs) { 511 if ((addr = getpropint(node, "address", 0)) == 0) 512 panic("findzs: zs%d not mapped by PROM", zs); 513 return ((void *)addr); 514 } 515 node = nextsibling(node); 516 } 517 panic("findzs: cannot find zs%d", zs); 518 /* NOTREACHED */ 519 } 520 521 int 522 makememarr(ap, max, which) 523 register struct memarr *ap; 524 int max, which; 525 { 526 struct v2rmi { 527 int zero; 528 int addr; 529 int len; 530 } v2rmi[200]; /* version 2 rom meminfo layout */ 531 #define MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi)) 532 register struct v0mlist *mp; 533 register int i, node, len; 534 char *prop; 535 536 switch (i = promvec->pv_romvec_vers) { 537 538 case 0: 539 /* 540 * Version 0 PROMs use a linked list to describe these 541 * guys. 542 */ 543 switch (which) { 544 545 case MEMARR_AVAILPHYS: 546 mp = *promvec->pv_v0mem.v0_physavail; 547 break; 548 549 case MEMARR_TOTALPHYS: 550 mp = *promvec->pv_v0mem.v0_phystot; 551 break; 552 553 default: 554 panic("makememarr"); 555 } 556 for (i = 0; mp != NULL; mp = mp->next, i++) { 557 if (i >= max) 558 goto overflow; 559 ap->addr = (u_int)mp->addr; 560 ap->len = mp->nbytes; 561 ap++; 562 } 563 break; 564 565 default: 566 printf("makememarr: hope version %d PROM is like version 2\n", 567 i); 568 /* FALLTHROUGH */ 569 570 case 2: 571 /* 572 * Version 2 PROMs use a property array to describe them. 573 */ 574 if (max > MAXMEMINFO) { 575 printf("makememarr: limited to %d\n", MAXMEMINFO); 576 max = MAXMEMINFO; 577 } 578 if ((node = findnode(firstchild(findroot()), "memory")) == 0) 579 panic("makememarr: cannot find \"memory\" node"); 580 switch (which) { 581 582 case MEMARR_AVAILPHYS: 583 prop = "available"; 584 break; 585 586 case MEMARR_TOTALPHYS: 587 prop = "reg"; 588 break; 589 590 default: 591 panic("makememarr"); 592 } 593 len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) / 594 sizeof(struct v2rmi); 595 for (i = 0; i < len; i++) { 596 if (i >= max) 597 goto overflow; 598 ap->addr = v2rmi[i].addr; 599 ap->len = v2rmi[i].len; 600 ap++; 601 } 602 break; 603 } 604 605 /* 606 * Success! (Hooray) 607 */ 608 if (i == 0) 609 panic("makememarr: no memory found"); 610 return (i); 611 612 overflow: 613 /* 614 * Oops, there are more things in the PROM than our caller 615 * provided space for. Truncate any extras. 616 */ 617 printf("makememarr: WARNING: lost some memory\n"); 618 return (i); 619 } 620 621 /* 622 * Internal form of getprop(). Returns the actual length. 623 */ 624 int 625 getprop(node, name, buf, bufsiz) 626 int node; 627 char *name; 628 void *buf; 629 register int bufsiz; 630 { 631 register struct nodeops *no; 632 register int len; 633 634 no = promvec->pv_nodeops; 635 len = no->no_proplen(node, name); 636 if (len > bufsiz) { 637 printf("node %x property %s length %d > %d\n", 638 node, name, len, bufsiz); 639 #ifdef DEBUG 640 panic("getprop"); 641 #else 642 return (0); 643 #endif 644 } 645 no->no_getprop(node, name, buf); 646 return (len); 647 } 648 649 /* 650 * Return a string property. There is a (small) limit on the length; 651 * the string is fetched into a static buffer which is overwritten on 652 * subsequent calls. 653 */ 654 char * 655 getpropstring(node, name) 656 int node; 657 char *name; 658 { 659 register int len; 660 static char stringbuf[32]; 661 662 len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1); 663 stringbuf[len] = '\0'; /* usually unnecessary */ 664 return (stringbuf); 665 } 666 667 /* 668 * Fetch an integer (or pointer) property. 669 * The return value is the property, or the default if there was none. 670 */ 671 int 672 getpropint(node, name, deflt) 673 int node; 674 char *name; 675 int deflt; 676 { 677 register int len; 678 char intbuf[16]; 679 680 len = getprop(node, name, (void *)intbuf, sizeof intbuf); 681 if (len != 4) 682 return (deflt); 683 return (*(int *)intbuf); 684 } 685 686 /* 687 * OPENPROM functions. These are here mainly to hide the OPENPROM interface 688 * from the rest of the kernel. 689 */ 690 int 691 firstchild(node) 692 int node; 693 { 694 695 return (promvec->pv_nodeops->no_child(node)); 696 } 697 698 int 699 nextsibling(node) 700 int node; 701 { 702 703 return (promvec->pv_nodeops->no_nextnode(node)); 704 } 705 706 #ifdef RCONSOLE 707 /* Pass a string to the FORTH PROM to be interpreted */ 708 void 709 rominterpret(s) 710 register char *s; 711 { 712 713 if (promvec->pv_romvec_vers < 2) 714 promvec->pv_fortheval.v0_eval(strlen(s), s); 715 else 716 promvec->pv_fortheval.v2_eval(s); 717 } 718 719 /* 720 * Try to figure out where the PROM stores the cursor row & column 721 * variables. Returns nonzero on error. 722 */ 723 int 724 romgetcursoraddr(rowp, colp) 725 register int **rowp, **colp; 726 { 727 char buf[100]; 728 729 /* 730 * line# and column# are global in older proms (rom vector < 2) 731 * and in some newer proms. They are local in version 2.9. The 732 * correct cutoff point is unknown, as yet; we use 2.9 here. 733 */ 734 if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009) 735 sprintf(buf, 736 "' line# >body >user %x ! ' column# >body >user %x !", 737 rowp, colp); 738 else 739 sprintf(buf, 740 "stdout @ is my-self addr line# %x ! addr column# %x !", 741 rowp, colp); 742 *rowp = *colp = NULL; 743 rominterpret(buf); 744 return (*rowp == NULL || *colp == NULL); 745 } 746 #endif 747 748 volatile void 749 romhalt() 750 { 751 752 promvec->pv_halt(); 753 panic("PROM exit failed"); 754 } 755 756 volatile void 757 romboot(str) 758 char *str; 759 { 760 761 promvec->pv_reboot(str); 762 panic("PROM boot failed"); 763 } 764 765 callrom() 766 { 767 768 #ifdef notdef /* sun4c FORTH PROMs do this for us */ 769 fb_unblank(); 770 #endif 771 promvec->pv_abort(); 772 } 773 774 /* 775 * Configure swap space and related parameters. 776 */ 777 swapconf() 778 { 779 register struct swdevt *swp; 780 register int nblks; 781 782 for (swp = swdevt; swp->sw_dev != NODEV; swp++) 783 if (bdevsw[major(swp->sw_dev)].d_psize) { 784 nblks = 785 (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); 786 if (nblks != -1 && 787 (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) 788 swp->sw_nblks = nblks; 789 } 790 } 791 792 #define DOSWAP /* Change swdevt and dumpdev too */ 793 u_long bootdev; /* should be dev_t, but not until 32 bits */ 794 795 #define PARTITIONMASK 0x7 796 #define PARTITIONSHIFT 3 797 798 static int 799 findblkmajor(dv) 800 register struct dkdevice *dv; 801 { 802 register int i; 803 804 for (i = 0; i < nblkdev; ++i) 805 if ((void (*)(struct buf *))bdevsw[i].d_strategy == 806 dv->dk_driver->d_strategy) 807 return (i); 808 809 return (-1); 810 } 811 812 static struct device * 813 getdisk(str, len, defpart, devp) 814 char *str; 815 int len, defpart; 816 dev_t *devp; 817 { 818 register struct device *dv; 819 820 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 821 printf("use one of:"); 822 for (dv = alldevs; dv != NULL; dv = dv->dv_next) 823 if (dv->dv_class == DV_DISK) 824 printf(" %s[a-h]", dv->dv_xname); 825 printf("\n"); 826 } 827 return (dv); 828 } 829 830 struct device * 831 parsedisk(str, len, defpart, devp) 832 char *str; 833 int len, defpart; 834 dev_t *devp; 835 { 836 register struct device *dv; 837 register char *cp, c; 838 int majdev, mindev, part; 839 840 if (len == 0) 841 return (NULL); 842 cp = str + len - 1; 843 c = *cp; 844 if (c >= 'a' && c <= 'h') { 845 part = c - 'a'; 846 *cp = '\0'; 847 } else 848 part = defpart; 849 850 for (dv = alldevs; dv != NULL; dv = dv->dv_next) { 851 if (dv->dv_class == DV_DISK && 852 strcmp(str, dv->dv_xname) == 0) { 853 majdev = findblkmajor((struct dkdevice *)dv); 854 if (majdev < 0) 855 panic("parsedisk"); 856 mindev = (dv->dv_unit << PARTITIONSHIFT) + part; 857 *devp = makedev(majdev, mindev); 858 break; 859 } 860 } 861 862 *cp = c; 863 return (dv); 864 } 865 866 /* 867 * Attempt to find the device from which we were booted. 868 * If we can do so, and not instructed not to do so, 869 * change rootdev to correspond to the load device. 870 */ 871 void 872 setroot() 873 { 874 register struct swdevt *swp; 875 register struct device *dv; 876 register int len, majdev, mindev, part; 877 dev_t nrootdev, nswapdev; 878 char buf[128]; 879 #ifdef DOSWAP 880 dev_t temp; 881 #endif 882 #ifdef NFS 883 extern int (*mountroot)(), nfs_mountroot(); 884 #endif 885 886 if (boothowto & RB_ASKNAME) { 887 for (;;) { 888 printf("root device? "); 889 len = getstr(buf, sizeof(buf)); 890 #ifdef GENERIC 891 if (len > 0 && buf[len - 1] == '*') { 892 buf[--len] = '\0'; 893 dv = getdisk(buf, len, 1, &nrootdev); 894 if (dv != NULL) { 895 bootdv = dv; 896 nswapdev = nrootdev; 897 goto gotswap; 898 } 899 } 900 #endif 901 dv = getdisk(buf, len, 0, &nrootdev); 902 if (dv != NULL) { 903 bootdv = dv; 904 break; 905 } 906 } 907 for (;;) { 908 printf("swap device (default %sb)? ", bootdv->dv_xname); 909 len = getstr(buf, sizeof(buf)); 910 if (len == 0) { 911 nswapdev = makedev(major(nrootdev), 912 (minor(nrootdev) & ~ PARTITIONMASK) | 1); 913 break; 914 } 915 if (getdisk(buf, len, 1, &nswapdev) != NULL) 916 break; 917 } 918 #ifdef GENERIC 919 gotswap: 920 #endif 921 rootdev = nrootdev; 922 swapdev = nswapdev; 923 dumpdev = nswapdev; /* ??? */ 924 swdevt[0].sw_dev = nswapdev; 925 swdevt[1].sw_dev = NODEV; 926 return; 927 } 928 929 /* XXX currently there's no way to set RB_DFLTROOT... */ 930 if (boothowto & RB_DFLTROOT || bootdv == NULL) 931 return; 932 933 switch (bootdv->dv_class) { 934 935 #ifdef NFS 936 case DV_IFNET: 937 mountroot = nfs_mountroot; 938 return; 939 #endif 940 941 #if defined(FFS) || defined(LFS) 942 case DV_DISK: 943 majdev = findblkmajor((struct dkdevice *)bootdv); 944 if (majdev < 0) 945 return; 946 part = 0; 947 mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part; 948 break; 949 #endif 950 951 default: 952 printf("can't figure root, hope your kernel is right\n"); 953 return; 954 } 955 956 /* 957 * Form a new rootdev 958 */ 959 nrootdev = makedev(majdev, mindev); 960 /* 961 * If the original rootdev is the same as the one 962 * just calculated, don't need to adjust the swap configuration. 963 */ 964 if (rootdev == nrootdev) 965 return; 966 967 rootdev = nrootdev; 968 printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a'); 969 970 #ifdef DOSWAP 971 mindev &= ~PARTITIONMASK; 972 temp = NODEV; 973 for (swp = swdevt; swp->sw_dev != NODEV; swp++) { 974 if (majdev == major(swp->sw_dev) && 975 mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { 976 temp = swdevt[0].sw_dev; 977 swdevt[0].sw_dev = swp->sw_dev; 978 swp->sw_dev = temp; 979 break; 980 } 981 } 982 if (swp->sw_dev == NODEV) 983 return; 984 985 /* 986 * If dumpdev was the same as the old primary swap device, move 987 * it to the new primary swap device. 988 */ 989 if (temp == dumpdev) 990 dumpdev = swdevt[0].sw_dev; 991 #endif 992 } 993 994 static int 995 getstr(cp, size) 996 register char *cp; 997 register int size; 998 { 999 register char *lp; 1000 register int c; 1001 register int len; 1002 1003 lp = cp; 1004 len = 0; 1005 for (;;) { 1006 c = cngetc(); 1007 switch (c) { 1008 case '\n': 1009 case '\r': 1010 printf("\n"); 1011 *lp++ = '\0'; 1012 return (len); 1013 case '\b': 1014 case '\177': 1015 case '#': 1016 if (len) { 1017 --len; 1018 --lp; 1019 printf(" \b "); 1020 } 1021 continue; 1022 case '@': 1023 case 'u'&037: 1024 len = 0; 1025 lp = cp; 1026 printf("\n"); 1027 continue; 1028 default: 1029 if (len + 1 >= size || c < ' ') { 1030 printf("\007"); 1031 continue; 1032 } 1033 printf("%c", c); 1034 ++len; 1035 *lp++ = c; 1036 } 1037 } 1038 } 1039