david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[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>
This commit is contained in:
Michael Brown 2017-03-26 21:03:50 +03:00
parent bb5a54b79a
commit ebceb8ad8a
1 changed files with 45 additions and 11 deletions

View File

@ -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;
}