xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 64691)
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*64691Storek  *	@(#)autoconf.c	8.4 (Berkeley) 10/01/93
1755143Storek  *
18*64691Storek  * from: $Header: autoconf.c,v 1.38 93/10/01 21:24:51 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 *));
5855143Storek 
5959219Storek struct	bootpath bootpath[8];
6055143Storek 
6155143Storek /*
6255143Storek  * Most configuration on the SPARC is done by matching OPENPROM Forth
6355143Storek  * device names with our internal names.
6455143Storek  */
6555143Storek int
matchbyname(parent,cf,aux)6655143Storek matchbyname(parent, cf, aux)
6755143Storek 	struct device *parent;
6855143Storek 	struct cfdata *cf;
6955143Storek 	void *aux;
7055143Storek {
7155143Storek 
7255143Storek 	return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0);
7355143Storek }
7455143Storek 
7555143Storek /*
7655143Storek  * Convert hex ASCII string to a value.  Returns updated pointer.
7755143Storek  * Depends on ASCII order (this *is* machine-dependent code, you know).
7855143Storek  */
7955143Storek static char *
str2hex(str,vp)8055143Storek str2hex(str, vp)
8155143Storek 	register char *str;
8255143Storek 	register int *vp;
8355143Storek {
8455143Storek 	register int v, c;
8555143Storek 
8655143Storek 	for (v = 0;; v = v * 16 + c, str++) {
8755143Storek 		c = *(u_char *)str;
8855143Storek 		if (c <= '9') {
8955143Storek 			if ((c -= '0') < 0)
9055143Storek 				break;
9155143Storek 		} else if (c <= 'F') {
9255143Storek 			if ((c -= 'A' - 10) < 10)
9355143Storek 				break;
9455143Storek 		} else if (c <= 'f') {
9555143Storek 			if ((c -= 'a' - 10) < 10)
9655143Storek 				break;
9755143Storek 		} else
9855143Storek 			break;
9955143Storek 	}
10055143Storek 	*vp = v;
10155143Storek 	return (str);
10255143Storek }
10355143Storek 
10455143Storek /*
10555143Storek  * locore.s code calls bootstrap() just before calling main(), after double
10655143Storek  * mapping the kernel to high memory and setting up the trap base register.
10755143Storek  * We must finish mapping the kernel properly and glean any bootstrap info.
10855143Storek  */
10955143Storek void
bootstrap()11055143Storek bootstrap()
11155143Storek {
11259219Storek 	register char *cp, *pp;
11359219Storek 	register struct bootpath *bp;
11459219Storek 	int v0val[3];
11555143Storek 	int nmmu, ncontext, node;
11655143Storek #ifdef KGDB
11755143Storek 	extern int kgdb_debug_panic;
11855143Storek #endif
11955143Storek 
12055143Storek 	node = findroot();
12155143Storek 	nmmu = getpropint(node, "mmu-npmg", 128);
12255143Storek 	ncontext = getpropint(node, "mmu-nctx", 8);
12355143Storek 	pmap_bootstrap(nmmu, ncontext);
12455143Storek #ifdef KGDB
12555143Storek 	zs_kgdb_init();			/* XXX */
12655143Storek #endif
12755143Storek 	/*
12855143Storek 	 * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
12955143Storek 	 * that were given after the boot command.  On SS2s, pv_v0bootargs
13055143Storek 	 * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
13155143Storek 	 * "vmunix -s" or whatever.
13255143Storek 	 * ###	DO THIS BEFORE pmap_boostrap?
13355143Storek 	 */
13459219Storek 	bp = bootpath;
13555143Storek 	if (promvec->pv_romvec_vers < 2) {
13655143Storek 		/* Grab boot device name and values. */
13755143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[0];
13855143Storek 		if (cp != NULL) {
13959219Storek 			/* Kludge something up */
14059219Storek 			pp = cp + 2;
14159219Storek 			v0val[0] = v0val[1] = v0val[2] = 0;
14259219Storek 			if (*pp == '(' &&
14359219Storek 			    *(pp = str2hex(++pp, &v0val[0])) == ',' &&
14459219Storek 			    *(pp = str2hex(++pp, &v0val[1])) == ',')
14559219Storek 				(void)str2hex(++pp, &v0val[2]);
14655143Storek 
14759219Storek 			/* Assume sbus0 */
14859219Storek 			strcpy(bp->name, "sbus");
14959219Storek 			bp->val[0] = 0;
15059219Storek 			++bp;
15159219Storek 
15259219Storek 			if (cp[0] == 'l' && cp[1] == 'e') {
15359219Storek 				/* le */
15459219Storek 				strcpy(bp->name, "le");
15559219Storek 				bp->val[0] = -1;
15659219Storek 				bp->val[1] = v0val[0];
15759219Storek 			} else {
15859219Storek 				/* sd or maybe st; assume espN */
15959219Storek 				strcpy(bp->name, "esp");
16059219Storek 				bp->val[0] = -1;
16159219Storek 				bp->val[1] = v0val[0];
16259219Storek 
16359219Storek /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */
16459219Storek #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v))
16559219Storek 
16659219Storek 				++bp;
16759219Storek 				bp->name[0] = cp[0];
16859219Storek 				bp->name[1] = cp[1];
16959219Storek 				bp->name[2] = '\0';
17059219Storek 				bp->val[0] = CRAZYMAP(v0val[1]);
17159219Storek 				bp->val[1] = v0val[2];
17259219Storek 			}
17355143Storek 		}
17455143Storek 
17555143Storek 		/* Setup pointer to boot flags */
17655143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[1];
17755143Storek 		if (cp == NULL || *cp != '-')
17855143Storek 			return;
17955143Storek 	} else {
18059219Storek 		/* Grab boot path */
18155143Storek 		cp = *promvec->pv_v2bootargs.v2_bootpath;
18259219Storek 		while (cp != NULL && *cp == '/') {
18359219Storek 			/* Step over '/' */
18455143Storek 			++cp;
18559219Storek 			/* Extract name */
18659219Storek 			pp = bp->name;
18759219Storek 			while (*cp != '@' && *cp != '/' && *cp != '\0')
18859219Storek 				*pp++ = *cp++;
18959219Storek 			*pp = '\0';
19055143Storek 
19159219Storek 			if (*cp == '@') {
19259219Storek 				cp = str2hex(++cp, &bp->val[0]);
19359219Storek 				if (*cp == ',')
19459219Storek 					cp = str2hex(++cp, &bp->val[1]);
19559219Storek 			}
19659219Storek 			++bp;
19755143Storek 		}
19855143Storek 
19955143Storek 		/* Setup pointer to boot flags */
20055143Storek 		cp = *promvec->pv_v2bootargs.v2_bootargs;
20155143Storek 		if (cp == NULL)
20255143Storek 			return;
20355143Storek 		while (*cp != '-')
20455143Storek 			if (*cp++ == '\0')
20555143Storek 				return;
20655143Storek 	}
20755143Storek 	for (;;) {
20855143Storek 		switch (*++cp) {
20955143Storek 
21055143Storek 		case '\0':
21155143Storek 			return;
21255143Storek 
21355143Storek 		case 'a':
21455143Storek 			boothowto |= RB_ASKNAME;
21555143Storek 			break;
21655143Storek 
21755143Storek 		case 'b':
21855143Storek 			boothowto |= RB_DFLTROOT;
21955143Storek 			break;
22055143Storek 
22155143Storek 		case 'd':	/* kgdb - always on zs	XXX */
22255143Storek #ifdef KGDB
22355143Storek 			boothowto |= RB_KDB;	/* XXX unused */
22455143Storek 			kgdb_debug_panic = 1;
22555143Storek 			kgdb_connect(1);
22655143Storek #else
22755143Storek 			printf("kernel not compiled with KGDB\n");
22855143Storek #endif
22955143Storek 			break;
23055143Storek 
23155143Storek 		case 's':
23255143Storek 			boothowto |= RB_SINGLE;
23355143Storek 			break;
23455143Storek 		}
23555143Storek 	}
23655143Storek }
23755143Storek 
23855143Storek /*
23955143Storek  * Determine mass storage and memory configuration for a machine.
24055143Storek  * We get the PROM's root device and make sure we understand it, then
24155143Storek  * attach it as `mainbus0'.  We also set up to handle the PROM `sync'
24255143Storek  * command.
24355143Storek  */
configure()24455143Storek configure()
24555143Storek {
24655143Storek 	register int node;
24755143Storek 	register char *cp;
24855143Storek 	struct romaux ra;
24955143Storek 	void sync_crash();
25055143Storek 
25155143Storek 	node = findroot();
25255143Storek 	cp = getpropstring(node, "device_type");
25355143Storek 	if (strcmp(cp, "cpu") != 0) {
25455143Storek 		printf("PROM root device type = %s\n", cp);
25555143Storek 		panic("need CPU as root");
25655143Storek 	}
25755143Storek 	*promvec->pv_synchook = sync_crash;
25855143Storek 	ra.ra_node = node;
25955143Storek 	ra.ra_name = cp = "mainbus";
26055143Storek 	if (!config_rootfound(cp, (void *)&ra))
26155143Storek 		panic("mainbus not configured");
26259219Storek 	(void)spl0();
26359219Storek 	if (bootdv)
26459219Storek 		printf("Found boot device %s\n", bootdv->dv_xname);
26555143Storek 	cold = 0;
26655143Storek 	setroot();
26755143Storek 	swapconf();
26859219Storek 	dumpconf();
26955143Storek }
27055143Storek 
27155143Storek /*
27255143Storek  * Console `sync' command.  SunOS just does a `panic: zero' so I guess
27355143Storek  * no one really wants anything fancy...
27455143Storek  */
27555143Storek void
sync_crash()27655143Storek sync_crash()
27755143Storek {
27855143Storek 
27955143Storek 	panic("PROM sync command");
28055143Storek }
28155143Storek 
28255143Storek char *
clockfreq(freq)28355143Storek clockfreq(freq)
28455143Storek 	register int freq;
28555143Storek {
28655143Storek 	register char *p;
28755143Storek 	static char buf[10];
28855143Storek 
28955143Storek 	freq /= 1000;
29055143Storek 	sprintf(buf, "%d", freq / 1000);
29155143Storek 	freq %= 1000;
29255143Storek 	if (freq) {
29355143Storek 		freq += 1000;	/* now in 1000..1999 */
29455143Storek 		p = buf + strlen(buf);
29555143Storek 		sprintf(p, "%d", freq);
29655143Storek 		*p = '.';	/* now buf = %d.%3d */
29755143Storek 	}
29855143Storek 	return (buf);
29955143Storek }
30055143Storek 
30155143Storek /* ARGSUSED */
30255143Storek static int
mbprint(aux,name)30355143Storek mbprint(aux, name)
30455143Storek 	void *aux;
30555143Storek 	char *name;
30655143Storek {
30755143Storek 	register struct romaux *ra = aux;
30855143Storek 
30955143Storek 	if (name)
31055143Storek 		printf("%s at %s", ra->ra_name, name);
31155143Storek 	if (ra->ra_paddr)
31255143Storek 		printf(" %saddr 0x%x", ra->ra_iospace ? "io" : "",
31355143Storek 		    (int)ra->ra_paddr);
31455143Storek 	return (UNCONF);
31555143Storek }
31655143Storek 
31755143Storek int
findroot()31855143Storek findroot()
31955143Storek {
32055143Storek 	register int node;
32155143Storek 
32255143Storek 	if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0)
32355143Storek 		panic("no PROM root device");
32455143Storek 	rootnode = node;
32555143Storek 	return (node);
32655143Storek }
32755143Storek 
32855143Storek /*
32955143Storek  * Given a `first child' node number, locate the node with the given name.
33055143Storek  * Return the node number, or 0 if not found.
33155143Storek  */
33255143Storek int
findnode(first,name)33355143Storek findnode(first, name)
33455143Storek 	int first;
33555143Storek 	register char *name;
33655143Storek {
33755143Storek 	register int node;
33855143Storek 
33955143Storek 	for (node = first; node; node = nextsibling(node))
34055143Storek 		if (strcmp(getpropstring(node, "name"), name) == 0)
34155143Storek 			return (node);
34255143Storek 	return (0);
34355143Storek }
34455143Storek 
34555143Storek /*
34655143Storek  * Fill in a romaux.  Returns 1 on success, 0 if the register property
34755143Storek  * was not the right size.
34855143Storek  */
34955143Storek int
romprop(rp,cp,node)35055143Storek romprop(rp, cp, node)
35155143Storek 	register struct romaux *rp;
35255143Storek 	const char *cp;
35355143Storek 	register int node;
35455143Storek {
35555143Storek 	register int len;
35655143Storek 	union { char regbuf[64]; int ireg[3]; } u;
35755143Storek 	static const char pl[] = "property length";
35855143Storek 
35955143Storek 	len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf);
36055143Storek 	if (len < 12) {
36155143Storek 		printf("%s \"reg\" %s = %d (need 12)\n", cp, pl, len);
36255143Storek 		return (0);
36355143Storek 	}
36455143Storek 	if (len > 12)
36555143Storek 		printf("warning: %s \"reg\" %s %d > 12, excess ignored\n",
36655143Storek 		    cp, pl, len);
36755143Storek 	rp->ra_node = node;
36855143Storek 	rp->ra_name = cp;
36955143Storek 	rp->ra_iospace = u.ireg[0];
37055143Storek 	rp->ra_paddr = (caddr_t)u.ireg[1];
37155143Storek 	rp->ra_len = u.ireg[2];
37255143Storek 	rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0);
37355143Storek 	len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr);
37455143Storek 	if (len == -1)
37555143Storek 		len = 0;
37655143Storek 	if (len & 7) {
37755143Storek 		printf("%s \"intr\" %s = %d (need multiple of 8)\n",
37855143Storek 		    cp, pl, len);
37955143Storek 		len = 0;
38055143Storek 	}
38155143Storek 	rp->ra_nintr = len >>= 3;
38255143Storek 	/* SPARCstation interrupts are not hardware-vectored */
38355143Storek 	while (--len >= 0) {
38455143Storek 		if (rp->ra_intr[len].int_vec) {
38555143Storek 			printf("WARNING: %s interrupt %d has nonzero vector\n",
38655143Storek 			    cp, len);
38755143Storek 			break;
38855143Storek 		}
38955143Storek 	}
39055143Storek 	return (1);
39155143Storek }
39255143Storek 
39355143Storek /*
39455143Storek  * Attach the mainbus.
39555143Storek  *
39655143Storek  * Our main job is to attach the CPU (the root node we got in configure())
39755143Storek  * and iterate down the list of `mainbus devices' (children of that node).
39855143Storek  * We also record the `node id' of the default frame buffer, if any.
39955143Storek  */
40055143Storek static void
mainbus_attach(parent,dev,aux)40155143Storek mainbus_attach(parent, dev, aux)
40255143Storek 	struct device *parent, *dev;
40355143Storek 	void *aux;
40455143Storek {
40555143Storek 	register int node0, node;
40655143Storek 	register const char *cp, *const *ssp, *sp;
40755143Storek #define L1A_HACK		/* XXX hack to allow L1-A during autoconf */
40855143Storek #ifdef L1A_HACK
40955143Storek 	int nzs = 0, audio = 0;
41055143Storek #endif
41155143Storek 	struct romaux ra;
41255143Storek 	static const char *const special[] = {
41355143Storek 		/* find these first (end with empty string) */
414*64691Storek 		"memory-error",	/* as early as convenient, in case of error */
41564662Storek 		"eeprom",
41664662Storek 		"counter-timer",
41764662Storek 		"",
41855143Storek 
41955143Storek 		/* ignore these (end with NULL) */
42064662Storek 		"aliases",
42164662Storek 		"interrupt-enable",
42264662Storek 		"memory",
42364662Storek 		"openprom",
42464662Storek 		"options",
42564662Storek 		"packages",
42664662Storek 		"virtual-memory",
42764662Storek 		NULL
42855143Storek 	};
42955143Storek 
43055143Storek 	printf("\n");
43155143Storek 
43255143Storek 	/* configure the cpu */
43355143Storek 	node = ((struct romaux *)aux)->ra_node;
43455143Storek 	ra.ra_node = node;
43555143Storek 	ra.ra_name = cp = "cpu";
43655143Storek 	ra.ra_paddr = 0;
43755143Storek 	config_found(dev, (void *)&ra, mbprint);
43855143Storek 
43955143Storek 	/* remember which frame buffer, if any, is to be /dev/fb */
44055143Storek 	fbnode = getpropint(node, "fb", 0);
44155143Storek 
44255143Storek 	/* Find the "options" node */
44355143Storek 	node0 = firstchild(node);
44455143Storek 	optionsnode = findnode(node0, "options");
44555143Storek 	if (optionsnode == 0)
44655143Storek 		panic("no options in OPENPROM");
44755143Storek 
44859219Storek 	/* Start at the beginning of the bootpath */
44959219Storek 	ra.ra_bp = bootpath;
45059219Storek 
45155143Storek 	/*
45255143Storek 	 * Locate and configure the ``early'' devices.  These must be
45355143Storek 	 * configured before we can do the rest.  For instance, the
45455143Storek 	 * EEPROM contains the Ethernet address for the LANCE chip.
45555143Storek 	 * If the device cannot be located or configured, panic.
45655143Storek 	 */
45755143Storek 	for (ssp = special; *(sp = *ssp) != 0; ssp++) {
45855143Storek 		if ((node = findnode(node0, sp)) == 0) {
45955143Storek 			printf("could not find %s in OPENPROM\n", sp);
46055143Storek 			panic(sp);
46155143Storek 		}
46255143Storek 		if (!romprop(&ra, sp, node) ||
46355143Storek 		    !config_found(dev, (void *)&ra, mbprint))
46455143Storek 			panic(sp);
46555143Storek 	}
46655143Storek 
46755143Storek 	/*
46855143Storek 	 * Configure the rest of the devices, in PROM order.  Skip
46955143Storek 	 * PROM entries that are not for devices, or which must be
47055143Storek 	 * done before we get here.
47155143Storek 	 */
47255143Storek 	for (node = node0; node; node = nextsibling(node)) {
47355143Storek 		cp = getpropstring(node, "name");
47455143Storek 		for (ssp = special; (sp = *ssp) != NULL; ssp++)
47555143Storek 			if (strcmp(cp, sp) == 0)
47655143Storek 				break;
47755143Storek 		if (sp == NULL && romprop(&ra, cp, node)) {
47855143Storek #ifdef L1A_HACK
47955143Storek 			if (strcmp(cp, "audio") == 0)
48055143Storek 				audio = 1;
48155143Storek 			if (strcmp(cp, "zs") == 0)
48255143Storek 				nzs++;
48355143Storek 			if (audio && nzs >= 2)
48455143Storek 				(void) splx(11 << 8);	/* XXX */
48555143Storek #endif
48655143Storek 			(void) config_found(dev, (void *)&ra, mbprint);
48755143Storek 		}
48855143Storek 	}
48955143Storek }
49055143Storek 
49155143Storek struct cfdriver mainbuscd =
49255143Storek     { NULL, "mainbus", matchbyname, mainbus_attach,
49355143Storek       DV_DULL, sizeof(struct device) };
49455143Storek 
49555143Storek /*
49655143Storek  * findzs() is called from the zs driver (which is, at least in theory,
49755143Storek  * generic to any machine with a Zilog ZSCC chip).  It should return the
49855143Storek  * address of the corresponding zs channel.  It may not fail, and it
49955143Storek  * may be called before the VM code can be used.  Here we count on the
50055143Storek  * FORTH PROM to map in the required zs chips.
50155143Storek  */
50255143Storek void *
findzs(zs)50355143Storek findzs(zs)
50455143Storek 	int zs;
50555143Storek {
50655143Storek 	register int node, addr;
50755143Storek 
50855143Storek 	node = firstchild(findroot());
50955143Storek 	while ((node = findnode(node, "zs")) != 0) {
51055143Storek 		if (getpropint(node, "slave", -1) == zs) {
51155143Storek 			if ((addr = getpropint(node, "address", 0)) == 0)
51255143Storek 				panic("findzs: zs%d not mapped by PROM", zs);
51355143Storek 			return ((void *)addr);
51455143Storek 		}
51555143Storek 		node = nextsibling(node);
51655143Storek 	}
51755143Storek 	panic("findzs: cannot find zs%d", zs);
51855143Storek 	/* NOTREACHED */
51955143Storek }
52055143Storek 
52155143Storek int
makememarr(ap,max,which)52255143Storek makememarr(ap, max, which)
52355143Storek 	register struct memarr *ap;
52455143Storek 	int max, which;
52555143Storek {
52655143Storek 	struct v2rmi {
52755143Storek 		int	zero;
52855143Storek 		int	addr;
52955143Storek 		int	len;
53055143Storek 	} v2rmi[200];		/* version 2 rom meminfo layout */
53155143Storek #define	MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
53255143Storek 	register struct v0mlist *mp;
53355143Storek 	register int i, node, len;
53455143Storek 	char *prop;
53555143Storek 
53655143Storek 	switch (i = promvec->pv_romvec_vers) {
53755143Storek 
53855143Storek 	case 0:
53955143Storek 		/*
54055143Storek 		 * Version 0 PROMs use a linked list to describe these
54155143Storek 		 * guys.
54255143Storek 		 */
54355143Storek 		switch (which) {
54455143Storek 
54555143Storek 		case MEMARR_AVAILPHYS:
54655143Storek 			mp = *promvec->pv_v0mem.v0_physavail;
54755143Storek 			break;
54855143Storek 
54955143Storek 		case MEMARR_TOTALPHYS:
55055143Storek 			mp = *promvec->pv_v0mem.v0_phystot;
55155143Storek 			break;
55255143Storek 
55355143Storek 		default:
55455143Storek 			panic("makememarr");
55555143Storek 		}
55655143Storek 		for (i = 0; mp != NULL; mp = mp->next, i++) {
55755143Storek 			if (i >= max)
55855143Storek 				goto overflow;
55955143Storek 			ap->addr = (u_int)mp->addr;
56055143Storek 			ap->len = mp->nbytes;
56155143Storek 			ap++;
56255143Storek 		}
56355143Storek 		break;
56455143Storek 
56555143Storek 	default:
56655143Storek 		printf("makememarr: hope version %d PROM is like version 2\n",
56755143Storek 		    i);
56855143Storek 		/* FALLTHROUGH */
56955143Storek 
57055143Storek 	case 2:
57155143Storek 		/*
57255143Storek 		 * Version 2 PROMs use a property array to describe them.
57355143Storek 		 */
57455143Storek 		if (max > MAXMEMINFO) {
57555143Storek 			printf("makememarr: limited to %d\n", MAXMEMINFO);
57655143Storek 			max = MAXMEMINFO;
57755143Storek 		}
57855143Storek 		if ((node = findnode(firstchild(findroot()), "memory")) == 0)
57955143Storek 			panic("makememarr: cannot find \"memory\" node");
58055143Storek 		switch (which) {
58155143Storek 
58255143Storek 		case MEMARR_AVAILPHYS:
58355143Storek 			prop = "available";
58455143Storek 			break;
58555143Storek 
58655143Storek 		case MEMARR_TOTALPHYS:
58755143Storek 			prop = "reg";
58855143Storek 			break;
58955143Storek 
59055143Storek 		default:
59155143Storek 			panic("makememarr");
59255143Storek 		}
59355143Storek 		len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
59455143Storek 		    sizeof(struct v2rmi);
59555143Storek 		for (i = 0; i < len; i++) {
59655143Storek 			if (i >= max)
59755143Storek 				goto overflow;
59855143Storek 			ap->addr = v2rmi[i].addr;
59955143Storek 			ap->len = v2rmi[i].len;
60055143Storek 			ap++;
60155143Storek 		}
60255143Storek 		break;
60355143Storek 	}
60455143Storek 
60555143Storek 	/*
60655143Storek 	 * Success!  (Hooray)
60755143Storek 	 */
60855143Storek 	if (i == 0)
60955143Storek 		panic("makememarr: no memory found");
61055143Storek 	return (i);
61155143Storek 
61255143Storek overflow:
61355143Storek 	/*
61455143Storek 	 * Oops, there are more things in the PROM than our caller
61555143Storek 	 * provided space for.  Truncate any extras.
61655143Storek 	 */
61755143Storek 	printf("makememarr: WARNING: lost some memory\n");
61855143Storek 	return (i);
61955143Storek }
62055143Storek 
62155143Storek /*
62255143Storek  * Internal form of getprop().  Returns the actual length.
62355143Storek  */
62455143Storek int
getprop(node,name,buf,bufsiz)62555143Storek getprop(node, name, buf, bufsiz)
62655143Storek 	int node;
62755143Storek 	char *name;
62855143Storek 	void *buf;
62955143Storek 	register int bufsiz;
63055143Storek {
63155143Storek 	register struct nodeops *no;
63255143Storek 	register int len;
63355143Storek 
63455143Storek 	no = promvec->pv_nodeops;
63555143Storek 	len = no->no_proplen(node, name);
63655143Storek 	if (len > bufsiz) {
63755143Storek 		printf("node %x property %s length %d > %d\n",
63855143Storek 		    node, name, len, bufsiz);
63955143Storek #ifdef DEBUG
64055143Storek 		panic("getprop");
64155143Storek #else
64255143Storek 		return (0);
64355143Storek #endif
64455143Storek 	}
64555143Storek 	no->no_getprop(node, name, buf);
64655143Storek 	return (len);
64755143Storek }
64855143Storek 
64955143Storek /*
65055143Storek  * Return a string property.  There is a (small) limit on the length;
65155143Storek  * the string is fetched into a static buffer which is overwritten on
65255143Storek  * subsequent calls.
65355143Storek  */
65455143Storek char *
getpropstring(node,name)65555143Storek getpropstring(node, name)
65655143Storek 	int node;
65755143Storek 	char *name;
65855143Storek {
65955143Storek 	register int len;
66055143Storek 	static char stringbuf[32];
66155143Storek 
66255143Storek 	len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
66355143Storek 	stringbuf[len] = '\0';	/* usually unnecessary */
66455143Storek 	return (stringbuf);
66555143Storek }
66655143Storek 
66755143Storek /*
66855143Storek  * Fetch an integer (or pointer) property.
66955143Storek  * The return value is the property, or the default if there was none.
67055143Storek  */
67155143Storek int
getpropint(node,name,deflt)67255143Storek getpropint(node, name, deflt)
67355143Storek 	int node;
67455143Storek 	char *name;
67555143Storek 	int deflt;
67655143Storek {
67755143Storek 	register int len;
67855143Storek 	char intbuf[16];
67955143Storek 
68055143Storek 	len = getprop(node, name, (void *)intbuf, sizeof intbuf);
68155143Storek 	if (len != 4)
68255143Storek 		return (deflt);
68355143Storek 	return (*(int *)intbuf);
68455143Storek }
68555143Storek 
68655143Storek /*
68755143Storek  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
68855143Storek  * from the rest of the kernel.
68955143Storek  */
69055143Storek int
firstchild(node)69155143Storek firstchild(node)
69255143Storek 	int node;
69355143Storek {
69455143Storek 
69555143Storek 	return (promvec->pv_nodeops->no_child(node));
69655143Storek }
69755143Storek 
69855143Storek int
nextsibling(node)69955143Storek nextsibling(node)
70055143Storek 	int node;
70155143Storek {
70255143Storek 
70355143Storek 	return (promvec->pv_nodeops->no_nextnode(node));
70455143Storek }
70555143Storek 
70664662Storek #ifdef RCONSOLE
70755143Storek /* Pass a string to the FORTH PROM to be interpreted */
70855143Storek void
rominterpret(s)70955143Storek rominterpret(s)
71055143Storek 	register char *s;
71155143Storek {
71255143Storek 
71355143Storek 	if (promvec->pv_romvec_vers < 2)
71455143Storek 		promvec->pv_fortheval.v0_eval(strlen(s), s);
71555143Storek 	else
71655143Storek 		promvec->pv_fortheval.v2_eval(s);
71755143Storek }
71855143Storek 
71964662Storek /*
72064662Storek  * Try to figure out where the PROM stores the cursor row & column
72164662Storek  * variables.  Returns nonzero on error.
72264662Storek  */
72364662Storek int
romgetcursoraddr(rowp,colp)72464662Storek romgetcursoraddr(rowp, colp)
72564662Storek 	register int **rowp, **colp;
72664662Storek {
72764662Storek 	char buf[100];
72864662Storek 
72964662Storek 	/*
73064662Storek 	 * line# and column# are global in older proms (rom vector < 2)
73164662Storek 	 * and in some newer proms.  They are local in version 2.9.  The
73264662Storek 	 * correct cutoff point is unknown, as yet; we use 2.9 here.
73364662Storek 	 */
73464662Storek 	if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
73564662Storek 		sprintf(buf,
73664662Storek 		    "' line# >body >user %x ! ' column# >body >user %x !",
73764662Storek 		    rowp, colp);
73864662Storek 	else
73964662Storek 		sprintf(buf,
74064662Storek 		    "stdout @ is my-self addr line# %x ! addr column# %x !",
74164662Storek 		    rowp, colp);
74264662Storek 	*rowp = *colp = NULL;
74364662Storek 	rominterpret(buf);
74464662Storek 	return (*rowp == NULL || *colp == NULL);
74564662Storek }
74664662Storek #endif
74764662Storek 
74855143Storek volatile void
romhalt()74955143Storek romhalt()
75055143Storek {
75155143Storek 
75255143Storek 	promvec->pv_halt();
75355143Storek 	panic("PROM exit failed");
75455143Storek }
75555143Storek 
75655143Storek volatile void
romboot(str)75755143Storek romboot(str)
75855143Storek 	char *str;
75955143Storek {
76055143Storek 
76155143Storek 	promvec->pv_reboot(str);
76255143Storek 	panic("PROM boot failed");
76355143Storek }
76455143Storek 
callrom()76555143Storek callrom()
76655143Storek {
76755143Storek 
76855143Storek #ifdef notdef		/* sun4c FORTH PROMs do this for us */
76955143Storek 	fb_unblank();
77055143Storek #endif
77155143Storek 	promvec->pv_abort();
77255143Storek }
77355143Storek 
77455143Storek /*
77555143Storek  * Configure swap space and related parameters.
77655143Storek  */
swapconf()77755143Storek swapconf()
77855143Storek {
77955143Storek 	register struct swdevt *swp;
78055143Storek 	register int nblks;
78155143Storek 
78259219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++)
78355143Storek 		if (bdevsw[major(swp->sw_dev)].d_psize) {
78455143Storek 			nblks =
78555143Storek 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
78655143Storek 			if (nblks != -1 &&
78755143Storek 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
78855143Storek 				swp->sw_nblks = nblks;
78955143Storek 		}
79055143Storek }
79155143Storek 
79259219Storek #define	DOSWAP			/* Change swdevt and dumpdev too */
79355143Storek u_long	bootdev;		/* should be dev_t, but not until 32 bits */
79455143Storek 
79555143Storek #define	PARTITIONMASK	0x7
79655143Storek #define	PARTITIONSHIFT	3
79755143Storek 
79859219Storek static int
findblkmajor(dv)79959219Storek findblkmajor(dv)
80059219Storek 	register struct dkdevice *dv;
80159219Storek {
80259219Storek 	register int i;
80359219Storek 
80459219Storek 	for (i = 0; i < nblkdev; ++i)
80559219Storek 		if ((void (*)(struct buf *))bdevsw[i].d_strategy ==
80659219Storek 		    dv->dk_driver->d_strategy)
80759219Storek 			return (i);
80859219Storek 
80959219Storek 	return (-1);
81059219Storek }
81159219Storek 
81259219Storek static struct device *
getdisk(str,len,defpart,devp)81359219Storek getdisk(str, len, defpart, devp)
81459219Storek 	char *str;
81559219Storek 	int len, defpart;
81659219Storek 	dev_t *devp;
81759219Storek {
81859219Storek 	register struct device *dv;
81959219Storek 
82059219Storek 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
82159219Storek 		printf("use one of:");
82259219Storek 		for (dv = alldevs; dv != NULL; dv = dv->dv_next)
82359219Storek 			if (dv->dv_class == DV_DISK)
82459219Storek 				printf(" %s[a-h]", dv->dv_xname);
82559219Storek 		printf("\n");
82659219Storek 	}
82759219Storek 	return (dv);
82859219Storek }
82959219Storek 
83064686Storek struct device *
parsedisk(str,len,defpart,devp)83159219Storek parsedisk(str, len, defpart, devp)
83259219Storek 	char *str;
83359219Storek 	int len, defpart;
83459219Storek 	dev_t *devp;
83559219Storek {
83659219Storek 	register struct device *dv;
83764686Storek 	register char *cp, c;
83859219Storek 	int majdev, mindev, part;
83959219Storek 
84059219Storek 	if (len == 0)
84159219Storek 		return (NULL);
84259219Storek 	cp = str + len - 1;
84364686Storek 	c = *cp;
84464686Storek 	if (c >= 'a' && c <= 'h') {
84564686Storek 		part = c - 'a';
84664686Storek 		*cp = '\0';
84759219Storek 	} else
84859219Storek 		part = defpart;
84959219Storek 
85064686Storek 	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);
85864686Storek 			break;
85959219Storek 		}
86064686Storek 	}
86159219Storek 
86264686Storek 	*cp = c;
86364686Storek 	return (dv);
86459219Storek }
86559219Storek 
86655143Storek /*
86755143Storek  * Attempt to find the device from which we were booted.
86855143Storek  * If we can do so, and not instructed not to do so,
86955143Storek  * change rootdev to correspond to the load device.
87055143Storek  */
87159219Storek void
setroot()87255143Storek setroot()
87355143Storek {
87459219Storek 	register struct swdevt *swp;
87559219Storek 	register struct device *dv;
87659219Storek 	register int len, majdev, mindev, part;
87759219Storek 	dev_t nrootdev, nswapdev;
87859219Storek 	char buf[128];
87959219Storek #ifdef DOSWAP
88059219Storek 	dev_t temp;
88159219Storek #endif
88259219Storek #ifdef NFS
88359219Storek 	extern int (*mountroot)(), nfs_mountroot();
88459219Storek #endif
88555143Storek 
88659219Storek 	if (boothowto & RB_ASKNAME) {
88759219Storek 		for (;;) {
88859219Storek 			printf("root device? ");
88959219Storek 			len = getstr(buf, sizeof(buf));
89059219Storek #ifdef GENERIC
89159219Storek 			if (len > 0 && buf[len - 1] == '*') {
89259219Storek 				buf[--len] = '\0';
89359219Storek 				dv = getdisk(buf, len, 1, &nrootdev);
89459219Storek 				if (dv != NULL) {
89559219Storek 					bootdv = dv;
89659219Storek 					nswapdev = nrootdev;
89760518Storek 					goto gotswap;
89859219Storek 				}
89959219Storek 			}
90059219Storek #endif
90159219Storek 			dv = getdisk(buf, len, 0, &nrootdev);
90259219Storek 			if (dv != NULL) {
90359219Storek 				bootdv = dv;
90459219Storek 				break;
90559219Storek 			}
90659219Storek 		}
90759219Storek 		for (;;) {
90859219Storek 			printf("swap device (default %sb)? ", bootdv->dv_xname);
90959219Storek 			len = getstr(buf, sizeof(buf));
91059219Storek 			if (len == 0) {
91159219Storek 				nswapdev = makedev(major(nrootdev),
91259219Storek 				    (minor(nrootdev) & ~ PARTITIONMASK) | 1);
91359219Storek 				break;
91459219Storek 			}
91559219Storek 			if (getdisk(buf, len, 1, &nswapdev) != NULL)
91659219Storek 				break;
91759219Storek 		}
91860518Storek #ifdef GENERIC
91960518Storek gotswap:
92060518Storek #endif
92159219Storek 		rootdev = nrootdev;
92259219Storek 		swapdev = nswapdev;
92359219Storek 		dumpdev = nswapdev;		/* ??? */
92459219Storek 		swdevt[0].sw_dev = nswapdev;
92559219Storek 		swdevt[1].sw_dev = NODEV;
92655143Storek 		return;
92759219Storek 	}
92859219Storek 
92959219Storek 	/* XXX currently there's no way to set RB_DFLTROOT... */
93059219Storek 	if (boothowto & RB_DFLTROOT || bootdv == NULL)
93155143Storek 		return;
93259219Storek 
93359219Storek 	switch (bootdv->dv_class) {
93459219Storek 
93559219Storek #ifdef NFS
93659219Storek 	case DV_IFNET:
93759219Storek 		mountroot = nfs_mountroot;
93855143Storek 		return;
93959219Storek #endif
94059219Storek 
94159219Storek #if defined(FFS) || defined(LFS)
94259219Storek 	case DV_DISK:
94359219Storek 		majdev = findblkmajor((struct dkdevice *)bootdv);
94459219Storek 		if (majdev < 0)
94559219Storek 			return;
94659219Storek 		part = 0;
94759219Storek 		mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part;
94859219Storek 		break;
94959219Storek #endif
95059219Storek 
95159219Storek 	default:
95259219Storek 		printf("can't figure root, hope your kernel is right\n");
95355143Storek 		return;
95459219Storek 	}
95559219Storek 
95655143Storek 	/*
95755143Storek 	 * Form a new rootdev
95855143Storek 	 */
95959219Storek 	nrootdev = makedev(majdev, mindev);
96055143Storek 	/*
96155143Storek 	 * If the original rootdev is the same as the one
96255143Storek 	 * just calculated, don't need to adjust the swap configuration.
96355143Storek 	 */
96459219Storek 	if (rootdev == nrootdev)
96555143Storek 		return;
96655143Storek 
96759219Storek 	rootdev = nrootdev;
96859219Storek 	printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a');
96955143Storek 
97055143Storek #ifdef DOSWAP
97155143Storek 	mindev &= ~PARTITIONMASK;
97259219Storek 	temp = NODEV;
97359219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
97455143Storek 		if (majdev == major(swp->sw_dev) &&
97555143Storek 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
97655143Storek 			temp = swdevt[0].sw_dev;
97755143Storek 			swdevt[0].sw_dev = swp->sw_dev;
97855143Storek 			swp->sw_dev = temp;
97955143Storek 			break;
98055143Storek 		}
98155143Storek 	}
98259219Storek 	if (swp->sw_dev == NODEV)
98355143Storek 		return;
98455143Storek 
98555143Storek 	/*
98659219Storek 	 * If dumpdev was the same as the old primary swap device, move
98759219Storek 	 * it to the new primary swap device.
98855143Storek 	 */
98955143Storek 	if (temp == dumpdev)
99055143Storek 		dumpdev = swdevt[0].sw_dev;
99155143Storek #endif
99255143Storek }
99355143Storek 
99459219Storek static int
getstr(cp,size)99559219Storek getstr(cp, size)
99655143Storek 	register char *cp;
99759219Storek 	register int size;
99855143Storek {
99955143Storek 	register char *lp;
100055143Storek 	register int c;
100159219Storek 	register int len;
100255143Storek 
100355143Storek 	lp = cp;
100459219Storek 	len = 0;
100555143Storek 	for (;;) {
100655143Storek 		c = cngetc();
100755143Storek 		switch (c) {
100855143Storek 		case '\n':
100955143Storek 		case '\r':
101055143Storek 			printf("\n");
101155143Storek 			*lp++ = '\0';
101259219Storek 			return (len);
101355143Storek 		case '\b':
101455143Storek 		case '\177':
101555143Storek 		case '#':
101659219Storek 			if (len) {
101759219Storek 				--len;
101859219Storek 				--lp;
101955143Storek 				printf(" \b ");
102055143Storek 			}
102155143Storek 			continue;
102255143Storek 		case '@':
102355143Storek 		case 'u'&037:
102459219Storek 			len = 0;
102555143Storek 			lp = cp;
102659219Storek 			printf("\n");
102755143Storek 			continue;
102855143Storek 		default:
102959219Storek 			if (len + 1 >= size || c < ' ') {
103059219Storek 				printf("\007");
103155143Storek 				continue;
103259219Storek 			}
103359219Storek 			printf("%c", c);
103459219Storek 			++len;
103555143Storek 			*lp++ = c;
103655143Storek 		}
103755143Storek 	}
103855143Storek }
1039