Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[int13] Pairwise swap drive numbers, instead of shifting all drive nu…
…mbers

Shifting all INT13 drive numbers causes problems on systems that use a
sparse drive number space (e.g. qemu BIOS, which uses 0xe0 for the CD-ROM
drive).

The strategy now is:

  Each drive is assigned a "natural" drive number, being the next
  available drive number in the system (based on the BIOS drive count).

  Each drive is accessed using its specified drive number.  If the
  specified drive number is -1, the natural drive number will be used.

  Accesses to the specified drive number will be delivered to the
  emulated drive, masking out any preexisting drive using this number.

  Accesses to the natural drive number, if different, will be remapped to
  the masked-out drive.

The overall upshot is that, for examples:

  System has no drives.  Emulated INT13 drive gets natural number 0x80
  and specified number 0x80.  Accesses to drive 0x80 go to the emulated
  drive, and there is no remapping.

  System has one drive.  Emulated INT13 drive gets natural number 0x81
  and specified number 0x80.  Accesses to drive 0x80 go to the emulated
  drive.  Accesses to drive 0x81 get remapped to the original drive 0x80.
  • Loading branch information
Michael Brown committed Jul 15, 2008
1 parent 21e9e80 commit bb41ec3
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 22 deletions.
14 changes: 13 additions & 1 deletion src/arch/i386/include/int13.h
Expand Up @@ -69,8 +69,20 @@ struct int13_drive {
/** Underlying block device */
struct block_device *blockdev;

/** BIOS drive number (0x80-0xff) */
/** BIOS in-use drive number (0x80-0xff) */
unsigned int drive;
/** BIOS natural drive number (0x80-0xff)
*
* This is the drive number that would have been assigned by
* 'naturally' appending the drive to the end of the BIOS
* drive list.
*
* If the emulated drive replaces a preexisting drive, this is
* the drive number that the preexisting drive gets remapped
* to.
*/
unsigned int natural_drive;

/** Number of cylinders
*
* The cylinder number field in an INT 13 call is ten bits
Expand Down
49 changes: 28 additions & 21 deletions src/arch/i386/interface/pcbios/int13.c
Expand Up @@ -325,15 +325,20 @@ static int int13_get_extended_parameters ( struct int13_drive *drive,
static __cdecl void int13 ( struct i386_all_regs *ix86 ) {
int command = ix86->regs.ah;
unsigned int bios_drive = ix86->regs.dl;
unsigned int original_bios_drive = bios_drive;
struct int13_drive *drive;
int status;

list_for_each_entry ( drive, &drives, list ) {
if ( drive->drive > bios_drive )
continue;
if ( drive->drive < bios_drive ) {
original_bios_drive--;

if ( bios_drive != drive->drive ) {
/* Remap any accesses to this drive's natural number */
if ( bios_drive == drive->natural_drive ) {
DBG ( "INT 13,%04x (%02x) remapped to "
"(%02x)\n", ix86->regs.ax,
bios_drive, drive->drive );
ix86->regs.dl = drive->drive;
return;
}
continue;
}

Expand Down Expand Up @@ -393,13 +398,6 @@ static __cdecl void int13 ( struct i386_all_regs *ix86 ) {

return;
}

/* Remap BIOS drive */
if ( bios_drive != original_bios_drive ) {
DBG ( "INT 13,%04x (%02x) remapped to (%02x)\n",
ix86->regs.ax, bios_drive, original_bios_drive );
}
ix86->regs.dl = original_bios_drive;
}

/**
Expand Down Expand Up @@ -542,19 +540,28 @@ void register_int13_drive ( struct int13_drive *drive ) {
/* Give drive a default geometry if none specified */
guess_int13_geometry ( drive );

/* Assign drive number if none specified, update BIOS drive count */
/* Assign natural drive number */
get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
if ( ( drive->drive & 0xff ) == 0xff )
drive->drive = num_drives;
drive->drive |= 0x80;
drive->natural_drive = ( num_drives | 0x80 );
num_drives++;
if ( num_drives <= ( drive->drive & 0x7f ) )
num_drives = ( ( drive->drive & 0x7f ) + 1 );

/* Assign drive number */
if ( ( drive->drive & 0xff ) == 0xff ) {
/* Drive number == -1 => use natural drive number */
drive->drive = drive->natural_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 with C/H/S geometry %d/%d/%d\n",
drive->drive, drive->cylinders, drive->heads,
drive->sectors_per_track );
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 );

/* Hook INT 13 vector if not already hooked */
if ( list_empty ( &drives ) )
Expand Down

0 comments on commit bb41ec3

Please sign in to comment.