1 /* $NetBSD: autoconf.c,v 1.60 2002/01/07 21:47:00 thorpej Exp $ */ 2 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 * 38 * @(#)autoconf.c 7.1 (Berkeley) 5/9/91 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 */ 49 50 #include <sys/cdefs.h> 51 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.60 2002/01/07 21:47:00 thorpej Exp $"); 52 53 #include "opt_compat_oldboot.h" 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/buf.h> 58 #include <sys/dkstat.h> 59 #include <sys/disklabel.h> 60 #include <sys/conf.h> 61 #ifdef COMPAT_OLDBOOT 62 #include <sys/reboot.h> 63 #endif 64 #include <sys/device.h> 65 #include <sys/malloc.h> 66 #include <sys/vnode.h> 67 #include <sys/fcntl.h> 68 #include <sys/dkio.h> 69 70 #include <machine/pte.h> 71 #include <machine/cpu.h> 72 #include <machine/bootinfo.h> 73 74 static int match_harddisk __P((struct device *, struct btinfo_bootdisk *)); 75 static void matchbiosdisks __P((void)); 76 static void findroot __P((void)); 77 static int is_valid_disk __P((struct device *)); 78 79 extern struct disklist *i386_alldisks; 80 extern int i386_ndisks; 81 82 #include "bios32.h" 83 #if NBIOS32 > 0 84 #include <machine/bios32.h> 85 #endif 86 87 #include "opt_pcibios.h" 88 #ifdef PCIBIOS 89 #include <dev/pci/pcireg.h> 90 #include <dev/pci/pcivar.h> 91 #include <i386/pci/pcibios.h> 92 #endif 93 94 struct device *booted_device; 95 int booted_partition; 96 97 /* 98 * Determine i/o configuration for a machine. 99 */ 100 void 101 cpu_configure() 102 { 103 104 startrtclock(); 105 106 #if NBIOS32 > 0 107 bios32_init(); 108 #endif 109 #ifdef PCIBIOS 110 pcibios_init(); 111 #endif 112 113 if (config_rootfound("mainbus", NULL) == NULL) 114 panic("configure: mainbus not configured"); 115 116 printf("biomask %x netmask %x ttymask %x\n", 117 (u_short)imask[IPL_BIO], (u_short)imask[IPL_NET], 118 (u_short)imask[IPL_TTY]); 119 120 spl0(); 121 122 /* Set up proc0's TSS and LDT (after the FPU is configured). */ 123 i386_proc0_tss_ldt_init(); 124 125 /* XXX Finish deferred buffer cache allocation. */ 126 i386_bufinit(); 127 } 128 129 void 130 cpu_rootconf() 131 { 132 findroot(); 133 matchbiosdisks(); 134 135 printf("boot device: %s\n", 136 booted_device ? booted_device->dv_xname : "<unknown>"); 137 138 setroot(booted_device, booted_partition); 139 } 140 141 /* 142 * XXX ugly bit of code. But, this is the only safe time that the 143 * match between BIOS disks and native disks can be done. 144 */ 145 static void 146 matchbiosdisks() 147 { 148 struct btinfo_biosgeom *big; 149 struct bi_biosgeom_entry *be; 150 struct device *dv; 151 struct devnametobdevmaj *d; 152 int i, ck, error, m, n; 153 struct vnode *tv; 154 char mbr[DEV_BSIZE]; 155 int dklist_size; 156 157 big = lookup_bootinfo(BTINFO_BIOSGEOM); 158 159 if (big == NULL) 160 return; 161 162 /* 163 * First, count all native disks 164 */ 165 for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) 166 if (is_valid_disk(dv)) 167 i386_ndisks++; 168 169 if (i386_ndisks == 0) 170 return; 171 172 dklist_size = sizeof (struct disklist) + (i386_ndisks - 1) * 173 sizeof (struct nativedisk_info); 174 175 /* XXX M_TEMP is wrong */ 176 i386_alldisks = malloc(dklist_size, M_TEMP, M_NOWAIT); 177 if (i386_alldisks == NULL) 178 return; 179 180 memset(i386_alldisks, 0, dklist_size); 181 182 i386_alldisks->dl_nnativedisks = i386_ndisks; 183 i386_alldisks->dl_nbiosdisks = big->num; 184 for (i = 0; i < big->num; i++) { 185 i386_alldisks->dl_biosdisks[i].bi_dev = big->disk[i].dev; 186 i386_alldisks->dl_biosdisks[i].bi_sec = big->disk[i].sec; 187 i386_alldisks->dl_biosdisks[i].bi_head = big->disk[i].head; 188 i386_alldisks->dl_biosdisks[i].bi_cyl = big->disk[i].cyl; 189 i386_alldisks->dl_biosdisks[i].bi_lbasecs = big->disk[i].totsec; 190 i386_alldisks->dl_biosdisks[i].bi_flags = big->disk[i].flags; 191 } 192 193 /* 194 * XXX code duplication from findroot() 195 */ 196 n = -1; 197 for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) { 198 if (dv->dv_class != DV_DISK) 199 continue; 200 #ifdef GEOM_DEBUG 201 printf("matchbiosdisks: trying to match (%s) %s\n", 202 dv->dv_xname, dv->dv_cfdata->cf_driver->cd_name); 203 #endif 204 if (is_valid_disk(dv)) { 205 n++; 206 sprintf(i386_alldisks->dl_nativedisks[n].ni_devname, 207 "%s%d", dv->dv_cfdata->cf_driver->cd_name, 208 dv->dv_unit); 209 210 for (d = dev_name2blk; d->d_name && 211 strcmp(d->d_name, dv->dv_cfdata->cf_driver->cd_name); 212 d++); 213 if (d->d_name == NULL) 214 return; 215 216 if (bdevvp(MAKEDISKDEV(d->d_maj, dv->dv_unit, RAW_PART), 217 &tv)) 218 panic("matchbiosdisks: can't alloc vnode"); 219 220 error = VOP_OPEN(tv, FREAD, NOCRED, 0); 221 if (error) { 222 vput(tv); 223 continue; 224 } 225 error = vn_rdwr(UIO_READ, tv, mbr, DEV_BSIZE, 0, 226 UIO_SYSSPACE, 0, NOCRED, NULL, 0); 227 VOP_CLOSE(tv, FREAD, NOCRED, 0); 228 if (error) { 229 #ifdef GEOM_DEBUG 230 printf("matchbiosdisks: %s: MBR read failure\n", 231 dv->dv_xname); 232 #endif 233 continue; 234 } 235 236 for (ck = i = 0; i < DEV_BSIZE; i++) 237 ck += mbr[i]; 238 for (m = i = 0; i < big->num; i++) { 239 be = &big->disk[i]; 240 #ifdef GEOM_DEBUG 241 printf("match %s with %d\n", dv->dv_xname, i); 242 printf("dev ck %x bios ck %x\n", ck, be->cksum); 243 #endif 244 if (be->flags & BI_GEOM_INVALID) 245 continue; 246 if (be->cksum == ck && 247 !memcmp(&mbr[MBR_PARTOFF], be->dosparts, 248 NMBRPART * 249 sizeof (struct mbr_partition))) { 250 #ifdef GEOM_DEBUG 251 printf("matched bios disk %x with %s\n", 252 be->dev, be->devname); 253 #endif 254 i386_alldisks->dl_nativedisks[n]. 255 ni_biosmatches[m++] = i; 256 } 257 } 258 i386_alldisks->dl_nativedisks[n].ni_nmatches = m; 259 vput(tv); 260 } 261 } 262 } 263 264 #ifdef COMPAT_OLDBOOT 265 u_long bootdev = 0; /* should be dev_t, but not until 32 bits */ 266 #endif 267 268 /* 269 * helper function for "findroot()": 270 * return nonzero if disk device matches bootinfo 271 */ 272 static int 273 match_harddisk(dv, bid) 274 struct device *dv; 275 struct btinfo_bootdisk *bid; 276 { 277 struct devnametobdevmaj *i; 278 struct vnode *tmpvn; 279 int error; 280 struct disklabel label; 281 int found = 0; 282 283 /* 284 * A disklabel is required here. The 285 * bootblocks don't refuse to boot from 286 * a disk without a label, but this is 287 * normally not wanted. 288 */ 289 if (bid->labelsector == -1) 290 return(0); 291 292 /* 293 * lookup major number for disk block device 294 */ 295 i = dev_name2blk; 296 while (i->d_name && 297 strcmp(i->d_name, dv->dv_cfdata->cf_driver->cd_name)) 298 i++; 299 if (i->d_name == NULL) 300 return(0); /* XXX panic() ??? */ 301 302 /* 303 * Fake a temporary vnode for the disk, open 304 * it, and read the disklabel for comparison. 305 */ 306 if (bdevvp(MAKEDISKDEV(i->d_maj, dv->dv_unit, bid->partition), &tmpvn)) 307 panic("findroot can't alloc vnode"); 308 error = VOP_OPEN(tmpvn, FREAD, NOCRED, 0); 309 if (error) { 310 #ifndef DEBUG 311 /* 312 * Ignore errors caused by missing 313 * device, partition or medium. 314 */ 315 if (error != ENXIO && error != ENODEV) 316 #endif 317 printf("findroot: can't open dev %s%c (%d)\n", 318 dv->dv_xname, 'a' + bid->partition, error); 319 vput(tmpvn); 320 return(0); 321 } 322 error = VOP_IOCTL(tmpvn, DIOCGDINFO, (caddr_t)&label, FREAD, NOCRED, 0); 323 if (error) { 324 /* 325 * XXX can't happen - open() would 326 * have errored out (or faked up one) 327 */ 328 printf("can't get label for dev %s%c (%d)\n", 329 dv->dv_xname, 'a' + bid->partition, error); 330 goto closeout; 331 } 332 333 /* compare with our data */ 334 if (label.d_type == bid->label.type && 335 label.d_checksum == bid->label.checksum && 336 !strncmp(label.d_packname, bid->label.packname, 16)) 337 found = 1; 338 339 closeout: 340 VOP_CLOSE(tmpvn, FREAD, NOCRED, 0); 341 vput(tmpvn); 342 return(found); 343 } 344 345 /* 346 * Attempt to find the device from which we were booted. 347 * If we can do so, and not instructed not to do so, 348 * change rootdev to correspond to the load device. 349 */ 350 void 351 findroot(void) 352 { 353 struct btinfo_bootdisk *bid; 354 struct device *dv; 355 #ifdef COMPAT_OLDBOOT 356 int i, majdev, unit, part; 357 char buf[32]; 358 #endif 359 360 if (booted_device) 361 return; 362 363 if (lookup_bootinfo(BTINFO_NETIF)) { 364 /* 365 * We got netboot interface information, but 366 * "device_register()" couldn't match it to a configured 367 * device. Bootdisk information cannot be present at the 368 * same time, so give up. 369 */ 370 printf("findroot: netboot interface not found\n"); 371 return; 372 } 373 374 bid = lookup_bootinfo(BTINFO_BOOTDISK); 375 if (bid) { 376 /* 377 * Scan all disk devices for ones that match the passed data. 378 * Don't break if one is found, to get possible multiple 379 * matches - for problem tracking. Use the first match anyway 380 * because lower device numbers are more likely to be the 381 * boot device. 382 */ 383 for (dv = alldevs.tqh_first; dv != NULL; 384 dv = dv->dv_list.tqe_next) { 385 if (dv->dv_class != DV_DISK) 386 continue; 387 388 if (!strcmp(dv->dv_cfdata->cf_driver->cd_name, "fd")) { 389 /* 390 * Assume the configured unit number matches 391 * the BIOS device number. (This is the old 392 * behaviour.) Needs some ideas how to handle 393 * BIOS's "swap floppy drive" options. 394 */ 395 if ((bid->biosdev & 0x80) || 396 dv->dv_unit != bid->biosdev) 397 continue; 398 399 goto found; 400 } 401 402 if (is_valid_disk(dv)) { 403 /* 404 * Don't trust BIOS device numbers, try 405 * to match the information passed by the 406 * bootloader instead. 407 */ 408 if ((bid->biosdev & 0x80) == 0 || 409 !match_harddisk(dv, bid)) 410 continue; 411 412 goto found; 413 } 414 415 /* no "fd", "wd", "sd", "ld", "ed" */ 416 continue; 417 418 found: 419 if (booted_device) { 420 printf("warning: double match for boot " 421 "device (%s, %s)\n", booted_device->dv_xname, 422 dv->dv_xname); 423 continue; 424 } 425 booted_device = dv; 426 booted_partition = bid->partition; 427 } 428 429 if (booted_device) 430 return; 431 } 432 433 #ifdef COMPAT_OLDBOOT 434 #if 0 435 printf("howto %x bootdev %x ", boothowto, bootdev); 436 #endif 437 438 if ((bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC) 439 return; 440 441 majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK; 442 for (i = 0; dev_name2blk[i].d_name != NULL; i++) 443 if (majdev == dev_name2blk[i].d_maj) 444 break; 445 if (dev_name2blk[i].d_name == NULL) 446 return; 447 448 part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK; 449 unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK; 450 451 sprintf(buf, "%s%d", dev_name2blk[i].d_name, unit); 452 for (dv = alldevs.tqh_first; dv != NULL; 453 dv = dv->dv_list.tqe_next) { 454 if (strcmp(buf, dv->dv_xname) == 0) { 455 booted_device = dv; 456 booted_partition = part; 457 return; 458 } 459 } 460 #endif 461 } 462 463 #include "pci.h" 464 465 #include <dev/isa/isavar.h> 466 #if NPCI > 0 467 #include <dev/pci/pcivar.h> 468 #endif 469 470 void 471 device_register(dev, aux) 472 struct device *dev; 473 void *aux; 474 { 475 /* 476 * Handle network interfaces here, the attachment information is 477 * not available driver independantly later. 478 * For disks, there is nothing useful available at attach time. 479 */ 480 if (dev->dv_class == DV_IFNET) { 481 struct btinfo_netif *bin = lookup_bootinfo(BTINFO_NETIF); 482 if (bin == NULL) 483 return; 484 485 /* 486 * We don't check the driver name against the device name 487 * passed by the boot ROM. The ROM should stay usable 488 * if the driver gets obsoleted. 489 * The physical attachment information (checked below) 490 * must be sufficient to identify the device. 491 */ 492 493 if (bin->bus == BI_BUS_ISA && 494 !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name, 495 "isa")) { 496 struct isa_attach_args *iaa = aux; 497 498 /* compare IO base address */ 499 /* XXXJRT what about multiple I/O addrs? */ 500 if (iaa->ia_nio > 0 && 501 bin->addr.iobase == iaa->ia_io[0].ir_addr) 502 goto found; 503 } 504 #if NPCI > 0 505 if (bin->bus == BI_BUS_PCI && 506 !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name, 507 "pci")) { 508 struct pci_attach_args *paa = aux; 509 int b, d, f; 510 511 /* 512 * Calculate BIOS representation of: 513 * 514 * <bus,device,function> 515 * 516 * and compare. 517 */ 518 pci_decompose_tag(paa->pa_pc, paa->pa_tag, &b, &d, &f); 519 if (bin->addr.tag == ((b << 8) | (d << 3) | f)) 520 goto found; 521 } 522 #endif 523 } 524 return; 525 526 found: 527 if (booted_device) { 528 /* XXX should be a "panic()" */ 529 printf("warning: double match for boot device (%s, %s)\n", 530 booted_device->dv_xname, dev->dv_xname); 531 return; 532 } 533 booted_device = dev; 534 } 535 536 static int 537 is_valid_disk(struct device *dv) 538 { 539 const char *name; 540 541 if (dv->dv_class != DV_DISK) 542 return (0); 543 544 name = dv->dv_cfdata->cf_driver->cd_name; 545 546 return (strcmp(name, "sd") == 0 || strcmp(name, "wd") == 0 || 547 strcmp(name, "ld") == 0 || strcmp(name, "ed") == 0); 548 } 549