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*64662Storek * @(#)autoconf.c 8.2 (Berkeley) 09/27/93 1755143Storek * 18*64662Storek * from: $Header: autoconf.c,v 1.35 93/09/27 00:50:04 torek Exp $ (LBL) 1955143Storek */ 2055143Storek 2156541Sbostic #include <sys/param.h> 2256541Sbostic #include <sys/map.h> 2356541Sbostic #include <sys/buf.h> 2456541Sbostic #include <sys/disklabel.h> 2556541Sbostic #include <sys/device.h> 2659219Storek #include <sys/disk.h> 2756541Sbostic #include <sys/dkstat.h> 2856541Sbostic #include <sys/conf.h> 2956541Sbostic #include <sys/dmap.h> 3056541Sbostic #include <sys/reboot.h> 3156541Sbostic #include <sys/socket.h> 3256541Sbostic #include <sys/systm.h> 3355143Storek 3456541Sbostic #include <net/if.h> 3555143Storek 3656541Sbostic #include <machine/autoconf.h> 3756541Sbostic #include <machine/bsd_openprom.h> 3856541Sbostic #include <machine/cpu.h> 3955143Storek 4055143Storek /* 4155143Storek * The following several variables are related to 4255143Storek * the configuration process, and are used in initializing 4355143Storek * the machine. 4455143Storek */ 4555143Storek int cold; /* if 1, still working on cold-start */ 4655143Storek int dkn; /* number of iostat dk numbers assigned so far */ 4755143Storek int fbnode; /* node ID of ROM's console frame buffer */ 4855143Storek int optionsnode; /* node ID of ROM's options */ 4955143Storek 5059219Storek extern struct promvec *promvec; 5155143Storek 5255143Storek static int rootnode; 5359219Storek int findroot __P((void)); 5459219Storek void setroot __P((void)); 5559219Storek static int getstr __P((char *, int)); 5659219Storek static int findblkmajor __P((struct dkdevice *)); 5759219Storek static struct device *getdisk __P((char *, int, int, dev_t *)); 5859219Storek static struct device *parsedisk __P((char *, int, int, dev_t *)); 5955143Storek 6059219Storek struct bootpath bootpath[8]; 6155143Storek 6255143Storek /* 6355143Storek * Most configuration on the SPARC is done by matching OPENPROM Forth 6455143Storek * device names with our internal names. 6555143Storek */ 6655143Storek int 6755143Storek matchbyname(parent, cf, aux) 6855143Storek struct device *parent; 6955143Storek struct cfdata *cf; 7055143Storek void *aux; 7155143Storek { 7255143Storek 7355143Storek return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0); 7455143Storek } 7555143Storek 7655143Storek /* 7755143Storek * Convert hex ASCII string to a value. Returns updated pointer. 7855143Storek * Depends on ASCII order (this *is* machine-dependent code, you know). 7955143Storek */ 8055143Storek static char * 8155143Storek str2hex(str, vp) 8255143Storek register char *str; 8355143Storek register int *vp; 8455143Storek { 8555143Storek register int v, c; 8655143Storek 8755143Storek for (v = 0;; v = v * 16 + c, str++) { 8855143Storek c = *(u_char *)str; 8955143Storek if (c <= '9') { 9055143Storek if ((c -= '0') < 0) 9155143Storek break; 9255143Storek } else if (c <= 'F') { 9355143Storek if ((c -= 'A' - 10) < 10) 9455143Storek break; 9555143Storek } else if (c <= 'f') { 9655143Storek if ((c -= 'a' - 10) < 10) 9755143Storek break; 9855143Storek } else 9955143Storek break; 10055143Storek } 10155143Storek *vp = v; 10255143Storek return (str); 10355143Storek } 10455143Storek 10555143Storek /* 10655143Storek * locore.s code calls bootstrap() just before calling main(), after double 10755143Storek * mapping the kernel to high memory and setting up the trap base register. 10855143Storek * We must finish mapping the kernel properly and glean any bootstrap info. 10955143Storek */ 11055143Storek void 11155143Storek bootstrap() 11255143Storek { 11359219Storek register char *cp, *pp; 11459219Storek register struct bootpath *bp; 11559219Storek int v0val[3]; 11655143Storek int nmmu, ncontext, node; 11755143Storek #ifdef KGDB 11855143Storek extern int kgdb_debug_panic; 11955143Storek #endif 12055143Storek 12155143Storek node = findroot(); 12255143Storek nmmu = getpropint(node, "mmu-npmg", 128); 12355143Storek ncontext = getpropint(node, "mmu-nctx", 8); 12455143Storek pmap_bootstrap(nmmu, ncontext); 12555143Storek #ifdef KGDB 12655143Storek zs_kgdb_init(); /* XXX */ 12755143Storek #endif 12855143Storek /* 12955143Storek * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags 13055143Storek * that were given after the boot command. On SS2s, pv_v0bootargs 13155143Storek * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to 13255143Storek * "vmunix -s" or whatever. 13355143Storek * ### DO THIS BEFORE pmap_boostrap? 13455143Storek */ 13559219Storek bp = bootpath; 13655143Storek if (promvec->pv_romvec_vers < 2) { 13755143Storek /* Grab boot device name and values. */ 13855143Storek cp = (*promvec->pv_v0bootargs)->ba_argv[0]; 13955143Storek if (cp != NULL) { 14059219Storek /* Kludge something up */ 14159219Storek pp = cp + 2; 14259219Storek v0val[0] = v0val[1] = v0val[2] = 0; 14359219Storek if (*pp == '(' && 14459219Storek *(pp = str2hex(++pp, &v0val[0])) == ',' && 14559219Storek *(pp = str2hex(++pp, &v0val[1])) == ',') 14659219Storek (void)str2hex(++pp, &v0val[2]); 14755143Storek 14859219Storek /* Assume sbus0 */ 14959219Storek strcpy(bp->name, "sbus"); 15059219Storek bp->val[0] = 0; 15159219Storek ++bp; 15259219Storek 15359219Storek if (cp[0] == 'l' && cp[1] == 'e') { 15459219Storek /* le */ 15559219Storek strcpy(bp->name, "le"); 15659219Storek bp->val[0] = -1; 15759219Storek bp->val[1] = v0val[0]; 15859219Storek } else { 15959219Storek /* sd or maybe st; assume espN */ 16059219Storek strcpy(bp->name, "esp"); 16159219Storek bp->val[0] = -1; 16259219Storek bp->val[1] = v0val[0]; 16359219Storek 16459219Storek /* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */ 16559219Storek #define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v)) 16659219Storek 16759219Storek ++bp; 16859219Storek bp->name[0] = cp[0]; 16959219Storek bp->name[1] = cp[1]; 17059219Storek bp->name[2] = '\0'; 17159219Storek bp->val[0] = CRAZYMAP(v0val[1]); 17259219Storek bp->val[1] = v0val[2]; 17359219Storek } 17455143Storek } 17555143Storek 17655143Storek /* Setup pointer to boot flags */ 17755143Storek cp = (*promvec->pv_v0bootargs)->ba_argv[1]; 17855143Storek if (cp == NULL || *cp != '-') 17955143Storek return; 18055143Storek } else { 18159219Storek /* Grab boot path */ 18255143Storek cp = *promvec->pv_v2bootargs.v2_bootpath; 18359219Storek while (cp != NULL && *cp == '/') { 18459219Storek /* Step over '/' */ 18555143Storek ++cp; 18659219Storek /* Extract name */ 18759219Storek pp = bp->name; 18859219Storek while (*cp != '@' && *cp != '/' && *cp != '\0') 18959219Storek *pp++ = *cp++; 19059219Storek *pp = '\0'; 19155143Storek 19259219Storek if (*cp == '@') { 19359219Storek cp = str2hex(++cp, &bp->val[0]); 19459219Storek if (*cp == ',') 19559219Storek cp = str2hex(++cp, &bp->val[1]); 19659219Storek } 19759219Storek ++bp; 19855143Storek } 19955143Storek 20055143Storek /* Setup pointer to boot flags */ 20155143Storek cp = *promvec->pv_v2bootargs.v2_bootargs; 20255143Storek if (cp == NULL) 20355143Storek return; 20455143Storek while (*cp != '-') 20555143Storek if (*cp++ == '\0') 20655143Storek return; 20755143Storek } 20855143Storek for (;;) { 20955143Storek switch (*++cp) { 21055143Storek 21155143Storek case '\0': 21255143Storek return; 21355143Storek 21455143Storek case 'a': 21555143Storek boothowto |= RB_ASKNAME; 21655143Storek break; 21755143Storek 21855143Storek case 'b': 21955143Storek boothowto |= RB_DFLTROOT; 22055143Storek break; 22155143Storek 22255143Storek case 'd': /* kgdb - always on zs XXX */ 22355143Storek #ifdef KGDB 22455143Storek boothowto |= RB_KDB; /* XXX unused */ 22555143Storek kgdb_debug_panic = 1; 22655143Storek kgdb_connect(1); 22755143Storek #else 22855143Storek printf("kernel not compiled with KGDB\n"); 22955143Storek #endif 23055143Storek break; 23155143Storek 23255143Storek case 's': 23355143Storek boothowto |= RB_SINGLE; 23455143Storek break; 23555143Storek } 23655143Storek } 23755143Storek } 23855143Storek 23955143Storek /* 24055143Storek * Determine mass storage and memory configuration for a machine. 24155143Storek * We get the PROM's root device and make sure we understand it, then 24255143Storek * attach it as `mainbus0'. We also set up to handle the PROM `sync' 24355143Storek * command. 24455143Storek */ 24555143Storek configure() 24655143Storek { 24755143Storek register int node; 24855143Storek register char *cp; 24955143Storek struct romaux ra; 25055143Storek void sync_crash(); 25155143Storek 25255143Storek node = findroot(); 25355143Storek cp = getpropstring(node, "device_type"); 25455143Storek if (strcmp(cp, "cpu") != 0) { 25555143Storek printf("PROM root device type = %s\n", cp); 25655143Storek panic("need CPU as root"); 25755143Storek } 25855143Storek *promvec->pv_synchook = sync_crash; 25955143Storek ra.ra_node = node; 26055143Storek ra.ra_name = cp = "mainbus"; 26155143Storek if (!config_rootfound(cp, (void *)&ra)) 26255143Storek panic("mainbus not configured"); 26359219Storek (void)spl0(); 26459219Storek if (bootdv) 26559219Storek printf("Found boot device %s\n", bootdv->dv_xname); 26655143Storek cold = 0; 26755143Storek setroot(); 26855143Storek swapconf(); 26959219Storek dumpconf(); 27055143Storek } 27155143Storek 27255143Storek /* 27355143Storek * Console `sync' command. SunOS just does a `panic: zero' so I guess 27455143Storek * no one really wants anything fancy... 27555143Storek */ 27655143Storek void 27755143Storek sync_crash() 27855143Storek { 27955143Storek 28055143Storek panic("PROM sync command"); 28155143Storek } 28255143Storek 28355143Storek char * 28455143Storek clockfreq(freq) 28555143Storek register int freq; 28655143Storek { 28755143Storek register char *p; 28855143Storek static char buf[10]; 28955143Storek 29055143Storek freq /= 1000; 29155143Storek sprintf(buf, "%d", freq / 1000); 29255143Storek freq %= 1000; 29355143Storek if (freq) { 29455143Storek freq += 1000; /* now in 1000..1999 */ 29555143Storek p = buf + strlen(buf); 29655143Storek sprintf(p, "%d", freq); 29755143Storek *p = '.'; /* now buf = %d.%3d */ 29855143Storek } 29955143Storek return (buf); 30055143Storek } 30155143Storek 30255143Storek /* ARGSUSED */ 30355143Storek static int 30455143Storek mbprint(aux, name) 30555143Storek void *aux; 30655143Storek char *name; 30755143Storek { 30855143Storek register struct romaux *ra = aux; 30955143Storek 31055143Storek if (name) 31155143Storek printf("%s at %s", ra->ra_name, name); 31255143Storek if (ra->ra_paddr) 31355143Storek printf(" %saddr 0x%x", ra->ra_iospace ? "io" : "", 31455143Storek (int)ra->ra_paddr); 31555143Storek return (UNCONF); 31655143Storek } 31755143Storek 31855143Storek int 31955143Storek findroot() 32055143Storek { 32155143Storek register int node; 32255143Storek 32355143Storek if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0) 32455143Storek panic("no PROM root device"); 32555143Storek rootnode = node; 32655143Storek return (node); 32755143Storek } 32855143Storek 32955143Storek /* 33055143Storek * Given a `first child' node number, locate the node with the given name. 33155143Storek * Return the node number, or 0 if not found. 33255143Storek */ 33355143Storek int 33455143Storek findnode(first, name) 33555143Storek int first; 33655143Storek register char *name; 33755143Storek { 33855143Storek register int node; 33955143Storek 34055143Storek for (node = first; node; node = nextsibling(node)) 34155143Storek if (strcmp(getpropstring(node, "name"), name) == 0) 34255143Storek return (node); 34355143Storek return (0); 34455143Storek } 34555143Storek 34655143Storek /* 34755143Storek * Fill in a romaux. Returns 1 on success, 0 if the register property 34855143Storek * was not the right size. 34955143Storek */ 35055143Storek int 35155143Storek romprop(rp, cp, node) 35255143Storek register struct romaux *rp; 35355143Storek const char *cp; 35455143Storek register int node; 35555143Storek { 35655143Storek register int len; 35755143Storek union { char regbuf[64]; int ireg[3]; } u; 35855143Storek static const char pl[] = "property length"; 35955143Storek 36055143Storek len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf); 36155143Storek if (len < 12) { 36255143Storek printf("%s \"reg\" %s = %d (need 12)\n", cp, pl, len); 36355143Storek return (0); 36455143Storek } 36555143Storek if (len > 12) 36655143Storek printf("warning: %s \"reg\" %s %d > 12, excess ignored\n", 36755143Storek cp, pl, len); 36855143Storek rp->ra_node = node; 36955143Storek rp->ra_name = cp; 37055143Storek rp->ra_iospace = u.ireg[0]; 37155143Storek rp->ra_paddr = (caddr_t)u.ireg[1]; 37255143Storek rp->ra_len = u.ireg[2]; 37355143Storek rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0); 37455143Storek len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr); 37555143Storek if (len == -1) 37655143Storek len = 0; 37755143Storek if (len & 7) { 37855143Storek printf("%s \"intr\" %s = %d (need multiple of 8)\n", 37955143Storek cp, pl, len); 38055143Storek len = 0; 38155143Storek } 38255143Storek rp->ra_nintr = len >>= 3; 38355143Storek /* SPARCstation interrupts are not hardware-vectored */ 38455143Storek while (--len >= 0) { 38555143Storek if (rp->ra_intr[len].int_vec) { 38655143Storek printf("WARNING: %s interrupt %d has nonzero vector\n", 38755143Storek cp, len); 38855143Storek break; 38955143Storek } 39055143Storek } 39155143Storek return (1); 39255143Storek } 39355143Storek 39455143Storek /* 39555143Storek * Attach the mainbus. 39655143Storek * 39755143Storek * Our main job is to attach the CPU (the root node we got in configure()) 39855143Storek * and iterate down the list of `mainbus devices' (children of that node). 39955143Storek * We also record the `node id' of the default frame buffer, if any. 40055143Storek */ 40155143Storek static void 40255143Storek mainbus_attach(parent, dev, aux) 40355143Storek struct device *parent, *dev; 40455143Storek void *aux; 40555143Storek { 40655143Storek register int node0, node; 40755143Storek register const char *cp, *const *ssp, *sp; 40855143Storek #define L1A_HACK /* XXX hack to allow L1-A during autoconf */ 40955143Storek #ifdef L1A_HACK 41055143Storek int nzs = 0, audio = 0; 41155143Storek #endif 41255143Storek struct romaux ra; 41355143Storek static const char *const special[] = { 41455143Storek /* find these first (end with empty string) */ 415*64662Storek "eeprom", 416*64662Storek "counter-timer", 417*64662Storek "memory-error", 418*64662Storek "", 41955143Storek 42055143Storek /* ignore these (end with NULL) */ 421*64662Storek "aliases", 422*64662Storek "interrupt-enable", 423*64662Storek "memory", 424*64662Storek "openprom", 425*64662Storek "options", 426*64662Storek "packages", 427*64662Storek "virtual-memory", 428*64662Storek NULL 42955143Storek }; 43055143Storek 43155143Storek printf("\n"); 43255143Storek 43355143Storek /* configure the cpu */ 43455143Storek node = ((struct romaux *)aux)->ra_node; 43555143Storek ra.ra_node = node; 43655143Storek ra.ra_name = cp = "cpu"; 43755143Storek ra.ra_paddr = 0; 43855143Storek config_found(dev, (void *)&ra, mbprint); 43955143Storek 44055143Storek /* remember which frame buffer, if any, is to be /dev/fb */ 44155143Storek fbnode = getpropint(node, "fb", 0); 44255143Storek 44355143Storek /* Find the "options" node */ 44455143Storek node0 = firstchild(node); 44555143Storek optionsnode = findnode(node0, "options"); 44655143Storek if (optionsnode == 0) 44755143Storek panic("no options in OPENPROM"); 44855143Storek 44959219Storek /* Start at the beginning of the bootpath */ 45059219Storek ra.ra_bp = bootpath; 45159219Storek 45255143Storek /* 45355143Storek * Locate and configure the ``early'' devices. These must be 45455143Storek * configured before we can do the rest. For instance, the 45555143Storek * EEPROM contains the Ethernet address for the LANCE chip. 45655143Storek * If the device cannot be located or configured, panic. 45755143Storek */ 45855143Storek for (ssp = special; *(sp = *ssp) != 0; ssp++) { 45955143Storek if ((node = findnode(node0, sp)) == 0) { 46055143Storek printf("could not find %s in OPENPROM\n", sp); 46155143Storek panic(sp); 46255143Storek } 46355143Storek if (!romprop(&ra, sp, node) || 46455143Storek !config_found(dev, (void *)&ra, mbprint)) 46555143Storek panic(sp); 46655143Storek } 46755143Storek 46855143Storek /* 46955143Storek * Configure the rest of the devices, in PROM order. Skip 47055143Storek * PROM entries that are not for devices, or which must be 47155143Storek * done before we get here. 47255143Storek */ 47355143Storek for (node = node0; node; node = nextsibling(node)) { 47455143Storek cp = getpropstring(node, "name"); 47555143Storek for (ssp = special; (sp = *ssp) != NULL; ssp++) 47655143Storek if (strcmp(cp, sp) == 0) 47755143Storek break; 47855143Storek if (sp == NULL && romprop(&ra, cp, node)) { 47955143Storek #ifdef L1A_HACK 48055143Storek if (strcmp(cp, "audio") == 0) 48155143Storek audio = 1; 48255143Storek if (strcmp(cp, "zs") == 0) 48355143Storek nzs++; 48455143Storek if (audio && nzs >= 2) 48555143Storek (void) splx(11 << 8); /* XXX */ 48655143Storek #endif 48755143Storek (void) config_found(dev, (void *)&ra, mbprint); 48855143Storek } 48955143Storek } 49055143Storek } 49155143Storek 49255143Storek struct cfdriver mainbuscd = 49355143Storek { NULL, "mainbus", matchbyname, mainbus_attach, 49455143Storek DV_DULL, sizeof(struct device) }; 49555143Storek 49655143Storek /* 49755143Storek * findzs() is called from the zs driver (which is, at least in theory, 49855143Storek * generic to any machine with a Zilog ZSCC chip). It should return the 49955143Storek * address of the corresponding zs channel. It may not fail, and it 50055143Storek * may be called before the VM code can be used. Here we count on the 50155143Storek * FORTH PROM to map in the required zs chips. 50255143Storek */ 50355143Storek void * 50455143Storek findzs(zs) 50555143Storek int zs; 50655143Storek { 50755143Storek register int node, addr; 50855143Storek 50955143Storek node = firstchild(findroot()); 51055143Storek while ((node = findnode(node, "zs")) != 0) { 51155143Storek if (getpropint(node, "slave", -1) == zs) { 51255143Storek if ((addr = getpropint(node, "address", 0)) == 0) 51355143Storek panic("findzs: zs%d not mapped by PROM", zs); 51455143Storek return ((void *)addr); 51555143Storek } 51655143Storek node = nextsibling(node); 51755143Storek } 51855143Storek panic("findzs: cannot find zs%d", zs); 51955143Storek /* NOTREACHED */ 52055143Storek } 52155143Storek 52255143Storek int 52355143Storek makememarr(ap, max, which) 52455143Storek register struct memarr *ap; 52555143Storek int max, which; 52655143Storek { 52755143Storek struct v2rmi { 52855143Storek int zero; 52955143Storek int addr; 53055143Storek int len; 53155143Storek } v2rmi[200]; /* version 2 rom meminfo layout */ 53255143Storek #define MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi)) 53355143Storek register struct v0mlist *mp; 53455143Storek register int i, node, len; 53555143Storek char *prop; 53655143Storek 53755143Storek switch (i = promvec->pv_romvec_vers) { 53855143Storek 53955143Storek case 0: 54055143Storek /* 54155143Storek * Version 0 PROMs use a linked list to describe these 54255143Storek * guys. 54355143Storek */ 54455143Storek switch (which) { 54555143Storek 54655143Storek case MEMARR_AVAILPHYS: 54755143Storek mp = *promvec->pv_v0mem.v0_physavail; 54855143Storek break; 54955143Storek 55055143Storek case MEMARR_TOTALPHYS: 55155143Storek mp = *promvec->pv_v0mem.v0_phystot; 55255143Storek break; 55355143Storek 55455143Storek default: 55555143Storek panic("makememarr"); 55655143Storek } 55755143Storek for (i = 0; mp != NULL; mp = mp->next, i++) { 55855143Storek if (i >= max) 55955143Storek goto overflow; 56055143Storek ap->addr = (u_int)mp->addr; 56155143Storek ap->len = mp->nbytes; 56255143Storek ap++; 56355143Storek } 56455143Storek break; 56555143Storek 56655143Storek default: 56755143Storek printf("makememarr: hope version %d PROM is like version 2\n", 56855143Storek i); 56955143Storek /* FALLTHROUGH */ 57055143Storek 57155143Storek case 2: 57255143Storek /* 57355143Storek * Version 2 PROMs use a property array to describe them. 57455143Storek */ 57555143Storek if (max > MAXMEMINFO) { 57655143Storek printf("makememarr: limited to %d\n", MAXMEMINFO); 57755143Storek max = MAXMEMINFO; 57855143Storek } 57955143Storek if ((node = findnode(firstchild(findroot()), "memory")) == 0) 58055143Storek panic("makememarr: cannot find \"memory\" node"); 58155143Storek switch (which) { 58255143Storek 58355143Storek case MEMARR_AVAILPHYS: 58455143Storek prop = "available"; 58555143Storek break; 58655143Storek 58755143Storek case MEMARR_TOTALPHYS: 58855143Storek prop = "reg"; 58955143Storek break; 59055143Storek 59155143Storek default: 59255143Storek panic("makememarr"); 59355143Storek } 59455143Storek len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) / 59555143Storek sizeof(struct v2rmi); 59655143Storek for (i = 0; i < len; i++) { 59755143Storek if (i >= max) 59855143Storek goto overflow; 59955143Storek ap->addr = v2rmi[i].addr; 60055143Storek ap->len = v2rmi[i].len; 60155143Storek ap++; 60255143Storek } 60355143Storek break; 60455143Storek } 60555143Storek 60655143Storek /* 60755143Storek * Success! (Hooray) 60855143Storek */ 60955143Storek if (i == 0) 61055143Storek panic("makememarr: no memory found"); 61155143Storek return (i); 61255143Storek 61355143Storek overflow: 61455143Storek /* 61555143Storek * Oops, there are more things in the PROM than our caller 61655143Storek * provided space for. Truncate any extras. 61755143Storek */ 61855143Storek printf("makememarr: WARNING: lost some memory\n"); 61955143Storek return (i); 62055143Storek } 62155143Storek 62255143Storek /* 62355143Storek * Internal form of getprop(). Returns the actual length. 62455143Storek */ 62555143Storek int 62655143Storek getprop(node, name, buf, bufsiz) 62755143Storek int node; 62855143Storek char *name; 62955143Storek void *buf; 63055143Storek register int bufsiz; 63155143Storek { 63255143Storek register struct nodeops *no; 63355143Storek register int len; 63455143Storek 63555143Storek no = promvec->pv_nodeops; 63655143Storek len = no->no_proplen(node, name); 63755143Storek if (len > bufsiz) { 63855143Storek printf("node %x property %s length %d > %d\n", 63955143Storek node, name, len, bufsiz); 64055143Storek #ifdef DEBUG 64155143Storek panic("getprop"); 64255143Storek #else 64355143Storek return (0); 64455143Storek #endif 64555143Storek } 64655143Storek no->no_getprop(node, name, buf); 64755143Storek return (len); 64855143Storek } 64955143Storek 65055143Storek /* 65155143Storek * Return a string property. There is a (small) limit on the length; 65255143Storek * the string is fetched into a static buffer which is overwritten on 65355143Storek * subsequent calls. 65455143Storek */ 65555143Storek char * 65655143Storek getpropstring(node, name) 65755143Storek int node; 65855143Storek char *name; 65955143Storek { 66055143Storek register int len; 66155143Storek static char stringbuf[32]; 66255143Storek 66355143Storek len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1); 66455143Storek stringbuf[len] = '\0'; /* usually unnecessary */ 66555143Storek return (stringbuf); 66655143Storek } 66755143Storek 66855143Storek /* 66955143Storek * Fetch an integer (or pointer) property. 67055143Storek * The return value is the property, or the default if there was none. 67155143Storek */ 67255143Storek int 67355143Storek getpropint(node, name, deflt) 67455143Storek int node; 67555143Storek char *name; 67655143Storek int deflt; 67755143Storek { 67855143Storek register int len; 67955143Storek char intbuf[16]; 68055143Storek 68155143Storek len = getprop(node, name, (void *)intbuf, sizeof intbuf); 68255143Storek if (len != 4) 68355143Storek return (deflt); 68455143Storek return (*(int *)intbuf); 68555143Storek } 68655143Storek 68755143Storek /* 68855143Storek * OPENPROM functions. These are here mainly to hide the OPENPROM interface 68955143Storek * from the rest of the kernel. 69055143Storek */ 69155143Storek int 69255143Storek firstchild(node) 69355143Storek int node; 69455143Storek { 69555143Storek 69655143Storek return (promvec->pv_nodeops->no_child(node)); 69755143Storek } 69855143Storek 69955143Storek int 70055143Storek nextsibling(node) 70155143Storek int node; 70255143Storek { 70355143Storek 70455143Storek return (promvec->pv_nodeops->no_nextnode(node)); 70555143Storek } 70655143Storek 707*64662Storek #ifdef RCONSOLE 70855143Storek /* Pass a string to the FORTH PROM to be interpreted */ 70955143Storek void 71055143Storek rominterpret(s) 71155143Storek register char *s; 71255143Storek { 71355143Storek 71455143Storek if (promvec->pv_romvec_vers < 2) 71555143Storek promvec->pv_fortheval.v0_eval(strlen(s), s); 71655143Storek else 71755143Storek promvec->pv_fortheval.v2_eval(s); 71855143Storek } 71955143Storek 720*64662Storek /* 721*64662Storek * Try to figure out where the PROM stores the cursor row & column 722*64662Storek * variables. Returns nonzero on error. 723*64662Storek */ 724*64662Storek int 725*64662Storek romgetcursoraddr(rowp, colp) 726*64662Storek register int **rowp, **colp; 727*64662Storek { 728*64662Storek char buf[100]; 729*64662Storek 730*64662Storek /* 731*64662Storek * line# and column# are global in older proms (rom vector < 2) 732*64662Storek * and in some newer proms. They are local in version 2.9. The 733*64662Storek * correct cutoff point is unknown, as yet; we use 2.9 here. 734*64662Storek */ 735*64662Storek if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009) 736*64662Storek sprintf(buf, 737*64662Storek "' line# >body >user %x ! ' column# >body >user %x !", 738*64662Storek rowp, colp); 739*64662Storek else 740*64662Storek sprintf(buf, 741*64662Storek "stdout @ is my-self addr line# %x ! addr column# %x !", 742*64662Storek rowp, colp); 743*64662Storek *rowp = *colp = NULL; 744*64662Storek rominterpret(buf); 745*64662Storek return (*rowp == NULL || *colp == NULL); 746*64662Storek } 747*64662Storek #endif 748*64662Storek 74955143Storek volatile void 75055143Storek romhalt() 75155143Storek { 75255143Storek 75355143Storek promvec->pv_halt(); 75455143Storek panic("PROM exit failed"); 75555143Storek } 75655143Storek 75755143Storek volatile void 75855143Storek romboot(str) 75955143Storek char *str; 76055143Storek { 76155143Storek 76255143Storek promvec->pv_reboot(str); 76355143Storek panic("PROM boot failed"); 76455143Storek } 76555143Storek 76655143Storek callrom() 76755143Storek { 76855143Storek 76955143Storek #ifdef notdef /* sun4c FORTH PROMs do this for us */ 77055143Storek fb_unblank(); 77155143Storek #endif 77255143Storek promvec->pv_abort(); 77355143Storek } 77455143Storek 77555143Storek /* 77655143Storek * Configure swap space and related parameters. 77755143Storek */ 77855143Storek swapconf() 77955143Storek { 78055143Storek register struct swdevt *swp; 78155143Storek register int nblks; 78255143Storek 78359219Storek for (swp = swdevt; swp->sw_dev != NODEV; swp++) 78455143Storek if (bdevsw[major(swp->sw_dev)].d_psize) { 78555143Storek nblks = 78655143Storek (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); 78755143Storek if (nblks != -1 && 78855143Storek (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) 78955143Storek swp->sw_nblks = nblks; 79055143Storek } 79155143Storek } 79255143Storek 79359219Storek #define DOSWAP /* Change swdevt and dumpdev too */ 79455143Storek u_long bootdev; /* should be dev_t, but not until 32 bits */ 79555143Storek 79655143Storek #define PARTITIONMASK 0x7 79755143Storek #define PARTITIONSHIFT 3 79855143Storek 79959219Storek static int 80059219Storek findblkmajor(dv) 80159219Storek register struct dkdevice *dv; 80259219Storek { 80359219Storek register int i; 80459219Storek 80559219Storek for (i = 0; i < nblkdev; ++i) 80659219Storek if ((void (*)(struct buf *))bdevsw[i].d_strategy == 80759219Storek dv->dk_driver->d_strategy) 80859219Storek return (i); 80959219Storek 81059219Storek return (-1); 81159219Storek } 81259219Storek 81359219Storek static struct device * 81459219Storek getdisk(str, len, defpart, devp) 81559219Storek char *str; 81659219Storek int len, defpart; 81759219Storek dev_t *devp; 81859219Storek { 81959219Storek register struct device *dv; 82059219Storek 82159219Storek if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { 82259219Storek printf("use one of:"); 82359219Storek for (dv = alldevs; dv != NULL; dv = dv->dv_next) 82459219Storek if (dv->dv_class == DV_DISK) 82559219Storek printf(" %s[a-h]", dv->dv_xname); 82659219Storek printf("\n"); 82759219Storek } 82859219Storek return (dv); 82959219Storek } 83059219Storek 83159219Storek static struct device * 83259219Storek parsedisk(str, len, defpart, devp) 83359219Storek char *str; 83459219Storek int len, defpart; 83559219Storek dev_t *devp; 83659219Storek { 83759219Storek register struct device *dv; 83859219Storek register char *cp; 83959219Storek int majdev, mindev, part; 84059219Storek 84159219Storek if (len == 0) 84259219Storek return (NULL); 84359219Storek cp = str + len - 1; 84459219Storek if (*cp >= 'a' && *cp <= 'h') { 84559219Storek part = *cp - 'a'; 84659219Storek *cp-- = '\0'; 84759219Storek } else 84859219Storek part = defpart; 84959219Storek 85059219Storek 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); 85859219Storek return (dv); 85959219Storek } 86059219Storek 86159219Storek return (NULL); 86259219Storek } 86359219Storek 86455143Storek /* 86555143Storek * Attempt to find the device from which we were booted. 86655143Storek * If we can do so, and not instructed not to do so, 86755143Storek * change rootdev to correspond to the load device. 86855143Storek */ 86959219Storek void 87055143Storek setroot() 87155143Storek { 87259219Storek register struct swdevt *swp; 87359219Storek register struct device *dv; 87459219Storek register int len, majdev, mindev, part; 87559219Storek dev_t nrootdev, nswapdev; 87659219Storek char buf[128]; 87759219Storek #ifdef DOSWAP 87859219Storek dev_t temp; 87959219Storek #endif 88059219Storek #ifdef NFS 88159219Storek extern int (*mountroot)(), nfs_mountroot(); 88259219Storek #endif 88355143Storek 88459219Storek if (boothowto & RB_ASKNAME) { 88559219Storek for (;;) { 88659219Storek printf("root device? "); 88759219Storek len = getstr(buf, sizeof(buf)); 88859219Storek #ifdef GENERIC 88959219Storek if (len > 0 && buf[len - 1] == '*') { 89059219Storek buf[--len] = '\0'; 89159219Storek dv = getdisk(buf, len, 1, &nrootdev); 89259219Storek if (dv != NULL) { 89359219Storek bootdv = dv; 89459219Storek nswapdev = nrootdev; 89560518Storek goto gotswap; 89659219Storek } 89759219Storek } 89859219Storek #endif 89959219Storek dv = getdisk(buf, len, 0, &nrootdev); 90059219Storek if (dv != NULL) { 90159219Storek bootdv = dv; 90259219Storek break; 90359219Storek } 90459219Storek } 90559219Storek for (;;) { 90659219Storek printf("swap device (default %sb)? ", bootdv->dv_xname); 90759219Storek len = getstr(buf, sizeof(buf)); 90859219Storek if (len == 0) { 90959219Storek nswapdev = makedev(major(nrootdev), 91059219Storek (minor(nrootdev) & ~ PARTITIONMASK) | 1); 91159219Storek break; 91259219Storek } 91359219Storek if (getdisk(buf, len, 1, &nswapdev) != NULL) 91459219Storek break; 91559219Storek } 91660518Storek #ifdef GENERIC 91760518Storek gotswap: 91860518Storek #endif 91959219Storek rootdev = nrootdev; 92059219Storek swapdev = nswapdev; 92159219Storek dumpdev = nswapdev; /* ??? */ 92259219Storek swdevt[0].sw_dev = nswapdev; 92359219Storek swdevt[1].sw_dev = NODEV; 92455143Storek return; 92559219Storek } 92659219Storek 92759219Storek /* XXX currently there's no way to set RB_DFLTROOT... */ 92859219Storek if (boothowto & RB_DFLTROOT || bootdv == NULL) 92955143Storek return; 93059219Storek 93159219Storek switch (bootdv->dv_class) { 93259219Storek 93359219Storek #ifdef NFS 93459219Storek case DV_IFNET: 93559219Storek mountroot = nfs_mountroot; 93655143Storek return; 93759219Storek #endif 93859219Storek 93959219Storek #if defined(FFS) || defined(LFS) 94059219Storek case DV_DISK: 94159219Storek majdev = findblkmajor((struct dkdevice *)bootdv); 94259219Storek if (majdev < 0) 94359219Storek return; 94459219Storek part = 0; 94559219Storek mindev = (bootdv->dv_unit << PARTITIONSHIFT) + part; 94659219Storek break; 94759219Storek #endif 94859219Storek 94959219Storek default: 95059219Storek printf("can't figure root, hope your kernel is right\n"); 95155143Storek return; 95259219Storek } 95359219Storek 95455143Storek /* 95555143Storek * Form a new rootdev 95655143Storek */ 95759219Storek nrootdev = makedev(majdev, mindev); 95855143Storek /* 95955143Storek * If the original rootdev is the same as the one 96055143Storek * just calculated, don't need to adjust the swap configuration. 96155143Storek */ 96259219Storek if (rootdev == nrootdev) 96355143Storek return; 96455143Storek 96559219Storek rootdev = nrootdev; 96659219Storek printf("Changing root device to %s%c\n", bootdv->dv_xname, part + 'a'); 96755143Storek 96855143Storek #ifdef DOSWAP 96955143Storek mindev &= ~PARTITIONMASK; 97059219Storek temp = NODEV; 97159219Storek for (swp = swdevt; swp->sw_dev != NODEV; swp++) { 97255143Storek if (majdev == major(swp->sw_dev) && 97355143Storek mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) { 97455143Storek temp = swdevt[0].sw_dev; 97555143Storek swdevt[0].sw_dev = swp->sw_dev; 97655143Storek swp->sw_dev = temp; 97755143Storek break; 97855143Storek } 97955143Storek } 98059219Storek if (swp->sw_dev == NODEV) 98155143Storek return; 98255143Storek 98355143Storek /* 98459219Storek * If dumpdev was the same as the old primary swap device, move 98559219Storek * it to the new primary swap device. 98655143Storek */ 98755143Storek if (temp == dumpdev) 98855143Storek dumpdev = swdevt[0].sw_dev; 98955143Storek #endif 99055143Storek } 99155143Storek 99259219Storek static int 99359219Storek getstr(cp, size) 99455143Storek register char *cp; 99559219Storek register int size; 99655143Storek { 99755143Storek register char *lp; 99855143Storek register int c; 99959219Storek register int len; 100055143Storek 100155143Storek lp = cp; 100259219Storek len = 0; 100355143Storek for (;;) { 100455143Storek c = cngetc(); 100555143Storek switch (c) { 100655143Storek case '\n': 100755143Storek case '\r': 100855143Storek printf("\n"); 100955143Storek *lp++ = '\0'; 101059219Storek return (len); 101155143Storek case '\b': 101255143Storek case '\177': 101355143Storek case '#': 101459219Storek if (len) { 101559219Storek --len; 101659219Storek --lp; 101755143Storek printf(" \b "); 101855143Storek } 101955143Storek continue; 102055143Storek case '@': 102155143Storek case 'u'&037: 102259219Storek len = 0; 102355143Storek lp = cp; 102459219Storek printf("\n"); 102555143Storek continue; 102655143Storek default: 102759219Storek if (len + 1 >= size || c < ' ') { 102859219Storek printf("\007"); 102955143Storek continue; 103059219Storek } 103159219Storek printf("%c", c); 103259219Storek ++len; 103355143Storek *lp++ = c; 103455143Storek } 103555143Storek } 103655143Storek } 1037