xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 63323)
155143Storek /*
2*63323Sbostic  * Copyright (c) 1992, 1993
3*63323Sbostic  *	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*63323Sbostic  *	@(#)autoconf.c	8.1 (Berkeley) 06/11/93
1755143Storek  *
1860518Storek  * from: $Header: autoconf.c,v 1.32 93/05/28 03:55:59 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) */
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 
44059219Storek 	/* Start at the beginning of the bootpath */
44159219Storek 	ra.ra_bp = bootpath;
44259219Storek 
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 
74459219Storek 	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 
75459219Storek #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 
76059219Storek static int
76159219Storek findblkmajor(dv)
76259219Storek 	register struct dkdevice *dv;
76359219Storek {
76459219Storek 	register int i;
76559219Storek 
76659219Storek 	for (i = 0; i < nblkdev; ++i)
76759219Storek 		if ((void (*)(struct buf *))bdevsw[i].d_strategy ==
76859219Storek 		    dv->dk_driver->d_strategy)
76959219Storek 			return (i);
77059219Storek 
77159219Storek 	return (-1);
77259219Storek }
77359219Storek 
77459219Storek static struct device *
77559219Storek getdisk(str, len, defpart, devp)
77659219Storek 	char *str;
77759219Storek 	int len, defpart;
77859219Storek 	dev_t *devp;
77959219Storek {
78059219Storek 	register struct device *dv;
78159219Storek 
78259219Storek 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
78359219Storek 		printf("use one of:");
78459219Storek 		for (dv = alldevs; dv != NULL; dv = dv->dv_next)
78559219Storek 			if (dv->dv_class == DV_DISK)
78659219Storek 				printf(" %s[a-h]", dv->dv_xname);
78759219Storek 		printf("\n");
78859219Storek 	}
78959219Storek 	return (dv);
79059219Storek }
79159219Storek 
79259219Storek static struct device *
79359219Storek parsedisk(str, len, defpart, devp)
79459219Storek 	char *str;
79559219Storek 	int len, defpart;
79659219Storek 	dev_t *devp;
79759219Storek {
79859219Storek 	register struct device *dv;
79959219Storek 	register char *cp;
80059219Storek 	int majdev, mindev, part;
80159219Storek 
80259219Storek 	if (len == 0)
80359219Storek 		return (NULL);
80459219Storek 	cp = str + len - 1;
80559219Storek 	if (*cp >= 'a' && *cp <= 'h') {
80659219Storek 		part = *cp - 'a';
80759219Storek 		*cp-- = '\0';
80859219Storek 	} else
80959219Storek 		part = defpart;
81059219Storek 
81159219Storek 	for (dv = alldevs; dv != NULL; dv = dv->dv_next)
81259219Storek 		if (dv->dv_class == DV_DISK &&
81359219Storek 		    strcmp(str, dv->dv_xname) == 0) {
81459219Storek 			majdev = findblkmajor((struct dkdevice *)dv);
81559219Storek 			if (majdev < 0)
81659219Storek 				panic("parsedisk");
81759219Storek 			mindev = (dv->dv_unit << PARTITIONSHIFT) + part;
81859219Storek 			*devp = makedev(majdev, mindev);
81959219Storek 			return (dv);
82059219Storek 		}
82159219Storek 
82259219Storek 	return (NULL);
82359219Storek }
82459219Storek 
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  */
83059219Storek void
83155143Storek setroot()
83255143Storek {
83359219Storek 	register struct swdevt *swp;
83459219Storek 	register struct device *dv;
83559219Storek 	register int len, majdev, mindev, part;
83659219Storek 	dev_t nrootdev, nswapdev;
83759219Storek 	char buf[128];
83859219Storek #ifdef DOSWAP
83959219Storek 	dev_t temp;
84059219Storek #endif
84159219Storek #ifdef NFS
84259219Storek 	extern int (*mountroot)(), nfs_mountroot();
84359219Storek #endif
84455143Storek 
84559219Storek 	if (boothowto & RB_ASKNAME) {
84659219Storek 		for (;;) {
84759219Storek 			printf("root device? ");
84859219Storek 			len = getstr(buf, sizeof(buf));
84959219Storek #ifdef GENERIC
85059219Storek 			if (len > 0 && buf[len - 1] == '*') {
85159219Storek 				buf[--len] = '\0';
85259219Storek 				dv = getdisk(buf, len, 1, &nrootdev);
85359219Storek 				if (dv != NULL) {
85459219Storek 					bootdv = dv;
85559219Storek 					nswapdev = nrootdev;
85660518Storek 					goto gotswap;
85759219Storek 				}
85859219Storek 			}
85959219Storek #endif
86059219Storek 			dv = getdisk(buf, len, 0, &nrootdev);
86159219Storek 			if (dv != NULL) {
86259219Storek 				bootdv = dv;
86359219Storek 				break;
86459219Storek 			}
86559219Storek 		}
86659219Storek 		for (;;) {
86759219Storek 			printf("swap device (default %sb)? ", bootdv->dv_xname);
86859219Storek 			len = getstr(buf, sizeof(buf));
86959219Storek 			if (len == 0) {
87059219Storek 				nswapdev = makedev(major(nrootdev),
87159219Storek 				    (minor(nrootdev) & ~ PARTITIONMASK) | 1);
87259219Storek 				break;
87359219Storek 			}
87459219Storek 			if (getdisk(buf, len, 1, &nswapdev) != NULL)
87559219Storek 				break;
87659219Storek 		}
87760518Storek #ifdef GENERIC
87860518Storek gotswap:
87960518Storek #endif
88059219Storek 		rootdev = nrootdev;
88159219Storek 		swapdev = nswapdev;
88259219Storek 		dumpdev = nswapdev;		/* ??? */
88359219Storek 		swdevt[0].sw_dev = nswapdev;
88459219Storek 		swdevt[1].sw_dev = NODEV;
88555143Storek 		return;
88659219Storek 	}
88759219Storek 
88859219Storek 	/* XXX currently there's no way to set RB_DFLTROOT... */
88959219Storek 	if (boothowto & RB_DFLTROOT || bootdv == NULL)
89055143Storek 		return;
89159219Storek 
89259219Storek 	switch (bootdv->dv_class) {
89359219Storek 
89459219Storek #ifdef NFS
89559219Storek 	case DV_IFNET:
89659219Storek 		mountroot = nfs_mountroot;
89759219Storek #ifdef LBL
89859219Storek 		lbl_diskless_setup();
89959219Storek #endif
90055143Storek 		return;
90159219Storek #endif
90259219Storek 
90359219Storek #if defined(FFS) || defined(LFS)
90459219Storek 	case DV_DISK:
90559219Storek 		majdev = findblkmajor((struct dkdevice *)bootdv);
90659219Storek 		if (majdev < 0)
90759219Storek 			return;
90859219Storek 		part = 0;
90959219Storek 		mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part;
91059219Storek 		break;
91159219Storek #endif
91259219Storek 
91359219Storek 	default:
91459219Storek 		printf("can't figure root, hope your kernel is right\n");
91555143Storek 		return;
91659219Storek 	}
91759219Storek 
91855143Storek 	/*
91955143Storek 	 * Form a new rootdev
92055143Storek 	 */
92159219Storek 	nrootdev = makedev(majdev, mindev);
92255143Storek 	/*
92355143Storek 	 * If the original rootdev is the same as the one
92455143Storek 	 * just calculated, don't need to adjust the swap configuration.
92555143Storek 	 */
92659219Storek 	if (rootdev == nrootdev)
92755143Storek 		return;
92855143Storek 
92959219Storek 	rootdev = nrootdev;
93059219Storek 	printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a');
93155143Storek 
93255143Storek #ifdef DOSWAP
93355143Storek 	mindev &= ~PARTITIONMASK;
93459219Storek 	temp = NODEV;
93559219Storek 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
93655143Storek 		if (majdev == major(swp->sw_dev) &&
93755143Storek 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
93855143Storek 			temp = swdevt[0].sw_dev;
93955143Storek 			swdevt[0].sw_dev = swp->sw_dev;
94055143Storek 			swp->sw_dev = temp;
94155143Storek 			break;
94255143Storek 		}
94355143Storek 	}
94459219Storek 	if (swp->sw_dev == NODEV)
94555143Storek 		return;
94655143Storek 
94755143Storek 	/*
94859219Storek 	 * If dumpdev was the same as the old primary swap device, move
94959219Storek 	 * it to the new primary swap device.
95055143Storek 	 */
95155143Storek 	if (temp == dumpdev)
95255143Storek 		dumpdev = swdevt[0].sw_dev;
95355143Storek #endif
95455143Storek }
95555143Storek 
95659219Storek static int
95759219Storek getstr(cp, size)
95855143Storek 	register char *cp;
95959219Storek 	register int size;
96055143Storek {
96155143Storek 	register char *lp;
96255143Storek 	register int c;
96359219Storek 	register int len;
96455143Storek 
96555143Storek 	lp = cp;
96659219Storek 	len = 0;
96755143Storek 	for (;;) {
96855143Storek 		c = cngetc();
96955143Storek 		switch (c) {
97055143Storek 		case '\n':
97155143Storek 		case '\r':
97255143Storek 			printf("\n");
97355143Storek 			*lp++ = '\0';
97459219Storek 			return (len);
97555143Storek 		case '\b':
97655143Storek 		case '\177':
97755143Storek 		case '#':
97859219Storek 			if (len) {
97959219Storek 				--len;
98059219Storek 				--lp;
98155143Storek 				printf(" \b ");
98255143Storek 			}
98355143Storek 			continue;
98455143Storek 		case '@':
98555143Storek 		case 'u'&037:
98659219Storek 			len = 0;
98755143Storek 			lp = cp;
98859219Storek 			printf("\n");
98955143Storek 			continue;
99055143Storek 		default:
99159219Storek 			if (len + 1 >= size || c < ' ') {
99259219Storek 				printf("\007");
99355143Storek 				continue;
99459219Storek 			}
99559219Storek 			printf("%c", c);
99659219Storek 			++len;
99755143Storek 			*lp++ = c;
99855143Storek 		}
99955143Storek 	}
100055143Storek }
1001