summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/x86/interface/pcbios/int13.c56
1 files changed, 45 insertions, 11 deletions
diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c
index c322440e..0bc123d7 100644
--- a/src/arch/x86/interface/pcbios/int13.c
+++ b/src/arch/x86/interface/pcbios/int13.c
@@ -219,14 +219,13 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
struct master_boot_record *mbr = scratch;
struct partition_table_entry *partition;
unsigned int i;
+ unsigned int start_cylinder;
+ unsigned int start_head;
+ unsigned int start_sector;
unsigned int end_head;
unsigned int end_sector;
int rc;
- /* Default guess is xx/255/63 */
- *heads = 255;
- *sectors = 63;
-
/* Read partition table */
if ( ( rc = sandev_rw ( sandev, 0, 1, virt_to_user ( mbr ),
block_read ) ) != 0 ) {
@@ -244,19 +243,54 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
* heads and sectors_per_track if we find any used
* partitions.
*/
+ *heads = 0;
+ *sectors = 0;
for ( i = 0 ; i < 4 ; i++ ) {
+
+ /* Skip empty partitions */
partition = &mbr->partitions[i];
+ if ( ! partition->type )
+ continue;
+
+ /* If partition starts on cylinder 0 then we can
+ * unambiguously determine the number of sectors.
+ */
+ start_cylinder = PART_CYLINDER ( partition->chs_start );
+ start_head = PART_HEAD ( partition->chs_start );
+ start_sector = PART_SECTOR ( partition->chs_start );
+ if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) {
+ *sectors = ( ( partition->start + 1 - start_sector ) /
+ start_head );
+ DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
+ "xx/xx/%d based on partition %d\n",
+ sandev->drive, *sectors, ( i + 1 ) );
+ }
+
+ /* If partition ends on a higher head or sector number
+ * than our current guess, then increase the guess.
+ */
end_head = PART_HEAD ( partition->chs_end );
end_sector = PART_SECTOR ( partition->chs_end );
- if ( ! ( partition->type && end_head && end_sector ) )
- continue;
- *heads = ( end_head + 1 );
- *sectors = end_sector;
- DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
- "on partition %d\n",
- sandev->drive, *heads, *sectors, ( i + 1 ) );
+ if ( ( end_head + 1 ) > *heads ) {
+ *heads = ( end_head + 1 );
+ DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
+ "xx/%d/xx based on partition %d\n",
+ sandev->drive, *heads, ( i + 1 ) );
+ }
+ if ( end_sector > *sectors ) {
+ *sectors = end_sector;
+ DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
+ "xx/xx/%d based on partition %d\n",
+ sandev->drive, *sectors, ( i + 1 ) );
+ }
}
+ /* Default guess is xx/255/63 */
+ if ( ! *heads )
+ *heads = 255;
+ if ( ! *sectors )
+ *sectors = 63;
+
return 0;
}