Annotation of src/sys/arch/i386/i386/autoconf.c, Revision 1.47
1.47 ! ad 1: /* $NetBSD: autoconf.c,v 1.46 2000/03/21 19:38:24 ad Exp $ */
1.11 cgd 2:
1.1 cgd 3: /*-
4: * Copyright (c) 1990 The Regents of the University of California.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to Berkeley by
8: * William Jolitz.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: *
1.11 cgd 38: * @(#)autoconf.c 7.1 (Berkeley) 5/9/91
1.1 cgd 39: */
40:
41: /*
42: * Setup the system to run on the current machine.
43: *
44: * Configure() is called at boot time and initializes the vba
45: * device tables and the memory controller monitoring. Available
46: * devices are determined (from possibilities mentioned in ioconf.c),
47: * and the drivers are initialized.
48: */
1.43 drochner 49:
50: #include "opt_compat_oldboot.h"
51:
1.9 mycroft 52: #include <sys/param.h>
53: #include <sys/systm.h>
54: #include <sys/buf.h>
55: #include <sys/dkstat.h>
56: #include <sys/disklabel.h>
57: #include <sys/conf.h>
1.43 drochner 58: #ifdef COMPAT_OLDBOOT
1.9 mycroft 59: #include <sys/reboot.h>
1.43 drochner 60: #endif
1.13 mycroft 61: #include <sys/device.h>
1.34 fvdl 62: #include <sys/malloc.h>
1.25 drochner 63: #include <sys/vnode.h>
64: #include <sys/fcntl.h>
65: #include <sys/dkio.h>
1.1 cgd 66:
1.9 mycroft 67: #include <machine/pte.h>
1.20 christos 68: #include <machine/cpu.h>
1.25 drochner 69: #include <machine/bootinfo.h>
1.1 cgd 70:
1.28 drochner 71: static int match_harddisk __P((struct device *, struct btinfo_bootdisk *));
1.32 fvdl 72: static void matchbiosdisks __P((void));
1.23 thorpej 73: void findroot __P((struct device **, int *));
1.19 mycroft 74:
1.35 fvdl 75: extern struct disklist *i386_alldisks;
76: extern int i386_ndisks;
1.34 fvdl 77:
1.45 thorpej 78: #include "bios32.h"
79: #if NBIOS32 > 0
80: #include <machine/bios32.h>
81: #endif
82:
83: #include "opt_pcibios.h"
84: #ifdef PCIBIOS
85: #include <dev/pci/pcireg.h>
86: #include <dev/pci/pcivar.h>
87: #include <i386/pci/pcibios.h>
88: #endif
89:
1.1 cgd 90: /*
91: * Determine i/o configuration for a machine.
92: */
1.19 mycroft 93: void
1.40 thorpej 94: cpu_configure()
1.1 cgd 95: {
96:
1.12 mycroft 97: startrtclock();
1.45 thorpej 98:
99: #if NBIOS32 > 0
100: bios32_init();
101: #endif
102: #ifdef PCIBIOS
103: pcibios_init();
104: #endif
1.12 mycroft 105:
1.18 cgd 106: if (config_rootfound("mainbus", NULL) == NULL)
107: panic("configure: mainbus not configured");
1.12 mycroft 108:
1.22 christos 109: printf("biomask %x netmask %x ttymask %x\n",
1.12 mycroft 110: (u_short)imask[IPL_BIO], (u_short)imask[IPL_NET],
111: (u_short)imask[IPL_TTY]);
112:
113: spl0();
1.37 thorpej 114:
115: /* Set up proc0's TSS and LDT (after the FPU is configured). */
116: i386_proc0_tss_ldt_init();
1.30 thorpej 117:
118: /* XXX Finish deferred buffer cache allocation. */
119: i386_bufinit();
1.24 gwr 120: }
1.28 drochner 121:
1.24 gwr 122: void
123: cpu_rootconf()
124: {
125: struct device *booted_device;
126: int booted_partition;
1.1 cgd 127:
1.23 thorpej 128: findroot(&booted_device, &booted_partition);
1.32 fvdl 129: matchbiosdisks();
1.23 thorpej 130:
131: printf("boot device: %s\n",
132: booted_device ? booted_device->dv_xname : "<unknown>");
133:
1.38 thorpej 134: setroot(booted_device, booted_partition);
1.1 cgd 135: }
136:
1.34 fvdl 137: /*
138: * XXX ugly bit of code. But, this is the only safe time that the
139: * match between BIOS disks and native disks can be done.
140: */
1.32 fvdl 141: static void
142: matchbiosdisks()
143: {
144: struct btinfo_biosgeom *big;
145: struct bi_biosgeom_entry *be;
146: struct device *dv;
147: struct devnametobdevmaj *d;
1.34 fvdl 148: int i, ck, error, m, n;
1.32 fvdl 149: struct vnode *tv;
1.34 fvdl 150: char mbr[DEV_BSIZE];
1.32 fvdl 151:
152: big = lookup_bootinfo(BTINFO_BIOSGEOM);
153:
1.36 fvdl 154: if (big == NULL)
1.32 fvdl 155: return;
156:
1.34 fvdl 157: /*
158: * First, count all native disks
159: */
160: for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next)
161: if (dv->dv_class == DV_DISK &&
162: (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "sd") ||
1.47 ! ad 163: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "wd") ||
! 164: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "ca")))
1.35 fvdl 165: i386_ndisks++;
166:
167: if (i386_ndisks == 0)
168: return;
1.34 fvdl 169:
170: /* XXX M_TEMP is wrong */
1.35 fvdl 171: i386_alldisks = malloc(sizeof (struct disklist) + (i386_ndisks - 1) *
172: sizeof (struct nativedisk_info),
173: M_TEMP, M_NOWAIT);
174: if (i386_alldisks == NULL)
1.34 fvdl 175: return;
176:
1.35 fvdl 177: i386_alldisks->dl_nnativedisks = i386_ndisks;
178: i386_alldisks->dl_nbiosdisks = big->num;
179: for (i = 0; i < big->num; i++) {
180: i386_alldisks->dl_biosdisks[i].bi_dev = big->disk[i].dev;
181: i386_alldisks->dl_biosdisks[i].bi_sec = big->disk[i].sec;
182: i386_alldisks->dl_biosdisks[i].bi_head = big->disk[i].head;
183: i386_alldisks->dl_biosdisks[i].bi_cyl = big->disk[i].cyl;
184: i386_alldisks->dl_biosdisks[i].bi_lbasecs = big->disk[i].totsec;
185: i386_alldisks->dl_biosdisks[i].bi_flags = big->disk[i].flags;
186: }
187:
1.34 fvdl 188: /*
189: * XXX code duplication from findroot()
190: */
191: n = -1;
1.32 fvdl 192: for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
193: if (dv->dv_class != DV_DISK)
194: continue;
195: #ifdef GEOM_DEBUG
196: printf("matchbiosdisks: trying to match (%s) %s\n",
197: dv->dv_xname, dv->dv_cfdata->cf_driver->cd_name);
198: #endif
199: if (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "sd") ||
1.47 ! ad 200: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "wd") ||
! 201: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "ca")) {
1.34 fvdl 202: n++;
1.35 fvdl 203: sprintf(i386_alldisks->dl_nativedisks[n].ni_devname,
204: "%s%d", dv->dv_cfdata->cf_driver->cd_name,
1.34 fvdl 205: dv->dv_unit);
206:
1.38 thorpej 207: for (d = dev_name2blk; d->d_name &&
1.32 fvdl 208: strcmp(d->d_name, dv->dv_cfdata->cf_driver->cd_name);
209: d++);
210: if (d->d_name == NULL)
211: return;
1.34 fvdl 212:
1.32 fvdl 213: if (bdevvp(MAKEDISKDEV(d->d_maj, dv->dv_unit, RAW_PART),
214: &tv))
215: panic("matchbiosdisks: can't alloc vnode");
1.34 fvdl 216:
1.33 fvdl 217: error = VOP_OPEN(tv, FREAD, NOCRED, 0);
218: if (error) {
1.42 fvdl 219: vput(tv);
1.33 fvdl 220: continue;
221: }
1.34 fvdl 222: error = vn_rdwr(UIO_READ, tv, mbr, DEV_BSIZE, 0,
223: UIO_SYSSPACE, 0, NOCRED, NULL, 0);
224: VOP_CLOSE(tv, FREAD, NOCRED, 0);
225: if (error) {
1.32 fvdl 226: #ifdef GEOM_DEBUG
227: printf("matchbiosdisks: %s: MBR read failure\n",
228: dv->dv_xname);
229: #endif
230: continue;
231: }
1.34 fvdl 232:
1.32 fvdl 233: for (ck = i = 0; i < DEV_BSIZE; i++)
234: ck += mbr[i];
1.34 fvdl 235: for (m = i = 0; i < big->num; i++) {
1.32 fvdl 236: be = &big->disk[i];
237: #ifdef GEOM_DEBUG
238: printf("match %s with %d\n", dv->dv_xname, i);
239: printf("dev ck %x bios ck %x\n", ck, be->cksum);
240: #endif
241: if (be->flags & BI_GEOM_INVALID)
242: continue;
243: if (be->cksum == ck &&
244: !memcmp(&mbr[MBR_PARTOFF], be->dosparts,
245: NMBRPART *
246: sizeof (struct mbr_partition))) {
247: #ifdef GEOM_DEBUG
248: printf("matched bios disk %x with %s\n",
249: be->dev, be->devname);
250: #endif
1.35 fvdl 251: i386_alldisks->dl_nativedisks[n].
252: ni_biosmatches[m++] = i;
1.32 fvdl 253: }
254: }
1.35 fvdl 255: i386_alldisks->dl_nativedisks[n].ni_nmatches = m;
1.42 fvdl 256: vput(tv);
1.32 fvdl 257: }
258: }
259: }
260:
1.43 drochner 261: #ifdef COMPAT_OLDBOOT
1.1 cgd 262: u_long bootdev = 0; /* should be dev_t, but not until 32 bits */
1.43 drochner 263: #endif
1.25 drochner 264: struct device *booted_device;
1.1 cgd 265:
266: /*
1.28 drochner 267: * helper function for "findroot()":
268: * return nonzero if disk device matches bootinfo
269: */
1.32 fvdl 270: static int
271: match_harddisk(dv, bid)
1.28 drochner 272: struct device *dv;
273: struct btinfo_bootdisk *bid;
274: {
275: struct devnametobdevmaj *i;
276: struct vnode *tmpvn;
277: int error;
278: struct disklabel label;
279: int found = 0;
280:
281: /*
282: * A disklabel is required here. The
283: * bootblocks don't refuse to boot from
284: * a disk without a label, but this is
285: * normally not wanted.
286: */
287: if (bid->labelsector == -1)
288: return(0);
289:
290: /*
291: * lookup major number for disk block device
292: */
1.38 thorpej 293: i = dev_name2blk;
1.28 drochner 294: while (i->d_name &&
295: strcmp(i->d_name, dv->dv_cfdata->cf_driver->cd_name))
296: i++;
297: if (i->d_name == NULL)
298: return(0); /* XXX panic() ??? */
299:
300: /*
301: * Fake a temporary vnode for the disk, open
302: * it, and read the disklabel for comparison.
303: */
304: if (bdevvp(MAKEDISKDEV(i->d_maj, dv->dv_unit, bid->partition), &tmpvn))
305: panic("findroot can't alloc vnode");
306: error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0);
307: if (error) {
308: #ifndef DEBUG
1.31 bouyer 309: /*
310: * Ignore errors caused by missing
311: * device, partition or medium.
312: */
313: if (error != ENXIO && error != ENODEV)
1.28 drochner 314: #endif
315: printf("findroot: can't open dev %s%c (%d)\n",
316: dv->dv_xname, 'a' + bid->partition, error);
1.42 fvdl 317: vput(tmpvn);
1.28 drochner 318: return(0);
319: }
320: error = VOP_IOCTL(tmpvn, DIOCGDINFO, (caddr_t)&label, FREAD, NOCRED, 0);
321: if (error) {
322: /*
323: * XXX can't happen - open() would
324: * have errored out (or faked up one)
325: */
326: printf("can't get label for dev %s%c (%d)\n",
327: dv->dv_xname, 'a' + bid->partition, error);
328: goto closeout;
329: }
330:
331: /* compare with our data */
332: if (label.d_type == bid->label.type &&
333: label.d_checksum == bid->label.checksum &&
334: !strncmp(label.d_packname, bid->label.packname, 16))
335: found = 1;
336:
337: closeout:
338: VOP_CLOSE(tmpvn, FREAD, NOCRED, 0);
1.42 fvdl 339: vput(tmpvn);
1.28 drochner 340: return(found);
341: }
342:
343: /*
1.1 cgd 344: * Attempt to find the device from which we were booted.
345: * If we can do so, and not instructed not to do so,
346: * change rootdev to correspond to the load device.
347: */
1.19 mycroft 348: void
1.23 thorpej 349: findroot(devpp, partp)
350: struct device **devpp;
351: int *partp;
1.1 cgd 352: {
1.25 drochner 353: struct btinfo_bootdisk *bid;
354: struct device *dv;
1.43 drochner 355: #ifdef COMPAT_OLDBOOT
1.23 thorpej 356: int i, majdev, unit, part;
357: char buf[32];
1.43 drochner 358: #endif
1.23 thorpej 359:
360: /*
361: * Default to "not found."
362: */
363: *devpp = NULL;
364: *partp = 0;
1.1 cgd 365:
1.26 thorpej 366: if (booted_device) {
1.25 drochner 367: *devpp = booted_device;
368: return;
369: }
1.26 thorpej 370: if (lookup_bootinfo(BTINFO_NETIF)) {
1.25 drochner 371: /*
372: * We got netboot interface information, but
373: * "device_register()" couldn't match it to a configured
374: * device. Bootdisk information cannot be present at the
375: * same time, so give up.
376: */
377: printf("findroot: netboot interface not found\n");
378: return;
379: }
380:
381: bid = lookup_bootinfo(BTINFO_BOOTDISK);
1.26 thorpej 382: if (bid) {
1.25 drochner 383: /*
384: * Scan all disk devices for ones that match the passed data.
385: * Don't break if one is found, to get possible multiple
386: * matches - for problem tracking. Use the first match anyway
387: * because lower device numbers are more likely to be the
388: * boot device.
389: */
390: for (dv = alldevs.tqh_first; dv != NULL;
391: dv = dv->dv_list.tqe_next) {
1.28 drochner 392: if (dv->dv_class != DV_DISK)
1.25 drochner 393: continue;
394:
1.26 thorpej 395: if (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "fd")) {
396: /*
397: * Assume the configured unit number matches
398: * the BIOS device number. (This is the old
399: * behaviour.) Needs some ideas how to handle
400: * BIOS's "swap floppy drive" options.
401: */
402: if ((bid->biosdev & 0x80) ||
403: dv->dv_unit != bid->biosdev)
1.25 drochner 404: continue;
405:
406: goto found;
407: }
408:
1.28 drochner 409: if (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "sd") ||
1.46 ad 410: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "wd") ||
411: !strcmp(dv->dv_cfdata->cf_driver->cd_name, "ca")) {
1.26 thorpej 412: /*
1.28 drochner 413: * Don't trust BIOS device numbers, try
414: * to match the information passed by the
415: * bootloader instead.
1.26 thorpej 416: */
1.28 drochner 417: if ((bid->biosdev & 0x80) == 0 ||
418: !match_harddisk(dv, bid))
1.25 drochner 419: continue;
420:
1.28 drochner 421: goto found;
1.25 drochner 422: }
423:
1.46 ad 424: /* no "fd", "wd", "sd" or "ca" */
1.25 drochner 425: continue;
426:
427: found:
1.26 thorpej 428: if (*devpp) {
429: printf("warning: double match for boot "
430: "device (%s, %s)\n", (*devpp)->dv_xname,
431: dv->dv_xname);
1.25 drochner 432: continue;
433: }
434: *devpp = dv;
435: *partp = bid->partition;
436: }
437:
1.26 thorpej 438: if (*devpp)
1.25 drochner 439: return;
440: }
441:
1.43 drochner 442: #ifdef COMPAT_OLDBOOT
1.20 christos 443: #if 0
1.22 christos 444: printf("howto %x bootdev %x ", boothowto, bootdev);
1.20 christos 445: #endif
1.23 thorpej 446:
447: if ((bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
1.1 cgd 448: return;
1.23 thorpej 449:
1.1 cgd 450: majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
1.38 thorpej 451: for (i = 0; dev_name2blk[i].d_name != NULL; i++)
452: if (majdev == dev_name2blk[i].d_maj)
1.23 thorpej 453: break;
1.38 thorpej 454: if (dev_name2blk[i].d_name == NULL)
1.1 cgd 455: return;
1.23 thorpej 456:
1.1 cgd 457: part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
458: unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
1.23 thorpej 459:
1.38 thorpej 460: sprintf(buf, "%s%d", dev_name2blk[i].d_name, unit);
1.23 thorpej 461: for (dv = alldevs.tqh_first; dv != NULL;
462: dv = dv->dv_list.tqe_next) {
463: if (strcmp(buf, dv->dv_xname) == 0) {
464: *devpp = dv;
465: *partp = part;
466: return;
1.1 cgd 467: }
468: }
1.43 drochner 469: #endif
1.25 drochner 470: }
471:
1.26 thorpej 472: #include "pci.h"
473:
1.25 drochner 474: #include <dev/isa/isavar.h>
1.26 thorpej 475: #if NPCI > 0
1.25 drochner 476: #include <dev/pci/pcivar.h>
1.26 thorpej 477: #endif
1.25 drochner 478:
479: void
480: device_register(dev, aux)
481: struct device *dev;
482: void *aux;
483: {
484: /*
485: * Handle network interfaces here, the attachment information is
486: * not available driver independantly later.
487: * For disks, there is nothing useful available at attach time.
488: */
1.26 thorpej 489: if (dev->dv_class == DV_IFNET) {
1.25 drochner 490: struct btinfo_netif *bin = lookup_bootinfo(BTINFO_NETIF);
1.26 thorpej 491: if (bin == NULL)
1.25 drochner 492: return;
493:
1.44 drochner 494: /*
495: * We don't check the driver name against the device name
496: * passed by the boot ROM. The ROM should stay usable
497: * if the driver gets obsoleted.
498: * The physical attachment information (checked below)
499: * must be sufficient to identify the device.
500: */
1.25 drochner 501:
1.26 thorpej 502: if (bin->bus == BI_BUS_ISA &&
503: !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name,
504: "isa")) {
1.25 drochner 505: struct isa_attach_args *iaa = aux;
506:
507: /* compare IO base address */
1.26 thorpej 508: if (bin->addr.iobase == iaa->ia_iobase)
1.27 drochner 509: goto found;
1.25 drochner 510: }
1.26 thorpej 511: #if NPCI > 0
512: if (bin->bus == BI_BUS_PCI &&
513: !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name,
514: "pci")) {
1.25 drochner 515: struct pci_attach_args *paa = aux;
516: int b, d, f;
517:
1.26 thorpej 518: /*
519: * Calculate BIOS representation of:
520: *
521: * <bus,device,function>
522: *
523: * and compare.
524: */
1.25 drochner 525: pci_decompose_tag(paa->pa_pc, paa->pa_tag, &b, &d, &f);
1.26 thorpej 526: if (bin->addr.tag == ((b << 8) | (d << 3) | f))
1.25 drochner 527: goto found;
528: }
1.26 thorpej 529: #endif
1.25 drochner 530: }
531: return;
532:
533: found:
1.26 thorpej 534: if (booted_device) {
1.25 drochner 535: /* XXX should be a "panic()" */
536: printf("warning: double match for boot device (%s, %s)\n",
1.26 thorpej 537: booted_device->dv_xname, dev->dv_xname);
1.25 drochner 538: return;
539: }
540: booted_device = dev;
1.1 cgd 541: }
CVSweb <webmaster@jp.NetBSD.org>