summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown2017-03-26 20:03:50 +0200
committerMichael Brown2017-03-26 20:03:50 +0200
commitebceb8ad8a5c3ad58ecbe513174c3620592d5976 (patch)
tree1afadcb3273eb45a10832dba97e02434834fff36 /src/arch
parent[block] Add basic multipath support (diff)
downloadipxe-ebceb8ad8a5c3ad58ecbe513174c3620592d5976.tar.gz
ipxe-ebceb8ad8a5c3ad58ecbe513174c3620592d5976.tar.xz
ipxe-ebceb8ad8a5c3ad58ecbe513174c3620592d5976.zip
[int13] Improve geometry guessing for unaligned partitions
Some partition tables have partitions that are not aligned to a cylinder boundary, which confuses the current geometry guessing logic. Enhance the existing logic to ensure that we never reduce our guesses for the number of heads or sectors per track, and add extra logic to calculate the exact number of sectors per track if we find a partition that starts within cylinder zero. Signed-off-by: Michael Brown <mcb30@ipxe.org>
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;
}