autoconf.c revision 31337
1/*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91 37 * $Id: autoconf.c,v 1.81 1997/11/21 18:14:02 bde Exp $ 38 */ 39 40/* 41 * Setup the system to run on the current machine. 42 * 43 * Configure() is called at boot time and initializes the vba 44 * device tables and the memory controller monitoring. Available 45 * devices are determined (from possibilities mentioned in ioconf.c), 46 * and the drivers are initialized. 47 */ 48#include "opt_cd9660.h" 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/conf.h> 53#include <sys/disklabel.h> 54#include <sys/reboot.h> 55#include <sys/kernel.h> 56#include <sys/mount.h> 57#include <sys/sysctl.h> 58 59#include <machine/bootinfo.h> 60#include <machine/cons.h> 61#include <machine/ipl.h> 62#include <machine/md_var.h> 63#ifdef APIC_IO 64#include <machine/smp.h> 65#endif /* APIC_IO */ 66 67#include <i386/isa/icu.h> /* For interrupts */ 68 69#include "isa.h" 70#if NISA > 0 71#include <i386/isa/isa_device.h> 72#endif 73 74#include "pnp.h" 75#if NPNP > 0 76#include <i386/isa/pnp.h> 77#endif 78 79#include "eisa.h" 80#if NEISA > 0 81#include <i386/eisa/eisaconf.h> 82#endif 83 84#include "pci.h" 85#if NPCI > 0 86#include <pci/pcivar.h> 87#endif 88 89#include "card.h" 90#if NCARD > 0 91#include <pccard/driver.h> 92#endif 93 94#include "scbus.h" 95#if NSCBUS > 0 96#include <scsi/scsiconf.h> 97#endif 98 99static void configure __P((void *)); 100SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL) 101 102static void configure_finish __P((void)); 103static void configure_start __P((void)); 104static int setdumpdev __P((dev_t dev)); 105static void setroot __P((void)); 106 107#ifdef CD9660 108 109#include <sys/fcntl.h> 110#include <sys/proc.h> 111#include <sys/stat.h> 112#include <machine/clock.h> 113 114/* 115 * XXX All this CD-ROM root stuff is fairly messy. Ick. 116 * 117 * We need to try out all our potential CDROM drives, so we need a table. 118 */ 119static struct { 120 char *name; 121 int major; 122} try_cdrom[] = { 123 { "cd", 6 }, 124 { "mcd", 7 }, 125 { "scd", 16 }, 126 { "matcd", 17 }, 127 { "wcd", 19 }, 128 { 0, 0} 129}; 130 131static int find_cdrom_root __P((void)); 132 133static int 134find_cdrom_root() 135{ 136 int i, j, error; 137 struct bdevsw *bd; 138 dev_t orootdev; 139 140#if CD9660_ROOTDELAY > 0 141 DELAY(CD9660_ROOTDELAY * 1000000); 142#endif 143 orootdev = rootdev; 144 for (i = 0 ; i < 2; i++) 145 for (j = 0 ; try_cdrom[j].name ; j++) { 146 if (try_cdrom[j].major >= nblkdev) 147 continue; 148 rootdev = makedev(try_cdrom[j].major, i * 8); 149 bd = bdevsw[major(rootdev)]; 150 if (bd == NULL || bd->d_open == NULL) 151 continue; 152 if (bootverbose) 153 printf("trying %s%d as rootdev (0x%x)\n", 154 try_cdrom[j].name, i, rootdev); 155 error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc); 156 if (error == 0) { 157 if (bd->d_close != NULL) 158 (bd->d_close)(rootdev, FREAD, S_IFBLK, 159 curproc); 160 return 0; 161 } 162 } 163 164 rootdev = orootdev; 165 return EINVAL; 166} 167#endif /* CD9660 */ 168 169static void 170configure_start() 171{ 172#if NSCBUS > 0 173 scsi_configure_start(); 174#endif 175} 176 177static void 178configure_finish() 179{ 180#if NSCBUS > 0 181 scsi_configure_finish(); 182#endif 183} 184 185/* 186 * Determine i/o configuration for a machine. 187 */ 188static void 189configure(dummy) 190 void *dummy; 191{ 192 int i; 193 194 configure_start(); 195 196 /* Allow all routines to decide for themselves if they want intrs */ 197 /* 198 * XXX Since this cannot be achieved on all architectures, we should 199 * XXX go back to disabling all interrupts until configuration is 200 * XXX completed and switch any devices that rely on the current 201 * XXX behavior to no longer rely on interrupts or to register an 202 * XXX interrupt_driven_config_hook for the task. 203 */ 204 /* 205 * XXX The above is wrong, because we're implicitly at splhigh(), 206 * XXX and should stay there, so enabling interrupts in the CPU 207 * XXX and the ICU at most gives pending interrupts which just get 208 * XXX in the way. 209 */ 210#ifdef APIC_IO 211 bsp_apic_configure(); 212 enable_intr(); 213#else 214 enable_intr(); 215 INTREN(IRQ_SLAVE); 216#endif /* APIC_IO */ 217 218#if NEISA > 0 219 eisa_configure(); 220#endif 221 222#if NPCI > 0 223 pci_configure(); 224#endif 225 226#if NPNP > 0 227 pnp_configure(); 228#endif 229 230#if NISA > 0 231 isa_configure(); 232#endif 233 234 /* 235 * Now we're ready to handle (pending) interrupts. 236 * XXX this is slightly misplaced. 237 */ 238 spl0(); 239 240 /* 241 * Allow lowering of the ipl to the lowest kernel level if we 242 * panic (or call tsleep() before clearing `cold'). No level is 243 * completely safe (since a panic may occur in a critical region 244 * at splhigh()), but we want at least bio interrupts to work. 245 */ 246 safepri = cpl; 247 248#if NCARD > 0 249 /* After everyone else has a chance at grabbing resources */ 250 pccard_configure(); 251#endif 252 253 configure_finish(); 254 255 cninit_finish(); 256 257 if (bootverbose) { 258 259#ifdef APIC_IO 260 imen_dump(); 261#endif /* APIC_IO */ 262 263 /* 264 * Print out the BIOS's idea of the disk geometries. 265 */ 266 printf("BIOS Geometries:\n"); 267 for (i = 0; i < N_BIOS_GEOM; i++) { 268 unsigned long bios_geom; 269 int max_cylinder, max_head, max_sector; 270 271 bios_geom = bootinfo.bi_bios_geom[i]; 272 273 /* 274 * XXX the bootstrap punts a 1200K floppy geometry 275 * when the get-disk-geometry interrupt fails. Skip 276 * drives that have this geometry. 277 */ 278 if (bios_geom == 0x4f010f) 279 continue; 280 281 printf(" %x:%08lx ", i, bios_geom); 282 max_cylinder = bios_geom >> 16; 283 max_head = (bios_geom >> 8) & 0xff; 284 max_sector = bios_geom & 0xff; 285 printf( 286 "0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n", 287 max_cylinder, max_cylinder + 1, 288 max_head, max_head + 1, 289 max_sector, max_sector); 290 } 291 printf(" %d accounted for\n", bootinfo.bi_n_bios_used); 292 293 printf("Device configuration finished.\n"); 294 } 295 cold = 0; 296} 297 298void 299cpu_rootconf() 300{ 301 /* 302 * XXX NetBSD has a much cleaner approach to finding root. 303 * XXX We should adopt their code. 304 */ 305#ifdef CD9660 306 if ((boothowto & RB_CDROM)) { 307 if (bootverbose) 308 printf("Considering CD-ROM root f/s.\n"); 309 /* NB: find_cdrom_root() sets rootdev if successful. */ 310 if (find_cdrom_root() == 0) 311 mountrootfsname = "cd9660"; 312 else if (bootverbose) 313 printf("No CD-ROM available as root f/s.\n"); 314 } 315#endif 316 317#ifdef MFS_ROOT 318 if (!mountrootfsname) { 319 if (bootverbose) 320 printf("Considering MFS root f/s.\n"); 321 mountrootfsname = "mfs"; 322 /* 323 * Ignore the -a flag if this kernel isn't compiled 324 * with a generic root/swap configuration: if we skip 325 * setroot() and we aren't a generic kernel, chaos 326 * will ensue because setconf() will be a no-op. 327 * (rootdev is always initialized to NODEV in a 328 * generic configuration, so we test for that.) 329 */ 330 if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) 331 setroot(); 332 } 333#endif 334 335#ifdef BOOTP_NFSROOT 336 if (!mountrootfsname && !nfs_diskless_valid) { 337 if (bootverbose) 338 printf("Considering BOOTP NFS root f/s.\n"); 339 mountrootfsname = "nfs"; 340 } 341#endif /* BOOTP_NFSROOT */ 342#ifdef NFS 343 if (!mountrootfsname && nfs_diskless_valid) { 344 if (bootverbose) 345 printf("Considering NFS root f/s.\n"); 346 mountrootfsname = "nfs"; 347 } 348#endif /* NFS */ 349 350#ifdef FFS 351 if (!mountrootfsname) { 352 mountrootfsname = "ufs"; 353 if (bootverbose) 354 printf("Considering FFS root f/s.\n"); 355 /* 356 * Ignore the -a flag if this kernel isn't compiled 357 * with a generic root/swap configuration: if we skip 358 * setroot() and we aren't a generic kernel, chaos 359 * will ensue because setconf() will be a no-op. 360 * (rootdev is always initialized to NODEV in a 361 * generic configuration, so we test for that.) 362 */ 363 if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) 364 setroot(); 365 } 366#endif 367 368#ifdef LFS 369 if (!mountrootfsname) { 370 if (bootverbose) 371 printf("Considering LFS root f/s.\n"); 372 mountrootfsname = "lfs"; 373 /* 374 * Ignore the -a flag if this kernel isn't compiled 375 * with a generic root/swap configuration: if we skip 376 * setroot() and we aren't a generic kernel, chaos 377 * will ensue because setconf() will be a no-op. 378 * (rootdev is always initialized to NODEV in a 379 * generic configuration, so we test for that.) 380 */ 381 if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV) 382 setroot(); 383 } 384#endif 385 386 if (!mountrootfsname) { 387 panic("Nobody wants to mount my root for me"); 388 } 389 390 setconf(); 391} 392 393void 394cpu_dumpconf() 395{ 396 if (setdumpdev(dumpdev) != 0) 397 dumpdev = NODEV; 398} 399 400static int 401setdumpdev(dev) 402 dev_t dev; 403{ 404 int maj, psize; 405 long newdumplo; 406 407 if (dev == NODEV) { 408 dumpdev = dev; 409 return (0); 410 } 411 maj = major(dev); 412 if (maj >= nblkdev) 413 return (ENXIO); 414 if (bdevsw[maj] == NULL) 415 return (ENXIO); /* XXX is this right? */ 416 if (bdevsw[maj]->d_psize == NULL) 417 return (ENXIO); /* XXX should be ENODEV ? */ 418 psize = bdevsw[maj]->d_psize(dev); 419 if (psize == -1) 420 return (ENXIO); /* XXX should be ENODEV ? */ 421 /* 422 * XXX should clean up checking in dumpsys() to be more like this, 423 * and nuke dodump sysctl (too many knobs), and move this to 424 * kern_shutdown.c... 425 */ 426 if (dkpart(dev) != SWAP_PART) 427 return (ENODEV); 428 newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE; 429 if (newdumplo < 0) 430 return (ENOSPC); 431 dumpdev = dev; 432 dumplo = newdumplo; 433 return (0); 434} 435 436u_long bootdev = 0; /* not a dev_t - encoding is different */ 437 438static char devname[][2] = { 439 {'w','d'}, /* 0 = wd */ 440 {'s','w'}, /* 1 = sw */ 441#define FDMAJOR 2 442 {'f','d'}, /* 2 = fd */ 443 {'w','t'}, /* 3 = wt */ 444 {'s','d'}, /* 4 = sd -- new SCSI system */ 445}; 446 447#define PARTITIONMASK 0x7 448#define PARTITIONSHIFT 3 449#define FDUNITSHIFT 6 450#define RAW_PART 2 451 452/* 453 * Attempt to find the device from which we were booted. 454 * If we can do so, and not instructed not to do so, 455 * change rootdev to correspond to the load device. 456 */ 457static void 458setroot() 459{ 460 int majdev, mindev, unit, part, adaptor; 461 dev_t orootdev; 462 463/*printf("howto %x bootdev %x ", boothowto, bootdev);*/ 464 if (boothowto & RB_DFLTROOT || 465 (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) 466 return; 467 majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; 468 if (majdev > sizeof(devname) / sizeof(devname[0])) 469 return; 470 adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK; 471 unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; 472 if (majdev == FDMAJOR) { 473 part = RAW_PART; 474 mindev = unit << FDUNITSHIFT; 475 } 476 else { 477 part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; 478 mindev = (unit << PARTITIONSHIFT) + part; 479 } 480 orootdev = rootdev; 481 rootdev = makedev(majdev, mindev); 482 /* 483 * If the original rootdev is the same as the one 484 * just calculated, don't need to adjust the swap configuration. 485 */ 486 if (rootdev == orootdev) 487 return; 488 printf("changing root device to %c%c%d%c\n", 489 devname[majdev][0], devname[majdev][1], 490 mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT), 491 part + 'a'); 492} 493 494static int 495sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS 496{ 497 int error; 498 dev_t ndumpdev; 499 500 ndumpdev = dumpdev; 501 error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); 502 if (error == 0 && req->newptr != NULL) 503 error = setdumpdev(ndumpdev); 504 return (error); 505} 506 507SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, 508 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", ""); 509