/* * Attempt to find the device from which we were booted. If we can do so, * and not instructed not to do so, change rootdev to correspond to the * load device. */ static void findroot(void) { struct btinfo_bootdisk *bid; struct device *dv; if (booted_device) return; if ((bid = lookup_bootinfo(BTINFO_BOOTDISK)) != NULL) { /* * Scan all disk devices for ones that match the passed data. * Don't break if one is found, to get possible multiple * matches - for problem tracking. Use the first match anyway * because lower device numbers are more likely to be the * boot device. */ for (dv = TAILQ_FIRST(&alldevs); dv != NULL; dv = TAILQ_NEXT(dv, dv_list)) { if (dv->dv_class != DV_DISK) continue; if (is_valid_disk(dv)) { if (match_bootdisk(dv, bid) == 0) continue; goto bootdisk_found; } continue; bootdisk_found: if (booted_device) { printf("WARNING: double match for boot " "device (%s, %s)\n", booted_device->dv_xname, dv->dv_xname); continue; } booted_device = dv; booted_partition = bid->partition; } if (booted_device) return; } }
/* * XXX Ugly bit of code. But, this is the only safe time that the * match between BIOS disks and native disks can be done. */ static void matchbiosdisks(void) { struct btinfo_biosgeom *big; struct bi_biosgeom_entry *be; device_t dv; deviter_t di; int i, ck, error, m, n; struct vnode *tv; char mbr[DEV_BSIZE]; int dklist_size; int numbig; if (x86_ndisks) return; big = lookup_bootinfo(BTINFO_BIOSGEOM); numbig = big ? big->num : 0; /* First, count all native disks. */ for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { if (is_valid_disk(dv)) x86_ndisks++; } deviter_release(&di); dklist_size = sizeof(struct disklist) + (x86_ndisks - 1) * sizeof(struct nativedisk_info); /* XXX M_TEMP is wrong */ x86_alldisks = malloc(dklist_size, M_TEMP, M_NOWAIT | M_ZERO); if (x86_alldisks == NULL) return; x86_alldisks->dl_nnativedisks = x86_ndisks; x86_alldisks->dl_nbiosdisks = numbig; for (i = 0; i < numbig; i++) { x86_alldisks->dl_biosdisks[i].bi_dev = big->disk[i].dev; x86_alldisks->dl_biosdisks[i].bi_sec = big->disk[i].sec; x86_alldisks->dl_biosdisks[i].bi_head = big->disk[i].head; x86_alldisks->dl_biosdisks[i].bi_cyl = big->disk[i].cyl; x86_alldisks->dl_biosdisks[i].bi_lbasecs = big->disk[i].totsec; x86_alldisks->dl_biosdisks[i].bi_flags = big->disk[i].flags; DPRINTF(("%s: disk %x: flags %x", __func__, big->disk[i].dev, big->disk[i].flags)); #ifdef BIOSDISK_EXTINFO_V3 DPRINTF((", interface %x, device %llx", big->disk[i].interface_path, big->disk[i].device_path)); #endif DPRINTF(("\n")); } /* XXX Code duplication from findroot(). */ n = -1; for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { if (!is_valid_disk(dv)) continue; DPRINTF(("%s: trying to match (%s) %s: ", __func__, device_xname(dv), device_cfdata(dv)->cf_name)); n++; snprintf(x86_alldisks->dl_nativedisks[n].ni_devname, sizeof(x86_alldisks->dl_nativedisks[n].ni_devname), "%s", device_xname(dv)); if ((tv = opendisk(dv)) == NULL) { DPRINTF(("cannot open\n")); continue; } error = vn_rdwr(UIO_READ, tv, mbr, DEV_BSIZE, 0, UIO_SYSSPACE, 0, NOCRED, NULL, NULL); VOP_CLOSE(tv, FREAD, NOCRED); vput(tv); if (error) { DPRINTF(("MBR read failure %d\n", error)); continue; } for (ck = i = 0; i < DEV_BSIZE; i++) ck += mbr[i]; for (m = i = 0; i < numbig; i++) { be = &big->disk[i]; if (be->flags & BI_GEOM_INVALID) continue; DPRINTF(("matched with %d dev ck %x bios ck %x\n", i, ck, be->cksum)); if (be->cksum == ck && memcmp(&mbr[MBR_PART_OFFSET], be->mbrparts, MBR_PART_COUNT * sizeof(struct mbr_partition)) == 0) { DPRINTF(("%s: matched BIOS disk %x with %s\n", __func__, be->dev, device_xname(dv))); x86_alldisks->dl_nativedisks[n]. ni_biosmatches[m++] = i; } } x86_alldisks->dl_nativedisks[n].ni_nmatches = m; } deviter_release(&di); }
/* * Attempt to find the device from which we were booted. If we can do so, * and not instructed not to do so, change rootdev to correspond to the * load device. */ static void findroot(void) { struct btinfo_rootdevice *biv; struct btinfo_bootdisk *bid; struct btinfo_bootwedge *biw; struct btinfo_biosgeom *big; device_t dv; deviter_t di; if (booted_device) return; if (lookup_bootinfo(BTINFO_NETIF) != NULL) { /* * We got netboot interface information, but device_register() * failed to match it to a configured device. Boot disk * information cannot be present at the same time, so give * up. */ printf("%s: netboot interface not found.\n", __func__); return; } if ((biv = lookup_bootinfo(BTINFO_ROOTDEVICE)) != NULL) { for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { cfdata_t cd; size_t len; if (device_class(dv) != DV_DISK) continue; cd = device_cfdata(dv); len = strlen(cd->cf_name); if (strncmp(cd->cf_name, biv->devname, len) == 0 && biv->devname[len] - '0' == device_unit(dv)) { booted_device = dv; booted_partition = biv->devname[len + 1] - 'a'; booted_nblks = 0; break; } } DPRINTF(("%s: BTINFO_ROOTDEVICE %s\n", __func__, booted_device ? device_xname(booted_device) : "not found")); deviter_release(&di); if (dv != NULL) return; } bid = lookup_bootinfo(BTINFO_BOOTDISK); biw = lookup_bootinfo(BTINFO_BOOTWEDGE); if (biw != NULL) { /* * Scan all disk devices for ones that match the passed data. * Don't break if one is found, to get possible multiple * matches - for problem tracking. Use the first match anyway * because lower devices numbers are more likely to be the * boot device. */ for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { if (is_valid_disk(dv)) { /* * Don't trust BIOS device numbers, try * to match the information passed by the * boot loader instead. */ if ((biw->biosdev & 0x80) == 0 || match_bootwedge(dv, biw) == 0) continue; goto bootwedge_found; } continue; bootwedge_found: if (booted_device) { dmatch(__func__, dv); continue; } booted_device = dv; booted_partition = bid != NULL ? bid->partition : 0; booted_nblks = biw->nblks; booted_startblk = biw->startblk; } deviter_release(&di); DPRINTF(("%s: BTINFO_BOOTWEDGE %s\n", __func__, booted_device ? device_xname(booted_device) : "not found")); if (booted_nblks) return; } if (bid != NULL) { /* * Scan all disk devices for ones that match the passed data. * Don't break if one is found, to get possible multiple * matches - for problem tracking. Use the first match anyway * because lower device numbers are more likely to be the * boot device. */ for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { if (device_is_a(dv, "fd") && device_class(dv) == DV_DISK) { /* * Assume the configured unit number matches * the BIOS device number. (This is the old * behavior.) Needs some ideas how to handle * the BIOS's "swap floppy drive" options. */ /* XXX device_unit() abuse */ if ((bid->biosdev & 0x80) != 0 || device_unit(dv) != bid->biosdev) continue; goto bootdisk_found; } if (is_valid_disk(dv)) { /* * Don't trust BIOS device numbers, try * to match the information passed by the * boot loader instead. */ if ((bid->biosdev & 0x80) == 0 || match_bootdisk(dv, bid) == 0) continue; goto bootdisk_found; } continue; bootdisk_found: if (booted_device) { dmatch(__func__, dv); continue; } booted_device = dv; booted_partition = bid->partition; booted_nblks = 0; } deviter_release(&di); DPRINTF(("%s: BTINFO_BOOTDISK %s\n", __func__, booted_device ? device_xname(booted_device) : "not found")); if (booted_device) return; /* * No booted device found; check CD-ROM boot at last. * * Our bootloader assumes CD-ROM boot if biosdev is larger * or equal than the number of hard drives recognized by the * BIOS. The number of drives can be found in BTINFO_BIOSGEOM * here. For example, if we have wd0, wd1, and cd0: * * big->num = 2 (for wd0 and wd1) * bid->biosdev = 0x80 (wd0) * bid->biosdev = 0x81 (wd1) * bid->biosdev = 0x82 (cd0) * * See src/sys/arch/i386/stand/boot/devopen.c and * src/sys/arch/i386/stand/lib/bootinfo_biosgeom.c . */ if ((big = lookup_bootinfo(BTINFO_BIOSGEOM)) != NULL && bid->biosdev >= 0x80 + big->num) { /* * XXX * There is no proper way to detect which unit is * recognized as a bootable CD-ROM drive by the BIOS. * Assume the first unit is the one. */ for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL; dv = deviter_next(&di)) { if (device_class(dv) == DV_DISK && device_is_a(dv, "cd")) { booted_device = dv; booted_partition = 0; booted_nblks = 0; break; } } deviter_release(&di); DPRINTF(("%s: BTINFO_BIOSGEOM %s\n", __func__, booted_device ? device_xname(booted_device) : "not found")); } } }