瀏覽代碼

Added geometry-guessing code based on the partition table

tags/v0.9.3
Michael Brown 18 年之前
父節點
當前提交
0566ab2a2f
共有 2 個文件被更改,包括 91 次插入11 次删除
  1. 39
    0
      src/arch/i386/include/int13.h
  2. 52
    11
      src/arch/i386/interface/pcbios/int13.c

+ 39
- 0
src/arch/i386/include/int13.h 查看文件

@@ -201,6 +201,45 @@ struct int13_disk_parameters {
201 201
 
202 202
 /** @} */ 
203 203
 
204
+/** A C/H/S address within a partition table entry */
205
+struct partition_chs {
206
+	/** Head number */
207
+	uint8_t head;
208
+	/** Sector number, plus high 2 bits of cylinder number */
209
+	uint8_t cyl_sector;
210
+	/** Low 8 bits of cylinder number */
211
+	uint8_t cyl;
212
+} __attribute__ (( packed ));
213
+
214
+#define PART_HEAD(chs) ( (chs).head )
215
+#define PART_SECTOR(chs) ( (chs).cyl_sector & 0x3f )
216
+#define PART_CYLINDER(chs) ( (chs).cyl | ( ( (chs).cyl_sector & 0xc0 ) << 2 ) )
217
+
218
+/** A partition table entry within the MBR */
219
+struct partition_table_entry {
220
+	/** Bootable flag */
221
+	uint8_t bootable;
222
+	/** C/H/S start address */
223
+	struct partition_chs chs_start;
224
+	/** System indicator (partition type) */
225
+	uint8_t type;
226
+	/** C/H/S end address */
227
+	struct partition_chs chs_end;
228
+	/** Linear start address */
229
+	uint32_t start;
230
+	/** Linear length */
231
+	uint32_t length;
232
+} __attribute__ (( packed ));
233
+
234
+/** A Master Boot Record */
235
+struct master_boot_record {
236
+	uint8_t pad[446];
237
+	/** Partition table */
238
+	struct partition_table_entry partitions[4];
239
+	/** 0x55aa MBR signature */
240
+	uint16_t signature;
241
+} __attribute__ (( packed ));
242
+
204 243
 extern void register_int13_drive ( struct int13_drive *drive );
205 244
 extern void unregister_int13_drive ( struct int13_drive *drive );
206 245
 extern int int13_boot ( unsigned int drive );

+ 52
- 11
src/arch/i386/interface/pcbios/int13.c 查看文件

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

Loading…
取消
儲存