Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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.
  • Loading branch information
Michael Brown committed Nov 18, 2009
1 parent 89de3e2 commit b515977
Showing 1 changed file with 48 additions and 6 deletions.
54 changes: 48 additions & 6 deletions src/arch/i386/interface/pcbios/int13.c
Expand Up @@ -51,6 +51,48 @@ extern void int13_wrapper ( void );
/** List of registered emulated drives */
static LIST_HEAD ( drives );

/**
* Number of BIOS drives
*
* Note that this is the number of drives in the system as a whole
* (i.e. a mirror of the counter at 40:75), rather than a count of the
* number of emulated drives.
*/
static uint8_t num_drives;

/**
* Update BIOS drive count
*/
static void int13_set_num_drives ( void ) {
struct int13_drive *drive;

/* Get current drive count */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );

/* Ensure count is large enough to cover all of our emulated drives */
list_for_each_entry ( drive, &drives, list ) {
if ( num_drives <= ( drive->drive & 0x7f ) )
num_drives = ( ( drive->drive & 0x7f ) + 1 );
}

/* Update current drive count */
put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
}

/**
* Check number of drives
*/
static void int13_check_num_drives ( void ) {
uint8_t check_num_drives;

get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
if ( check_num_drives != num_drives ) {
int13_set_num_drives();
DBG ( "INT13 fixing up number of drives from %d to %d\n",
check_num_drives, num_drives );
}
}

/**
* INT 13, 00 - Reset disk system
*
Expand Down Expand Up @@ -340,6 +382,9 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
struct int13_drive *drive;
int status;

/* Check BIOS hasn't killed off our drive */
int13_check_num_drives();

list_for_each_entry ( drive, &drives, list ) {

if ( bios_drive != drive->drive ) {
Expand Down Expand Up @@ -555,7 +600,6 @@ void register_int13_drive ( struct int13_drive *drive ) {
/* Assign natural drive number */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
drive->natural_drive = ( num_drives | 0x80 );
num_drives++;

/* Assign drive number */
if ( ( drive->drive & 0xff ) == 0xff ) {
Expand All @@ -564,13 +608,8 @@ void register_int13_drive ( struct int13_drive *drive ) {
} else {
/* Use specified drive number (+0x80 if necessary) */
drive->drive |= 0x80;
if ( num_drives <= ( drive->drive & 0x7f ) )
num_drives = ( ( drive->drive & 0x7f ) + 1 );
}

/* Update BIOS drive count */
put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );

DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S "
"geometry %d/%d/%d\n", drive->drive, drive->natural_drive,
drive->cylinders, drive->heads, drive->sectors_per_track );
Expand All @@ -581,6 +620,9 @@ void register_int13_drive ( struct int13_drive *drive ) {

/* Add to list of emulated drives */
list_add ( &drive->list, &drives );

/* Update BIOS drive count */
int13_set_num_drives();
}

/**
Expand Down

0 comments on commit b515977

Please sign in to comment.