diff options
author | Michael Brown | 2006-09-09 00:22:03 +0200 |
---|---|---|
committer | Michael Brown | 2006-09-09 00:22:03 +0200 |
commit | 0566ab2a2f814ae486032d603588933cbea8a387 (patch) | |
tree | 3920b21ec5f38154bda9ce6247ed13d09efbb273 /src/arch/i386/interface/pcbios/int13.c | |
parent | Fix gcc-induced reference to memcpy (diff) | |
download | ipxe-0566ab2a2f814ae486032d603588933cbea8a387.tar.gz ipxe-0566ab2a2f814ae486032d603588933cbea8a387.tar.xz ipxe-0566ab2a2f814ae486032d603588933cbea8a387.zip |
Added geometry-guessing code based on the partition table
Diffstat (limited to 'src/arch/i386/interface/pcbios/int13.c')
-rw-r--r-- | src/arch/i386/interface/pcbios/int13.c | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index 7204ce74..798fb6df 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -438,26 +438,47 @@ static void unhook_int13 ( void ) { } /** - * Register INT 13 emulated drive + * Guess INT 13 drive geometry * * @v drive Emulated drive * - * Registers the drive with the INT 13 emulation subsystem, and hooks - * the INT 13 interrupt vector (if not already hooked). - * - * The underlying block device must be valid. A drive number and - * geometry will be assigned if left blank. + * Guesses the drive geometry by inspecting the partition table. */ -void register_int13_drive ( struct int13_drive *drive ) { - uint8_t num_drives; +static void guess_int13_geometry ( struct int13_drive *drive ) { + struct master_boot_record mbr; + struct partition_table_entry *partition; + unsigned int guessed_heads = 255; + unsigned int guessed_sectors_per_track = 63; unsigned long blocks; unsigned long blocks_per_cyl; + unsigned int i; - /* Give drive a default geometry if none specified */ + /* Scan through partition table and modify guesses for heads + * and sectors_per_track if we find any used partitions. + */ + if ( drive->blockdev->read ( drive->blockdev, 0, 1, + virt_to_user ( &mbr ) ) == 0 ) { + for ( i = 0 ; i < 4 ; i++ ) { + partition = &mbr.partitions[i]; + if ( ! partition->type ) + continue; + guessed_heads = + ( PART_HEAD ( partition->chs_end ) + 1 ); + guessed_sectors_per_track = + PART_SECTOR ( partition->chs_end ); + DBG ( "Guessing C/H/S xx/%d/%d based on partition " + "%d\n", guessed_heads, + guessed_sectors_per_track, ( i + 1 ) ); + } + } else { + DBG ( "Could not read partition table to guess geometry\n" ); + } + + /* Apply guesses if no geometry already specified */ if ( ! drive->heads ) - drive->heads = 255; + drive->heads = guessed_heads; if ( ! drive->sectors_per_track ) - drive->sectors_per_track = 63; + drive->sectors_per_track = guessed_sectors_per_track; if ( ! drive->cylinders ) { /* Avoid attempting a 64-bit divide on a 32-bit system */ blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ? @@ -465,7 +486,27 @@ void register_int13_drive ( struct int13_drive *drive ) { blocks_per_cyl = ( drive->heads * drive->sectors_per_track ); assert ( blocks_per_cyl != 0 ); drive->cylinders = ( blocks / blocks_per_cyl ); + if ( drive->cylinders > 1024 ) + drive->cylinders = 1024; } +} + +/** + * Register INT 13 emulated drive + * + * @v drive Emulated drive + * + * Registers the drive with the INT 13 emulation subsystem, and hooks + * the INT 13 interrupt vector (if not already hooked). + * + * The underlying block device must be valid. A drive number and + * geometry will be assigned if left blank. + */ +void register_int13_drive ( struct int13_drive *drive ) { + uint8_t num_drives; + + /* Give drive a default geometry if none specified */ + guess_int13_geometry ( drive ); /* Assign drive number if none specified, update BIOS drive count */ get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); |