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
matchbyname(parent,cf,aux)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 *
str2hex(str,vp)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
bootstrap()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 */
configure()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
sync_crash()276 sync_crash()
277 {
278
279 panic("PROM sync command");
280 }
281
282 char *
clockfreq(freq)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
mbprint(aux,name)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
findroot()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
findnode(first,name)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
romprop(rp,cp,node)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
mainbus_attach(parent,dev,aux)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 *
findzs(zs)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
makememarr(ap,max,which)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
getprop(node,name,buf,bufsiz)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 *
getpropstring(node,name)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
getpropint(node,name,deflt)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
firstchild(node)691 firstchild(node)
692 int node;
693 {
694
695 return (promvec->pv_nodeops->no_child(node));
696 }
697
698 int
nextsibling(node)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
rominterpret(s)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
romgetcursoraddr(rowp,colp)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
romhalt()749 romhalt()
750 {
751
752 promvec->pv_halt();
753 panic("PROM exit failed");
754 }
755
756 volatile void
romboot(str)757 romboot(str)
758 char *str;
759 {
760
761 promvec->pv_reboot(str);
762 panic("PROM boot failed");
763 }
764
callrom()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 */
swapconf()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
findblkmajor(dv)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 *
getdisk(str,len,defpart,devp)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 *
parsedisk(str,len,defpart,devp)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
setroot()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
getstr(cp,size)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