xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 64662)
155143Storek /*
263323Sbostic  * Copyright (c) 1992, 1993
363323Sbostic  *	The Regents of the University of California.  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
1259219Storek  *	California, Lawrence Berkeley Laboratory.
1355504Sbostic  *
1455143Storek  * %sccs.include.redist.c%
1555143Storek  *
16*64662Storek  *	@(#)autoconf.c	8.2 (Berkeley) 09/27/93
1755143Storek  *
18*64662Storek  * from: $Header: autoconf.c,v 1.35 93/09/27 00:50:04 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>
2659219Storek #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 
5059219Storek extern	struct promvec *promvec;
5155143Storek 
5255143Storek static	int rootnode;
5359219Storek int	findroot __P((void));
5459219Storek void	setroot __P((void));
5559219Storek static	int getstr __P((char *, int));
5659219Storek static	int findblkmajor __P((struct dkdevice *));
5759219Storek static	struct device *getdisk __P((char *, int, int, dev_t *));
5859219Storek static	struct device *parsedisk __P((char *, int, int, dev_t *));
5955143Storek 
6059219Storek 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 {
11359219Storek 	register char *cp, *pp;
11459219Storek 	register struct bootpath *bp;
11559219Storek 	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 	 */
13559219Storek 	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) {
14059219Storek 			/* Kludge something up */
14159219Storek 			pp = cp + 2;
14259219Storek 			v0val[0] = v0val[1] = v0val[2] = 0;
14359219Storek 			if (*pp == '(' &&
14459219Storek 			    *(pp = str2hex(++pp, &v0val[0])) == ',' &&
14559219Storek 			    *(pp = str2hex(++pp, &v0val[1])) == ',')
14659219Storek 				(void)str2hex(++pp, &v0val[2]);
14755143Storek 
14859219Storek 			/* Assume sbus0 */
14959219Storek 			strcpy(bp->name, "sbus");
15059219Storek 			bp->val[0] = 0;
15159219Storek 			++bp;
15259219Storek 
15359219Storek 			if (cp[0] == 'l' && cp[1] == 'e') {
15459219Storek 				/* le */
15559219Storek 				strcpy(bp->name, "le");
15659219Storek 				bp->val[0] = -1;
15759219Storek 				bp->val[1] = v0val[0];
15859219Storek 			} else {
15959219Storek 				/* sd or maybe st; assume espN */
16059219Storek 				strcpy(bp->name, "esp");
16159219Storek 				bp->val[0] = -1;
16259219Storek 				bp->val[1] = v0val[0];
16359219Storek 
16459219Storek /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */
16559219Storek #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v))
16659219Storek 
16759219Storek 				++bp;
16859219Storek 				bp->name[0] = cp[0];
16959219Storek 				bp->name[1] = cp[1];
17059219Storek 				bp->name[2] = '\0';
17159219Storek 				bp->val[0] = CRAZYMAP(v0val[1]);
17259219Storek 				bp->val[1] = v0val[2];
17359219Storek 			}
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 {
18159219Storek 		/* Grab boot path */
18255143Storek 		cp = *promvec->pv_v2bootargs.v2_bootpath;
18359219Storek 		while (cp != NULL && *cp == '/') {
18459219Storek 			/* Step over '/' */
18555143Storek 			++cp;
18659219Storek 			/* Extract name */
18759219Storek 			pp = bp->name;
18859219Storek 			while (*cp != '@' && *cp != '/' && *cp != '\0')
18959219Storek 				*pp++ = *cp++;
19059219Storek 			*pp = '\0';
19155143Storek 
19259219Storek 			if (*cp == '@') {
19359219Storek 				cp = str2hex(++cp, &bp->val[0]);
19459219Storek 				if (*cp == ',')
19559219Storek 					cp = str2hex(++cp, &bp->val[1]);
19659219Storek 			}
19759219Storek 			++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");
26359219Storek 	(void)spl0();
26459219Storek 	if (bootdv)
26559219Storek 		printf("Found boot device %s\n", bootdv->dv_xname);
26655143Storek 	cold = 0;
26755143Storek 	setroot();
26855143Storek 	swapconf();
26959219Storek 	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) */
415*64662Storek 		"eeprom",
416*64662Storek 		"counter-timer",
417*64662Storek 		"memory-error",
418*64662Storek 		"",
41955143Storek 
42055143Storek 		/* ignore these (end with NULL) */
421*64662Storek 		"aliases",
422*64662Storek 		"interrupt-enable",
423*64662Storek 		"memory",
424*64662Storek 		"openprom",
425*64662Storek 		"options",
426*64662Storek 		"packages",
427*64662Storek 		"virtual-memory",
428*64662Storek 		NULL
42955143Storek 	};
43055143Storek 
43155143Storek 	printf("\n");
43255143Storek 
43355143Storek 	/* configure the cpu */
43455143Storek 	node = ((struct romaux *)aux)->ra_node;
43555143Storek 	ra.ra_node = node;
43655143Storek 	ra.ra_name = cp = "cpu";
43755143Storek 	ra.ra_paddr = 0;
43855143Storek 	config_found(dev, (void *)&ra, mbprint);
43955143Storek 
44055143Storek 	/* remember which frame buffer, if any, is to be /dev/fb */
44155143Storek 	fbnode = getpropint(node, "fb", 0);
44255143Storek 
44355143Storek 	/* Find the "options" node */
44455143Storek 	node0 = firstchild(node);
44555143Storek 	optionsnode = findnode(node0, "options");
44655143Storek 	if (optionsnode == 0)
44755143Storek 		panic("no options in OPENPROM");
44855143Storek 
44959219Storek 	/* Start at the beginning of the bootpath */
45059219Storek 	ra.ra_bp = bootpath;
45159219Storek 
45255143Storek 	/*
45355143Storek 	 * Locate and configure the ``early'' devices.  These must be
45455143Storek 	 * configured before we can do the rest.  For instance, the
45555143Storek 	 * EEPROM contains the Ethernet address for the LANCE chip.
45655143Storek 	 * If the device cannot be located or configured, panic.
45755143Storek 	 */
45855143Storek 	for (ssp = special; *(sp = *ssp) != 0; ssp++) {
45955143Storek 		if ((node = findnode(node0, sp)) == 0) {
46055143Storek 			printf("could not find %s in OPENPROM\n", sp);
46155143Storek 			panic(sp);
46255143Storek 		}
46355143Storek 		if (!romprop(&ra, sp, node) ||
46455143Storek 		    !config_found(dev, (void *)&ra, mbprint))
46555143Storek 			panic(sp);
46655143Storek 	}
46755143Storek 
46855143Storek 	/*
46955143Storek 	 * Configure the rest of the devices, in PROM order.  Skip
47055143Storek 	 * PROM entries that are not for devices, or which must be
47155143Storek 	 * done before we get here.
47255143Storek 	 */
47355143Storek 	for (node = node0; node; node = nextsibling(node)) {
47455143Storek 		cp = getpropstring(node, "name");
47555143Storek 		for (ssp = special; (sp = *ssp) != NULL; ssp++)
47655143Storek 			if (strcmp(cp, sp) == 0)
47755143Storek 				break;
47855143Storek 		if (sp == NULL && romprop(&ra, cp, node)) {
47955143Storek #ifdef L1A_HACK
48055143Storek 			if (strcmp(cp, "audio") == 0)
48155143Storek 				audio = 1;
48255143Storek 			if (strcmp(cp, "zs") == 0)
48355143Storek 				nzs++;
48455143Storek 			if (audio && nzs >= 2)
48555143Storek 				(void) splx(11 << 8);	/* XXX */
48655143Storek #endif
48755143Storek 			(void) config_found(dev, (void *)&ra, mbprint);
48855143Storek 		}
48955143Storek 	}
49055143Storek }
49155143Storek 
49255143Storek struct cfdriver mainbuscd =
49355143Storek     { NULL, "mainbus", matchbyname, mainbus_attach,
49455143Storek       DV_DULL, sizeof(struct device) };
49555143Storek 
49655143Storek /*
49755143Storek  * findzs() is called from the zs driver (which is, at least in theory,
49855143Storek  * generic to any machine with a Zilog ZSCC chip).  It should return the
49955143Storek  * address of the corresponding zs channel.  It may not fail, and it
50055143Storek  * may be called before the VM code can be used.  Here we count on the
50155143Storek  * FORTH PROM to map in the required zs chips.
50255143Storek  */
50355143Storek void *
50455143Storek findzs(zs)
50555143Storek 	int zs;
50655143Storek {
50755143Storek 	register int node, addr;
50855143Storek 
50955143Storek 	node = firstchild(findroot());
51055143Storek 	while ((node = findnode(node, "zs")) != 0) {
51155143Storek 		if (getpropint(node, "slave", -1) == zs) {
51255143Storek 			if ((addr = getpropint(node, "address", 0)) == 0)
51355143Storek 				panic("findzs: zs%d not mapped by PROM", zs);
51455143Storek 			return ((void *)addr);
51555143Storek 		}
51655143Storek 		node = nextsibling(node);
51755143Storek 	}
51855143Storek 	panic("findzs: cannot find zs%d", zs);
51955143Storek 	/* NOTREACHED */
52055143Storek }
52155143Storek 
52255143Storek int
52355143Storek makememarr(ap, max, which)
52455143Storek 	register struct memarr *ap;
52555143Storek 	int max, which;
52655143Storek {
52755143Storek 	struct v2rmi {
52855143Storek 		int	zero;
52955143Storek 		int	addr;
53055143Storek 		int	len;
53155143Storek 	} v2rmi[200];		/* version 2 rom meminfo layout */
53255143Storek #define	MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
53355143Storek 	register struct v0mlist *mp;
53455143Storek 	register int i, node, len;
53555143Storek 	char *prop;
53655143Storek 
53755143Storek 	switch (i = promvec->pv_romvec_vers) {
53855143Storek 
53955143Storek 	case 0:
54055143Storek 		/*
54155143Storek 		 * Version 0 PROMs use a linked list to describe these
54255143Storek 		 * guys.
54355143Storek 		 */
54455143Storek 		switch (which) {
54555143Storek 
54655143Storek 		case MEMARR_AVAILPHYS:
54755143Storek 			mp = *promvec->pv_v0mem.v0_physavail;
54855143Storek 			break;
54955143Storek 
55055143Storek 		case MEMARR_TOTALPHYS:
55155143Storek 			mp = *promvec->pv_v0mem.v0_phystot;
55255143Storek 			break;
55355143Storek 
55455143Storek 		default:
55555143Storek 			panic("makememarr");
55655143Storek 		}
55755143Storek 		for (i = 0; mp != NULL; mp = mp->next, i++) {
55855143Storek 			if (i >= max)
55955143Storek 				goto overflow;
56055143Storek 			ap->addr = (u_int)mp->addr;
56155143Storek 			ap->len = mp->nbytes;
56255143Storek 			ap++;
56355143Storek 		}
56455143Storek 		break;
56555143Storek 
56655143Storek 	default:
56755143Storek 		printf("makememarr: hope version %d PROM is like version 2\n",
56855143Storek 		    i);
56955143Storek 		/* FALLTHROUGH */
57055143Storek 
57155143Storek 	case 2:
57255143Storek 		/*
57355143Storek 		 * Version 2 PROMs use a property array to describe them.
57455143Storek 		 */
57555143Storek 		if (max > MAXMEMINFO) {
57655143Storek 			printf("makememarr: limited to %d\n", MAXMEMINFO);
57755143Storek 			max = MAXMEMINFO;
57855143Storek 		}
57955143Storek 		if ((node = findnode(firstchild(findroot()), "memory")) == 0)
58055143Storek 			panic("makememarr: cannot find \"memory\" node");
58155143Storek 		switch (which) {
58255143Storek 
58355143Storek 		case MEMARR_AVAILPHYS:
58455143Storek 			prop = "available";
58555143Storek 			break;
58655143Storek 
58755143Storek 		case MEMARR_TOTALPHYS:
58855143Storek 			prop = "reg";
58955143Storek 			break;
59055143Storek 
59155143Storek 		default:
59255143Storek 			panic("makememarr");
59355143Storek 		}
59455143Storek 		len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
59555143Storek 		    sizeof(struct v2rmi);
59655143Storek 		for (i = 0; i < len; i++) {
59755143Storek 			if (i >= max)
59855143Storek 				goto overflow;
59955143Storek 			ap->addr = v2rmi[i].addr;
60055143Storek 			ap->len = v2rmi[i].len;
60155143Storek 			ap++;
60255143Storek 		}
60355143Storek 		break;
60455143Storek 	}
60555143Storek 
60655143Storek 	/*
60755143Storek 	 * Success!  (Hooray)
60855143Storek 	 */
60955143Storek 	if (i == 0)
61055143Storek 		panic("makememarr: no memory found");
61155143Storek 	return (i);
61255143Storek 
61355143Storek overflow:
61455143Storek 	/*
61555143Storek 	 * Oops, there are more things in the PROM than our caller
61655143Storek 	 * provided space for.  Truncate any extras.
61755143Storek 	 */
61855143Storek 	printf("makememarr: WARNING: lost some memory\n");
61955143Storek 	return (i);
62055143Storek }
62155143Storek 
62255143Storek /*
62355143Storek  * Internal form of getprop().  Returns the actual length.
62455143Storek  */
62555143Storek int
62655143Storek getprop(node, name, buf, bufsiz)
62755143Storek 	int node;
62855143Storek 	char *name;
62955143Storek 	void *buf;
63055143Storek 	register int bufsiz;
63155143Storek {
63255143Storek 	register struct nodeops *no;
63355143Storek 	register int len;
63455143Storek 
63555143Storek 	no = promvec->pv_nodeops;
63655143Storek 	len = no->no_proplen(node, name);
63755143Storek 	if (len > bufsiz) {
63855143Storek 		printf("node %x property %s length %d > %d\n",
63955143Storek 		    node, name, len, bufsiz);
64055143Storek #ifdef DEBUG
64155143Storek 		panic("getprop");
64255143Storek #else
64355143Storek 		return (0);
64455143Storek #endif
64555143Storek 	}
64655143Storek 	no->no_getprop(node, name, buf);
64755143Storek 	return (len);
64855143Storek }
64955143Storek 
65055143Storek /*
65155143Storek  * Return a string property.  There is a (small) limit on the length;
65255143Storek  * the string is fetched into a static buffer which is overwritten on
65355143Storek  * subsequent calls.
65455143Storek  */
65555143Storek char *
65655143Storek getpropstring(node, name)
65755143Storek 	int node;
65855143Storek 	char *name;
65955143Storek {
66055143Storek 	register int len;
66155143Storek 	static char stringbuf[32];
66255143Storek 
66355143Storek 	len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
66455143Storek 	stringbuf[len] = '\0';	/* usually unnecessary */
66555143Storek 	return (stringbuf);
66655143Storek }
66755143Storek 
66855143Storek /*
66955143Storek  * Fetch an integer (or pointer) property.
67055143Storek  * The return value is the property, or the default if there was none.
67155143Storek  */
67255143Storek int
67355143Storek getpropint(node, name, deflt)
67455143Storek 	int node;
67555143Storek 	char *name;
67655143Storek 	int deflt;
67755143Storek {
67855143Storek 	register int len;
67955143Storek 	char intbuf[16];
68055143Storek 
68155143Storek 	len = getprop(node, name, (void *)intbuf, sizeof intbuf);
68255143Storek 	if (len != 4)
68355143Storek 		return (deflt);
68455143Storek 	return (*(int *)intbuf);
68555143Storek }
68655143Storek 
68755143Storek /*
68855143Storek  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
68955143Storek  * from the rest of the kernel.
69055143Storek  */
69155143Storek int
69255143Storek firstchild(node)
69355143Storek 	int node;
69455143Storek {
69555143Storek 
69655143Storek 	return (promvec->pv_nodeops->no_child(node));
69755143Storek }
69855143Storek 
69955143Storek int
70055143Storek nextsibling(node)
70155143Storek 	int node;
70255143Storek {
70355143Storek 
70455143Storek 	return (promvec->pv_nodeops->no_nextnode(node));
70555143Storek }
70655143Storek 
707*64662Storek #ifdef RCONSOLE
70855143Storek /* Pass a string to the FORTH PROM to be interpreted */
70955143Storek void
71055143Storek rominterpret(s)
71155143Storek 	register char *s;
71255143Storek {
71355143Storek 
71455143Storek 	if (promvec->pv_romvec_vers < 2)
71555143Storek 		promvec->pv_fortheval.v0_eval(strlen(s), s);
71655143Storek 	else
71755143Storek 		promvec->pv_fortheval.v2_eval(s);
71855143Storek }
71955143Storek 
720*64662Storek /*
721*64662Storek  * Try to figure out where the PROM stores the cursor row & column
722*64662Storek  * variables.  Returns nonzero on error.
723*64662Storek  */
724*64662Storek int
725*64662Storek romgetcursoraddr(rowp, colp)
726*64662Storek 	register int **rowp, **colp;
727*64662Storek {
728*64662Storek 	char buf[100];
729*64662Storek 
730*64662Storek 	/*
731*64662Storek 	 * line# and column# are global in older proms (rom vector < 2)
732*64662Storek 	 * and in some newer proms.  They are local in version 2.9.  The
733*64662Storek 	 * correct cutoff point is unknown, as yet; we use 2.9 here.
734*64662Storek 	 */
735*64662Storek 	if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
736*64662Storek 		sprintf(buf,
737*64662Storek 		    "' line# >body >user %x ! ' column# >body >user %x !",
738*64662Storek 		    rowp, colp);
739*64662Storek 	else
740*64662Storek 		sprintf(buf,
741*64662Storek 		    "stdout @ is my-self addr line# %x ! addr column# %x !",
742*64662Storek 		    rowp, colp);
743*64662Storek 	*rowp = *colp = NULL;
744*64662Storek 	rominterpret(buf);
745*64662Storek 	return (*rowp == NULL || *colp == NULL);
746*64662Storek }
747*64662Storek #endif
748*64662Storek 
74955143Storek volatile void
75055143Storek romhalt()
75155143Storek {
75255143Storek 
75355143Storek 	promvec->pv_halt();
75455143Storek 	panic("PROM exit failed");
75555143Storek }
75655143Storek 
75755143Storek volatile void
75855143Storek romboot(str)
75955143Storek 	char *str;
76055143Storek {
76155143Storek 
76255143Storek 	promvec->pv_reboot(str);
76355143Storek 	panic("PROM boot failed");
76455143Storek }
76555143Storek 
76655143Storek callrom()
76755143Storek {
76855143Storek 
76955143Storek #ifdef notdef		/* sun4c FORTH PROMs do this for us */
77055143Storek 	fb_unblank();
77155143Storek #endif
77255143Storek 	promvec->pv_abort();
77355143Storek }
77455143Storek 
77555143Storek /*
77655143Storek  * Configure swap space and related parameters.
77755143Storek  */
77855143Storek swapconf()
77955143Storek {
78055143Storek 	register struct swdevt *swp;
78155143Storek 	register int nblks;
78255143Storek 
78359219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++)
78455143Storek 		if (bdevsw[major(swp->sw_dev)].d_psize) {
78555143Storek 			nblks =
78655143Storek 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
78755143Storek 			if (nblks != -1 &&
78855143Storek 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
78955143Storek 				swp->sw_nblks = nblks;
79055143Storek 		}
79155143Storek }
79255143Storek 
79359219Storek #define	DOSWAP			/* Change swdevt and dumpdev too */
79455143Storek u_long	bootdev;		/* should be dev_t, but not until 32 bits */
79555143Storek 
79655143Storek #define	PARTITIONMASK	0x7
79755143Storek #define	PARTITIONSHIFT	3
79855143Storek 
79959219Storek static int
80059219Storek findblkmajor(dv)
80159219Storek 	register struct dkdevice *dv;
80259219Storek {
80359219Storek 	register int i;
80459219Storek 
80559219Storek 	for (i = 0; i < nblkdev; ++i)
80659219Storek 		if ((void (*)(struct buf *))bdevsw[i].d_strategy ==
80759219Storek 		    dv->dk_driver->d_strategy)
80859219Storek 			return (i);
80959219Storek 
81059219Storek 	return (-1);
81159219Storek }
81259219Storek 
81359219Storek static struct device *
81459219Storek getdisk(str, len, defpart, devp)
81559219Storek 	char *str;
81659219Storek 	int len, defpart;
81759219Storek 	dev_t *devp;
81859219Storek {
81959219Storek 	register struct device *dv;
82059219Storek 
82159219Storek 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
82259219Storek 		printf("use one of:");
82359219Storek 		for (dv = alldevs; dv != NULL; dv = dv->dv_next)
82459219Storek 			if (dv->dv_class == DV_DISK)
82559219Storek 				printf(" %s[a-h]", dv->dv_xname);
82659219Storek 		printf("\n");
82759219Storek 	}
82859219Storek 	return (dv);
82959219Storek }
83059219Storek 
83159219Storek static struct device *
83259219Storek parsedisk(str, len, defpart, devp)
83359219Storek 	char *str;
83459219Storek 	int len, defpart;
83559219Storek 	dev_t *devp;
83659219Storek {
83759219Storek 	register struct device *dv;
83859219Storek 	register char *cp;
83959219Storek 	int majdev, mindev, part;
84059219Storek 
84159219Storek 	if (len == 0)
84259219Storek 		return (NULL);
84359219Storek 	cp = str + len - 1;
84459219Storek 	if (*cp >= 'a' && *cp <= 'h') {
84559219Storek 		part = *cp - 'a';
84659219Storek 		*cp-- = '\0';
84759219Storek 	} else
84859219Storek 		part = defpart;
84959219Storek 
85059219Storek 	for (dv = alldevs; dv != NULL; dv = dv->dv_next)
85159219Storek 		if (dv->dv_class == DV_DISK &&
85259219Storek 		    strcmp(str, dv->dv_xname) == 0) {
85359219Storek 			majdev = findblkmajor((struct dkdevice *)dv);
85459219Storek 			if (majdev < 0)
85559219Storek 				panic("parsedisk");
85659219Storek 			mindev = (dv->dv_unit << PARTITIONSHIFT) + part;
85759219Storek 			*devp = makedev(majdev, mindev);
85859219Storek 			return (dv);
85959219Storek 		}
86059219Storek 
86159219Storek 	return (NULL);
86259219Storek }
86359219Storek 
86455143Storek /*
86555143Storek  * Attempt to find the device from which we were booted.
86655143Storek  * If we can do so, and not instructed not to do so,
86755143Storek  * change rootdev to correspond to the load device.
86855143Storek  */
86959219Storek void
87055143Storek setroot()
87155143Storek {
87259219Storek 	register struct swdevt *swp;
87359219Storek 	register struct device *dv;
87459219Storek 	register int len, majdev, mindev, part;
87559219Storek 	dev_t nrootdev, nswapdev;
87659219Storek 	char buf[128];
87759219Storek #ifdef DOSWAP
87859219Storek 	dev_t temp;
87959219Storek #endif
88059219Storek #ifdef NFS
88159219Storek 	extern int (*mountroot)(), nfs_mountroot();
88259219Storek #endif
88355143Storek 
88459219Storek 	if (boothowto & RB_ASKNAME) {
88559219Storek 		for (;;) {
88659219Storek 			printf("root device? ");
88759219Storek 			len = getstr(buf, sizeof(buf));
88859219Storek #ifdef GENERIC
88959219Storek 			if (len > 0 && buf[len - 1] == '*') {
89059219Storek 				buf[--len] = '\0';
89159219Storek 				dv = getdisk(buf, len, 1, &nrootdev);
89259219Storek 				if (dv != NULL) {
89359219Storek 					bootdv = dv;
89459219Storek 					nswapdev = nrootdev;
89560518Storek 					goto gotswap;
89659219Storek 				}
89759219Storek 			}
89859219Storek #endif
89959219Storek 			dv = getdisk(buf, len, 0, &nrootdev);
90059219Storek 			if (dv != NULL) {
90159219Storek 				bootdv = dv;
90259219Storek 				break;
90359219Storek 			}
90459219Storek 		}
90559219Storek 		for (;;) {
90659219Storek 			printf("swap device (default %sb)? ", bootdv->dv_xname);
90759219Storek 			len = getstr(buf, sizeof(buf));
90859219Storek 			if (len == 0) {
90959219Storek 				nswapdev = makedev(major(nrootdev),
91059219Storek 				    (minor(nrootdev) & ~ PARTITIONMASK) | 1);
91159219Storek 				break;
91259219Storek 			}
91359219Storek 			if (getdisk(buf, len, 1, &nswapdev) != NULL)
91459219Storek 				break;
91559219Storek 		}
91660518Storek #ifdef GENERIC
91760518Storek gotswap:
91860518Storek #endif
91959219Storek 		rootdev = nrootdev;
92059219Storek 		swapdev = nswapdev;
92159219Storek 		dumpdev = nswapdev;		/* ??? */
92259219Storek 		swdevt[0].sw_dev = nswapdev;
92359219Storek 		swdevt[1].sw_dev = NODEV;
92455143Storek 		return;
92559219Storek 	}
92659219Storek 
92759219Storek 	/* XXX currently there's no way to set RB_DFLTROOT... */
92859219Storek 	if (boothowto & RB_DFLTROOT || bootdv == NULL)
92955143Storek 		return;
93059219Storek 
93159219Storek 	switch (bootdv->dv_class) {
93259219Storek 
93359219Storek #ifdef NFS
93459219Storek 	case DV_IFNET:
93559219Storek 		mountroot = nfs_mountroot;
93655143Storek 		return;
93759219Storek #endif
93859219Storek 
93959219Storek #if defined(FFS) || defined(LFS)
94059219Storek 	case DV_DISK:
94159219Storek 		majdev = findblkmajor((struct dkdevice *)bootdv);
94259219Storek 		if (majdev < 0)
94359219Storek 			return;
94459219Storek 		part = 0;
94559219Storek 		mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part;
94659219Storek 		break;
94759219Storek #endif
94859219Storek 
94959219Storek 	default:
95059219Storek 		printf("can't figure root, hope your kernel is right\n");
95155143Storek 		return;
95259219Storek 	}
95359219Storek 
95455143Storek 	/*
95555143Storek 	 * Form a new rootdev
95655143Storek 	 */
95759219Storek 	nrootdev = makedev(majdev, mindev);
95855143Storek 	/*
95955143Storek 	 * If the original rootdev is the same as the one
96055143Storek 	 * just calculated, don't need to adjust the swap configuration.
96155143Storek 	 */
96259219Storek 	if (rootdev == nrootdev)
96355143Storek 		return;
96455143Storek 
96559219Storek 	rootdev = nrootdev;
96659219Storek 	printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a');
96755143Storek 
96855143Storek #ifdef DOSWAP
96955143Storek 	mindev &= ~PARTITIONMASK;
97059219Storek 	temp = NODEV;
97159219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
97255143Storek 		if (majdev == major(swp->sw_dev) &&
97355143Storek 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
97455143Storek 			temp = swdevt[0].sw_dev;
97555143Storek 			swdevt[0].sw_dev = swp->sw_dev;
97655143Storek 			swp->sw_dev = temp;
97755143Storek 			break;
97855143Storek 		}
97955143Storek 	}
98059219Storek 	if (swp->sw_dev == NODEV)
98155143Storek 		return;
98255143Storek 
98355143Storek 	/*
98459219Storek 	 * If dumpdev was the same as the old primary swap device, move
98559219Storek 	 * it to the new primary swap device.
98655143Storek 	 */
98755143Storek 	if (temp == dumpdev)
98855143Storek 		dumpdev = swdevt[0].sw_dev;
98955143Storek #endif
99055143Storek }
99155143Storek 
99259219Storek static int
99359219Storek getstr(cp, size)
99455143Storek 	register char *cp;
99559219Storek 	register int size;
99655143Storek {
99755143Storek 	register char *lp;
99855143Storek 	register int c;
99959219Storek 	register int len;
100055143Storek 
100155143Storek 	lp = cp;
100259219Storek 	len = 0;
100355143Storek 	for (;;) {
100455143Storek 		c = cngetc();
100555143Storek 		switch (c) {
100655143Storek 		case '\n':
100755143Storek 		case '\r':
100855143Storek 			printf("\n");
100955143Storek 			*lp++ = '\0';
101059219Storek 			return (len);
101155143Storek 		case '\b':
101255143Storek 		case '\177':
101355143Storek 		case '#':
101459219Storek 			if (len) {
101559219Storek 				--len;
101659219Storek 				--lp;
101755143Storek 				printf(" \b ");
101855143Storek 			}
101955143Storek 			continue;
102055143Storek 		case '@':
102155143Storek 		case 'u'&037:
102259219Storek 			len = 0;
102355143Storek 			lp = cp;
102459219Storek 			printf("\n");
102555143Storek 			continue;
102655143Storek 		default:
102759219Storek 			if (len + 1 >= size || c < ' ') {
102859219Storek 				printf("\007");
102955143Storek 				continue;
103059219Storek 			}
103159219Storek 			printf("%c", c);
103259219Storek 			++len;
103355143Storek 			*lp++ = c;
103455143Storek 		}
103555143Storek 	}
103655143Storek }
1037