|
@@ -438,26 +438,47 @@ static void unhook_int13 ( void ) {
|
438
|
438
|
}
|
439
|
439
|
|
440
|
440
|
/**
|
441
|
|
- * Register INT 13 emulated drive
|
|
441
|
+ * Guess INT 13 drive geometry
|
442
|
442
|
*
|
443
|
443
|
* @v drive Emulated drive
|
444
|
444
|
*
|
445
|
|
- * Registers the drive with the INT 13 emulation subsystem, and hooks
|
446
|
|
- * the INT 13 interrupt vector (if not already hooked).
|
447
|
|
- *
|
448
|
|
- * The underlying block device must be valid. A drive number and
|
449
|
|
- * geometry will be assigned if left blank.
|
|
445
|
+ * Guesses the drive geometry by inspecting the partition table.
|
450
|
446
|
*/
|
451
|
|
-void register_int13_drive ( struct int13_drive *drive ) {
|
452
|
|
- uint8_t num_drives;
|
|
447
|
+static void guess_int13_geometry ( struct int13_drive *drive ) {
|
|
448
|
+ struct master_boot_record mbr;
|
|
449
|
+ struct partition_table_entry *partition;
|
|
450
|
+ unsigned int guessed_heads = 255;
|
|
451
|
+ unsigned int guessed_sectors_per_track = 63;
|
453
|
452
|
unsigned long blocks;
|
454
|
453
|
unsigned long blocks_per_cyl;
|
|
454
|
+ unsigned int i;
|
455
|
455
|
|
456
|
|
- /* Give drive a default geometry if none specified */
|
|
456
|
+ /* Scan through partition table and modify guesses for heads
|
|
457
|
+ * and sectors_per_track if we find any used partitions.
|
|
458
|
+ */
|
|
459
|
+ if ( drive->blockdev->read ( drive->blockdev, 0, 1,
|
|
460
|
+ virt_to_user ( &mbr ) ) == 0 ) {
|
|
461
|
+ for ( i = 0 ; i < 4 ; i++ ) {
|
|
462
|
+ partition = &mbr.partitions[i];
|
|
463
|
+ if ( ! partition->type )
|
|
464
|
+ continue;
|
|
465
|
+ guessed_heads =
|
|
466
|
+ ( PART_HEAD ( partition->chs_end ) + 1 );
|
|
467
|
+ guessed_sectors_per_track =
|
|
468
|
+ PART_SECTOR ( partition->chs_end );
|
|
469
|
+ DBG ( "Guessing C/H/S xx/%d/%d based on partition "
|
|
470
|
+ "%d\n", guessed_heads,
|
|
471
|
+ guessed_sectors_per_track, ( i + 1 ) );
|
|
472
|
+ }
|
|
473
|
+ } else {
|
|
474
|
+ DBG ( "Could not read partition table to guess geometry\n" );
|
|
475
|
+ }
|
|
476
|
+
|
|
477
|
+ /* Apply guesses if no geometry already specified */
|
457
|
478
|
if ( ! drive->heads )
|
458
|
|
- drive->heads = 255;
|
|
479
|
+ drive->heads = guessed_heads;
|
459
|
480
|
if ( ! drive->sectors_per_track )
|
460
|
|
- drive->sectors_per_track = 63;
|
|
481
|
+ drive->sectors_per_track = guessed_sectors_per_track;
|
461
|
482
|
if ( ! drive->cylinders ) {
|
462
|
483
|
/* Avoid attempting a 64-bit divide on a 32-bit system */
|
463
|
484
|
blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ?
|
|
@@ -465,7 +486,27 @@ void register_int13_drive ( struct int13_drive *drive ) {
|
465
|
486
|
blocks_per_cyl = ( drive->heads * drive->sectors_per_track );
|
466
|
487
|
assert ( blocks_per_cyl != 0 );
|
467
|
488
|
drive->cylinders = ( blocks / blocks_per_cyl );
|
|
489
|
+ if ( drive->cylinders > 1024 )
|
|
490
|
+ drive->cylinders = 1024;
|
468
|
491
|
}
|
|
492
|
+}
|
|
493
|
+
|
|
494
|
+/**
|
|
495
|
+ * Register INT 13 emulated drive
|
|
496
|
+ *
|
|
497
|
+ * @v drive Emulated drive
|
|
498
|
+ *
|
|
499
|
+ * Registers the drive with the INT 13 emulation subsystem, and hooks
|
|
500
|
+ * the INT 13 interrupt vector (if not already hooked).
|
|
501
|
+ *
|
|
502
|
+ * The underlying block device must be valid. A drive number and
|
|
503
|
+ * geometry will be assigned if left blank.
|
|
504
|
+ */
|
|
505
|
+void register_int13_drive ( struct int13_drive *drive ) {
|
|
506
|
+ uint8_t num_drives;
|
|
507
|
+
|
|
508
|
+ /* Give drive a default geometry if none specified */
|
|
509
|
+ guess_int13_geometry ( drive );
|
469
|
510
|
|
470
|
511
|
/* Assign drive number if none specified, update BIOS drive count */
|
471
|
512
|
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
|