xref: /original-bsd/sys/sparc/sparc/autoconf.c (revision 3705696b)
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