Browse Source

[int13] Guard against BIOSes that "fix" the drive count

Some BIOSes (observed with an AMI BIOS on a SunFire X2200) seem to
reset the BIOS drive counter at 40:75 after a failed boot attempt.
This causes problems when attempting a Windows direct-to-iSCSI
installation: bootmgr.exe calls INT 13,0800 and gets told that there
are no hard disks, so never bothers to read the MBR in order to obtain
the boot disk signature.  The Windows iSCSI initiator will detect the
iBFT and connect to the target, and everything will appear to work
except for the error message "This computer's hardware may not support
booting to this disk.  Ensure that the disk's controller is enabled in
the computer's BIOS menu."

Fix by checking the BIOS drive counter on every INT 13 call, and
updating it whenever necessary.
tags/v1.0.0-rc1
Michael Brown 15 years ago
parent
commit
b515977955
1 changed files with 48 additions and 6 deletions
  1. 48
    6
      src/arch/i386/interface/pcbios/int13.c

+ 48
- 6
src/arch/i386/interface/pcbios/int13.c View File

@@ -51,6 +51,48 @@ extern void int13_wrapper ( void );
51 51
 /** List of registered emulated drives */
52 52
 static LIST_HEAD ( drives );
53 53
 
54
+/**
55
+ * Number of BIOS drives
56
+ *
57
+ * Note that this is the number of drives in the system as a whole
58
+ * (i.e. a mirror of the counter at 40:75), rather than a count of the
59
+ * number of emulated drives.
60
+ */
61
+static uint8_t num_drives;
62
+
63
+/**
64
+ * Update BIOS drive count
65
+ */
66
+static void int13_set_num_drives ( void ) {
67
+	struct int13_drive *drive;
68
+
69
+	/* Get current drive count */
70
+	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
71
+
72
+	/* Ensure count is large enough to cover all of our emulated drives */
73
+	list_for_each_entry ( drive, &drives, list ) {
74
+		if ( num_drives <= ( drive->drive & 0x7f ) )
75
+			num_drives = ( ( drive->drive & 0x7f ) + 1 );
76
+	}
77
+
78
+	/* Update current drive count */
79
+	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
80
+}
81
+
82
+/**
83
+ * Check number of drives
84
+ */
85
+static void int13_check_num_drives ( void ) {
86
+	uint8_t check_num_drives;
87
+
88
+	get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
89
+	if ( check_num_drives != num_drives ) {
90
+		int13_set_num_drives();
91
+		DBG ( "INT13 fixing up number of drives from %d to %d\n",
92
+		      check_num_drives, num_drives );
93
+	}
94
+}
95
+
54 96
 /**
55 97
  * INT 13, 00 - Reset disk system
56 98
  *
@@ -340,6 +382,9 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
340 382
 	struct int13_drive *drive;
341 383
 	int status;
342 384
 
385
+	/* Check BIOS hasn't killed off our drive */
386
+	int13_check_num_drives();
387
+
343 388
 	list_for_each_entry ( drive, &drives, list ) {
344 389
 
345 390
 		if ( bios_drive != drive->drive ) {
@@ -555,7 +600,6 @@ void register_int13_drive ( struct int13_drive *drive ) {
555 600
 	/* Assign natural drive number */
556 601
 	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
557 602
 	drive->natural_drive = ( num_drives | 0x80 );
558
-	num_drives++;
559 603
 
560 604
 	/* Assign drive number */
561 605
 	if ( ( drive->drive & 0xff ) == 0xff ) {
@@ -564,13 +608,8 @@ void register_int13_drive ( struct int13_drive *drive ) {
564 608
 	} else {
565 609
 		/* Use specified drive number (+0x80 if necessary) */
566 610
 		drive->drive |= 0x80;
567
-		if ( num_drives <= ( drive->drive & 0x7f ) )
568
-			num_drives = ( ( drive->drive & 0x7f ) + 1 );
569 611
 	}
570 612
 
571
-	/* Update BIOS drive count */
572
-	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
573
-
574 613
 	DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S "
575 614
 	      "geometry %d/%d/%d\n", drive->drive, drive->natural_drive,
576 615
 	      drive->cylinders, drive->heads, drive->sectors_per_track );
@@ -581,6 +620,9 @@ void register_int13_drive ( struct int13_drive *drive ) {
581 620
 
582 621
 	/* Add to list of emulated drives */
583 622
 	list_add ( &drive->list, &drives );
623
+
624
+	/* Update BIOS drive count */
625
+	int13_set_num_drives();
584 626
 }
585 627
 
586 628
 /**

Loading…
Cancel
Save