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