📄 autoconf.c
字号:
/* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)autoconf.c 8.4 (Berkeley) 10/1/93 * * from: $Header: autoconf.c,v 1.38 93/10/01 21:24:51 torek Exp $ (LBL) */#include <sys/param.h>#include <sys/map.h>#include <sys/buf.h>#include <sys/disklabel.h>#include <sys/device.h>#include <sys/disk.h>#include <sys/dkstat.h>#include <sys/conf.h>#include <sys/dmap.h>#include <sys/reboot.h>#include <sys/socket.h>#include <sys/systm.h>#include <net/if.h>#include <machine/autoconf.h>#include <machine/bsd_openprom.h>#include <machine/cpu.h>/* * The following several variables are related to * the configuration process, and are used in initializing * the machine. */int cold; /* if 1, still working on cold-start */int dkn; /* number of iostat dk numbers assigned so far */int fbnode; /* node ID of ROM's console frame buffer */int optionsnode; /* node ID of ROM's options */extern struct promvec *promvec;static int rootnode;int findroot __P((void));void setroot __P((void));static int getstr __P((char *, int));static int findblkmajor __P((struct dkdevice *));static struct device *getdisk __P((char *, int, int, dev_t *));struct bootpath bootpath[8];/* * Most configuration on the SPARC is done by matching OPENPROM Forth * device names with our internal names. */intmatchbyname(parent, cf, aux) struct device *parent; struct cfdata *cf; void *aux;{ return (strcmp(cf->cf_driver->cd_name, *(char **)aux) == 0);}/* * Convert hex ASCII string to a value. Returns updated pointer. * Depends on ASCII order (this *is* machine-dependent code, you know). */static char *str2hex(str, vp) register char *str; register int *vp;{ register int v, c; for (v = 0;; v = v * 16 + c, str++) { c = *(u_char *)str; if (c <= '9') { if ((c -= '0') < 0) break; } else if (c <= 'F') { if ((c -= 'A' - 10) < 10) break; } else if (c <= 'f') { if ((c -= 'a' - 10) < 10) break; } else break; } *vp = v; return (str);}/* * locore.s code calls bootstrap() just before calling main(), after double * mapping the kernel to high memory and setting up the trap base register. * We must finish mapping the kernel properly and glean any bootstrap info. */voidbootstrap(){ register char *cp, *pp; register struct bootpath *bp; int v0val[3]; int nmmu, ncontext, node;#ifdef KGDB extern int kgdb_debug_panic;#endif node = findroot(); nmmu = getpropint(node, "mmu-npmg", 128); ncontext = getpropint(node, "mmu-nctx", 8); pmap_bootstrap(nmmu, ncontext);#ifdef KGDB zs_kgdb_init(); /* XXX */#endif /* * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags * that were given after the boot command. On SS2s, pv_v0bootargs * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to * "vmunix -s" or whatever. * ### DO THIS BEFORE pmap_boostrap? */ bp = bootpath; if (promvec->pv_romvec_vers < 2) { /* Grab boot device name and values. */ cp = (*promvec->pv_v0bootargs)->ba_argv[0]; if (cp != NULL) { /* Kludge something up */ pp = cp + 2; v0val[0] = v0val[1] = v0val[2] = 0; if (*pp == '(' && *(pp = str2hex(++pp, &v0val[0])) == ',' && *(pp = str2hex(++pp, &v0val[1])) == ',') (void)str2hex(++pp, &v0val[2]); /* Assume sbus0 */ strcpy(bp->name, "sbus"); bp->val[0] = 0; ++bp; if (cp[0] == 'l' && cp[1] == 'e') { /* le */ strcpy(bp->name, "le"); bp->val[0] = -1; bp->val[1] = v0val[0]; } else { /* sd or maybe st; assume espN */ strcpy(bp->name, "esp"); bp->val[0] = -1; bp->val[1] = v0val[0];/* XXX map target 0 to 3, 3 to 0. Should really see how the prom is configed */#define CRAZYMAP(v) ((v) == 3 ? 0 : (v) == 0 ? 3 : (v)) ++bp; bp->name[0] = cp[0]; bp->name[1] = cp[1]; bp->name[2] = '\0'; bp->val[0] = CRAZYMAP(v0val[1]); bp->val[1] = v0val[2]; } } /* Setup pointer to boot flags */ cp = (*promvec->pv_v0bootargs)->ba_argv[1]; if (cp == NULL || *cp != '-') return; } else { /* Grab boot path */ cp = *promvec->pv_v2bootargs.v2_bootpath; while (cp != NULL && *cp == '/') { /* Step over '/' */ ++cp; /* Extract name */ pp = bp->name; while (*cp != '@' && *cp != '/' && *cp != '\0') *pp++ = *cp++; *pp = '\0'; if (*cp == '@') { cp = str2hex(++cp, &bp->val[0]); if (*cp == ',') cp = str2hex(++cp, &bp->val[1]); } ++bp; } /* Setup pointer to boot flags */ cp = *promvec->pv_v2bootargs.v2_bootargs; if (cp == NULL) return; while (*cp != '-') if (*cp++ == '\0') return; } for (;;) { switch (*++cp) { case '\0': return; case 'a': boothowto |= RB_ASKNAME; break; case 'b': boothowto |= RB_DFLTROOT; break; case 'd': /* kgdb - always on zs XXX */#ifdef KGDB boothowto |= RB_KDB; /* XXX unused */ kgdb_debug_panic = 1; kgdb_connect(1);#else printf("kernel not compiled with KGDB\n");#endif break; case 's': boothowto |= RB_SINGLE; break; } }}/* * Determine mass storage and memory configuration for a machine. * We get the PROM's root device and make sure we understand it, then * attach it as `mainbus0'. We also set up to handle the PROM `sync' * command. */configure(){ register int node; register char *cp; struct romaux ra; void sync_crash(); node = findroot(); cp = getpropstring(node, "device_type"); if (strcmp(cp, "cpu") != 0) { printf("PROM root device type = %s\n", cp); panic("need CPU as root"); } *promvec->pv_synchook = sync_crash; ra.ra_node = node; ra.ra_name = cp = "mainbus"; if (!config_rootfound(cp, (void *)&ra)) panic("mainbus not configured"); (void)spl0(); if (bootdv) printf("Found boot device %s\n", bootdv->dv_xname); cold = 0; setroot(); swapconf(); dumpconf();}/* * Console `sync' command. SunOS just does a `panic: zero' so I guess * no one really wants anything fancy... */voidsync_crash(){ panic("PROM sync command");}char *clockfreq(freq) register int freq;{ register char *p; static char buf[10]; freq /= 1000; sprintf(buf, "%d", freq / 1000); freq %= 1000; if (freq) { freq += 1000; /* now in 1000..1999 */ p = buf + strlen(buf); sprintf(p, "%d", freq); *p = '.'; /* now buf = %d.%3d */ } return (buf);}/* ARGSUSED */static intmbprint(aux, name) void *aux; char *name;{ register struct romaux *ra = aux; if (name) printf("%s at %s", ra->ra_name, name); if (ra->ra_paddr) printf(" %saddr 0x%x", ra->ra_iospace ? "io" : "", (int)ra->ra_paddr); return (UNCONF);}intfindroot(){ register int node; if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0) panic("no PROM root device"); rootnode = node; return (node);}/* * Given a `first child' node number, locate the node with the given name. * Return the node number, or 0 if not found. */intfindnode(first, name) int first; register char *name;{ register int node; for (node = first; node; node = nextsibling(node)) if (strcmp(getpropstring(node, "name"), name) == 0) return (node); return (0);}/* * Fill in a romaux. Returns 1 on success, 0 if the register property * was not the right size. */intromprop(rp, cp, node) register struct romaux *rp; const char *cp; register int node;{ register int len; union { char regbuf[64]; int ireg[3]; } u; static const char pl[] = "property length"; len = getprop(node, "reg", (void *)u.regbuf, sizeof u.regbuf); if (len < 12) { printf("%s \"reg\" %s = %d (need 12)\n", cp, pl, len); return (0); } if (len > 12) printf("warning: %s \"reg\" %s %d > 12, excess ignored\n", cp, pl, len); rp->ra_node = node; rp->ra_name = cp; rp->ra_iospace = u.ireg[0]; rp->ra_paddr = (caddr_t)u.ireg[1]; rp->ra_len = u.ireg[2]; rp->ra_vaddr = (caddr_t)getpropint(node, "address", 0); len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr); if (len == -1) len = 0; if (len & 7) { printf("%s \"intr\" %s = %d (need multiple of 8)\n", cp, pl, len); len = 0; } rp->ra_nintr = len >>= 3; /* SPARCstation interrupts are not hardware-vectored */ while (--len >= 0) { if (rp->ra_intr[len].int_vec) { printf("WARNING: %s interrupt %d has nonzero vector\n", cp, len); break; } } return (1);}/* * Attach the mainbus. * * Our main job is to attach the CPU (the root node we got in configure()) * and iterate down the list of `mainbus devices' (children of that node). * We also record the `node id' of the default frame buffer, if any. */static voidmainbus_attach(parent, dev, aux) struct device *parent, *dev; void *aux;{ register int node0, node; register const char *cp, *const *ssp, *sp;#define L1A_HACK /* XXX hack to allow L1-A during autoconf */#ifdef L1A_HACK int nzs = 0, audio = 0;#endif struct romaux ra; static const char *const special[] = { /* find these first (end with empty string) */ "memory-error", /* as early as convenient, in case of error */ "eeprom", "counter-timer", "", /* ignore these (end with NULL) */ "aliases", "interrupt-enable", "memory", "openprom", "options", "packages", "virtual-memory", NULL }; printf("\n"); /* configure the cpu */ node = ((struct romaux *)aux)->ra_node; ra.ra_node = node; ra.ra_name = cp = "cpu"; ra.ra_paddr = 0; config_found(dev, (void *)&ra, mbprint); /* remember which frame buffer, if any, is to be /dev/fb */ fbnode = getpropint(node, "fb", 0); /* Find the "options" node */ node0 = firstchild(node); optionsnode = findnode(node0, "options"); if (optionsnode == 0) panic("no options in OPENPROM"); /* Start at the beginning of the bootpath */ ra.ra_bp = bootpath; /* * Locate and configure the ``early'' devices. These must be * configured before we can do the rest. For instance, the * EEPROM contains the Ethernet address for the LANCE chip. * If the device cannot be located or configured, panic. */ for (ssp = special; *(sp = *ssp) != 0; ssp++) { if ((node = findnode(node0, sp)) == 0) { printf("could not find %s in OPENPROM\n", sp); panic(sp); } if (!romprop(&ra, sp, node) || !config_found(dev, (void *)&ra, mbprint)) panic(sp); } /* * Configure the rest of the devices, in PROM order. Skip * PROM entries that are not for devices, or which must be * done before we get here. */ for (node = node0; node; node = nextsibling(node)) { cp = getpropstring(node, "name"); for (ssp = special; (sp = *ssp) != NULL; ssp++) if (strcmp(cp, sp) == 0) break; if (sp == NULL && romprop(&ra, cp, node)) {#ifdef L1A_HACK if (strcmp(cp, "audio") == 0) audio = 1; if (strcmp(cp, "zs") == 0) nzs++; if (audio && nzs >= 2) (void) splx(11 << 8); /* XXX */#endif (void) config_found(dev, (void *)&ra, mbprint); } }}struct cfdriver mainbuscd = { NULL, "mainbus", matchbyname, mainbus_attach, DV_DULL, sizeof(struct device) };/* * findzs() is called from the zs driver (which is, at least in theory, * generic to any machine with a Zilog ZSCC chip). It should return the * address of the corresponding zs channel. It may not fail, and it * may be called before the VM code can be used. Here we count on the * FORTH PROM to map in the required zs chips. */void *findzs(zs) int zs;{ register int node, addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -