xref: /csrg-svn/sys/sparc/sparc/autoconf.c (revision 56541)
155143Storek /*
255143Storek  * Copyright (c) 1992 The Regents of the University of California.
355143Storek  * All rights reserved.
455143Storek  *
555143Storek  * This software was developed by the Computer Systems Engineering group
655143Storek  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755143Storek  * contributed to Berkeley.
855143Storek  *
955504Sbostic  * All advertising materials mentioning features or use of this software
1055504Sbostic  * must display the following acknowledgement:
1155504Sbostic  *	This product includes software developed by the University of
1255504Sbostic  *	California, Lawrence Berkeley Laboratories.
1355504Sbostic  *
1455143Storek  * %sccs.include.redist.c%
1555143Storek  *
16*56541Sbostic  *	@(#)autoconf.c	7.3 (Berkeley) 10/11/92
1755143Storek  *
1855143Storek  * from: $Header: autoconf.c,v 1.23 92/07/10 22:35:23 torek Exp $ (LBL)
1955143Storek  */
2055143Storek 
21*56541Sbostic #include <sys/param.h>
22*56541Sbostic #include <sys/map.h>
23*56541Sbostic #include <sys/buf.h>
24*56541Sbostic #include <sys/disklabel.h>
25*56541Sbostic #include <sys/device.h>
26*56541Sbostic #include <sys/dkstat.h>
27*56541Sbostic #include <sys/conf.h>
28*56541Sbostic #include <sys/dmap.h>
29*56541Sbostic #include <sys/reboot.h>
30*56541Sbostic #include <sys/socket.h>
31*56541Sbostic #include <sys/systm.h>
3255143Storek 
33*56541Sbostic #include <net/if.h>
3455143Storek 
35*56541Sbostic #include <machine/autoconf.h>
36*56541Sbostic #include <machine/bsd_openprom.h>
37*56541Sbostic #include <machine/cpu.h>
3855143Storek 
3955143Storek #ifndef	FS_NFS		/* XXX */
4055143Storek #define	FS_NFS	100	/* XXX */
4155143Storek #endif			/* XXX */
4255143Storek 
4355143Storek /*
4455143Storek  * The following several variables are related to
4555143Storek  * the configuration process, and are used in initializing
4655143Storek  * the machine.
4755143Storek  */
4855143Storek int	cold;		/* if 1, still working on cold-start */
4955143Storek int	dkn;		/* number of iostat dk numbers assigned so far */
5055143Storek int	cpuspeed = 10;	/* relative cpu speed */
5155143Storek int	fbnode;		/* node ID of ROM's console frame buffer */
5255143Storek int	optionsnode;	/* node ID of ROM's options */
5355143Storek 
5455143Storek extern struct promvec *promvec;
5555143Storek 
5655143Storek static	int rootnode;
5755143Storek int	findroot();
5855143Storek static	struct	bootinfo *findbootdev();
5955143Storek 
6055143Storek static	struct bootinfo {
6155143Storek 	char	name[16];	/* device name */
6255143Storek 	int	val[3];		/* up to 3 values */
6355143Storek 	int	type;		/* FS type */
6455143Storek 	caddr_t	data;		/* FS dependant info */
6555143Storek } bootinfo;
6655143Storek 
6755143Storek 
6855143Storek /*
6955143Storek  * Most configuration on the SPARC is done by matching OPENPROM Forth
7055143Storek  * device names with our internal names.
7155143Storek  */
7255143Storek int
7355143Storek matchbyname(parent, cf, aux)
7455143Storek 	struct device *parent;
7555143Storek 	struct cfdata *cf;
7655143Storek 	void *aux;
7755143Storek {
7855143Storek 
7955143Storek 	return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0);
8055143Storek }
8155143Storek 
8255143Storek /*
8355143Storek  * Convert hex ASCII string to a value.  Returns updated pointer.
8455143Storek  * Depends on ASCII order (this *is* machine-dependent code, you know).
8555143Storek  */
8655143Storek static char *
8755143Storek str2hex(str, vp)
8855143Storek 	register char *str;
8955143Storek 	register int *vp;
9055143Storek {
9155143Storek 	register int v, c;
9255143Storek 
9355143Storek 	for (v = 0;; v = v * 16 + c, str++) {
9455143Storek 		c = *(u_char *)str;
9555143Storek 		if (c <= '9') {
9655143Storek 			if ((c -= '0') < 0)
9755143Storek 				break;
9855143Storek 		} else if (c <= 'F') {
9955143Storek 			if ((c -= 'A' - 10) < 10)
10055143Storek 				break;
10155143Storek 		} else if (c <= 'f') {
10255143Storek 			if ((c -= 'a' - 10) < 10)
10355143Storek 				break;
10455143Storek 		} else
10555143Storek 			break;
10655143Storek 	}
10755143Storek 	*vp = v;
10855143Storek 	return (str);
10955143Storek }
11055143Storek 
11155143Storek /*
11255143Storek  * locore.s code calls bootstrap() just before calling main(), after double
11355143Storek  * mapping the kernel to high memory and setting up the trap base register.
11455143Storek  * We must finish mapping the kernel properly and glean any bootstrap info.
11555143Storek  */
11655143Storek void
11755143Storek bootstrap()
11855143Storek {
11955143Storek 	register char *cp, *bp, *ep;
12055143Storek 	register int i;
12155143Storek 	int nmmu, ncontext, node;
12255143Storek #ifdef KGDB
12355143Storek 	extern int kgdb_debug_panic;
12455143Storek #endif
12555143Storek 	extern char *rindex(const char *, int);
12655143Storek 
12755143Storek 	node = findroot();
12855143Storek 	nmmu = getpropint(node, "mmu-npmg", 128);
12955143Storek 	ncontext = getpropint(node, "mmu-nctx", 8);
13055143Storek 	pmap_bootstrap(nmmu, ncontext);
13155143Storek #ifdef KGDB
13255143Storek 	zs_kgdb_init();			/* XXX */
13355143Storek #endif
13455143Storek 	/*
13555143Storek 	 * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
13655143Storek 	 * that were given after the boot command.  On SS2s, pv_v0bootargs
13755143Storek 	 * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
13855143Storek 	 * "vmunix -s" or whatever.
13955143Storek 	 * ###	DO THIS BEFORE pmap_boostrap?
14055143Storek 	 */
14155143Storek 	if (promvec->pv_romvec_vers < 2) {
14255143Storek 		/* Grab boot device name and values. */
14355143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[0];
14455143Storek 		if (cp != NULL) {
14555143Storek 			bp = bootinfo.name;
14655143Storek 			ep = &bootinfo.name[sizeof(bootinfo.name)];
14755143Storek 			while (*cp != '(' && *cp != '\0' && bp < ep - 1)
14855143Storek 				*bp++ = *cp++;
14955143Storek 			*bp = '\0';
15055143Storek 
15155143Storek 			if (*cp == '(' &&
15255143Storek 			    *(cp = str2hex(++cp, &bootinfo.val[0])) == ',' &&
15355143Storek 			    *(cp = str2hex(++cp, &bootinfo.val[1])) == ',')
15455143Storek 				(void)str2hex(++cp, &bootinfo.val[2]);
15555143Storek 		}
15655143Storek 
15755143Storek 		/* Setup pointer to boot flags */
15855143Storek 		cp = (*promvec->pv_v0bootargs)->ba_argv[1];
15955143Storek 		if (cp == NULL || *cp != '-')
16055143Storek 			return;
16155143Storek 	} else {
16255143Storek 		/* Grab boot device name and values. */
16355143Storek 		cp = *promvec->pv_v2bootargs.v2_bootpath;
16455143Storek 		if (cp != NULL && (cp = rindex(cp, '/')) != NULL) {
16555143Storek 			++cp;
16655143Storek 			bp = bootinfo.name;
16755143Storek 			ep = &bootinfo.name[sizeof(bootinfo.name)];
16855143Storek 			while (*cp != '@' && *cp != '\0' && bp < ep - 1)
16955143Storek 				*bp++ = *cp++;
17055143Storek 			*bp = '\0';
17155143Storek 
17255143Storek 			if (*cp == '@' &&
17355143Storek 			    *(cp = str2hex(++cp, &bootinfo.val[0])) == ',' &&
17455143Storek 			    *(cp = str2hex(++cp, &bootinfo.val[1])) == ',')
17555143Storek 				(void)str2hex(++cp, &bootinfo.val[2]);
17655143Storek 		}
17755143Storek 
17855143Storek 		/* Setup pointer to boot flags */
17955143Storek 		cp = *promvec->pv_v2bootargs.v2_bootargs;
18055143Storek 		if (cp == NULL)
18155143Storek 			return;
18255143Storek 		while (*cp != '-')
18355143Storek 			if (*cp++ == '\0')
18455143Storek 				return;
18555143Storek 	}
18655143Storek 	for (;;) {
18755143Storek 		switch (*++cp) {
18855143Storek 
18955143Storek 		case '\0':
19055143Storek 			return;
19155143Storek 
19255143Storek 		case 'a':
19355143Storek 			boothowto |= RB_ASKNAME;
19455143Storek 			break;
19555143Storek 
19655143Storek 		case 'b':
19755143Storek 			boothowto |= RB_DFLTROOT;
19855143Storek 			break;
19955143Storek 
20055143Storek 		case 'd':	/* kgdb - always on zs	XXX */
20155143Storek #ifdef KGDB
20255143Storek 			boothowto |= RB_KDB;	/* XXX unused */
20355143Storek 			kgdb_debug_panic = 1;
20455143Storek 			kgdb_connect(1);
20555143Storek #else
20655143Storek 			printf("kernel not compiled with KGDB\n");
20755143Storek #endif
20855143Storek 			break;
20955143Storek 
21055143Storek 		case 's':
21155143Storek 			boothowto |= RB_SINGLE;
21255143Storek 			break;
21355143Storek 		}
21455143Storek 	}
21555143Storek }
21655143Storek 
21755143Storek /*
21855143Storek  * Determine mass storage and memory configuration for a machine.
21955143Storek  * We get the PROM's root device and make sure we understand it, then
22055143Storek  * attach it as `mainbus0'.  We also set up to handle the PROM `sync'
22155143Storek  * command.
22255143Storek  */
22355143Storek configure()
22455143Storek {
22555143Storek 	register int node;
22655143Storek 	register char *cp;
22755143Storek 	struct romaux ra;
22855143Storek 	void sync_crash();
22955143Storek #ifdef NFS
23055143Storek 	register struct bootinfo *bi;
23155143Storek 	extern int (*mountroot)(), nfs_mountroot();
23255143Storek #endif
23355143Storek 
23455143Storek 	node = findroot();
23555143Storek 	cp = getpropstring(node, "device_type");
23655143Storek 	if (strcmp(cp, "cpu") != 0) {
23755143Storek 		printf("PROM root device type = %s\n", cp);
23855143Storek 		panic("need CPU as root");
23955143Storek 	}
24055143Storek 	*promvec->pv_synchook = sync_crash;
24155143Storek 	ra.ra_node = node;
24255143Storek 	ra.ra_name = cp = "mainbus";
24355143Storek 	if (!config_rootfound(cp, (void *)&ra))
24455143Storek 		panic("mainbus not configured");
24555143Storek 	(void) spl0();
24655143Storek 	cold = 0;
24755143Storek #ifdef NFS
24855143Storek 	if (boothowto & RB_ASKNAME) {
24955143Storek 		char ans[100];
25055143Storek 
25155143Storek 		printf("nfs root? (y/n) [n] ");
25255143Storek 		gets(ans);
25355143Storek 		if (ans[0] == 'y')
25455143Storek 			mountroot = nfs_mountroot;
25555143Storek 	} else if ((bi = findbootdev()) != NULL && bi->type == FS_NFS) {
25655143Storek 		mountroot = nfs_mountroot;
25755143Storek #ifdef LBL
25855143Storek 		lbl_diskless_setup();
25955143Storek #endif /* LBL */
26055143Storek 	}
26155143Storek #endif /* NFS */
26255143Storek #if GENERIC
26355143Storek 	if ((boothowto & RB_ASKNAME) == 0)
26455143Storek 		setroot();
26555143Storek 	setconf();
26655143Storek #else
26755143Storek 	setroot();
26855143Storek #endif
26955143Storek 	swapconf();
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 
44055143Storek 	/*
44155143Storek 	 * Locate and configure the ``early'' devices.  These must be
44255143Storek 	 * configured before we can do the rest.  For instance, the
44355143Storek 	 * EEPROM contains the Ethernet address for the LANCE chip.
44455143Storek 	 * If the device cannot be located or configured, panic.
44555143Storek 	 */
44655143Storek 	for (ssp = special; *(sp = *ssp) != 0; ssp++) {
44755143Storek 		if ((node = findnode(node0, sp)) == 0) {
44855143Storek 			printf("could not find %s in OPENPROM\n", sp);
44955143Storek 			panic(sp);
45055143Storek 		}
45155143Storek 		if (!romprop(&ra, sp, node) ||
45255143Storek 		    !config_found(dev, (void *)&ra, mbprint))
45355143Storek 			panic(sp);
45455143Storek 	}
45555143Storek 
45655143Storek 	/*
45755143Storek 	 * Configure the rest of the devices, in PROM order.  Skip
45855143Storek 	 * PROM entries that are not for devices, or which must be
45955143Storek 	 * done before we get here.
46055143Storek 	 */
46155143Storek 	for (node = node0; node; node = nextsibling(node)) {
46255143Storek 		cp = getpropstring(node, "name");
46355143Storek 		for (ssp = special; (sp = *ssp) != NULL; ssp++)
46455143Storek 			if (strcmp(cp, sp) == 0)
46555143Storek 				break;
46655143Storek 		if (sp == NULL && romprop(&ra, cp, node)) {
46755143Storek #ifdef L1A_HACK
46855143Storek 			if (strcmp(cp, "audio") == 0)
46955143Storek 				audio = 1;
47055143Storek 			if (strcmp(cp, "zs") == 0)
47155143Storek 				nzs++;
47255143Storek 			if (audio && nzs >= 2)
47355143Storek 				(void) splx(11 << 8);	/* XXX */
47455143Storek #endif
47555143Storek 			(void) config_found(dev, (void *)&ra, mbprint);
47655143Storek 		}
47755143Storek 	}
47855143Storek }
47955143Storek 
48055143Storek struct cfdriver mainbuscd =
48155143Storek     { NULL, "mainbus", matchbyname, mainbus_attach,
48255143Storek       DV_DULL, sizeof(struct device) };
48355143Storek 
48455143Storek /*
48555143Storek  * findzs() is called from the zs driver (which is, at least in theory,
48655143Storek  * generic to any machine with a Zilog ZSCC chip).  It should return the
48755143Storek  * address of the corresponding zs channel.  It may not fail, and it
48855143Storek  * may be called before the VM code can be used.  Here we count on the
48955143Storek  * FORTH PROM to map in the required zs chips.
49055143Storek  */
49155143Storek void *
49255143Storek findzs(zs)
49355143Storek 	int zs;
49455143Storek {
49555143Storek 	register int node, addr;
49655143Storek 
49755143Storek 	node = firstchild(findroot());
49855143Storek 	while ((node = findnode(node, "zs")) != 0) {
49955143Storek 		if (getpropint(node, "slave", -1) == zs) {
50055143Storek 			if ((addr = getpropint(node, "address", 0)) == 0)
50155143Storek 				panic("findzs: zs%d not mapped by PROM", zs);
50255143Storek 			return ((void *)addr);
50355143Storek 		}
50455143Storek 		node = nextsibling(node);
50555143Storek 	}
50655143Storek 	panic("findzs: cannot find zs%d", zs);
50755143Storek 	/* NOTREACHED */
50855143Storek }
50955143Storek 
51055143Storek int
51155143Storek makememarr(ap, max, which)
51255143Storek 	register struct memarr *ap;
51355143Storek 	int max, which;
51455143Storek {
51555143Storek 	struct v2rmi {
51655143Storek 		int	zero;
51755143Storek 		int	addr;
51855143Storek 		int	len;
51955143Storek 	} v2rmi[200];		/* version 2 rom meminfo layout */
52055143Storek #define	MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
52155143Storek 	register struct v0mlist *mp;
52255143Storek 	register int i, node, len;
52355143Storek 	char *prop;
52455143Storek 
52555143Storek 	switch (i = promvec->pv_romvec_vers) {
52655143Storek 
52755143Storek 	case 0:
52855143Storek 		/*
52955143Storek 		 * Version 0 PROMs use a linked list to describe these
53055143Storek 		 * guys.
53155143Storek 		 */
53255143Storek 		switch (which) {
53355143Storek 
53455143Storek 		case MEMARR_AVAILPHYS:
53555143Storek 			mp = *promvec->pv_v0mem.v0_physavail;
53655143Storek 			break;
53755143Storek 
53855143Storek 		case MEMARR_TOTALPHYS:
53955143Storek 			mp = *promvec->pv_v0mem.v0_phystot;
54055143Storek 			break;
54155143Storek 
54255143Storek 		default:
54355143Storek 			panic("makememarr");
54455143Storek 		}
54555143Storek 		for (i = 0; mp != NULL; mp = mp->next, i++) {
54655143Storek 			if (i >= max)
54755143Storek 				goto overflow;
54855143Storek 			ap->addr = (u_int)mp->addr;
54955143Storek 			ap->len = mp->nbytes;
55055143Storek 			ap++;
55155143Storek 		}
55255143Storek 		break;
55355143Storek 
55455143Storek 	default:
55555143Storek 		printf("makememarr: hope version %d PROM is like version 2\n",
55655143Storek 		    i);
55755143Storek 		/* FALLTHROUGH */
55855143Storek 
55955143Storek 	case 2:
56055143Storek 		/*
56155143Storek 		 * Version 2 PROMs use a property array to describe them.
56255143Storek 		 */
56355143Storek 		if (max > MAXMEMINFO) {
56455143Storek 			printf("makememarr: limited to %d\n", MAXMEMINFO);
56555143Storek 			max = MAXMEMINFO;
56655143Storek 		}
56755143Storek 		if ((node = findnode(firstchild(findroot()), "memory")) == 0)
56855143Storek 			panic("makememarr: cannot find \"memory\" node");
56955143Storek 		switch (which) {
57055143Storek 
57155143Storek 		case MEMARR_AVAILPHYS:
57255143Storek 			prop = "available";
57355143Storek 			break;
57455143Storek 
57555143Storek 		case MEMARR_TOTALPHYS:
57655143Storek 			prop = "reg";
57755143Storek 			break;
57855143Storek 
57955143Storek 		default:
58055143Storek 			panic("makememarr");
58155143Storek 		}
58255143Storek 		len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
58355143Storek 		    sizeof(struct v2rmi);
58455143Storek 		for (i = 0; i < len; i++) {
58555143Storek 			if (i >= max)
58655143Storek 				goto overflow;
58755143Storek 			ap->addr = v2rmi[i].addr;
58855143Storek 			ap->len = v2rmi[i].len;
58955143Storek 			ap++;
59055143Storek 		}
59155143Storek 		break;
59255143Storek 	}
59355143Storek 
59455143Storek 	/*
59555143Storek 	 * Success!  (Hooray)
59655143Storek 	 */
59755143Storek 	if (i == 0)
59855143Storek 		panic("makememarr: no memory found");
59955143Storek 	return (i);
60055143Storek 
60155143Storek overflow:
60255143Storek 	/*
60355143Storek 	 * Oops, there are more things in the PROM than our caller
60455143Storek 	 * provided space for.  Truncate any extras.
60555143Storek 	 */
60655143Storek 	printf("makememarr: WARNING: lost some memory\n");
60755143Storek 	return (i);
60855143Storek }
60955143Storek 
61055143Storek /*
61155143Storek  * Internal form of getprop().  Returns the actual length.
61255143Storek  */
61355143Storek int
61455143Storek getprop(node, name, buf, bufsiz)
61555143Storek 	int node;
61655143Storek 	char *name;
61755143Storek 	void *buf;
61855143Storek 	register int bufsiz;
61955143Storek {
62055143Storek 	register struct nodeops *no;
62155143Storek 	register int len;
62255143Storek 
62355143Storek 	no = promvec->pv_nodeops;
62455143Storek 	len = no->no_proplen(node, name);
62555143Storek 	if (len > bufsiz) {
62655143Storek 		printf("node %x property %s length %d > %d\n",
62755143Storek 		    node, name, len, bufsiz);
62855143Storek #ifdef DEBUG
62955143Storek 		panic("getprop");
63055143Storek #else
63155143Storek 		return (0);
63255143Storek #endif
63355143Storek 	}
63455143Storek 	no->no_getprop(node, name, buf);
63555143Storek 	return (len);
63655143Storek }
63755143Storek 
63855143Storek /*
63955143Storek  * Return a string property.  There is a (small) limit on the length;
64055143Storek  * the string is fetched into a static buffer which is overwritten on
64155143Storek  * subsequent calls.
64255143Storek  */
64355143Storek char *
64455143Storek getpropstring(node, name)
64555143Storek 	int node;
64655143Storek 	char *name;
64755143Storek {
64855143Storek 	register int len;
64955143Storek 	static char stringbuf[32];
65055143Storek 
65155143Storek 	len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
65255143Storek 	stringbuf[len] = '\0';	/* usually unnecessary */
65355143Storek 	return (stringbuf);
65455143Storek }
65555143Storek 
65655143Storek /*
65755143Storek  * Fetch an integer (or pointer) property.
65855143Storek  * The return value is the property, or the default if there was none.
65955143Storek  */
66055143Storek int
66155143Storek getpropint(node, name, deflt)
66255143Storek 	int node;
66355143Storek 	char *name;
66455143Storek 	int deflt;
66555143Storek {
66655143Storek 	register int len;
66755143Storek 	char intbuf[16];
66855143Storek 
66955143Storek 	len = getprop(node, name, (void *)intbuf, sizeof intbuf);
67055143Storek 	if (len != 4)
67155143Storek 		return (deflt);
67255143Storek 	return (*(int *)intbuf);
67355143Storek }
67455143Storek 
67555143Storek /*
67655143Storek  * OPENPROM functions.  These are here mainly to hide the OPENPROM interface
67755143Storek  * from the rest of the kernel.
67855143Storek  */
67955143Storek int
68055143Storek firstchild(node)
68155143Storek 	int node;
68255143Storek {
68355143Storek 
68455143Storek 	return (promvec->pv_nodeops->no_child(node));
68555143Storek }
68655143Storek 
68755143Storek int
68855143Storek nextsibling(node)
68955143Storek 	int node;
69055143Storek {
69155143Storek 
69255143Storek 	return (promvec->pv_nodeops->no_nextnode(node));
69355143Storek }
69455143Storek 
69555143Storek /* Pass a string to the FORTH PROM to be interpreted */
69655143Storek void
69755143Storek rominterpret(s)
69855143Storek 	register char *s;
69955143Storek {
70055143Storek 
70155143Storek 	if (promvec->pv_romvec_vers < 2)
70255143Storek 		promvec->pv_fortheval.v0_eval(strlen(s), s);
70355143Storek 	else
70455143Storek 		promvec->pv_fortheval.v2_eval(s);
70555143Storek }
70655143Storek 
70755143Storek volatile void
70855143Storek romhalt()
70955143Storek {
71055143Storek 
71155143Storek 	promvec->pv_halt();
71255143Storek 	panic("PROM exit failed");
71355143Storek }
71455143Storek 
71555143Storek volatile void
71655143Storek romboot(str)
71755143Storek 	char *str;
71855143Storek {
71955143Storek 
72055143Storek 	promvec->pv_reboot(str);
72155143Storek 	panic("PROM boot failed");
72255143Storek }
72355143Storek 
72455143Storek callrom()
72555143Storek {
72655143Storek 
72755143Storek #ifdef notdef		/* sun4c FORTH PROMs do this for us */
72855143Storek 	fb_unblank();
72955143Storek #endif
73055143Storek 	promvec->pv_abort();
73155143Storek }
73255143Storek 
73355143Storek /*
73455143Storek  * Configure swap space and related parameters.
73555143Storek  */
73655143Storek swapconf()
73755143Storek {
73855143Storek 	register struct swdevt *swp;
73955143Storek 	register int nblks;
74055143Storek 
74155143Storek 	for (swp = swdevt; swp->sw_dev; swp++)
74255143Storek 		if (bdevsw[major(swp->sw_dev)].d_psize) {
74355143Storek 			nblks =
74455143Storek 			  (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev);
74555143Storek 			if (nblks != -1 &&
74655143Storek 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
74755143Storek 				swp->sw_nblks = nblks;
74855143Storek 		}
74955143Storek 	dumpconf();
75055143Storek }
75155143Storek 
75255143Storek #define	DOSWAP			/* Change swdevt, argdev, and dumpdev too */
75355143Storek u_long	bootdev;		/* should be dev_t, but not until 32 bits */
75455143Storek 
75555143Storek static	char devname[][2] = {
75655143Storek 	0,0,		/* 0 = xx */
75755143Storek };
75855143Storek 
75955143Storek #define	PARTITIONMASK	0x7
76055143Storek #define	PARTITIONSHIFT	3
76155143Storek 
76255143Storek /*
76355143Storek  * Attempt to find the device from which we were booted.
76455143Storek  * If we can do so, and not instructed not to do so,
76555143Storek  * change rootdev to correspond to the load device.
76655143Storek  */
76755143Storek setroot()
76855143Storek {
76955143Storek #ifdef notyet
77055143Storek 	struct swdevt *swp;
77155143Storek 
77255143Storek 	if (boothowto & RB_DFLTROOT ||
77355143Storek 	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
77455143Storek 		return;
77555143Storek 	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
77655143Storek 	if (majdev > sizeof(devname) / sizeof(devname[0]))
77755143Storek 		return;
77855143Storek 	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
77955143Storek 	part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
78055143Storek 	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
78155143Storek 	/*
78255143Storek 	 * First, find the controller type which support this device.
78355143Storek 	 */
78455143Storek 	for (hd = hp_dinit; hd->hp_driver; hd++)
78555143Storek 		if (hd->hp_driver->d_name[0] == devname[majdev][0] &&
78655143Storek 		    hd->hp_driver->d_name[1] == devname[majdev][1])
78755143Storek 			break;
78855143Storek 	if (hd->hp_driver == 0)
78955143Storek 		return;
79055143Storek 	/*
79155143Storek 	 * Next, find the controller of that type corresponding to
79255143Storek 	 * the adaptor number.
79355143Storek 	 */
79455143Storek 	for (hc = hp_cinit; hc->hp_driver; hc++)
79555143Storek 		if (hc->hp_alive && hc->hp_unit == adaptor &&
79655143Storek 		    hc->hp_driver == hd->hp_cdriver)
79755143Storek 			break;
79855143Storek 	if (hc->hp_driver == 0)
79955143Storek 		return;
80055143Storek 	/*
80155143Storek 	 * Finally, find the device in question attached to that controller.
80255143Storek 	 */
80355143Storek 	for (hd = hp_dinit; hd->hp_driver; hd++)
80455143Storek 		if (hd->hp_alive && hd->hp_slave == unit &&
80555143Storek 		    hd->hp_cdriver == hc->hp_driver &&
80655143Storek 		    hd->hp_ctlr == hc->hp_unit)
80755143Storek 			break;
80855143Storek 	if (hd->hp_driver == 0)
80955143Storek 		return;
81055143Storek 	mindev = hd->hp_unit;
81155143Storek 	/*
81255143Storek 	 * Form a new rootdev
81355143Storek 	 */
81455143Storek 	mindev = (mindev << PARTITIONSHIFT) + part;
81555143Storek 	orootdev = rootdev;
81655143Storek 	rootdev = makedev(majdev, mindev);
81755143Storek 	/*
81855143Storek 	 * If the original rootdev is the same as the one
81955143Storek 	 * just calculated, don't need to adjust the swap configuration.
82055143Storek 	 */
82155143Storek 	if (rootdev == orootdev)
82255143Storek 		return;
82355143Storek 
82455143Storek 	printf("Changing root device to %c%c%d%c\n",
82555143Storek 		devname[majdev][0], devname[majdev][1],
82655143Storek 		mindev >> PARTITIONSHIFT, part + 'a');
82755143Storek 
82855143Storek #ifdef DOSWAP
82955143Storek 	mindev &= ~PARTITIONMASK;
83055143Storek 	for (swp = swdevt; swp->sw_dev; swp++) {
83155143Storek 		if (majdev == major(swp->sw_dev) &&
83255143Storek 		    mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
83355143Storek 			temp = swdevt[0].sw_dev;
83455143Storek 			swdevt[0].sw_dev = swp->sw_dev;
83555143Storek 			swp->sw_dev = temp;
83655143Storek 			break;
83755143Storek 		}
83855143Storek 	}
83955143Storek 	if (swp->sw_dev == 0)
84055143Storek 		return;
84155143Storek 
84255143Storek 	/*
84355143Storek 	 * If argdev and dumpdev were the same as the old primary swap
84455143Storek 	 * device, move them to the new primary swap device.
84555143Storek 	 */
84655143Storek 	if (temp == dumpdev)
84755143Storek 		dumpdev = swdevt[0].sw_dev;
84855143Storek 	if (temp == argdev)
84955143Storek 		argdev = swdevt[0].sw_dev;
85055143Storek #endif
85155143Storek #endif
85255143Storek }
85355143Storek 
85455143Storek /*
85555143Storek  * Return pointer to device we booted from. Return NULL if we can't
85655143Storek  * figure this out.
85755143Storek  * XXX currently only works for network devices.
85855143Storek  */
85955143Storek 
86055143Storek static struct bootinfo *
86155143Storek findbootdev()
86255143Storek {
86355143Storek 	register struct bootinfo *bi;
86455143Storek 	register char *bp;
86555143Storek 	register int unit, controller;
86655143Storek 	register struct ifnet *ifp;
86755143Storek 
86855143Storek 	bi = &bootinfo;
86955143Storek 	bp = bi->name;
87055143Storek printf("findbootdev: (v%d rom) trying \"%s(%x,%x,%x)\"... ",
87155143Storek     promvec->pv_romvec_vers, bp, bi->val[0], bi->val[1], bi->val[2]);
87255143Storek 
87355143Storek 	/* Try network devices first */
87455143Storek 	unit = bi->val[0];
87555143Storek 	for (ifp = ifnet; ifp; ifp = ifp->if_next)
87655143Storek 		if (unit == ifp->if_unit && strcmp(bp, ifp->if_name) == 0) {
87755143Storek printf("found \"%s%d\"\n", ifp->if_name, ifp->if_unit);
87855143Storek 			bi->type = FS_NFS;
87955143Storek 			bi->data = (caddr_t)ifp;
88055143Storek 			return (bi);
88155143Storek 		}
88255143Storek printf("not found\n");
88355143Storek 	return (NULL);
88455143Storek }
88555143Storek 
88655143Storek gets(cp)
88755143Storek 	register char *cp;
88855143Storek {
88955143Storek 	register char *lp;
89055143Storek 	register int c;
89155143Storek 
89255143Storek 	lp = cp;
89355143Storek 	for (;;) {
89455143Storek 		c = cngetc();
89555143Storek 		switch (c) {
89655143Storek 		case '\n':
89755143Storek 		case '\r':
89855143Storek 			printf("\n");
89955143Storek 			*lp++ = '\0';
90055143Storek 			return;
90155143Storek 		case '\b':
90255143Storek 		case '\177':
90355143Storek 		case '#':
90455143Storek 			if (lp > cp) {
90555143Storek 				lp--;
90655143Storek 				printf(" \b ");
90755143Storek 			}
90855143Storek 			continue;
90955143Storek 		case '@':
91055143Storek 		case 'u'&037:
91155143Storek 			lp = cp;
91255143Storek 			cnputc('\n');
91355143Storek 			continue;
91455143Storek 		default:
91555143Storek 			if (c < ' ')
91655143Storek 				continue;
91755143Storek 			cnputc(c);
91855143Storek 			*lp++ = c;
91955143Storek 		}
92055143Storek 	}
92155143Storek }
922