xref: /original-bsd/sys/sparc/sparc/autoconf.c (revision c98fd05d)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California.
3  * 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 Laboratories.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)autoconf.c	7.2 (Berkeley) 07/21/92
17  *
18  * from: $Header: autoconf.c,v 1.23 92/07/10 22:35:23 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/dkstat.h"
27 #include "sys/conf.h"
28 #include "sys/dmap.h"
29 #include "sys/reboot.h"
30 #include "sys/socket.h"
31 #include "sys/systm.h"
32 
33 #include "net/if.h"
34 
35 #include "machine/autoconf.h"
36 #include "machine/bsd_openprom.h"
37 #include "machine/cpu.h"
38 
39 #ifndef	FS_NFS		/* XXX */
40 #define	FS_NFS	100	/* XXX */
41 #endif			/* XXX */
42 
43 /*
44  * The following several variables are related to
45  * the configuration process, and are used in initializing
46  * the machine.
47  */
48 int	cold;		/* if 1, still working on cold-start */
49 int	dkn;		/* number of iostat dk numbers assigned so far */
50 int	cpuspeed = 10;	/* relative cpu speed */
51 int	fbnode;		/* node ID of ROM's console frame buffer */
52 int	optionsnode;	/* node ID of ROM's options */
53 
54 extern struct promvec *promvec;
55 
56 static	int rootnode;
57 int	findroot();
58 static	struct	bootinfo *findbootdev();
59 
60 static	struct bootinfo {
61 	char	name[16];	/* device name */
62 	int	val[3];		/* up to 3 values */
63 	int	type;		/* FS type */
64 	caddr_t	data;		/* FS dependant info */
65 } bootinfo;
66 
67 
68 /*
69  * Most configuration on the SPARC is done by matching OPENPROM Forth
70  * device names with our internal names.
71  */
72 int
73 matchbyname(parent, cf, aux)
74 	struct device *parent;
75 	struct cfdata *cf;
76 	void *aux;
77 {
78 
79 	return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0);
80 }
81 
82 /*
83  * Convert hex ASCII string to a value.  Returns updated pointer.
84  * Depends on ASCII order (this *is* machine-dependent code, you know).
85  */
86 static char *
87 str2hex(str, vp)
88 	register char *str;
89 	register int *vp;
90 {
91 	register int v, c;
92 
93 	for (v = 0;; v = v * 16 + c, str++) {
94 		c = *(u_char *)str;
95 		if (c <= '9') {
96 			if ((c -= '0') < 0)
97 				break;
98 		} else if (c <= 'F') {
99 			if ((c -= 'A' - 10) < 10)
100 				break;
101 		} else if (c <= 'f') {
102 			if ((c -= 'a' - 10) < 10)
103 				break;
104 		} else
105 			break;
106 	}
107 	*vp = v;
108 	return (str);
109 }
110 
111 /*
112  * locore.s code calls bootstrap() just before calling main(), after double
113  * mapping the kernel to high memory and setting up the trap base register.
114  * We must finish mapping the kernel properly and glean any bootstrap info.
115  */
116 void
117 bootstrap()
118 {
119 	register char *cp, *bp, *ep;
120 	register int i;
121 	int nmmu, ncontext, node;
122 #ifdef KGDB
123 	extern int kgdb_debug_panic;
124 #endif
125 	extern char *rindex(const char *, int);
126 
127 	node = findroot();
128 	nmmu = getpropint(node, "mmu-npmg", 128);
129 	ncontext = getpropint(node, "mmu-nctx", 8);
130 	pmap_bootstrap(nmmu, ncontext);
131 #ifdef KGDB
132 	zs_kgdb_init();			/* XXX */
133 #endif
134 	/*
135 	 * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
136 	 * that were given after the boot command.  On SS2s, pv_v0bootargs
137 	 * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
138 	 * "vmunix -s" or whatever.
139 	 * ###	DO THIS BEFORE pmap_boostrap?
140 	 */
141 	if (promvec->pv_romvec_vers < 2) {
142 		/* Grab boot device name and values. */
143 		cp = (*promvec->pv_v0bootargs)->ba_argv[0];
144 		if (cp != NULL) {
145 			bp = bootinfo.name;
146 			ep = &bootinfo.name[sizeof(bootinfo.name)];
147 			while (*cp != '(' && *cp != '\0' && bp < ep - 1)
148 				*bp++ = *cp++;
149 			*bp = '\0';
150 
151 			if (*cp == '(' &&
152 			    *(cp = str2hex(++cp, &bootinfo.val[0])) == ',' &&
153 			    *(cp = str2hex(++cp, &bootinfo.val[1])) == ',')
154 				(void)str2hex(++cp, &bootinfo.val[2]);
155 		}
156 
157 		/* Setup pointer to boot flags */
158 		cp = (*promvec->pv_v0bootargs)->ba_argv[1];
159 		if (cp == NULL || *cp != '-')
160 			return;
161 	} else {
162 		/* Grab boot device name and values. */
163 		cp = *promvec->pv_v2bootargs.v2_bootpath;
164 		if (cp != NULL && (cp = rindex(cp, '/')) != NULL) {
165 			++cp;
166 			bp = bootinfo.name;
167 			ep = &bootinfo.name[sizeof(bootinfo.name)];
168 			while (*cp != '@' && *cp != '\0' && bp < ep - 1)
169 				*bp++ = *cp++;
170 			*bp = '\0';
171 
172 			if (*cp == '@' &&
173 			    *(cp = str2hex(++cp, &bootinfo.val[0])) == ',' &&
174 			    *(cp = str2hex(++cp, &bootinfo.val[1])) == ',')
175 				(void)str2hex(++cp, &bootinfo.val[2]);
176 		}
177 
178 		/* Setup pointer to boot flags */
179 		cp = *promvec->pv_v2bootargs.v2_bootargs;
180 		if (cp == NULL)
181 			return;
182 		while (*cp != '-')
183 			if (*cp++ == '\0')
184 				return;
185 	}
186 	for (;;) {
187 		switch (*++cp) {
188 
189 		case '\0':
190 			return;
191 
192 		case 'a':
193 			boothowto |= RB_ASKNAME;
194 			break;
195 
196 		case 'b':
197 			boothowto |= RB_DFLTROOT;
198 			break;
199 
200 		case 'd':	/* kgdb - always on zs	XXX */
201 #ifdef KGDB
202 			boothowto |= RB_KDB;	/* XXX unused */
203 			kgdb_debug_panic = 1;
204 			kgdb_connect(1);
205 #else
206 			printf("kernel not compiled with KGDB\n");
207 #endif
208 			break;
209 
210 		case 's':
211 			boothowto |= RB_SINGLE;
212 			break;
213 		}
214 	}
215 }
216 
217 /*
218  * Determine mass storage and memory configuration for a machine.
219  * We get the PROM's root device and make sure we understand it, then
220  * attach it as `mainbus0'.  We also set up to handle the PROM `sync'
221  * command.
222  */
223 configure()
224 {
225 	register int node;
226 	register char *cp;
227 	struct romaux ra;
228 	void sync_crash();
229 #ifdef NFS
230 	register struct bootinfo *bi;
231 	extern int (*mountroot)(), nfs_mountroot();
232 #endif
233 
234 	node = findroot();
235 	cp = getpropstring(node, "device_type");
236 	if (strcmp(cp, "cpu") != 0) {
237 		printf("PROM root device type = %s\n", cp);
238 		panic("need CPU as root");
239 	}
240 	*promvec->pv_synchook = sync_crash;
241 	ra.ra_node = node;
242 	ra.ra_name = cp = "mainbus";
243 	if (!config_rootfound(cp, (void *)&ra))
244 		panic("mainbus not configured");
245 	(void) spl0();
246 	cold = 0;
247 #ifdef NFS
248 	if (boothowto & RB_ASKNAME) {
249 		char ans[100];
250 
251 		printf("nfs root? (y/n) [n] ");
252 		gets(ans);
253 		if (ans[0] == 'y')
254 			mountroot = nfs_mountroot;
255 	} else if ((bi = findbootdev()) != NULL && bi->type == FS_NFS) {
256 		mountroot = nfs_mountroot;
257 #ifdef LBL
258 		lbl_diskless_setup();
259 #endif /* LBL */
260 	}
261 #endif /* NFS */
262 #if GENERIC
263 	if ((boothowto & RB_ASKNAME) == 0)
264 		setroot();
265 	setconf();
266 #else
267 	setroot();
268 #endif
269 	swapconf();
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 	/*
441 	 * Locate and configure the ``early'' devices.  These must be
442 	 * configured before we can do the rest.  For instance, the
443 	 * EEPROM contains the Ethernet address for the LANCE chip.
444 	 * If the device cannot be located or configured, panic.
445 	 */
446 	for (ssp = special; *(sp = *ssp) != 0; ssp++) {
447 		if ((node = findnode(node0, sp)) == 0) {
448 			printf("could not find %s in OPENPROM\n", sp);
449 			panic(sp);
450 		}
451 		if (!romprop(&ra, sp, node) ||
452 		    !config_found(dev, (void *)&ra, mbprint))
453 			panic(sp);
454 	}
455 
456 	/*
457 	 * Configure the rest of the devices, in PROM order.  Skip
458 	 * PROM entries that are not for devices, or which must be
459 	 * done before we get here.
460 	 */
461 	for (node = node0; node; node = nextsibling(node)) {
462 		cp = getpropstring(node, "name");
463 		for (ssp = special; (sp = *ssp) != NULL; ssp++)
464 			if (strcmp(cp, sp) == 0)
465 				break;
466 		if (sp == NULL && romprop(&ra, cp, node)) {
467 #ifdef L1A_HACK
468 			if (strcmp(cp, "audio") == 0)
469 				audio = 1;
470 			if (strcmp(cp, "zs") == 0)
471 				nzs++;
472 			if (audio && nzs >= 2)
473 				(void) splx(11 << 8);	/* XXX */
474 #endif
475 			(void) config_found(dev, (void *)&ra, mbprint);
476 		}
477 	}
478 }
479 
480 struct cfdriver mainbuscd =
481     { NULL, "mainbus", matchbyname, mainbus_attach,
482       DV_DULL, sizeof(struct device) };
483 
484 /*
485  * findzs() is called from the zs driver (which is, at least in theory,
486  * generic to any machine with a Zilog ZSCC chip).  It should return the
487  * address of the corresponding zs channel.  It may not fail, and it
488  * may be called before the VM code can be used.  Here we count on the
489  * FORTH PROM to map in the required zs chips.
490  */
491 void *
492 findzs(zs)
493 	int zs;
494 {
495 	register int node, addr;
496 
497 	node = firstchild(findroot());
498 	while ((node = findnode(node, "zs")) != 0) {
499 		if (getpropint(node, "slave", -1) == zs) {
500 			if ((addr = getpropint(node, "address", 0)) == 0)
501 				panic("findzs: zs%d not mapped by PROM", zs);
502 			return ((void *)addr);
503 		}
504 		node = nextsibling(node);
505 	}
506 	panic("findzs: cannot find zs%d", zs);
507 	/* NOTREACHED */
508 }
509 
510 int
511 makememarr(ap, max, which)
512 	register struct memarr *ap;
513 	int max, which;
514 {
515 	struct v2rmi {
516 		int	zero;
517 		int	addr;
518 		int	len;
519 	} v2rmi[200];		/* version 2 rom meminfo layout */
520 #define	MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
521 	register struct v0mlist *mp;
522 	register int i, node, len;
523 	char *prop;
524 
525 	switch (i = promvec->pv_romvec_vers) {
526 
527 	case 0:
528 		/*
529 		 * Version 0 PROMs use a linked list to describe these
530 		 * guys.
531 		 */
532 		switch (which) {
533 
534 		case MEMARR_AVAILPHYS:
535 			mp = *promvec->pv_v0mem.v0_physavail;
536 			break;
537 
538 		case MEMARR_TOTALPHYS:
539 			mp = *promvec->pv_v0mem.v0_phystot;
540 			break;
541 
542 		default:
543 			panic("makememarr");
544 		}
545 		for (i = 0; mp != NULL; mp = mp->next, i++) {
546 			if (i >= max)
547 				goto overflow;
548 			ap->addr = (u_int)mp->addr;
549 			ap->len = mp->nbytes;
550 			ap++;
551 		}
552 		break;
553 
554 	default:
555 		printf("makememarr: hope version %d PROM is like version 2\n",
556 		    i);
557 		/* FALLTHROUGH */
558 
559 	case 2:
560 		/*
561 		 * Version 2 PROMs use a property array to describe them.
562 		 */
563 		if (max > MAXMEMINFO) {
564 			printf("makememarr: limited to %d\n", MAXMEMINFO);
565 			max = MAXMEMINFO;
566 		}
567 		if ((node = findnode(firstchild(findroot()), "memory")) == 0)
568 			panic("makememarr: cannot find \"memory\" node");
569 		switch (which) {
570 
571 		case MEMARR_AVAILPHYS:
572 			prop = "available";
573 			break;
574 
575 		case MEMARR_TOTALPHYS:
576 			prop = "reg";
577 			break;
578 
579 		default:
580 			panic("makememarr");
581 		}
582 		len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
583 		    sizeof(struct v2rmi);
584 		for (i = 0; i < len; i++) {
585 			if (i >= max)
586 				goto overflow;
587 			ap->addr = v2rmi[i].addr;
588 			ap->len = v2rmi[i].len;
589 			ap++;
590 		}
591 		break;
592 	}
593 
594 	/*
595 	 * Success!  (Hooray)
596 	 */
597 	if (i == 0)
598 		panic("makememarr: no memory found");
599 	return (i);
600 
601 overflow:
602 	/*
603 	 * Oops, there are more things in the PROM than our caller
604 	 * provided space for.  Truncate any extras.
605 	 */
606 	printf("makememarr: WARNING: lost some memory\n");
607 	return (i);
608 }
609 
610 /*
611  * Internal form of getprop().  Returns the actual length.
612  */
613 int
614 getprop(node, name, buf, bufsiz)
615 	int node;
616 	char *name;
617 	void *buf;
618 	register int bufsiz;
619 {
620 	register struct nodeops *no;
621 	register int len;
622 
623 	no = promvec->pv_nodeops;
624 	len = no->no_proplen(node, name);
625 	if (len > bufsiz) {
626 		printf("node %x property %s length %d > %d\n",
627 		    node, name, len, bufsiz);
628 #ifdef DEBUG
629 		panic("getprop");
630 #else
631 		return (0);
632 #endif
633 	}
634 	no->no_getprop(node, name, buf);
635 	return (len);
636 }
637 
638 /*
639  * Return a string property.  There is a (small) limit on the length;
640  * the string is fetched into a static buffer which is overwritten on
641  * subsequent calls.
642  */
643 char *
644 getpropstring(node, name)
645 	int node;
646 	char *name;
647 {
648 	register int len;
649 	static char stringbuf[32];
650 
651 	len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
652 	stringbuf[len] = '\0';	/* usually unnecessary */
653 	return (stringbuf);
654 }
655 
656 /*
657  * Fetch an integer (or pointer) property.
658  * The return value is the property, or the default if there was none.
659  */
660 int
661 getpropint(node, name, deflt)
662 	int node;
663 	char *name;
664 	int deflt;
665 {
666 	register int len;
667 	char intbuf[16];
668 
669 	len = getprop(node, name, (void *)intbuf, sizeof intbuf);
670 	if (len != 4)
671 		return (deflt);
672 	return (*(int *)intbuf);
673 }
674 
675 /*
676  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
677  * from the rest of the kernel.
678  */
679 int
680 firstchild(node)
681 	int node;
682 {
683 
684 	return (promvec->pv_nodeops->no_child(node));
685 }
686 
687 int
688 nextsibling(node)
689 	int node;
690 {
691 
692 	return (promvec->pv_nodeops->no_nextnode(node));
693 }
694 
695 /* Pass a string to the FORTH PROM to be interpreted */
696 void
697 rominterpret(s)
698 	register char *s;
699 {
700 
701 	if (promvec->pv_romvec_vers < 2)
702 		promvec->pv_fortheval.v0_eval(strlen(s), s);
703 	else
704 		promvec->pv_fortheval.v2_eval(s);
705 }
706 
707 volatile void
708 romhalt()
709 {
710 
711 	promvec->pv_halt();
712 	panic("PROM exit failed");
713 }
714 
715 volatile void
716 romboot(str)
717 	char *str;
718 {
719 
720 	promvec->pv_reboot(str);
721 	panic("PROM boot failed");
722 }
723 
724 callrom()
725 {
726 
727 #ifdef notdef		/* sun4c FORTH PROMs do this for us */
728 	fb_unblank();
729 #endif
730 	promvec->pv_abort();
731 }
732 
733 /*
734  * Configure swap space and related parameters.
735  */
736 swapconf()
737 {
738 	register struct swdevt *swp;
739 	register int nblks;
740 
741 	for (swp = swdevt; swp->sw_dev; swp++)
742 		if (bdevsw[major(swp->sw_dev)].d_psize) {
743 			nblks =
744 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
745 			if (nblks != -1 &&
746 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
747 				swp->sw_nblks = nblks;
748 		}
749 	dumpconf();
750 }
751 
752 #define	DOSWAP			/* Change swdevt, argdev, and dumpdev too */
753 u_long	bootdev;		/* should be dev_t, but not until 32 bits */
754 
755 static	char devname[][2] = {
756 	0,0,		/* 0 = xx */
757 };
758 
759 #define	PARTITIONMASK	0x7
760 #define	PARTITIONSHIFT	3
761 
762 /*
763  * Attempt to find the device from which we were booted.
764  * If we can do so, and not instructed not to do so,
765  * change rootdev to correspond to the load device.
766  */
767 setroot()
768 {
769 #ifdef notyet
770 	struct swdevt *swp;
771 
772 	if (boothowto & RB_DFLTROOT ||
773 	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
774 		return;
775 	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
776 	if (majdev > sizeof(devname) / sizeof(devname[0]))
777 		return;
778 	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
779 	part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
780 	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
781 	/*
782 	 * First, find the controller type which support this device.
783 	 */
784 	for (hd = hp_dinit; hd->hp_driver; hd++)
785 		if (hd->hp_driver->d_name[0] == devname[majdev][0] &&
786 		    hd->hp_driver->d_name[1] == devname[majdev][1])
787 			break;
788 	if (hd->hp_driver == 0)
789 		return;
790 	/*
791 	 * Next, find the controller of that type corresponding to
792 	 * the adaptor number.
793 	 */
794 	for (hc = hp_cinit; hc->hp_driver; hc++)
795 		if (hc->hp_alive && hc->hp_unit == adaptor &&
796 		    hc->hp_driver == hd->hp_cdriver)
797 			break;
798 	if (hc->hp_driver == 0)
799 		return;
800 	/*
801 	 * Finally, find the device in question attached to that controller.
802 	 */
803 	for (hd = hp_dinit; hd->hp_driver; hd++)
804 		if (hd->hp_alive && hd->hp_slave == unit &&
805 		    hd->hp_cdriver == hc->hp_driver &&
806 		    hd->hp_ctlr == hc->hp_unit)
807 			break;
808 	if (hd->hp_driver == 0)
809 		return;
810 	mindev = hd->hp_unit;
811 	/*
812 	 * Form a new rootdev
813 	 */
814 	mindev = (mindev << PARTITIONSHIFT) + part;
815 	orootdev = rootdev;
816 	rootdev = makedev(majdev, mindev);
817 	/*
818 	 * If the original rootdev is the same as the one
819 	 * just calculated, don't need to adjust the swap configuration.
820 	 */
821 	if (rootdev == orootdev)
822 		return;
823 
824 	printf("Changing root device to %c%c%d%c\n",
825 		devname[majdev][0], devname[majdev][1],
826 		mindev >> PARTITIONSHIFT, part + 'a');
827 
828 #ifdef DOSWAP
829 	mindev &= ~PARTITIONMASK;
830 	for (swp = swdevt; swp->sw_dev; swp++) {
831 		if (majdev == major(swp->sw_dev) &&
832 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
833 			temp = swdevt[0].sw_dev;
834 			swdevt[0].sw_dev = swp->sw_dev;
835 			swp->sw_dev = temp;
836 			break;
837 		}
838 	}
839 	if (swp->sw_dev == 0)
840 		return;
841 
842 	/*
843 	 * If argdev and dumpdev were the same as the old primary swap
844 	 * device, move them to the new primary swap device.
845 	 */
846 	if (temp == dumpdev)
847 		dumpdev = swdevt[0].sw_dev;
848 	if (temp == argdev)
849 		argdev = swdevt[0].sw_dev;
850 #endif
851 #endif
852 }
853 
854 /*
855  * Return pointer to device we booted from. Return NULL if we can't
856  * figure this out.
857  * XXX currently only works for network devices.
858  */
859 
860 static struct bootinfo *
861 findbootdev()
862 {
863 	register struct bootinfo *bi;
864 	register char *bp;
865 	register int unit, controller;
866 	register struct ifnet *ifp;
867 
868 	bi = &bootinfo;
869 	bp = bi->name;
870 printf("findbootdev: (v%d rom) trying \"%s(%x,%x,%x)\"... ",
871     promvec->pv_romvec_vers, bp, bi->val[0], bi->val[1], bi->val[2]);
872 
873 	/* Try network devices first */
874 	unit = bi->val[0];
875 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
876 		if (unit == ifp->if_unit && strcmp(bp, ifp->if_name) == 0) {
877 printf("found \"%s%d\"\n", ifp->if_name, ifp->if_unit);
878 			bi->type = FS_NFS;
879 			bi->data = (caddr_t)ifp;
880 			return (bi);
881 		}
882 printf("not found\n");
883 	return (NULL);
884 }
885 
886 gets(cp)
887 	register char *cp;
888 {
889 	register char *lp;
890 	register int c;
891 
892 	lp = cp;
893 	for (;;) {
894 		c = cngetc();
895 		switch (c) {
896 		case '\n':
897 		case '\r':
898 			printf("\n");
899 			*lp++ = '\0';
900 			return;
901 		case '\b':
902 		case '\177':
903 		case '#':
904 			if (lp > cp) {
905 				lp--;
906 				printf(" \b ");
907 			}
908 			continue;
909 		case '@':
910 		case 'u'&037:
911 			lp = cp;
912 			cnputc('\n');
913 			continue;
914 		default:
915 			if (c < ' ')
916 				continue;
917 			cnputc(c);
918 			*lp++ = c;
919 		}
920 	}
921 }
922