summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/interface/pcbios/int13.c
diff options
context:
space:
mode:
authorMichael Brown2006-09-09 00:22:03 +0200
committerMichael Brown2006-09-09 00:22:03 +0200
commit0566ab2a2f814ae486032d603588933cbea8a387 (patch)
tree3920b21ec5f38154bda9ce6247ed13d09efbb273 /src/arch/i386/interface/pcbios/int13.c
parentFix gcc-induced reference to memcpy (diff)
downloadipxe-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.c63
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 );