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