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*64686Storek * @(#)autoconf.c 8.3 (Berkeley) 09/30/93 1755143Storek * 18*64686Storek * from: $Header: autoconf.c,v 1.37 93/09/28 07:19:48 leres 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 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 * 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 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 */ 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 27655143Storek sync_crash() 27755143Storek { 27855143Storek 27955143Storek panic("PROM sync command"); 28055143Storek } 28155143Storek 28255143Storek char * 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 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 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 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 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 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) */ 41464662Storek "eeprom", 41564662Storek "counter-timer", 41664662Storek "memory-error", 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 * 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 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 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 * 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 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 69155143Storek firstchild(node) 69255143Storek int node; 69355143Storek { 69455143Storek 69555143Storek return (promvec->pv_nodeops->no_child(node)); 69655143Storek } 69755143Storek 69855143Storek int 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 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 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 74955143Storek romhalt() 75055143Storek { 75155143Storek 75255143Storek promvec->pv_halt(); 75355143Storek panic("PROM exit failed"); 75455143Storek } 75555143Storek 75655143Storek volatile void 75755143Storek romboot(str) 75855143Storek char *str; 75955143Storek { 76055143Storek 76155143Storek promvec->pv_reboot(str); 76255143Storek panic("PROM boot failed"); 76355143Storek } 76455143Storek 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 */ 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 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 * 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 830*64686Storek struct device * 83159219Storek parsedisk(str, len, defpart, devp) 83259219Storek char *str; 83359219Storek int len, defpart; 83459219Storek dev_t *devp; 83559219Storek { 83659219Storek register struct device *dv; 837*64686Storek register char *cp, c; 83859219Storek int majdev, mindev, part; 83959219Storek 84059219Storek if (len == 0) 84159219Storek return (NULL); 84259219Storek cp = str + len - 1; 843*64686Storek c = *cp; 844*64686Storek if (c >= 'a' && c <= 'h') { 845*64686Storek part = c - 'a'; 846*64686Storek *cp = '\0'; 84759219Storek } else 84859219Storek part = defpart; 84959219Storek 850*64686Storek 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); 858*64686Storek break; 85959219Storek } 860*64686Storek } 86159219Storek 862*64686Storek *cp = c; 863*64686Storek 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 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 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