autoconf.c revision 46808
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.119 1999/05/09 16:45:49 phk 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_bootp.h" 49#include "opt_ffs.h" 50#include "opt_cd9660.h" 51#include "opt_mfs.h" 52#include "opt_nfsroot.h" 53#include "opt_bus.h" 54#include "opt_rootdevname.h" 55 56#include <sys/param.h> 57#include <sys/systm.h> 58#include <sys/bus.h> 59#include <sys/conf.h> 60#include <sys/disklabel.h> 61#include <sys/diskslice.h> 62#include <sys/reboot.h> 63#include <sys/kernel.h> 64#include <sys/malloc.h> 65#include <sys/mount.h> 66#include <sys/sysctl.h> 67 68#include <machine/bootinfo.h> 69#include <machine/cons.h> 70#include <machine/ipl.h> 71#include <machine/md_var.h> 72#ifdef APIC_IO 73#include <machine/smp.h> 74#endif /* APIC_IO */ 75 76#include <i386/isa/icu.h> 77 78#include "isa.h" 79#if NISA > 0 80device_t isa_bus_device = 0; 81#endif 82 83#include "pnp.h" 84#if NPNP > 0 85#include <i386/isa/isa_device.h> 86#include <i386/isa/pnp.h> 87#endif 88 89#include "eisa.h" 90#if NEISA > 0 91#include <i386/eisa/eisaconf.h> 92#endif 93 94#include "pci.h" 95#if NPCI > 0 96#include <pci/pcivar.h> 97#endif 98 99static void configure_first __P((void *)); 100static void configure __P((void *)); 101static void configure_final __P((void *)); 102 103static void configure_finish __P((void)); 104static void configure_start __P((void)); 105static int setdumpdev __P((dev_t dev)); 106static void setroot __P((void)); 107static int setrootbyname __P((char *name)); 108static void gets __P((char *)); 109 110SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL); 111/* SI_ORDER_SECOND is hookable */ 112SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL); 113/* SI_ORDER_MIDDLE is hookable */ 114SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL); 115 116dev_t rootdev = NODEV; 117dev_t dumpdev = NODEV; 118 119#if defined(CD9660) || defined(CD9660_ROOT) 120 121#include <sys/fcntl.h> 122#include <sys/proc.h> 123#include <sys/stat.h> 124#include <machine/clock.h> 125 126/* 127 * XXX All this CD-ROM root stuff is fairly messy. Ick. 128 * 129 * We need to try out all our potential CDROM drives, so we need a table. 130 */ 131static struct { 132 char *name; 133 int major; 134} try_cdrom[] = { 135 { "cd", 6 }, 136 { "mcd", 7 }, 137 { "scd", 16 }, 138 { "matcd", 17 }, 139 { "wcd", 19 }, 140 { 0, 0} 141}; 142 143static int find_cdrom_root __P((void)); 144 145static int 146find_cdrom_root() 147{ 148 int i, j, error; 149 struct cdevsw *bd; 150 dev_t orootdev; 151 152#if CD9660_ROOTDELAY > 0 153 DELAY(CD9660_ROOTDELAY * 1000000); 154#endif 155 orootdev = rootdev; 156 for (i = 0 ; i < 2; i++) 157 for (j = 0 ; try_cdrom[j].name ; j++) { 158 if (try_cdrom[j].major >= nblkdev) 159 continue; 160 rootdev = makedev(try_cdrom[j].major, i * 8); 161 bd = bdevsw(rootdev); 162 if (bd == NULL || bd->d_open == NULL) 163 continue; 164 if (bootverbose) 165 printf("trying %s%d as rootdev (0x%x)\n", 166 try_cdrom[j].name, i, rootdev); 167 error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc); 168 if (error == 0) { 169 if (bd->d_close != NULL) 170 (bd->d_close)(rootdev, FREAD, S_IFBLK, 171 curproc); 172 return 0; 173 } 174 } 175 176 rootdev = orootdev; 177 return EINVAL; 178} 179#endif /* CD9660 || CD9660_ROOT */ 180 181#ifdef MFS_ROOT 182extern u_char *mfs_getimage __P((void)); 183#endif 184 185static void 186configure_start() 187{ 188} 189 190static void 191configure_finish() 192{ 193} 194 195device_t nexus_dev; 196 197/* 198 * Determine i/o configuration for a machine. 199 */ 200static void 201configure_first(dummy) 202 void *dummy; 203{ 204 205 configure_start(); /* DDB hook? */ 206} 207 208static void 209configure(dummy) 210 void *dummy; 211{ 212 213 /* Allow all routines to decide for themselves if they want intrs */ 214 /* 215 * XXX Since this cannot be achieved on all architectures, we should 216 * XXX go back to disabling all interrupts until configuration is 217 * XXX completed and switch any devices that rely on the current 218 * XXX behavior to no longer rely on interrupts or to register an 219 * XXX interrupt_driven_config_hook for the task. 220 */ 221 /* 222 * XXX The above is wrong, because we're implicitly at splhigh(), 223 * XXX and should stay there, so enabling interrupts in the CPU 224 * XXX and the ICU at most gives pending interrupts which just get 225 * XXX in the way. 226 */ 227#ifdef APIC_IO 228 bsp_apic_configure(); 229 enable_intr(); 230#else 231 enable_intr(); 232 INTREN(IRQ_SLAVE); 233#endif /* APIC_IO */ 234 235#if NPNP > 0 236 pnp_configure(); 237#endif 238 239 /* nexus0 is the top of the i386 device tree */ 240 device_add_child(root_bus, "nexus", 0, 0); 241 242 /* initialize new bus architecture */ 243 root_bus_configure(); 244 245#if NISA > 0 246 if (isa_bus_device) 247 bus_generic_attach(isa_bus_device); 248#endif 249 250 /* 251 * Now we're ready to handle (pending) interrupts. 252 * XXX this is slightly misplaced. 253 */ 254 spl0(); 255 256 /* 257 * Allow lowering of the ipl to the lowest kernel level if we 258 * panic (or call tsleep() before clearing `cold'). No level is 259 * completely safe (since a panic may occur in a critical region 260 * at splhigh()), but we want at least bio interrupts to work. 261 */ 262 safepri = cpl; 263} 264 265static void 266configure_final(dummy) 267 void *dummy; 268{ 269 int i; 270 271 configure_finish(); /* DDB hook? */ 272 273 cninit_finish(); 274 275 if (bootverbose) { 276 277#ifdef APIC_IO 278 imen_dump(); 279#endif /* APIC_IO */ 280 281 /* 282 * Print out the BIOS's idea of the disk geometries. 283 */ 284 printf("BIOS Geometries:\n"); 285 for (i = 0; i < N_BIOS_GEOM; i++) { 286 unsigned long bios_geom; 287 int max_cylinder, max_head, max_sector; 288 289 bios_geom = bootinfo.bi_bios_geom[i]; 290 291 /* 292 * XXX the bootstrap punts a 1200K floppy geometry 293 * when the get-disk-geometry interrupt fails. Skip 294 * drives that have this geometry. 295 */ 296 if (bios_geom == 0x4f010f) 297 continue; 298 299 printf(" %x:%08lx ", i, bios_geom); 300 max_cylinder = bios_geom >> 16; 301 max_head = (bios_geom >> 8) & 0xff; 302 max_sector = bios_geom & 0xff; 303 printf( 304 "0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n", 305 max_cylinder, max_cylinder + 1, 306 max_head, max_head + 1, 307 max_sector, max_sector); 308 } 309 printf(" %d accounted for\n", bootinfo.bi_n_bios_used); 310 311 printf("Device configuration finished.\n"); 312 } 313 cold = 0; 314} 315 316 317void 318cpu_rootconf() 319{ 320 /* 321 * XXX NetBSD has a much cleaner approach to finding root. 322 * XXX We should adopt their code. 323 */ 324#if defined(CD9660) || defined(CD9660_ROOT) 325 if ((boothowto & RB_CDROM)) { 326 if (bootverbose) 327 printf("Considering CD-ROM root f/s.\n"); 328 /* NB: find_cdrom_root() sets rootdev if successful. */ 329 if (find_cdrom_root() == 0) 330 mountrootfsname = "cd9660"; 331 else if (bootverbose) 332 printf("No CD-ROM available as root f/s.\n"); 333 } 334#endif 335 336#ifdef MFS_ROOT 337 if (!mountrootfsname) { 338 if (bootverbose) 339 printf("Considering MFS root f/s.\n"); 340 if (mfs_getimage()) 341 mountrootfsname = "mfs"; 342 else if (bootverbose) 343 printf("No MFS image available as root f/s.\n"); 344 } 345#endif 346 347#ifdef BOOTP_NFSROOT 348 if (!mountrootfsname && !nfs_diskless_valid) { 349 if (bootverbose) 350 printf("Considering BOOTP NFS root f/s.\n"); 351 mountrootfsname = "nfs"; 352 } 353#endif /* BOOTP_NFSROOT */ 354#if defined(NFS) || defined(NFS_ROOT) 355 if (!mountrootfsname && nfs_diskless_valid) { 356 if (bootverbose) 357 printf("Considering NFS root f/s.\n"); 358 mountrootfsname = "nfs"; 359 } 360#endif /* NFS */ 361 362#if defined(FFS) || defined(FFS_ROOT) 363 if (!mountrootfsname) { 364 mountrootfsname = "ufs"; 365 if (bootverbose) 366 printf("Considering FFS root f/s.\n"); 367 if (boothowto & RB_ASKNAME) 368 setconf(); 369 else 370 setroot(); 371 } 372#endif 373 374 if (!mountrootfsname) { 375 panic("Nobody wants to mount my root for me"); 376 } 377} 378 379 380void 381cpu_dumpconf() 382{ 383 if (setdumpdev(dumpdev) != 0) 384 dumpdev = NODEV; 385} 386 387static int 388setdumpdev(dev) 389 dev_t dev; 390{ 391 int maj, psize; 392 long newdumplo; 393 394 if (dev == NODEV) { 395 dumpdev = dev; 396 return (0); 397 } 398 maj = major(dev); 399 if (maj >= nblkdev || bdevsw(dev) == NULL) 400 return (ENXIO); /* XXX is this right? */ 401 if (bdevsw(dev)->d_psize == NULL) 402 return (ENXIO); /* XXX should be ENODEV ? */ 403 psize = bdevsw(dev)->d_psize(dev); 404 if (psize == -1) 405 return (ENXIO); /* XXX should be ENODEV ? */ 406 /* 407 * XXX should clean up checking in dumpsys() to be more like this, 408 * and nuke dodump sysctl (too many knobs), and move this to 409 * kern_shutdown.c... 410 */ 411 newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE; 412 if (newdumplo < 0) 413 return (ENOSPC); 414 dumpdev = dev; 415 dumplo = newdumplo; 416 return (0); 417} 418 419 420u_long bootdev = 0; /* not a dev_t - encoding is different */ 421 422#define FDMAJOR 2 423#define FDUNITSHIFT 6 424 425/* 426 * Attempt to find the device from which we were booted. 427 * If we can do so, and not instructed not to do so, 428 * set rootdevs[] and rootdevnames[] to correspond to the 429 * boot device(s). 430 */ 431static void 432setroot() 433{ 434 int majdev, mindev, unit, slice, part; 435 dev_t newrootdev, dev; 436 char partname[2]; 437 char *sname; 438 439 if (boothowto & RB_DFLTROOT) { 440#ifdef ROOTDEVNAME 441 setrootbyname(ROOTDEVNAME); 442#else 443 setconf(); 444#endif 445 return; 446 } 447 if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) 448 return; 449 majdev = B_TYPE(bootdev); 450 dev = makedev(majdev, 0); 451 if (majdev >= nblkdev || bdevsw(dev) == NULL) 452 return; 453 unit = B_UNIT(bootdev); 454 slice = B_SLICE(bootdev); 455 if (slice == WHOLE_DISK_SLICE) 456 slice = COMPATIBILITY_SLICE; 457 if (slice < 0 || slice >= MAX_SLICES) 458 return; 459 460 /* 461 * XXX kludge for inconsistent unit numbering and lack of slice 462 * support for floppies. 463 */ 464 if (majdev == FDMAJOR) { 465 slice = COMPATIBILITY_SLICE; 466 part = RAW_PART; 467 mindev = unit << FDUNITSHIFT; 468 } else { 469 part = B_PARTITION(bootdev); 470 mindev = dkmakeminor(unit, slice, part); 471 } 472 473 newrootdev = makedev(majdev, mindev); 474 rootdevs[0] = newrootdev; 475 sname = dsname(bdevsw(newrootdev)->d_name, unit, slice, part, partname); 476 rootdevnames[0] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT); 477 sprintf(rootdevnames[0], "%s%s", sname, partname); 478 479 /* 480 * For properly dangerously dedicated disks (ones with a historical 481 * bogus partition table), the boot blocks will give slice = 4, but 482 * the kernel will only provide the compatibility slice since it 483 * knows that slice 4 is not a real slice. Arrange to try mounting 484 * the compatibility slice as root if mounting the slice passed by 485 * the boot blocks fails. This handles the dangerously dedicated 486 * case and perhaps others. 487 */ 488 if (slice == COMPATIBILITY_SLICE) 489 return; 490 slice = COMPATIBILITY_SLICE; 491 rootdevs[1] = dkmodslice(newrootdev, slice); 492 sname = dsname(bdevsw(newrootdev)->d_name, unit, slice, part, partname); 493 rootdevnames[1] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT); 494 sprintf(rootdevnames[1], "%s%s", sname, partname); 495} 496 497 498static int 499sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS 500{ 501 int error; 502 dev_t ndumpdev; 503 504 ndumpdev = dumpdev; 505 error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req); 506 if (error == 0 && req->newptr != NULL) 507 error = setdumpdev(ndumpdev); 508 return (error); 509} 510 511SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW, 512 0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", ""); 513 514 515 516static int 517setrootbyname(char *name) 518{ 519 char *cp; 520 int bd, unit, slice, part; 521 dev_t dev; 522 523 slice = 0; 524 part = 0; 525 cp = name; 526 while (cp != '\0' && (*cp < '0' || *cp > '9')) 527 cp++; 528 if (cp == name) { 529 printf("missing device name\n"); 530 return(1); 531 } 532 if (*cp == '\0') { 533 printf("missing unit number\n"); 534 return(1); 535 } 536 unit = *cp - '0'; 537 *cp++ = '\0'; 538 for (bd = 0; bd < nblkdev; bd++) { 539 dev = makedev(bd, 0); 540 if (bdevsw(dev) != NULL && 541 strcmp(bdevsw(dev)->d_name, name) == 0) 542 goto gotit; 543 } 544 return (2); 545gotit: 546 while (*cp >= '0' && *cp <= '9') 547 unit += 10 * unit + *cp++ - '0'; 548 if (*cp == 's' && cp[1] >= '0' && cp[1] <= '9') { 549 slice = cp[1] - '0'; 550 cp += 2; 551 } 552 if (*cp >= 'a' && *cp <= 'h') { 553 part = *cp - 'a'; 554 cp++; 555 } 556 if (*cp != '\0') { 557 printf("junk after name\n"); 558 return (1); 559 } 560 printf("driver=%s, unit=%d, slice=%d, part=%d\n", 561 name, unit, slice, part); 562 rootdev = makedev(bd, dkmakeminor(unit, slice, part)); 563 return 0; 564} 565 566void 567setconf() 568{ 569 char name[128]; 570 int i; 571 dev_t dev; 572 573 for(;;) { 574 printf("root device? "); 575 gets(name); 576 i = setrootbyname(name); 577 if (!i) 578 return; 579 580 printf("use one of:\n"); 581 for (i = 0; i < nblkdev; i++) { 582 dev = makedev(i, 0); 583 if (bdevsw(dev) != NULL) 584 printf(" %s", bdevsw(dev)->d_name); 585 } 586 printf(" followed by a unit number...\n"); 587 } 588} 589 590static void 591gets(cp) 592 char *cp; 593{ 594 register char *lp; 595 register int c; 596 597 lp = cp; 598 for (;;) { 599 printf("%c", c = cngetc() & 0177); 600 switch (c) { 601 case -1: 602 case '\n': 603 case '\r': 604 *lp++ = '\0'; 605 return; 606 case '\b': 607 case '\177': 608 if (lp > cp) { 609 printf(" \b"); 610 lp--; 611 } 612 continue; 613 case '#': 614 lp--; 615 if (lp < cp) 616 lp = cp; 617 continue; 618 case '@': 619 case 'u' & 037: 620 lp = cp; 621 printf("%c", '\n'); 622 continue; 623 default: 624 *lp++ = c; 625 } 626 } 627} 628