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 12*59219Storek * California, Lawrence Berkeley Laboratory. 1355504Sbostic * 1455143Storek * %sccs.include.redist.c% 1555143Storek * 16*59219Storek * @(#)autoconf.c 7.4 (Berkeley) 04/20/93 1755143Storek * 18*59219Storek * from: $Header: autoconf.c,v 1.31 93/04/07 01:34:47 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> 26*59219Storek #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 50*59219Storek extern struct promvec *promvec; 5155143Storek 5255143Storek static int rootnode; 53*59219Storek int findroot __P((void)); 54*59219Storek void setroot __P((void)); 55*59219Storek static int getstr __P((char *, int)); 56*59219Storek static int findblkmajor __P((struct dkdevice *)); 57*59219Storek static struct device *getdisk __P((char *, int, int, dev_t *)); 58*59219Storek static struct device *parsedisk __P((char *, int, int, dev_t *)); 5955143Storek 60*59219Storek 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 { 113*59219Storek register char *cp, *pp; 114*59219Storek register struct bootpath *bp; 115*59219Storek 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 */ 135*59219Storek 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) { 140*59219Storek /* Kludge something up */ 141*59219Storek pp = cp + 2; 142*59219Storek v0val[0] = v0val[1] = v0val[2] = 0; 143*59219Storek if (*pp == '(' && 144*59219Storek *(pp = str2hex(++pp, &v0val[0])) == ',' && 145*59219Storek *(pp = str2hex(++pp, &v0val[1])) == ',') 146*59219Storek (void)str2hex(++pp, &v0val[2]); 14755143Storek 148*59219Storek /* Assume sbus0 */ 149*59219Storek strcpy(bp->name, "sbus"); 150*59219Storek bp->val[0] = 0; 151*59219Storek ++bp; 152*59219Storek 153*59219Storek if (cp[0] == 'l' && cp[1] == 'e') { 154*59219Storek /* le */ 155*59219Storek strcpy(bp->name, "le"); 156*59219Storek bp->val[0] = -1; 157*59219Storek bp->val[1] = v0val[0]; 158*59219Storek } else { 159*59219Storek /* sd or maybe st; assume espN */ 160*59219Storek strcpy(bp->name, "esp"); 161*59219Storek bp->val[0] = -1; 162*59219Storek bp->val[1] = v0val[0]; 163*59219Storek 164*59219Storek /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */ 165*59219Storek #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v)) 166*59219Storek 167*59219Storek ++bp; 168*59219Storek bp->name[0] = cp[0]; 169*59219Storek bp->name[1] = cp[1]; 170*59219Storek bp->name[2] = '\0'; 171*59219Storek bp->val[0] = CRAZYMAP(v0val[1]); 172*59219Storek bp->val[1] = v0val[2]; 173*59219Storek } 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 { 181*59219Storek /* Grab boot path */ 18255143Storek cp = *promvec->pv_v2bootargs.v2_bootpath; 183*59219Storek while (cp != NULL && *cp == '/') { 184*59219Storek /* Step over '/' */ 18555143Storek ++cp; 186*59219Storek /* Extract name */ 187*59219Storek pp = bp->name; 188*59219Storek while (*cp != '@' && *cp != '/' && *cp != '\0') 189*59219Storek *pp++ = *cp++; 190*59219Storek *pp = '\0'; 19155143Storek 192*59219Storek if (*cp == '@') { 193*59219Storek cp = str2hex(++cp, &bp->val[0]); 194*59219Storek if (*cp == ',') 195*59219Storek cp = str2hex(++cp, &bp->val[1]); 196*59219Storek } 197*59219Storek ++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"); 263*59219Storek (void)spl0(); 264*59219Storek if (bootdv) 265*59219Storek printf("Found boot device %s\n", bootdv->dv_xname); 26655143Storek cold = 0; 26755143Storek setroot(); 26855143Storek swapconf(); 269*59219Storek 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 440*59219Storek /* Start at the beginning of the bootpath */ 441*59219Storek ra.ra_bp = bootpath; 442*59219Storek 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 744*59219Storek 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 754*59219Storek #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 760*59219Storek static int 761*59219Storek findblkmajor(dv) 762*59219Storek register struct dkdevice *dv; 763*59219Storek { 764*59219Storek register int i; 765*59219Storek 766*59219Storek for (i = 0; i < nblkdev; ++i) 767*59219Storek if ((void (*)(struct buf *))bdevsw[i].d_strategy == 768*59219Storek dv->dk_driver->d_strategy) 769*59219Storek return (i); 770*59219Storek 771*59219Storek return (-1); 772*59219Storek } 773*59219Storek 774*59219Storek static struct device * 775*59219Storek getdisk(str, len, defpart, devp) 776*59219Storek char *str; 777*59219Storek int len, defpart; 778*59219Storek dev_t *devp; 779*59219Storek { 780*59219Storek register struct device *dv; 781*59219Storek 782*59219Storek if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 783*59219Storek printf("use one of:"); 784*59219Storek for (dv = alldevs; dv != NULL; dv = dv->dv_next) 785*59219Storek if (dv->dv_class == DV_DISK) 786*59219Storek printf(" %s[a-h]", dv->dv_xname); 787*59219Storek printf("\n"); 788*59219Storek } 789*59219Storek return (dv); 790*59219Storek } 791*59219Storek 792*59219Storek static struct device * 793*59219Storek parsedisk(str, len, defpart, devp) 794*59219Storek char *str; 795*59219Storek int len, defpart; 796*59219Storek dev_t *devp; 797*59219Storek { 798*59219Storek register struct device *dv; 799*59219Storek register char *cp; 800*59219Storek int majdev, mindev, part; 801*59219Storek 802*59219Storek if (len == 0) 803*59219Storek return (NULL); 804*59219Storek cp = str + len - 1; 805*59219Storek if (*cp >= 'a' && *cp <= 'h') { 806*59219Storek part = *cp - 'a'; 807*59219Storek *cp-- = '\0'; 808*59219Storek } else 809*59219Storek part = defpart; 810*59219Storek 811*59219Storek for (dv = alldevs; dv != NULL; dv = dv->dv_next) 812*59219Storek if (dv->dv_class == DV_DISK && 813*59219Storek strcmp(str, dv->dv_xname) == 0) { 814*59219Storek majdev = findblkmajor((struct dkdevice *)dv); 815*59219Storek if (majdev < 0) 816*59219Storek panic("parsedisk"); 817*59219Storek mindev = (dv->dv_unit << PARTITIONSHIFT) + part; 818*59219Storek *devp = makedev(majdev, mindev); 819*59219Storek return (dv); 820*59219Storek } 821*59219Storek 822*59219Storek return (NULL); 823*59219Storek } 824*59219Storek 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 */ 830*59219Storek void 83155143Storek setroot() 83255143Storek { 833*59219Storek register struct swdevt *swp; 834*59219Storek register struct device *dv; 835*59219Storek register int len, majdev, mindev, part; 836*59219Storek dev_t nrootdev, nswapdev; 837*59219Storek char buf[128]; 838*59219Storek #ifdef DOSWAP 839*59219Storek dev_t temp; 840*59219Storek #endif 841*59219Storek #ifdef NFS 842*59219Storek extern int (*mountroot)(), nfs_mountroot(); 843*59219Storek #endif 84455143Storek 845*59219Storek if (boothowto & RB_ASKNAME) { 846*59219Storek for (;;) { 847*59219Storek printf("root device? "); 848*59219Storek len = getstr(buf, sizeof(buf)); 849*59219Storek #ifdef GENERIC 850*59219Storek if (len > 0 && buf[len - 1] == '*') { 851*59219Storek buf[--len] = '\0'; 852*59219Storek dv = getdisk(buf, len, 1, &nrootdev); 853*59219Storek if (dv != NULL) { 854*59219Storek bootdv = dv; 855*59219Storek nswapdev = nrootdev; 856*59219Storek swaponroot++; 857*59219Storek goto setswap; 858*59219Storek } 859*59219Storek } 860*59219Storek #endif 861*59219Storek dv = getdisk(buf, len, 0, &nrootdev); 862*59219Storek if (dv != NULL) { 863*59219Storek bootdv = dv; 864*59219Storek break; 865*59219Storek } 866*59219Storek } 867*59219Storek for (;;) { 868*59219Storek printf("swap device (default %sb)? ", bootdv->dv_xname); 869*59219Storek len = getstr(buf, sizeof(buf)); 870*59219Storek if (len == 0) { 871*59219Storek nswapdev = makedev(major(nrootdev), 872*59219Storek (minor(nrootdev) & ~ PARTITIONMASK) | 1); 873*59219Storek break; 874*59219Storek } 875*59219Storek if (getdisk(buf, len, 1, &nswapdev) != NULL) 876*59219Storek break; 877*59219Storek } 878*59219Storek rootdev = nrootdev; 879*59219Storek swapdev = nswapdev; 880*59219Storek dumpdev = nswapdev; /* ??? */ 881*59219Storek swdevt[0].sw_dev = nswapdev; 882*59219Storek swdevt[1].sw_dev = NODEV; 88355143Storek return; 884*59219Storek } 885*59219Storek 886*59219Storek /* XXX currently there's no way to set RB_DFLTROOT... */ 887*59219Storek if (boothowto & RB_DFLTROOT || bootdv == NULL) 88855143Storek return; 889*59219Storek 890*59219Storek switch (bootdv->dv_class) { 891*59219Storek 892*59219Storek #ifdef NFS 893*59219Storek case DV_IFNET: 894*59219Storek mountroot = nfs_mountroot; 895*59219Storek #ifdef LBL 896*59219Storek lbl_diskless_setup(); 897*59219Storek #endif 89855143Storek return; 899*59219Storek #endif 900*59219Storek 901*59219Storek #if defined(FFS) || defined(LFS) 902*59219Storek case DV_DISK: 903*59219Storek majdev = findblkmajor((struct dkdevice *)bootdv); 904*59219Storek if (majdev < 0) 905*59219Storek return; 906*59219Storek part = 0; 907*59219Storek mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part; 908*59219Storek break; 909*59219Storek #endif 910*59219Storek 911*59219Storek default: 912*59219Storek printf("can't figure root, hope your kernel is right\n"); 91355143Storek return; 914*59219Storek } 915*59219Storek 91655143Storek /* 91755143Storek * Form a new rootdev 91855143Storek */ 919*59219Storek nrootdev = makedev(majdev, mindev); 92055143Storek /* 92155143Storek * If the original rootdev is the same as the one 92255143Storek * just calculated, don't need to adjust the swap configuration. 92355143Storek */ 924*59219Storek if (rootdev == nrootdev) 92555143Storek return; 92655143Storek 927*59219Storek rootdev = nrootdev; 928*59219Storek printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a'); 92955143Storek 93055143Storek #ifdef DOSWAP 93155143Storek mindev &= ~PARTITIONMASK; 932*59219Storek temp = NODEV; 933*59219Storek for (swp = swdevt; swp->sw_dev != NODEV; swp++) { 93455143Storek if (majdev == major(swp->sw_dev) && 93555143Storek mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { 93655143Storek temp = swdevt[0].sw_dev; 93755143Storek swdevt[0].sw_dev = swp->sw_dev; 93855143Storek swp->sw_dev = temp; 93955143Storek break; 94055143Storek } 94155143Storek } 942*59219Storek if (swp->sw_dev == NODEV) 94355143Storek return; 94455143Storek 94555143Storek /* 946*59219Storek * If dumpdev was the same as the old primary swap device, move 947*59219Storek * it to the new primary swap device. 94855143Storek */ 94955143Storek if (temp == dumpdev) 95055143Storek dumpdev = swdevt[0].sw_dev; 95155143Storek #endif 95255143Storek } 95355143Storek 954*59219Storek static int 955*59219Storek getstr(cp, size) 95655143Storek register char *cp; 957*59219Storek register int size; 95855143Storek { 95955143Storek register char *lp; 96055143Storek register int c; 961*59219Storek register int len; 96255143Storek 96355143Storek lp = cp; 964*59219Storek len = 0; 96555143Storek for (;;) { 96655143Storek c = cngetc(); 96755143Storek switch (c) { 96855143Storek case '\n': 96955143Storek case '\r': 97055143Storek printf("\n"); 97155143Storek *lp++ = '\0'; 972*59219Storek return (len); 97355143Storek case '\b': 97455143Storek case '\177': 97555143Storek case '#': 976*59219Storek if (len) { 977*59219Storek --len; 978*59219Storek --lp; 97955143Storek printf(" \b "); 98055143Storek } 98155143Storek continue; 98255143Storek case '@': 98355143Storek case 'u'&037: 984*59219Storek len = 0; 98555143Storek lp = cp; 986*59219Storek printf("\n"); 98755143Storek continue; 98855143Storek default: 989*59219Storek if (len + 1 >= size || c < ' ') { 990*59219Storek printf("\007"); 99155143Storek continue; 992*59219Storek } 993*59219Storek printf("%c", c); 994*59219Storek ++len; 99555143Storek *lp++ = c; 99655143Storek } 99755143Storek } 99855143Storek } 999