autoconf.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 518 行
C
518 行
/*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * 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. * * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 * $Id: autoconf.c,v 1.111 1999/01/19 00:10:59 peter Exp $ *//* * Setup the system to run on the current machine. * * Configure() is called at boot time and initializes the vba * device tables and the memory controller monitoring. Available * devices are determined (from possibilities mentioned in ioconf.c), * and the drivers are initialized. */#include "opt_bootp.h"#include "opt_ffs.h"#include "opt_cd9660.h"#include "opt_mfs.h"#include "opt_nfsroot.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/disklabel.h>#include <sys/diskslice.h>#include <sys/reboot.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/mount.h>#include <sys/sysctl.h>#include <machine/bootinfo.h>#include <machine/cons.h>#include <machine/ipl.h>#include <machine/md_var.h>#ifdef APIC_IO#include <machine/smp.h>#endif /* APIC_IO */#include <i386/isa/icu.h>#include "isa.h"#if NISA > 0#include <i386/isa/isa_device.h>#endif#include "pnp.h"#if NPNP > 0#include <i386/isa/pnp.h>#endif#include "eisa.h"#if NEISA > 0#include <i386/eisa/eisaconf.h>#endif#include "pci.h"#if NPCI > 0#include <pci/pcivar.h>#endif#include <sys/bus.h>static void configure_first __P((void *));static void configure __P((void *));static void configure_final __P((void *));static void configure_finish __P((void));static void configure_start __P((void));static int setdumpdev __P((dev_t dev));static void setroot __P((void));SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);/* SI_ORDER_SECOND is hookable */SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);/* SI_ORDER_MIDDLE is hookable */SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);#if defined(CD9660) || defined(CD9660_ROOT)#include <sys/fcntl.h>#include <sys/proc.h>#include <sys/stat.h>#include <machine/clock.h>/* * XXX All this CD-ROM root stuff is fairly messy. Ick. * * We need to try out all our potential CDROM drives, so we need a table. */static struct { char *name; int major;} try_cdrom[] = { { "cd", 6 }, { "mcd", 7 }, { "scd", 16 }, { "matcd", 17 }, { "wcd", 19 }, { 0, 0}};static int find_cdrom_root __P((void));static intfind_cdrom_root(){ int i, j, error; struct cdevsw *bd; dev_t orootdev;#if CD9660_ROOTDELAY > 0 DELAY(CD9660_ROOTDELAY * 1000000);#endif orootdev = rootdev; for (i = 0 ; i < 2; i++) for (j = 0 ; try_cdrom[j].name ; j++) { if (try_cdrom[j].major >= nblkdev) continue; rootdev = makedev(try_cdrom[j].major, i * 8); bd = bdevsw[major(rootdev)]; if (bd == NULL || bd->d_open == NULL) continue; if (bootverbose) printf("trying %s%d as rootdev (0x%x)\n", try_cdrom[j].name, i, rootdev); error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc); if (error == 0) { if (bd->d_close != NULL) (bd->d_close)(rootdev, FREAD, S_IFBLK, curproc); return 0; } } rootdev = orootdev; return EINVAL;}#endif /* CD9660 || CD9660_ROOT */#ifdef MFS_ROOTextern u_char *mfs_getimage __P((void));#endifstatic voidconfigure_start(){}static voidconfigure_finish(){}/* * Determine i/o configuration for a machine. */static voidconfigure_first(dummy) void *dummy;{ configure_start(); /* DDB hook? */}static voidconfigure(dummy) void *dummy;{ /* Allow all routines to decide for themselves if they want intrs */ /* * XXX Since this cannot be achieved on all architectures, we should * XXX go back to disabling all interrupts until configuration is * XXX completed and switch any devices that rely on the current * XXX behavior to no longer rely on interrupts or to register an * XXX interrupt_driven_config_hook for the task. */ /* * XXX The above is wrong, because we're implicitly at splhigh(), * XXX and should stay there, so enabling interrupts in the CPU * XXX and the ICU at most gives pending interrupts which just get * XXX in the way. */#ifdef APIC_IO bsp_apic_configure(); enable_intr();#else enable_intr(); INTREN(IRQ_SLAVE);#endif /* APIC_IO */#if NEISA > 0 eisa_configure();#endif#if NPCI > 0 pci_configure();#endif#if NPNP > 0 pnp_configure();#endif#if NISA > 0 isa_configure();#endif /* initialize new bus architecture */ root_bus_configure(); /* * Now we're ready to handle (pending) interrupts. * XXX this is slightly misplaced. */ spl0(); /* * Allow lowering of the ipl to the lowest kernel level if we * panic (or call tsleep() before clearing `cold'). No level is * completely safe (since a panic may occur in a critical region * at splhigh()), but we want at least bio interrupts to work. */ safepri = cpl;}static voidconfigure_final(dummy) void *dummy;{ int i; configure_finish(); /* DDB hook? */ cninit_finish(); if (bootverbose) {#ifdef APIC_IO imen_dump();#endif /* APIC_IO */ /* * Print out the BIOS's idea of the disk geometries. */ printf("BIOS Geometries:\n"); for (i = 0; i < N_BIOS_GEOM; i++) { unsigned long bios_geom; int max_cylinder, max_head, max_sector; bios_geom = bootinfo.bi_bios_geom[i]; /* * XXX the bootstrap punts a 1200K floppy geometry * when the get-disk-geometry interrupt fails. Skip * drives that have this geometry. */ if (bios_geom == 0x4f010f) continue; printf(" %x:%08lx ", i, bios_geom); max_cylinder = bios_geom >> 16; max_head = (bios_geom >> 8) & 0xff; max_sector = bios_geom & 0xff; printf( "0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n", max_cylinder, max_cylinder + 1, max_head, max_head + 1, max_sector, max_sector); } printf(" %d accounted for\n", bootinfo.bi_n_bios_used); printf("Device configuration finished.\n"); } cold = 0;}voidcpu_rootconf(){ /* * XXX NetBSD has a much cleaner approach to finding root. * XXX We should adopt their code. */#if defined(CD9660) || defined(CD9660_ROOT) if ((boothowto & RB_CDROM)) { if (bootverbose) printf("Considering CD-ROM root f/s.\n"); /* NB: find_cdrom_root() sets rootdev if successful. */ if (find_cdrom_root() == 0) mountrootfsname = "cd9660"; else if (bootverbose) printf("No CD-ROM available as root f/s.\n"); }#endif#ifdef MFS_ROOT if (!mountrootfsname) { if (bootverbose) printf("Considering MFS root f/s.\n"); if (mfs_getimage()) { mountrootfsname = "mfs"; /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip * setroot() and we aren't a generic kernel, chaos * will ensue because setconf() will be a no-op. * (rootdev is always initialized to NODEV in a * generic configuration, so we test for that.) */ if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) setroot(); } else if (bootverbose) printf("No MFS image available as root f/s.\n"); }#endif#ifdef BOOTP_NFSROOT if (!mountrootfsname && !nfs_diskless_valid) { if (bootverbose) printf("Considering BOOTP NFS root f/s.\n"); mountrootfsname = "nfs"; }#endif /* BOOTP_NFSROOT */#if defined(NFS) || defined(NFS_ROOT) if (!mountrootfsname && nfs_diskless_valid) { if (bootverbose) printf("Considering NFS root f/s.\n"); mountrootfsname = "nfs"; }#endif /* NFS */#if defined(FFS) || defined(FFS_ROOT) if (!mountrootfsname) { mountrootfsname = "ufs"; if (bootverbose) printf("Considering FFS root f/s.\n"); /* * Ignore the -a flag if this kernel isn't compiled * with a generic root/swap configuration: if we skip * setroot() and we aren't a generic kernel, chaos * will ensue because setconf() will be a no-op. * (rootdev is always initialized to NODEV in a * generic configuration, so we test for that.) */ if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) setroot(); }#endif if (!mountrootfsname) { panic("Nobody wants to mount my root for me"); } setconf();}voidcpu_dumpconf(){ if (setdumpdev(dumpdev) != 0) dumpdev = NODEV;}static intsetdumpdev(dev) dev_t dev;{ int maj, psize; long newdumplo; if (dev == NODEV) { dumpdev = dev; return (0); } maj = major(dev); if (maj >= nblkdev || bdevsw[maj] == NULL) return (ENXIO); /* XXX is this right? */ if (bdevsw[maj]->d_psize == NULL) return (ENXIO); /* XXX should be ENODEV ? */ psize = bdevsw[maj]->d_psize(dev); if (psize == -1) return (ENXIO); /* XXX should be ENODEV ? */ /* * XXX should clean up checking in dumpsys() to be more like this, * and nuke dodump sysctl (too many knobs), and move this to * kern_shutdown.c... */ newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE; if (newdumplo < 0) return (ENOSPC); dumpdev = dev; dumplo = newdumplo; return (0);}u_long bootdev = 0; /* not a dev_t - encoding is different */#define FDMAJOR 2#define FDUNITSHIFT 6/* * Attempt to find the device from which we were booted. * If we can do so, and not instructed not to do so, * set rootdevs[] and rootdevnames[] to correspond to the * boot device(s). */static voidsetroot(){ int majdev, mindev, unit, slice, part; dev_t newrootdev; char partname[2]; char *sname; if (boothowto & RB_DFLTROOT || (bootdev & B_MAGICMASK) != B_DEVMAGIC) return; majdev = B_TYPE(bootdev); if (majdev >= nblkdev || bdevsw[majdev] == NULL) return; unit = B_UNIT(bootdev); slice = B_SLICE(bootdev); if (slice == WHOLE_DISK_SLICE) slice = COMPATIBILITY_SLICE; if (slice < 0 || slice >= MAX_SLICES) return; /* * XXX kludge for inconsistent unit numbering and lack of slice * support for floppies. */ if (majdev == FDMAJOR) { slice = COMPATIBILITY_SLICE; part = RAW_PART; mindev = unit << FDUNITSHIFT; } else { part = B_PARTITION(bootdev); mindev = dkmakeminor(unit, slice, part); } newrootdev = makedev(majdev, mindev); rootdevs[0] = newrootdev; sname = dsname(bdevsw[majdev]->d_name, unit, slice, part, partname); rootdevnames[0] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT); sprintf(rootdevnames[0], "%s%s", sname, partname); /* * For properly dangerously dedicated disks (ones with a historical * bogus partition table), the boot blocks will give slice = 4, but * the kernel will only provide the compatibility slice since it * knows that slice 4 is not a real slice. Arrange to try mounting * the compatibility slice as root if mounting the slice passed by * the boot blocks fails. This handles the dangerously dedicated * case and perhaps others. */ if (slice == COMPATIBILITY_SLICE) return; slice = COMPATIBILITY_SLICE; rootdevs[1] = dkmodslice(newrootdev, slice); sname = dsname(bdevsw[majdev]->d_name, unit, slice, part, partname); rootdevnames[1] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT); sprintf(rootdevnames[1], "%s%s", sname, partname);}static intsysctl_kern_dumpdev SYSCTL_HANDLER_ARGS{ int error; dev_t ndumpdev; ndumpdev = dumpdev; error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); if (error == 0 && req->newptr != NULL) error = setdumpdev(ndumpdev); return (error);}SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?