xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 64662)
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