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.1 (Berkeley) 06/11/93 17 * 18 * from: $Header: autoconf.c,v 1.32 93/05/28 03:55:59 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 "memory-error", "eeprom", "counter-timer", "", 416 417 /* ignore these (end with NULL) */ 418 "options", "packages", "openprom", "memory", "virtual-memory", 419 "interrupt-enable", NULL 420 }; 421 422 printf("\n"); 423 424 /* configure the cpu */ 425 node = ((struct romaux *)aux)->ra_node; 426 ra.ra_node = node; 427 ra.ra_name = cp = "cpu"; 428 ra.ra_paddr = 0; 429 config_found(dev, (void *)&ra, mbprint); 430 431 /* remember which frame buffer, if any, is to be /dev/fb */ 432 fbnode = getpropint(node, "fb", 0); 433 434 /* Find the "options" node */ 435 node0 = firstchild(node); 436 optionsnode = findnode(node0, "options"); 437 if (optionsnode == 0) 438 panic("no options in OPENPROM"); 439 440 /* Start at the beginning of the bootpath */ 441 ra.ra_bp = bootpath; 442 443 /* 444 * Locate and configure the ``early'' devices. These must be 445 * configured before we can do the rest. For instance, the 446 * EEPROM contains the Ethernet address for the LANCE chip. 447 * If the device cannot be located or configured, panic. 448 */ 449 for (ssp = special; *(sp = *ssp) != 0; ssp++) { 450 if ((node = findnode(node0, sp)) == 0) { 451 printf("could not find %s in OPENPROM\n", sp); 452 panic(sp); 453 } 454 if (!romprop(&ra, sp, node) || 455 !config_found(dev, (void *)&ra, mbprint)) 456 panic(sp); 457 } 458 459 /* 460 * Configure the rest of the devices, in PROM order. Skip 461 * PROM entries that are not for devices, or which must be 462 * done before we get here. 463 */ 464 for (node = node0; node; node = nextsibling(node)) { 465 cp = getpropstring(node, "name"); 466 for (ssp = special; (sp = *ssp) != NULL; ssp++) 467 if (strcmp(cp, sp) == 0) 468 break; 469 if (sp == NULL && romprop(&ra, cp, node)) { 470 #ifdef L1A_HACK 471 if (strcmp(cp, "audio") == 0) 472 audio = 1; 473 if (strcmp(cp, "zs") == 0) 474 nzs++; 475 if (audio && nzs >= 2) 476 (void) splx(11 << 8); /* XXX */ 477 #endif 478 (void) config_found(dev, (void *)&ra, mbprint); 479 } 480 } 481 } 482 483 struct cfdriver mainbuscd = 484 { NULL, "mainbus", matchbyname, mainbus_attach, 485 DV_DULL, sizeof(struct device) }; 486 487 /* 488 * findzs() is called from the zs driver (which is, at least in theory, 489 * generic to any machine with a Zilog ZSCC chip). It should return the 490 * address of the corresponding zs channel. It may not fail, and it 491 * may be called before the VM code can be used. Here we count on the 492 * FORTH PROM to map in the required zs chips. 493 */ 494 void * 495 findzs(zs) 496 int zs; 497 { 498 register int node, addr; 499 500 node = firstchild(findroot()); 501 while ((node = findnode(node, "zs")) != 0) { 502 if (getpropint(node, "slave", -1) == zs) { 503 if ((addr = getpropint(node, "address", 0)) == 0) 504 panic("findzs: zs%d not mapped by PROM", zs); 505 return ((void *)addr); 506 } 507 node = nextsibling(node); 508 } 509 panic("findzs: cannot find zs%d", zs); 510 /* NOTREACHED */ 511 } 512 513 int 514 makememarr(ap, max, which) 515 register struct memarr *ap; 516 int max, which; 517 { 518 struct v2rmi { 519 int zero; 520 int addr; 521 int len; 522 } v2rmi[200]; /* version 2 rom meminfo layout */ 523 #define MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi)) 524 register struct v0mlist *mp; 525 register int i, node, len; 526 char *prop; 527 528 switch (i = promvec->pv_romvec_vers) { 529 530 case 0: 531 /* 532 * Version 0 PROMs use a linked list to describe these 533 * guys. 534 */ 535 switch (which) { 536 537 case MEMARR_AVAILPHYS: 538 mp = *promvec->pv_v0mem.v0_physavail; 539 break; 540 541 case MEMARR_TOTALPHYS: 542 mp = *promvec->pv_v0mem.v0_phystot; 543 break; 544 545 default: 546 panic("makememarr"); 547 } 548 for (i = 0; mp != NULL; mp = mp->next, i++) { 549 if (i >= max) 550 goto overflow; 551 ap->addr = (u_int)mp->addr; 552 ap->len = mp->nbytes; 553 ap++; 554 } 555 break; 556 557 default: 558 printf("makememarr: hope version %d PROM is like version 2\n", 559 i); 560 /* FALLTHROUGH */ 561 562 case 2: 563 /* 564 * Version 2 PROMs use a property array to describe them. 565 */ 566 if (max > MAXMEMINFO) { 567 printf("makememarr: limited to %d\n", MAXMEMINFO); 568 max = MAXMEMINFO; 569 } 570 if ((node = findnode(firstchild(findroot()), "memory")) == 0) 571 panic("makememarr: cannot find \"memory\" node"); 572 switch (which) { 573 574 case MEMARR_AVAILPHYS: 575 prop = "available"; 576 break; 577 578 case MEMARR_TOTALPHYS: 579 prop = "reg"; 580 break; 581 582 default: 583 panic("makememarr"); 584 } 585 len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) / 586 sizeof(struct v2rmi); 587 for (i = 0; i < len; i++) { 588 if (i >= max) 589 goto overflow; 590 ap->addr = v2rmi[i].addr; 591 ap->len = v2rmi[i].len; 592 ap++; 593 } 594 break; 595 } 596 597 /* 598 * Success! (Hooray) 599 */ 600 if (i == 0) 601 panic("makememarr: no memory found"); 602 return (i); 603 604 overflow: 605 /* 606 * Oops, there are more things in the PROM than our caller 607 * provided space for. Truncate any extras. 608 */ 609 printf("makememarr: WARNING: lost some memory\n"); 610 return (i); 611 } 612 613 /* 614 * Internal form of getprop(). Returns the actual length. 615 */ 616 int 617 getprop(node, name, buf, bufsiz) 618 int node; 619 char *name; 620 void *buf; 621 register int bufsiz; 622 { 623 register struct nodeops *no; 624 register int len; 625 626 no = promvec->pv_nodeops; 627 len = no->no_proplen(node, name); 628 if (len > bufsiz) { 629 printf("node %x property %s length %d > %d\n", 630 node, name, len, bufsiz); 631 #ifdef DEBUG 632 panic("getprop"); 633 #else 634 return (0); 635 #endif 636 } 637 no->no_getprop(node, name, buf); 638 return (len); 639 } 640 641 /* 642 * Return a string property. There is a (small) limit on the length; 643 * the string is fetched into a static buffer which is overwritten on 644 * subsequent calls. 645 */ 646 char * 647 getpropstring(node, name) 648 int node; 649 char *name; 650 { 651 register int len; 652 static char stringbuf[32]; 653 654 len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1); 655 stringbuf[len] = '\0'; /* usually unnecessary */ 656 return (stringbuf); 657 } 658 659 /* 660 * Fetch an integer (or pointer) property. 661 * The return value is the property, or the default if there was none. 662 */ 663 int 664 getpropint(node, name, deflt) 665 int node; 666 char *name; 667 int deflt; 668 { 669 register int len; 670 char intbuf[16]; 671 672 len = getprop(node, name, (void *)intbuf, sizeof intbuf); 673 if (len != 4) 674 return (deflt); 675 return (*(int *)intbuf); 676 } 677 678 /* 679 * OPENPROM functions. These are here mainly to hide the OPENPROM interface 680 * from the rest of the kernel. 681 */ 682 int 683 firstchild(node) 684 int node; 685 { 686 687 return (promvec->pv_nodeops->no_child(node)); 688 } 689 690 int 691 nextsibling(node) 692 int node; 693 { 694 695 return (promvec->pv_nodeops->no_nextnode(node)); 696 } 697 698 /* Pass a string to the FORTH PROM to be interpreted */ 699 void 700 rominterpret(s) 701 register char *s; 702 { 703 704 if (promvec->pv_romvec_vers < 2) 705 promvec->pv_fortheval.v0_eval(strlen(s), s); 706 else 707 promvec->pv_fortheval.v2_eval(s); 708 } 709 710 volatile void 711 romhalt() 712 { 713 714 promvec->pv_halt(); 715 panic("PROM exit failed"); 716 } 717 718 volatile void 719 romboot(str) 720 char *str; 721 { 722 723 promvec->pv_reboot(str); 724 panic("PROM boot failed"); 725 } 726 727 callrom() 728 { 729 730 #ifdef notdef /* sun4c FORTH PROMs do this for us */ 731 fb_unblank(); 732 #endif 733 promvec->pv_abort(); 734 } 735 736 /* 737 * Configure swap space and related parameters. 738 */ 739 swapconf() 740 { 741 register struct swdevt *swp; 742 register int nblks; 743 744 for (swp = swdevt; swp->sw_dev != NODEV; swp++) 745 if (bdevsw[major(swp->sw_dev)].d_psize) { 746 nblks = 747 (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); 748 if (nblks != -1 && 749 (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) 750 swp->sw_nblks = nblks; 751 } 752 } 753 754 #define DOSWAP /* Change swdevt and dumpdev too */ 755 u_long bootdev; /* should be dev_t, but not until 32 bits */ 756 757 #define PARTITIONMASK 0x7 758 #define PARTITIONSHIFT 3 759 760 static int 761 findblkmajor(dv) 762 register struct dkdevice *dv; 763 { 764 register int i; 765 766 for (i = 0; i < nblkdev; ++i) 767 if ((void (*)(struct buf *))bdevsw[i].d_strategy == 768 dv->dk_driver->d_strategy) 769 return (i); 770 771 return (-1); 772 } 773 774 static struct device * 775 getdisk(str, len, defpart, devp) 776 char *str; 777 int len, defpart; 778 dev_t *devp; 779 { 780 register struct device *dv; 781 782 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 783 printf("use one of:"); 784 for (dv = alldevs; dv != NULL; dv = dv->dv_next) 785 if (dv->dv_class == DV_DISK) 786 printf(" %s[a-h]", dv->dv_xname); 787 printf("\n"); 788 } 789 return (dv); 790 } 791 792 static struct device * 793 parsedisk(str, len, defpart, devp) 794 char *str; 795 int len, defpart; 796 dev_t *devp; 797 { 798 register struct device *dv; 799 register char *cp; 800 int majdev, mindev, part; 801 802 if (len == 0) 803 return (NULL); 804 cp = str + len - 1; 805 if (*cp >= 'a' && *cp <= 'h') { 806 part = *cp - 'a'; 807 *cp-- = '\0'; 808 } else 809 part = defpart; 810 811 for (dv = alldevs; dv != NULL; dv = dv->dv_next) 812 if (dv->dv_class == DV_DISK && 813 strcmp(str, dv->dv_xname) == 0) { 814 majdev = findblkmajor((struct dkdevice *)dv); 815 if (majdev < 0) 816 panic("parsedisk"); 817 mindev = (dv->dv_unit << PARTITIONSHIFT) + part; 818 *devp = makedev(majdev, mindev); 819 return (dv); 820 } 821 822 return (NULL); 823 } 824 825 /* 826 * Attempt to find the device from which we were booted. 827 * If we can do so, and not instructed not to do so, 828 * change rootdev to correspond to the load device. 829 */ 830 void 831 setroot() 832 { 833 register struct swdevt *swp; 834 register struct device *dv; 835 register int len, majdev, mindev, part; 836 dev_t nrootdev, nswapdev; 837 char buf[128]; 838 #ifdef DOSWAP 839 dev_t temp; 840 #endif 841 #ifdef NFS 842 extern int (*mountroot)(), nfs_mountroot(); 843 #endif 844 845 if (boothowto & RB_ASKNAME) { 846 for (;;) { 847 printf("root device? "); 848 len = getstr(buf, sizeof(buf)); 849 #ifdef GENERIC 850 if (len > 0 && buf[len - 1] == '*') { 851 buf[--len] = '\0'; 852 dv = getdisk(buf, len, 1, &nrootdev); 853 if (dv != NULL) { 854 bootdv = dv; 855 nswapdev = nrootdev; 856 goto gotswap; 857 } 858 } 859 #endif 860 dv = getdisk(buf, len, 0, &nrootdev); 861 if (dv != NULL) { 862 bootdv = dv; 863 break; 864 } 865 } 866 for (;;) { 867 printf("swap device (default %sb)? ", bootdv->dv_xname); 868 len = getstr(buf, sizeof(buf)); 869 if (len == 0) { 870 nswapdev = makedev(major(nrootdev), 871 (minor(nrootdev) & ~ PARTITIONMASK) | 1); 872 break; 873 } 874 if (getdisk(buf, len, 1, &nswapdev) != NULL) 875 break; 876 } 877 #ifdef GENERIC 878 gotswap: 879 #endif 880 rootdev = nrootdev; 881 swapdev = nswapdev; 882 dumpdev = nswapdev; /* ??? */ 883 swdevt[0].sw_dev = nswapdev; 884 swdevt[1].sw_dev = NODEV; 885 return; 886 } 887 888 /* XXX currently there's no way to set RB_DFLTROOT... */ 889 if (boothowto & RB_DFLTROOT || bootdv == NULL) 890 return; 891 892 switch (bootdv->dv_class) { 893 894 #ifdef NFS 895 case DV_IFNET: 896 mountroot = nfs_mountroot; 897 #ifdef LBL 898 lbl_diskless_setup(); 899 #endif 900 return; 901 #endif 902 903 #if defined(FFS) || defined(LFS) 904 case DV_DISK: 905 majdev = findblkmajor((struct dkdevice *)bootdv); 906 if (majdev < 0) 907 return; 908 part = 0; 909 mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part; 910 break; 911 #endif 912 913 default: 914 printf("can't figure root, hope your kernel is right\n"); 915 return; 916 } 917 918 /* 919 * Form a new rootdev 920 */ 921 nrootdev = makedev(majdev, mindev); 922 /* 923 * If the original rootdev is the same as the one 924 * just calculated, don't need to adjust the swap configuration. 925 */ 926 if (rootdev == nrootdev) 927 return; 928 929 rootdev = nrootdev; 930 printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a'); 931 932 #ifdef DOSWAP 933 mindev &= ~PARTITIONMASK; 934 temp = NODEV; 935 for (swp = swdevt; swp->sw_dev != NODEV; swp++) { 936 if (majdev == major(swp->sw_dev) && 937 mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { 938 temp = swdevt[0].sw_dev; 939 swdevt[0].sw_dev = swp->sw_dev; 940 swp->sw_dev = temp; 941 break; 942 } 943 } 944 if (swp->sw_dev == NODEV) 945 return; 946 947 /* 948 * If dumpdev was the same as the old primary swap device, move 949 * it to the new primary swap device. 950 */ 951 if (temp == dumpdev) 952 dumpdev = swdevt[0].sw_dev; 953 #endif 954 } 955 956 static int 957 getstr(cp, size) 958 register char *cp; 959 register int size; 960 { 961 register char *lp; 962 register int c; 963 register int len; 964 965 lp = cp; 966 len = 0; 967 for (;;) { 968 c = cngetc(); 969 switch (c) { 970 case '\n': 971 case '\r': 972 printf("\n"); 973 *lp++ = '\0'; 974 return (len); 975 case '\b': 976 case '\177': 977 case '#': 978 if (len) { 979 --len; 980 --lp; 981 printf(" \b "); 982 } 983 continue; 984 case '@': 985 case 'u'&037: 986 len = 0; 987 lp = cp; 988 printf("\n"); 989 continue; 990 default: 991 if (len + 1 >= size || c < ' ') { 992 printf("\007"); 993 continue; 994 } 995 printf("%c", c); 996 ++len; 997 *lp++ = c; 998 } 999 } 1000 } 1001