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