static void g_mbr_print(int i, struct dos_partition *dp) { printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ); printf(" s(CHS):%d/%d/%d", DPCYL(dp->dp_scyl, dp->dp_ssect), dp->dp_shd, DPSECT(dp->dp_ssect)); printf(" e(CHS):%d/%d/%d", DPCYL(dp->dp_ecyl, dp->dp_esect), dp->dp_ehd, DPSECT(dp->dp_esect)); printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size); }
int mbrinit(cdev_t dev, struct disk_info *info, struct diskslices **sspp) { struct buf *bp; u_char *cp; int dospart; struct dos_partition *dp; struct dos_partition *dp0; struct dos_partition dpcopy[NDOSPART]; int error; int max_ncyls; int max_nsectors; int max_ntracks; u_int64_t mbr_offset; char partname[2]; u_long secpercyl; char *sname = "tempname"; struct diskslice *sp; struct diskslices *ssp; cdev_t wdev; mbr_offset = DOSBBSECTOR; reread_mbr: /* * Don't bother if the block size is weird or the * media size is 0 (probably means no media present). */ if (info->d_media_blksize & DEV_BMASK) return (EIO); if (info->d_media_size == 0) return (EIO); /* * Read master boot record. */ wdev = dev; bp = geteblk((int)info->d_media_blksize); bp->b_bio1.bio_offset = (off_t)mbr_offset * info->d_media_blksize; bp->b_bio1.bio_done = biodone_sync; bp->b_bio1.bio_flags |= BIO_SYNC; bp->b_bcount = info->d_media_blksize; bp->b_cmd = BUF_CMD_READ; bp->b_flags |= B_FAILONDIS; dev_dstrategy(wdev, &bp->b_bio1); if (biowait(&bp->b_bio1, "mbrrd") != 0) { if ((info->d_dsflags & DSO_MBRQUIET) == 0) { diskerr(&bp->b_bio1, wdev, "reading primary partition table: error", LOG_PRINTF, 0); kprintf("\n"); } error = EIO; goto done; } /* Weakly verify it. */ cp = bp->b_data; sname = dsname(dev, 0, 0, 0, NULL); if (cp[0x1FE] != 0x55 || cp[0x1FF] != 0xAA) { if (bootverbose) kprintf("%s: invalid primary partition table: no magic\n", sname); error = EINVAL; goto done; } /* Make a copy of the partition table to avoid alignment problems. */ memcpy(&dpcopy[0], cp + DOSPARTOFF, sizeof(dpcopy)); dp0 = &dpcopy[0]; /* * Check for "Ontrack Diskmanager" or GPT. If a GPT is found in * the first dos partition, ignore the rest of the MBR and go * to GPT processing. */ for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dospart == 0 && (dp->dp_typ == DOSPTYP_PMBR || dp->dp_typ == DOSPTYP_GPT)) { if (bootverbose) kprintf( "%s: Found GPT in slice #%d\n", sname, dospart + 1); error = gptinit(dev, info, sspp); goto done; } if (dp->dp_typ == DOSPTYP_ONTRACK) { if (bootverbose) kprintf( "%s: Found \"Ontrack Disk Manager\" on this disk.\n", sname); bp->b_flags |= B_INVAL | B_AGE; brelse(bp); mbr_offset = 63; goto reread_mbr; } } if (bcmp(dp0, historical_bogus_partition_table, sizeof historical_bogus_partition_table) == 0 || bcmp(dp0, historical_bogus_partition_table_fixed, sizeof historical_bogus_partition_table_fixed) == 0) { #if 0 TRACE(("%s: invalid primary partition table: historical\n", sname)); #endif /* 0 */ if (bootverbose) kprintf( "%s: invalid primary partition table: Dangerously Dedicated (ignored)\n", sname); error = EINVAL; goto done; } /* Guess the geometry. */ /* * TODO: * Perhaps skip entries with 0 size. * Perhaps only look at entries of type DOSPTYP_386BSD. */ max_ncyls = 0; max_nsectors = 0; max_ntracks = 0; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { int ncyls; int nsectors; int ntracks; ncyls = DPCYL(dp->dp_ecyl, dp->dp_esect) + 1; if (max_ncyls < ncyls) max_ncyls = ncyls; nsectors = DPSECT(dp->dp_esect); if (max_nsectors < nsectors) max_nsectors = nsectors; ntracks = dp->dp_ehd + 1; if (max_ntracks < ntracks) max_ntracks = ntracks; } /* * Check that we have guessed the geometry right by checking the * partition entries. */ /* * TODO: * As above. * Check for overlaps. * Check against d_secperunit if the latter is reliable. */ error = 0; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++) { if (dp->dp_scyl == 0 && dp->dp_shd == 0 && dp->dp_ssect == 0 && dp->dp_start == 0 && dp->dp_size == 0) continue; //sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart, // WHOLE_SLICE_PART, partname); /* * Temporarily ignore errors from this check. We could * simplify things by accepting the table eariler if we * always ignore errors here. Perhaps we should always * accept the table if the magic is right but not let * bad entries affect the geometry. */ check_part(sname, dp, mbr_offset, max_nsectors, max_ntracks, mbr_offset); } if (error != 0) goto done; /* * Accept the DOS partition table. * * Adjust the disk information structure with updated CHS * conversion parameters, but only use values extracted from * the primary partition table. * * NOTE! Regardless of our having to deal with this old cruft, * we do not screw around with the info->d_media* parameters. */ secpercyl = (u_long)max_nsectors * max_ntracks; if (secpercyl != 0 && mbr_offset == DOSBBSECTOR) { info->d_secpertrack = max_nsectors; info->d_nheads = max_ntracks; info->d_secpercyl = secpercyl; info->d_ncylinders = info->d_media_blocks / secpercyl; } /* * We are passed a pointer to a suitably initialized minimal * slices "struct" with no dangling pointers in it. Replace it * by a maximal one. This usually oversizes the "struct", but * enlarging it while searching for logical drives would be * inconvenient. */ kfree(*sspp, M_DEVBUF); ssp = dsmakeslicestruct(MAX_SLICES, info); *sspp = ssp; /* Initialize normal slices. */ sp = &ssp->dss_slices[BASE_SLICE]; for (dospart = 0, dp = dp0; dospart < NDOSPART; dospart++, dp++, sp++) { sname = dsname(dev, dkunit(dev), BASE_SLICE + dospart, WHOLE_SLICE_PART, partname); (void)mbr_setslice(sname, info, sp, dp, mbr_offset); } ssp->dss_nslices = BASE_SLICE + NDOSPART; /* Handle extended partitions. */ sp -= NDOSPART; for (dospart = 0; dospart < NDOSPART; dospart++, sp++) { if (sp->ds_type == DOSPTYP_EXTENDED || sp->ds_type == DOSPTYP_EXTENDEDX) { mbr_extended(wdev, info, ssp, sp->ds_offset, sp->ds_size, sp->ds_offset, max_nsectors, max_ntracks, mbr_offset, 1); } } /* * mbr_extended() abuses ssp->dss_nslices for the number of slices * that would be found if there were no limit on the number of slices * in *ssp. Cut it back now. */ if (ssp->dss_nslices > MAX_SLICES) ssp->dss_nslices = MAX_SLICES; done: bp->b_flags |= B_INVAL | B_AGE; brelse(bp); if (error == EINVAL) error = 0; return (error); }
static int check_part(char *sname, struct dos_partition *dp, u_int64_t offset, int nsectors, int ntracks, u_int64_t mbr_offset) { int chs_ecyl; int chs_esect; int chs_scyl; int chs_ssect; int error; u_long secpercyl; u_int64_t esector; u_int64_t esector1; u_int64_t ssector; u_int64_t ssector1; secpercyl = (u_long)nsectors * ntracks; chs_scyl = DPCYL(dp->dp_scyl, dp->dp_ssect); chs_ssect = DPSECT(dp->dp_ssect); ssector = chs_ssect - 1 + dp->dp_shd * nsectors + chs_scyl * secpercyl + mbr_offset; ssector1 = offset + dp->dp_start; /* * If ssector1 is on a cylinder >= 1024, then ssector can't be right. * Allow the C/H/S for it to be 1023/ntracks-1/nsectors, or correct * apart from the cylinder being reduced modulo 1024. Always allow * 1023/255/63, because this is the official way to represent * pure-LBA for the starting position. */ if ((ssector < ssector1 && ((chs_ssect == nsectors && dp->dp_shd == ntracks - 1 && chs_scyl == 1023) || (secpercyl != 0 && (ssector1 - ssector) % (1024 * secpercyl) == 0))) || (dp->dp_scyl == 255 && dp->dp_shd == 255 && dp->dp_ssect == 255)) { TRACE(("%s: C/H/S start %d/%d/%d, start %llu: allow\n", sname, chs_scyl, dp->dp_shd, chs_ssect, (long long)ssector1)); ssector = ssector1; } chs_ecyl = DPCYL(dp->dp_ecyl, dp->dp_esect); chs_esect = DPSECT(dp->dp_esect); esector = chs_esect - 1 + dp->dp_ehd * nsectors + chs_ecyl * secpercyl + mbr_offset; esector1 = ssector1 + dp->dp_size - 1; /* * Allow certain bogus C/H/S values for esector, as above. However, * heads == 255 isn't really legal and causes some BIOS crashes. The * correct value to indicate a pure-LBA end is 1023/heads-1/sectors - * usually 1023/254/63. "heads" is base 0, "sectors" is base 1. */ if ((esector < esector1 && ((chs_esect == nsectors && dp->dp_ehd == ntracks - 1 && chs_ecyl == 1023) || (secpercyl != 0 && (esector1 - esector) % (1024 * secpercyl) == 0))) || (dp->dp_ecyl == 255 && dp->dp_ehd == 255 && dp->dp_esect == 255)) { TRACE(("%s: C/H/S end %d/%d/%d, end %llu: allow\n", sname, chs_ecyl, dp->dp_ehd, chs_esect, (long long)esector1)); esector = esector1; } error = (ssector == ssector1 && esector == esector1) ? 0 : EINVAL; if (bootverbose) kprintf("%s: type 0x%x, start %llu, end = %llu, size %u %s\n", sname, dp->dp_typ, (long long)ssector1, (long long)esector1, dp->dp_size, (error ? "" : ": OK")); if (ssector != ssector1 && bootverbose) kprintf("%s: C/H/S start %d/%d/%d (%llu) != start %llu: invalid\n", sname, chs_scyl, dp->dp_shd, chs_ssect, (long long)ssector, (long long)ssector1); if (esector != esector1 && bootverbose) kprintf("%s: C/H/S end %d/%d/%d (%llu) != end %llu: invalid\n", sname, chs_ecyl, dp->dp_ehd, chs_esect, (long long)esector, (long long)esector1); return (error); }