xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 59219)
155143Storek /*
255143Storek  * Copyright (c) 1992 The Regents of the University of California.
355143Storek  * All rights reserved.
455143Storek  *
555143Storek  * This software was developed by the Computer Systems Engineering group
655143Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755143Storek  * contributed to Berkeley.
855143Storek  *
955504Sbostic  * All advertising materials mentioning features or use of this software
1055504Sbostic  * must display the following acknowledgement:
1155504Sbostic  *	This product includes software developed by the University of
12*59219Storek  *	California, Lawrence Berkeley Laboratory.
1355504Sbostic  *
1455143Storek  * %sccs.include.redist.c%
1555143Storek  *
16*59219Storek  *	@(#)autoconf.c	7.4 (Berkeley) 04/20/93
1755143Storek  *
18*59219Storek  * from: $Header: autoconf.c,v 1.31 93/04/07 01:34:47 torek Exp $ (LBL)
1955143Storek  */
2055143Storek 
2156541Sbostic #include <sys/param.h>
2256541Sbostic #include <sys/map.h>
2356541Sbostic #include <sys/buf.h>
2456541Sbostic #include <sys/disklabel.h>
2556541Sbostic #include <sys/device.h>
26*59219Storek #include <sys/disk.h>
2756541Sbostic #include <sys/dkstat.h>
2856541Sbostic #include <sys/conf.h>
2956541Sbostic #include <sys/dmap.h>
3056541Sbostic #include <sys/reboot.h>
3156541Sbostic #include <sys/socket.h>
3256541Sbostic #include <sys/systm.h>
3355143Storek 
3456541Sbostic #include <net/if.h>
3555143Storek 
3656541Sbostic #include <machine/autoconf.h>
3756541Sbostic #include <machine/bsd_openprom.h>
3856541Sbostic #include <machine/cpu.h>
3955143Storek 
4055143Storek /*
4155143Storek  * The following several variables are related to
4255143Storek  * the configuration process, and are used in initializing
4355143Storek  * the machine.
4455143Storek  */
4555143Storek int	cold;		/* if 1, still working on cold-start */
4655143Storek int	dkn;		/* number of iostat dk numbers assigned so far */
4755143Storek int	fbnode;		/* node ID of ROM's console frame buffer */
4855143Storek int	optionsnode;	/* node ID of ROM's options */
4955143Storek 
50*59219Storek extern	struct promvec *promvec;
5155143Storek 
5255143Storek static	int rootnode;
53*59219Storek int	findroot __P((void));
54*59219Storek void	setroot __P((void));
55*59219Storek static	int getstr __P((char *, int));
56*59219Storek static	int findblkmajor __P((struct dkdevice *));
57*59219Storek static	struct device *getdisk __P((char *, int, int, dev_t *));
58*59219Storek static	struct device *parsedisk __P((char *, int, int, dev_t *));
5955143Storek 
60*59219Storek struct	bootpath bootpath[8];
6155143Storek 
6255143Storek /*
6355143Storek  * Most configuration on the SPARC is done by matching OPENPROM Forth
6455143Storek  * device names with our internal names.
6555143Storek  */
6655143Storek int
6755143Storek matchbyname(parent, cf, aux)
6855143Storek 	struct device *parent;
6955143Storek 	struct cfdata *cf;
7055143Storek 	void *aux;
7155143Storek {
7255143Storek 
7355143Storek 	return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0);
7455143Storek }
7555143Storek 
7655143Storek /*
7755143Storek  * Convert hex ASCII string to a value.  Returns updated pointer.
7855143Storek  * Depends on ASCII order (this *is* machine-dependent code, you know).
7955143Storek  */
8055143Storek static char *
8155143Storek str2hex(str, vp)
8255143Storek 	register char *str;
8355143Storek 	register int *vp;
8455143Storek {
8555143Storek 	register int v, c;
8655143Storek 
8755143Storek 	for (v = 0;; v = v * 16 + c, str++) {
8855143Storek 		c = *(u_char *)str;
8955143Storek 		if (c <= '9') {
9055143Storek 			if ((c -= '0') < 0)
9155143Storek 				break;
9255143Storek 		} else if (c <= 'F') {
9355143Storek 			if ((c -= 'A' - 10) < 10)
9455143Storek 				break;
9555143Storek 		} else if (c <= 'f') {
9655143Storek 			if ((c -= 'a' - 10) < 10)
9755143Storek 				break;
9855143Storek 		} else
9955143Storek 			break;
10055143Storek 	}
10155143Storek 	*vp = v;
10255143Storek 	return (str);
10355143Storek }
10455143Storek 
10555143Storek /*
10655143Storek  * locore.s code calls bootstrap() just before calling main(), after double
10755143Storek  * mapping the kernel to high memory and setting up the trap base register.
10855143Storek  * We must finish mapping the kernel properly and glean any bootstrap info.
10955143Storek  */
11055143Storek void
11155143Storek bootstrap()
11255143Storek {
113*59219Storek 	register char *cp, *pp;
114*59219Storek 	register struct bootpath *bp;
115*59219Storek 	int v0val[3];
11655143Storek 	int nmmu, ncontext, node;
11755143Storek #ifdef KGDB
11855143Storek 	extern int kgdb_debug_panic;
11955143Storek #endif
12055143Storek 
12155143Storek 	node = findroot();
12255143Storek 	nmmu = getpropint(node, "mmu-npmg", 128);
12355143Storek 	ncontext = getpropint(node, "mmu-nctx", 8);
12455143Storek 	pmap_bootstrap(nmmu, ncontext);
12555143Storek #ifdef KGDB
12655143Storek 	zs_kgdb_init();			/* XXX */
12755143Storek #endif
12855143Storek 	/*
12955143Storek 	 * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
13055143Storek 	 * that were given after the boot command.  On SS2s, pv_v0bootargs
13155143Storek 	 * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
13255143Storek 	 * "vmunix -s" or whatever.
13355143Storek 	 * ###	DO THIS BEFORE pmap_boostrap?
13455143Storek 	 */
135*59219Storek 	bp = bootpath;
13655143Storek 	if (promvec->pv_romvec_vers < 2) {
13755143Storek 		/* Grab boot device name and values. */
13855143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[0];
13955143Storek 		if (cp != NULL) {
140*59219Storek 			/* Kludge something up */
141*59219Storek 			pp = cp + 2;
142*59219Storek 			v0val[0] = v0val[1] = v0val[2] = 0;
143*59219Storek 			if (*pp == '(' &&
144*59219Storek 			    *(pp = str2hex(++pp, &v0val[0])) == ',' &&
145*59219Storek 			    *(pp = str2hex(++pp, &v0val[1])) == ',')
146*59219Storek 				(void)str2hex(++pp, &v0val[2]);
14755143Storek 
148*59219Storek 			/* Assume sbus0 */
149*59219Storek 			strcpy(bp->name, "sbus");
150*59219Storek 			bp->val[0] = 0;
151*59219Storek 			++bp;
152*59219Storek 
153*59219Storek 			if (cp[0] == 'l' && cp[1] == 'e') {
154*59219Storek 				/* le */
155*59219Storek 				strcpy(bp->name, "le");
156*59219Storek 				bp->val[0] = -1;
157*59219Storek 				bp->val[1] = v0val[0];
158*59219Storek 			} else {
159*59219Storek 				/* sd or maybe st; assume espN */
160*59219Storek 				strcpy(bp->name, "esp");
161*59219Storek 				bp->val[0] = -1;
162*59219Storek 				bp->val[1] = v0val[0];
163*59219Storek 
164*59219Storek /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */
165*59219Storek #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v))
166*59219Storek 
167*59219Storek 				++bp;
168*59219Storek 				bp->name[0] = cp[0];
169*59219Storek 				bp->name[1] = cp[1];
170*59219Storek 				bp->name[2] = '\0';
171*59219Storek 				bp->val[0] = CRAZYMAP(v0val[1]);
172*59219Storek 				bp->val[1] = v0val[2];
173*59219Storek 			}
17455143Storek 		}
17555143Storek 
17655143Storek 		/* Setup pointer to boot flags */
17755143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[1];
17855143Storek 		if (cp == NULL || *cp != '-')
17955143Storek 			return;
18055143Storek 	} else {
181*59219Storek 		/* Grab boot path */
18255143Storek 		cp = *promvec->pv_v2bootargs.v2_bootpath;
183*59219Storek 		while (cp != NULL && *cp == '/') {
184*59219Storek 			/* Step over '/' */
18555143Storek 			++cp;
186*59219Storek 			/* Extract name */
187*59219Storek 			pp = bp->name;
188*59219Storek 			while (*cp != '@' && *cp != '/' && *cp != '\0')
189*59219Storek 				*pp++ = *cp++;
190*59219Storek 			*pp = '\0';
19155143Storek 
192*59219Storek 			if (*cp == '@') {
193*59219Storek 				cp = str2hex(++cp, &bp->val[0]);
194*59219Storek 				if (*cp == ',')
195*59219Storek 					cp = str2hex(++cp, &bp->val[1]);
196*59219Storek 			}
197*59219Storek 			++bp;
19855143Storek 		}
19955143Storek 
20055143Storek 		/* Setup pointer to boot flags */
20155143Storek 		cp = *promvec->pv_v2bootargs.v2_bootargs;
20255143Storek 		if (cp == NULL)
20355143Storek 			return;
20455143Storek 		while (*cp != '-')
20555143Storek 			if (*cp++ == '\0')
20655143Storek 				return;
20755143Storek 	}
20855143Storek 	for (;;) {
20955143Storek 		switch (*++cp) {
21055143Storek 
21155143Storek 		case '\0':
21255143Storek 			return;
21355143Storek 
21455143Storek 		case 'a':
21555143Storek 			boothowto |= RB_ASKNAME;
21655143Storek 			break;
21755143Storek 
21855143Storek 		case 'b':
21955143Storek 			boothowto |= RB_DFLTROOT;
22055143Storek 			break;
22155143Storek 
22255143Storek 		case 'd':	/* kgdb - always on zs	XXX */
22355143Storek #ifdef KGDB
22455143Storek 			boothowto |= RB_KDB;	/* XXX unused */
22555143Storek 			kgdb_debug_panic = 1;
22655143Storek 			kgdb_connect(1);
22755143Storek #else
22855143Storek 			printf("kernel not compiled with KGDB\n");
22955143Storek #endif
23055143Storek 			break;
23155143Storek 
23255143Storek 		case 's':
23355143Storek 			boothowto |= RB_SINGLE;
23455143Storek 			break;
23555143Storek 		}
23655143Storek 	}
23755143Storek }
23855143Storek 
23955143Storek /*
24055143Storek  * Determine mass storage and memory configuration for a machine.
24155143Storek  * We get the PROM's root device and make sure we understand it, then
24255143Storek  * attach it as `mainbus0'.  We also set up to handle the PROM `sync'
24355143Storek  * command.
24455143Storek  */
24555143Storek configure()
24655143Storek {
24755143Storek 	register int node;
24855143Storek 	register char *cp;
24955143Storek 	struct romaux ra;
25055143Storek 	void sync_crash();
25155143Storek 
25255143Storek 	node = findroot();
25355143Storek 	cp = getpropstring(node, "device_type");
25455143Storek 	if (strcmp(cp, "cpu") != 0) {
25555143Storek 		printf("PROM root device type = %s\n", cp);
25655143Storek 		panic("need CPU as root");
25755143Storek 	}
25855143Storek 	*promvec->pv_synchook = sync_crash;
25955143Storek 	ra.ra_node = node;
26055143Storek 	ra.ra_name = cp = "mainbus";
26155143Storek 	if (!config_rootfound(cp, (void *)&ra))
26255143Storek 		panic("mainbus not configured");
263*59219Storek 	(void)spl0();
264*59219Storek 	if (bootdv)
265*59219Storek 		printf("Found boot device %s\n", bootdv->dv_xname);
26655143Storek 	cold = 0;
26755143Storek 	setroot();
26855143Storek 	swapconf();
269*59219Storek 	dumpconf();
27055143Storek }
27155143Storek 
27255143Storek /*
27355143Storek  * Console `sync' command.  SunOS just does a `panic: zero' so I guess
27455143Storek  * no one really wants anything fancy...
27555143Storek  */
27655143Storek void
27755143Storek sync_crash()
27855143Storek {
27955143Storek 
28055143Storek 	panic("PROM sync command");
28155143Storek }
28255143Storek 
28355143Storek char *
28455143Storek clockfreq(freq)
28555143Storek 	register int freq;
28655143Storek {
28755143Storek 	register char *p;
28855143Storek 	static char buf[10];
28955143Storek 
29055143Storek 	freq /= 1000;
29155143Storek 	sprintf(buf, "%d", freq / 1000);
29255143Storek 	freq %= 1000;
29355143Storek 	if (freq) {
29455143Storek 		freq += 1000;	/* now in 1000..1999 */
29555143Storek 		p = buf + strlen(buf);
29655143Storek 		sprintf(p, "%d", freq);
29755143Storek 		*p = '.';	/* now buf = %d.%3d */
29855143Storek 	}
29955143Storek 	return (buf);
30055143Storek }
30155143Storek 
30255143Storek /* ARGSUSED */
30355143Storek static int
30455143Storek mbprint(aux, name)
30555143Storek 	void *aux;
30655143Storek 	char *name;
30755143Storek {
30855143Storek 	register struct romaux *ra = aux;
30955143Storek 
31055143Storek 	if (name)
31155143Storek 		printf("%s at %s", ra->ra_name, name);
31255143Storek 	if (ra->ra_paddr)
31355143Storek 		printf(" %saddr 0x%x", ra->ra_iospace ? "io" : "",
31455143Storek 		    (int)ra->ra_paddr);
31555143Storek 	return (UNCONF);
31655143Storek }
31755143Storek 
31855143Storek int
31955143Storek findroot()
32055143Storek {
32155143Storek 	register int node;
32255143Storek 
32355143Storek 	if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0)
32455143Storek 		panic("no PROM root device");
32555143Storek 	rootnode = node;
32655143Storek 	return (node);
32755143Storek }
32855143Storek 
32955143Storek /*
33055143Storek  * Given a `first child' node number, locate the node with the given name.
33155143Storek  * Return the node number, or 0 if not found.
33255143Storek  */
33355143Storek int
33455143Storek findnode(first, name)
33555143Storek 	int first;
33655143Storek 	register char *name;
33755143Storek {
33855143Storek 	register int node;
33955143Storek 
34055143Storek 	for (node = first; node; node = nextsibling(node))
34155143Storek 		if (strcmp(getpropstring(node, "name"), name) == 0)
34255143Storek 			return (node);
34355143Storek 	return (0);
34455143Storek }
34555143Storek 
34655143Storek /*
34755143Storek  * Fill in a romaux.  Returns 1 on success, 0 if the register property
34855143Storek  * was not the right size.
34955143Storek  */
35055143Storek int
35155143Storek romprop(rp, cp, node)
35255143Storek 	register struct romaux *rp;
35355143Storek 	const char *cp;
35455143Storek 	register int node;
35555143Storek {
35655143Storek 	register int len;
35755143Storek 	union { char regbuf[64]; int ireg[3]; } u;
35855143Storek 	static const char pl[] = "property length";
35955143Storek 
36055143Storek 	len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf);
36155143Storek 	if (len < 12) {
36255143Storek 		printf("%s \"reg\" %s = %d (need 12)\n", cp, pl, len);
36355143Storek 		return (0);
36455143Storek 	}
36555143Storek 	if (len > 12)
36655143Storek 		printf("warning: %s \"reg\" %s %d > 12, excess ignored\n",
36755143Storek 		    cp, pl, len);
36855143Storek 	rp->ra_node = node;
36955143Storek 	rp->ra_name = cp;
37055143Storek 	rp->ra_iospace = u.ireg[0];
37155143Storek 	rp->ra_paddr = (caddr_t)u.ireg[1];
37255143Storek 	rp->ra_len = u.ireg[2];
37355143Storek 	rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0);
37455143Storek 	len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr);
37555143Storek 	if (len == -1)
37655143Storek 		len = 0;
37755143Storek 	if (len & 7) {
37855143Storek 		printf("%s \"intr\" %s = %d (need multiple of 8)\n",
37955143Storek 		    cp, pl, len);
38055143Storek 		len = 0;
38155143Storek 	}
38255143Storek 	rp->ra_nintr = len >>= 3;
38355143Storek 	/* SPARCstation interrupts are not hardware-vectored */
38455143Storek 	while (--len >= 0) {
38555143Storek 		if (rp->ra_intr[len].int_vec) {
38655143Storek 			printf("WARNING: %s interrupt %d has nonzero vector\n",
38755143Storek 			    cp, len);
38855143Storek 			break;
38955143Storek 		}
39055143Storek 	}
39155143Storek 	return (1);
39255143Storek }
39355143Storek 
39455143Storek /*
39555143Storek  * Attach the mainbus.
39655143Storek  *
39755143Storek  * Our main job is to attach the CPU (the root node we got in configure())
39855143Storek  * and iterate down the list of `mainbus devices' (children of that node).
39955143Storek  * We also record the `node id' of the default frame buffer, if any.
40055143Storek  */
40155143Storek static void
40255143Storek mainbus_attach(parent, dev, aux)
40355143Storek 	struct device *parent, *dev;
40455143Storek 	void *aux;
40555143Storek {
40655143Storek 	register int node0, node;
40755143Storek 	register const char *cp, *const *ssp, *sp;
40855143Storek #define L1A_HACK		/* XXX hack to allow L1-A during autoconf */
40955143Storek #ifdef L1A_HACK
41055143Storek 	int nzs = 0, audio = 0;
41155143Storek #endif
41255143Storek 	struct romaux ra;
41355143Storek 	static const char *const special[] = {
41455143Storek 		/* find these first (end with empty string) */
41555143Storek 		"memory-error", "eeprom", "counter-timer", "",
41655143Storek 
41755143Storek 		/* ignore these (end with NULL) */
41855143Storek 		"options", "packages", "openprom", "memory", "virtual-memory",
41955143Storek 		"interrupt-enable", NULL
42055143Storek 	};
42155143Storek 
42255143Storek 	printf("\n");
42355143Storek 
42455143Storek 	/* configure the cpu */
42555143Storek 	node = ((struct romaux *)aux)->ra_node;
42655143Storek 	ra.ra_node = node;
42755143Storek 	ra.ra_name = cp = "cpu";
42855143Storek 	ra.ra_paddr = 0;
42955143Storek 	config_found(dev, (void *)&ra, mbprint);
43055143Storek 
43155143Storek 	/* remember which frame buffer, if any, is to be /dev/fb */
43255143Storek 	fbnode = getpropint(node, "fb", 0);
43355143Storek 
43455143Storek 	/* Find the "options" node */
43555143Storek 	node0 = firstchild(node);
43655143Storek 	optionsnode = findnode(node0, "options");
43755143Storek 	if (optionsnode == 0)
43855143Storek 		panic("no options in OPENPROM");
43955143Storek 
440*59219Storek 	/* Start at the beginning of the bootpath */
441*59219Storek 	ra.ra_bp = bootpath;
442*59219Storek 
44355143Storek 	/*
44455143Storek 	 * Locate and configure the ``early'' devices.  These must be
44555143Storek 	 * configured before we can do the rest.  For instance, the
44655143Storek 	 * EEPROM contains the Ethernet address for the LANCE chip.
44755143Storek 	 * If the device cannot be located or configured, panic.
44855143Storek 	 */
44955143Storek 	for (ssp = special; *(sp = *ssp) != 0; ssp++) {
45055143Storek 		if ((node = findnode(node0, sp)) == 0) {
45155143Storek 			printf("could not find %s in OPENPROM\n", sp);
45255143Storek 			panic(sp);
45355143Storek 		}
45455143Storek 		if (!romprop(&ra, sp, node) ||
45555143Storek 		    !config_found(dev, (void *)&ra, mbprint))
45655143Storek 			panic(sp);
45755143Storek 	}
45855143Storek 
45955143Storek 	/*
46055143Storek 	 * Configure the rest of the devices, in PROM order.  Skip
46155143Storek 	 * PROM entries that are not for devices, or which must be
46255143Storek 	 * done before we get here.
46355143Storek 	 */
46455143Storek 	for (node = node0; node; node = nextsibling(node)) {
46555143Storek 		cp = getpropstring(node, "name");
46655143Storek 		for (ssp = special; (sp = *ssp) != NULL; ssp++)
46755143Storek 			if (strcmp(cp, sp) == 0)
46855143Storek 				break;
46955143Storek 		if (sp == NULL && romprop(&ra, cp, node)) {
47055143Storek #ifdef L1A_HACK
47155143Storek 			if (strcmp(cp, "audio") == 0)
47255143Storek 				audio = 1;
47355143Storek 			if (strcmp(cp, "zs") == 0)
47455143Storek 				nzs++;
47555143Storek 			if (audio && nzs >= 2)
47655143Storek 				(void) splx(11 << 8);	/* XXX */
47755143Storek #endif
47855143Storek 			(void) config_found(dev, (void *)&ra, mbprint);
47955143Storek 		}
48055143Storek 	}
48155143Storek }
48255143Storek 
48355143Storek struct cfdriver mainbuscd =
48455143Storek     { NULL, "mainbus", matchbyname, mainbus_attach,
48555143Storek       DV_DULL, sizeof(struct device) };
48655143Storek 
48755143Storek /*
48855143Storek  * findzs() is called from the zs driver (which is, at least in theory,
48955143Storek  * generic to any machine with a Zilog ZSCC chip).  It should return the
49055143Storek  * address of the corresponding zs channel.  It may not fail, and it
49155143Storek  * may be called before the VM code can be used.  Here we count on the
49255143Storek  * FORTH PROM to map in the required zs chips.
49355143Storek  */
49455143Storek void *
49555143Storek findzs(zs)
49655143Storek 	int zs;
49755143Storek {
49855143Storek 	register int node, addr;
49955143Storek 
50055143Storek 	node = firstchild(findroot());
50155143Storek 	while ((node = findnode(node, "zs")) != 0) {
50255143Storek 		if (getpropint(node, "slave", -1) == zs) {
50355143Storek 			if ((addr = getpropint(node, "address", 0)) == 0)
50455143Storek 				panic("findzs: zs%d not mapped by PROM", zs);
50555143Storek 			return ((void *)addr);
50655143Storek 		}
50755143Storek 		node = nextsibling(node);
50855143Storek 	}
50955143Storek 	panic("findzs: cannot find zs%d", zs);
51055143Storek 	/* NOTREACHED */
51155143Storek }
51255143Storek 
51355143Storek int
51455143Storek makememarr(ap, max, which)
51555143Storek 	register struct memarr *ap;
51655143Storek 	int max, which;
51755143Storek {
51855143Storek 	struct v2rmi {
51955143Storek 		int	zero;
52055143Storek 		int	addr;
52155143Storek 		int	len;
52255143Storek 	} v2rmi[200];		/* version 2 rom meminfo layout */
52355143Storek #define	MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
52455143Storek 	register struct v0mlist *mp;
52555143Storek 	register int i, node, len;
52655143Storek 	char *prop;
52755143Storek 
52855143Storek 	switch (i = promvec->pv_romvec_vers) {
52955143Storek 
53055143Storek 	case 0:
53155143Storek 		/*
53255143Storek 		 * Version 0 PROMs use a linked list to describe these
53355143Storek 		 * guys.
53455143Storek 		 */
53555143Storek 		switch (which) {
53655143Storek 
53755143Storek 		case MEMARR_AVAILPHYS:
53855143Storek 			mp = *promvec->pv_v0mem.v0_physavail;
53955143Storek 			break;
54055143Storek 
54155143Storek 		case MEMARR_TOTALPHYS:
54255143Storek 			mp = *promvec->pv_v0mem.v0_phystot;
54355143Storek 			break;
54455143Storek 
54555143Storek 		default:
54655143Storek 			panic("makememarr");
54755143Storek 		}
54855143Storek 		for (i = 0; mp != NULL; mp = mp->next, i++) {
54955143Storek 			if (i >= max)
55055143Storek 				goto overflow;
55155143Storek 			ap->addr = (u_int)mp->addr;
55255143Storek 			ap->len = mp->nbytes;
55355143Storek 			ap++;
55455143Storek 		}
55555143Storek 		break;
55655143Storek 
55755143Storek 	default:
55855143Storek 		printf("makememarr: hope version %d PROM is like version 2\n",
55955143Storek 		    i);
56055143Storek 		/* FALLTHROUGH */
56155143Storek 
56255143Storek 	case 2:
56355143Storek 		/*
56455143Storek 		 * Version 2 PROMs use a property array to describe them.
56555143Storek 		 */
56655143Storek 		if (max > MAXMEMINFO) {
56755143Storek 			printf("makememarr: limited to %d\n", MAXMEMINFO);
56855143Storek 			max = MAXMEMINFO;
56955143Storek 		}
57055143Storek 		if ((node = findnode(firstchild(findroot()), "memory")) == 0)
57155143Storek 			panic("makememarr: cannot find \"memory\" node");
57255143Storek 		switch (which) {
57355143Storek 
57455143Storek 		case MEMARR_AVAILPHYS:
57555143Storek 			prop = "available";
57655143Storek 			break;
57755143Storek 
57855143Storek 		case MEMARR_TOTALPHYS:
57955143Storek 			prop = "reg";
58055143Storek 			break;
58155143Storek 
58255143Storek 		default:
58355143Storek 			panic("makememarr");
58455143Storek 		}
58555143Storek 		len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
58655143Storek 		    sizeof(struct v2rmi);
58755143Storek 		for (i = 0; i < len; i++) {
58855143Storek 			if (i >= max)
58955143Storek 				goto overflow;
59055143Storek 			ap->addr = v2rmi[i].addr;
59155143Storek 			ap->len = v2rmi[i].len;
59255143Storek 			ap++;
59355143Storek 		}
59455143Storek 		break;
59555143Storek 	}
59655143Storek 
59755143Storek 	/*
59855143Storek 	 * Success!  (Hooray)
59955143Storek 	 */
60055143Storek 	if (i == 0)
60155143Storek 		panic("makememarr: no memory found");
60255143Storek 	return (i);
60355143Storek 
60455143Storek overflow:
60555143Storek 	/*
60655143Storek 	 * Oops, there are more things in the PROM than our caller
60755143Storek 	 * provided space for.  Truncate any extras.
60855143Storek 	 */
60955143Storek 	printf("makememarr: WARNING: lost some memory\n");
61055143Storek 	return (i);
61155143Storek }
61255143Storek 
61355143Storek /*
61455143Storek  * Internal form of getprop().  Returns the actual length.
61555143Storek  */
61655143Storek int
61755143Storek getprop(node, name, buf, bufsiz)
61855143Storek 	int node;
61955143Storek 	char *name;
62055143Storek 	void *buf;
62155143Storek 	register int bufsiz;
62255143Storek {
62355143Storek 	register struct nodeops *no;
62455143Storek 	register int len;
62555143Storek 
62655143Storek 	no = promvec->pv_nodeops;
62755143Storek 	len = no->no_proplen(node, name);
62855143Storek 	if (len > bufsiz) {
62955143Storek 		printf("node %x property %s length %d > %d\n",
63055143Storek 		    node, name, len, bufsiz);
63155143Storek #ifdef DEBUG
63255143Storek 		panic("getprop");
63355143Storek #else
63455143Storek 		return (0);
63555143Storek #endif
63655143Storek 	}
63755143Storek 	no->no_getprop(node, name, buf);
63855143Storek 	return (len);
63955143Storek }
64055143Storek 
64155143Storek /*
64255143Storek  * Return a string property.  There is a (small) limit on the length;
64355143Storek  * the string is fetched into a static buffer which is overwritten on
64455143Storek  * subsequent calls.
64555143Storek  */
64655143Storek char *
64755143Storek getpropstring(node, name)
64855143Storek 	int node;
64955143Storek 	char *name;
65055143Storek {
65155143Storek 	register int len;
65255143Storek 	static char stringbuf[32];
65355143Storek 
65455143Storek 	len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
65555143Storek 	stringbuf[len] = '\0';	/* usually unnecessary */
65655143Storek 	return (stringbuf);
65755143Storek }
65855143Storek 
65955143Storek /*
66055143Storek  * Fetch an integer (or pointer) property.
66155143Storek  * The return value is the property, or the default if there was none.
66255143Storek  */
66355143Storek int
66455143Storek getpropint(node, name, deflt)
66555143Storek 	int node;
66655143Storek 	char *name;
66755143Storek 	int deflt;
66855143Storek {
66955143Storek 	register int len;
67055143Storek 	char intbuf[16];
67155143Storek 
67255143Storek 	len = getprop(node, name, (void *)intbuf, sizeof intbuf);
67355143Storek 	if (len != 4)
67455143Storek 		return (deflt);
67555143Storek 	return (*(int *)intbuf);
67655143Storek }
67755143Storek 
67855143Storek /*
67955143Storek  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
68055143Storek  * from the rest of the kernel.
68155143Storek  */
68255143Storek int
68355143Storek firstchild(node)
68455143Storek 	int node;
68555143Storek {
68655143Storek 
68755143Storek 	return (promvec->pv_nodeops->no_child(node));
68855143Storek }
68955143Storek 
69055143Storek int
69155143Storek nextsibling(node)
69255143Storek 	int node;
69355143Storek {
69455143Storek 
69555143Storek 	return (promvec->pv_nodeops->no_nextnode(node));
69655143Storek }
69755143Storek 
69855143Storek /* Pass a string to the FORTH PROM to be interpreted */
69955143Storek void
70055143Storek rominterpret(s)
70155143Storek 	register char *s;
70255143Storek {
70355143Storek 
70455143Storek 	if (promvec->pv_romvec_vers < 2)
70555143Storek 		promvec->pv_fortheval.v0_eval(strlen(s), s);
70655143Storek 	else
70755143Storek 		promvec->pv_fortheval.v2_eval(s);
70855143Storek }
70955143Storek 
71055143Storek volatile void
71155143Storek romhalt()
71255143Storek {
71355143Storek 
71455143Storek 	promvec->pv_halt();
71555143Storek 	panic("PROM exit failed");
71655143Storek }
71755143Storek 
71855143Storek volatile void
71955143Storek romboot(str)
72055143Storek 	char *str;
72155143Storek {
72255143Storek 
72355143Storek 	promvec->pv_reboot(str);
72455143Storek 	panic("PROM boot failed");
72555143Storek }
72655143Storek 
72755143Storek callrom()
72855143Storek {
72955143Storek 
73055143Storek #ifdef notdef		/* sun4c FORTH PROMs do this for us */
73155143Storek 	fb_unblank();
73255143Storek #endif
73355143Storek 	promvec->pv_abort();
73455143Storek }
73555143Storek 
73655143Storek /*
73755143Storek  * Configure swap space and related parameters.
73855143Storek  */
73955143Storek swapconf()
74055143Storek {
74155143Storek 	register struct swdevt *swp;
74255143Storek 	register int nblks;
74355143Storek 
744*59219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++)
74555143Storek 		if (bdevsw[major(swp->sw_dev)].d_psize) {
74655143Storek 			nblks =
74755143Storek 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
74855143Storek 			if (nblks != -1 &&
74955143Storek 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
75055143Storek 				swp->sw_nblks = nblks;
75155143Storek 		}
75255143Storek }
75355143Storek 
754*59219Storek #define	DOSWAP			/* Change swdevt and dumpdev too */
75555143Storek u_long	bootdev;		/* should be dev_t, but not until 32 bits */
75655143Storek 
75755143Storek #define	PARTITIONMASK	0x7
75855143Storek #define	PARTITIONSHIFT	3
75955143Storek 
760*59219Storek static int
761*59219Storek findblkmajor(dv)
762*59219Storek 	register struct dkdevice *dv;
763*59219Storek {
764*59219Storek 	register int i;
765*59219Storek 
766*59219Storek 	for (i = 0; i < nblkdev; ++i)
767*59219Storek 		if ((void (*)(struct buf *))bdevsw[i].d_strategy ==
768*59219Storek 		    dv->dk_driver->d_strategy)
769*59219Storek 			return (i);
770*59219Storek 
771*59219Storek 	return (-1);
772*59219Storek }
773*59219Storek 
774*59219Storek static struct device *
775*59219Storek getdisk(str, len, defpart, devp)
776*59219Storek 	char *str;
777*59219Storek 	int len, defpart;
778*59219Storek 	dev_t *devp;
779*59219Storek {
780*59219Storek 	register struct device *dv;
781*59219Storek 
782*59219Storek 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
783*59219Storek 		printf("use one of:");
784*59219Storek 		for (dv = alldevs; dv != NULL; dv = dv->dv_next)
785*59219Storek 			if (dv->dv_class == DV_DISK)
786*59219Storek 				printf(" %s[a-h]", dv->dv_xname);
787*59219Storek 		printf("\n");
788*59219Storek 	}
789*59219Storek 	return (dv);
790*59219Storek }
791*59219Storek 
792*59219Storek static struct device *
793*59219Storek parsedisk(str, len, defpart, devp)
794*59219Storek 	char *str;
795*59219Storek 	int len, defpart;
796*59219Storek 	dev_t *devp;
797*59219Storek {
798*59219Storek 	register struct device *dv;
799*59219Storek 	register char *cp;
800*59219Storek 	int majdev, mindev, part;
801*59219Storek 
802*59219Storek 	if (len == 0)
803*59219Storek 		return (NULL);
804*59219Storek 	cp = str + len - 1;
805*59219Storek 	if (*cp >= 'a' && *cp <= 'h') {
806*59219Storek 		part = *cp - 'a';
807*59219Storek 		*cp-- = '\0';
808*59219Storek 	} else
809*59219Storek 		part = defpart;
810*59219Storek 
811*59219Storek 	for (dv = alldevs; dv != NULL; dv = dv->dv_next)
812*59219Storek 		if (dv->dv_class == DV_DISK &&
813*59219Storek 		    strcmp(str, dv->dv_xname) == 0) {
814*59219Storek 			majdev = findblkmajor((struct dkdevice *)dv);
815*59219Storek 			if (majdev < 0)
816*59219Storek 				panic("parsedisk");
817*59219Storek 			mindev = (dv->dv_unit << PARTITIONSHIFT) + part;
818*59219Storek 			*devp = makedev(majdev, mindev);
819*59219Storek 			return (dv);
820*59219Storek 		}
821*59219Storek 
822*59219Storek 	return (NULL);
823*59219Storek }
824*59219Storek 
82555143Storek /*
82655143Storek  * Attempt to find the device from which we were booted.
82755143Storek  * If we can do so, and not instructed not to do so,
82855143Storek  * change rootdev to correspond to the load device.
82955143Storek  */
830*59219Storek void
83155143Storek setroot()
83255143Storek {
833*59219Storek 	register struct swdevt *swp;
834*59219Storek 	register struct device *dv;
835*59219Storek 	register int len, majdev, mindev, part;
836*59219Storek 	dev_t nrootdev, nswapdev;
837*59219Storek 	char buf[128];
838*59219Storek #ifdef DOSWAP
839*59219Storek 	dev_t temp;
840*59219Storek #endif
841*59219Storek #ifdef NFS
842*59219Storek 	extern int (*mountroot)(), nfs_mountroot();
843*59219Storek #endif
84455143Storek 
845*59219Storek 	if (boothowto & RB_ASKNAME) {
846*59219Storek 		for (;;) {
847*59219Storek 			printf("root device? ");
848*59219Storek 			len = getstr(buf, sizeof(buf));
849*59219Storek #ifdef GENERIC
850*59219Storek 			if (len > 0 && buf[len - 1] == '*') {
851*59219Storek 				buf[--len] = '\0';
852*59219Storek 				dv = getdisk(buf, len, 1, &nrootdev);
853*59219Storek 				if (dv != NULL) {
854*59219Storek 					bootdv = dv;
855*59219Storek 					nswapdev = nrootdev;
856*59219Storek 					swaponroot++;
857*59219Storek 					goto setswap;
858*59219Storek 				}
859*59219Storek 			}
860*59219Storek #endif
861*59219Storek 			dv = getdisk(buf, len, 0, &nrootdev);
862*59219Storek 			if (dv != NULL) {
863*59219Storek 				bootdv = dv;
864*59219Storek 				break;
865*59219Storek 			}
866*59219Storek 		}
867*59219Storek 		for (;;) {
868*59219Storek 			printf("swap device (default %sb)? ", bootdv->dv_xname);
869*59219Storek 			len = getstr(buf, sizeof(buf));
870*59219Storek 			if (len == 0) {
871*59219Storek 				nswapdev = makedev(major(nrootdev),
872*59219Storek 				    (minor(nrootdev) & ~ PARTITIONMASK) | 1);
873*59219Storek 				break;
874*59219Storek 			}
875*59219Storek 			if (getdisk(buf, len, 1, &nswapdev) != NULL)
876*59219Storek 				break;
877*59219Storek 		}
878*59219Storek 		rootdev = nrootdev;
879*59219Storek 		swapdev = nswapdev;
880*59219Storek 		dumpdev = nswapdev;		/* ??? */
881*59219Storek 		swdevt[0].sw_dev = nswapdev;
882*59219Storek 		swdevt[1].sw_dev = NODEV;
88355143Storek 		return;
884*59219Storek 	}
885*59219Storek 
886*59219Storek 	/* XXX currently there's no way to set RB_DFLTROOT... */
887*59219Storek 	if (boothowto & RB_DFLTROOT || bootdv == NULL)
88855143Storek 		return;
889*59219Storek 
890*59219Storek 	switch (bootdv->dv_class) {
891*59219Storek 
892*59219Storek #ifdef NFS
893*59219Storek 	case DV_IFNET:
894*59219Storek 		mountroot = nfs_mountroot;
895*59219Storek #ifdef LBL
896*59219Storek 		lbl_diskless_setup();
897*59219Storek #endif
89855143Storek 		return;
899*59219Storek #endif
900*59219Storek 
901*59219Storek #if defined(FFS) || defined(LFS)
902*59219Storek 	case DV_DISK:
903*59219Storek 		majdev = findblkmajor((struct dkdevice *)bootdv);
904*59219Storek 		if (majdev < 0)
905*59219Storek 			return;
906*59219Storek 		part = 0;
907*59219Storek 		mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part;
908*59219Storek 		break;
909*59219Storek #endif
910*59219Storek 
911*59219Storek 	default:
912*59219Storek 		printf("can't figure root, hope your kernel is right\n");
91355143Storek 		return;
914*59219Storek 	}
915*59219Storek 
91655143Storek 	/*
91755143Storek 	 * Form a new rootdev
91855143Storek 	 */
919*59219Storek 	nrootdev = makedev(majdev, mindev);
92055143Storek 	/*
92155143Storek 	 * If the original rootdev is the same as the one
92255143Storek 	 * just calculated, don't need to adjust the swap configuration.
92355143Storek 	 */
924*59219Storek 	if (rootdev == nrootdev)
92555143Storek 		return;
92655143Storek 
927*59219Storek 	rootdev = nrootdev;
928*59219Storek 	printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a');
92955143Storek 
93055143Storek #ifdef DOSWAP
93155143Storek 	mindev &= ~PARTITIONMASK;
932*59219Storek 	temp = NODEV;
933*59219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
93455143Storek 		if (majdev == major(swp->sw_dev) &&
93555143Storek 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
93655143Storek 			temp = swdevt[0].sw_dev;
93755143Storek 			swdevt[0].sw_dev = swp->sw_dev;
93855143Storek 			swp->sw_dev = temp;
93955143Storek 			break;
94055143Storek 		}
94155143Storek 	}
942*59219Storek 	if (swp->sw_dev == NODEV)
94355143Storek 		return;
94455143Storek 
94555143Storek 	/*
946*59219Storek 	 * If dumpdev was the same as the old primary swap device, move
947*59219Storek 	 * it to the new primary swap device.
94855143Storek 	 */
94955143Storek 	if (temp == dumpdev)
95055143Storek 		dumpdev = swdevt[0].sw_dev;
95155143Storek #endif
95255143Storek }
95355143Storek 
954*59219Storek static int
955*59219Storek getstr(cp, size)
95655143Storek 	register char *cp;
957*59219Storek 	register int size;
95855143Storek {
95955143Storek 	register char *lp;
96055143Storek 	register int c;
961*59219Storek 	register int len;
96255143Storek 
96355143Storek 	lp = cp;
964*59219Storek 	len = 0;
96555143Storek 	for (;;) {
96655143Storek 		c = cngetc();
96755143Storek 		switch (c) {
96855143Storek 		case '\n':
96955143Storek 		case '\r':
97055143Storek 			printf("\n");
97155143Storek 			*lp++ = '\0';
972*59219Storek 			return (len);
97355143Storek 		case '\b':
97455143Storek 		case '\177':
97555143Storek 		case '#':
976*59219Storek 			if (len) {
977*59219Storek 				--len;
978*59219Storek 				--lp;
97955143Storek 				printf(" \b ");
98055143Storek 			}
98155143Storek 			continue;
98255143Storek 		case '@':
98355143Storek 		case 'u'&037:
984*59219Storek 			len = 0;
98555143Storek 			lp = cp;
986*59219Storek 			printf("\n");
98755143Storek 			continue;
98855143Storek 		default:
989*59219Storek 			if (len + 1 >= size || c < ' ') {
990*59219Storek 				printf("\007");
99155143Storek 				continue;
992*59219Storek 			}
993*59219Storek 			printf("%c", c);
994*59219Storek 			++len;
99555143Storek 			*lp++ = c;
99655143Storek 		}
99755143Storek 	}
99855143Storek }
999