int13.c File Reference

INT 13 emulation. More...

#include <stdint.h>
#include <limits.h>
#include <byteswap.h>
#include <errno.h>
#include <assert.h>
#include <gpxe/list.h>
#include <gpxe/blockdev.h>
#include <gpxe/memmap.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
#include <bootsector.h>
#include <int13.h>

Go to the source code of this file.

Defines

#define int13_vector   __use_text16 ( int13_vector )

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static struct segoff __text16 (int13_vector)
 Vector for chaining to other INT 13 handlers.
void int13_wrapper (void)
 Assembly wrapper.
static LIST_HEAD (drives)
 List of registered emulated drives.
static void int13_set_num_drives (void)
 Update BIOS drive count.
static void int13_check_num_drives (void)
 Check number of drives.
static int int13_reset (struct int13_drive *drive __unused, struct i386_all_regs *ix86 __unused)
 INT 13, 00 - Reset disk system.
static int int13_get_last_status (struct int13_drive *drive, struct i386_all_regs *ix86 __unused)
 INT 13, 01 - Get status of last operation.
static int int13_rw_sectors (struct int13_drive *drive, struct i386_all_regs *ix86, int(*io)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer))
 Read / write sectors.
static int int13_read_sectors (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 02 - Read sectors.
static int int13_write_sectors (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 03 - Write sectors.
static int int13_get_parameters (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 08 - Get drive parameters.
static int int13_get_disk_type (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 15 - Get disk type.
static int int13_extension_check (struct int13_drive *drive __unused, struct i386_all_regs *ix86)
 INT 13, 41 - Extensions installation check.
static int int13_extended_rw (struct int13_drive *drive, struct i386_all_regs *ix86, int(*io)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer))
 Extended read / write.
static int int13_extended_read (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 42 - Extended read.
static int int13_extended_write (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 43 - Extended write.
static int int13_get_extended_parameters (struct int13_drive *drive, struct i386_all_regs *ix86)
 INT 13, 48 - Get extended parameters.
static __asmcall void int13 (struct i386_all_regs *ix86)
 INT 13 handler.
static void hook_int13 (void)
 Hook INT 13 handler.
static void unhook_int13 (void)
 Unhook INT 13 handler.
static void guess_int13_geometry (struct int13_drive *drive)
 Guess INT 13 drive geometry.
void register_int13_drive (struct int13_drive *drive)
 Register INT 13 emulated drive.
void unregister_int13_drive (struct int13_drive *drive)
 Unregister INT 13 emulated drive.
int int13_boot (unsigned int drive)
 Attempt to boot from an INT 13 drive.

Variables

static uint8_t num_drives
 Number of BIOS drives.


Detailed Description

INT 13 emulation.

This module provides a mechanism for exporting block devices via the BIOS INT 13 disk interrupt interface.

Definition in file int13.c.


Define Documentation

#define int13_vector   __use_text16 ( int13_vector )

Definition at line 46 of file int13.c.

Referenced by hook_int13(), and unhook_int13().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static struct segoff __text16 ( int13_vector   )  [static, read]

Vector for chaining to other INT 13 handlers.

void int13_wrapper ( void   ) 

Assembly wrapper.

Referenced by hook_int13(), and unhook_int13().

static LIST_HEAD ( drives   )  [static]

List of registered emulated drives.

static void int13_set_num_drives ( void   )  [static]

Update BIOS drive count.

Definition at line 66 of file int13.c.

References BDA_NUM_DRIVES, BDA_SEG, int13_drive::drive, get_real, int13_drive::list, list_for_each_entry, num_drives, and put_real.

Referenced by int13_check_num_drives(), and register_int13_drive().

00066                                           {
00067         struct int13_drive *drive;
00068 
00069         /* Get current drive count */
00070         get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
00071 
00072         /* Ensure count is large enough to cover all of our emulated drives */
00073         list_for_each_entry ( drive, &drives, list ) {
00074                 if ( num_drives <= ( drive->drive & 0x7f ) )
00075                         num_drives = ( ( drive->drive & 0x7f ) + 1 );
00076         }
00077 
00078         /* Update current drive count */
00079         put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
00080 }

static void int13_check_num_drives ( void   )  [static]

Check number of drives.

Definition at line 85 of file int13.c.

References BDA_NUM_DRIVES, BDA_SEG, DBG, get_real, int13_set_num_drives(), and num_drives.

Referenced by int13().

00085                                             {
00086         uint8_t check_num_drives;
00087 
00088         get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
00089         if ( check_num_drives != num_drives ) {
00090                 int13_set_num_drives();
00091                 DBG ( "INT13 fixing up number of drives from %d to %d\n",
00092                       check_num_drives, num_drives );
00093         }
00094 }

static int int13_reset ( struct int13_drive *drive  __unused,
struct i386_all_regs *ix86  __unused 
) [static]

INT 13, 00 - Reset disk system.

Parameters:
drive Emulated drive
Return values:
status Status code

Definition at line 102 of file int13.c.

References DBG.

Referenced by int13().

00103                                                                {
00104         DBG ( "Reset drive\n" );
00105         return 0;
00106 }

static int int13_get_last_status ( struct int13_drive drive,
struct i386_all_regs *ix86  __unused 
) [static]

INT 13, 01 - Get status of last operation.

Parameters:
drive Emulated drive
Return values:
status Status code

Definition at line 114 of file int13.c.

References DBG, and int13_drive::last_status.

Referenced by int13().

00115                                                                          {
00116         DBG ( "Get status of last operation\n" );
00117         return drive->last_status;
00118 }

static int int13_rw_sectors ( struct int13_drive drive,
struct i386_all_regs ix86,
int(*)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer)  io 
) [static]

Read / write sectors.

Parameters:
drive Emulated drive
al Number of sectors to read or write (must be nonzero)
ch Low bits of cylinder number
cl (bits 7:6) High bits of cylinder number
cl (bits 5:0) Sector number
dh Head number
es:bx Data buffer
io Read / write method
Return values:
status Status code
al Number of sectors read or written

Definition at line 134 of file int13.c.

References i386_regs::al, assert, block_device::blksize, int13_drive::blockdev, i386_regs::bx, i386_regs::ch, i386_regs::cl, DBG, i386_regs::dh, i386_seg_regs::es, int13_drive::heads, INT13_BLKSIZE, INT13_STATUS_INVALID, INT13_STATUS_READ_ERROR, real_to_user(), i386_all_regs::regs, int13_drive::sectors_per_track, i386_all_regs::segs, and strerror().

Referenced by int13_read_sectors(), and int13_write_sectors().

00139                                                                   {
00140         struct block_device *blockdev = drive->blockdev;
00141         unsigned int cylinder, head, sector;
00142         unsigned long lba;
00143         unsigned int count;
00144         userptr_t buffer;
00145         int rc;
00146 
00147         /* Validate blocksize */
00148         if ( blockdev->blksize != INT13_BLKSIZE ) {
00149                 DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
00150                       blockdev->blksize );
00151                 return -INT13_STATUS_INVALID;
00152         }
00153         
00154         /* Calculate parameters */
00155         cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
00156         assert ( cylinder < drive->cylinders );
00157         head = ix86->regs.dh;
00158         assert ( head < drive->heads );
00159         sector = ( ix86->regs.cl & 0x3f );
00160         assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) );
00161         lba = ( ( ( ( cylinder * drive->heads ) + head )
00162                   * drive->sectors_per_track ) + sector - 1 );
00163         count = ix86->regs.al;
00164         buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );
00165 
00166         DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder,
00167               head, sector, lba, ix86->segs.es, ix86->regs.bx, count );
00168 
00169         /* Read from / write to block device */
00170         if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) {
00171                 DBG ( "INT 13 failed: %s\n", strerror ( rc ) );
00172                 return -INT13_STATUS_READ_ERROR;
00173         }
00174 
00175         return 0;
00176 }

static int int13_read_sectors ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 02 - Read sectors.

Parameters:
drive Emulated drive
al Number of sectors to read (must be nonzero)
ch Low bits of cylinder number
cl (bits 7:6) High bits of cylinder number
cl (bits 5:0) Sector number
dh Head number
es:bx Data buffer
Return values:
status Status code
al Number of sectors read

Definition at line 191 of file int13.c.

References int13_drive::blockdev, DBG, int13_rw_sectors(), block_device::op, and block_device_operations::read.

Referenced by int13().

00192                                                              {
00193         DBG ( "Read: " );
00194         return int13_rw_sectors ( drive, ix86, drive->blockdev->op->read );
00195 }

static int int13_write_sectors ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 03 - Write sectors.

Parameters:
drive Emulated drive
al Number of sectors to write (must be nonzero)
ch Low bits of cylinder number
cl (bits 7:6) High bits of cylinder number
cl (bits 5:0) Sector number
dh Head number
es:bx Data buffer
Return values:
status Status code
al Number of sectors written

Definition at line 210 of file int13.c.

References int13_drive::blockdev, DBG, int13_rw_sectors(), block_device::op, and block_device_operations::write.

Referenced by int13().

00211                                                               {
00212         DBG ( "Write: " );
00213         return int13_rw_sectors ( drive, ix86, drive->blockdev->op->write );
00214 }

static int int13_get_parameters ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 08 - Get drive parameters.

Parameters:
drive Emulated drive
Return values:
status Status code
ch Low bits of maximum cylinder number
cl (bits 7:6) High bits of maximum cylinder number
cl (bits 5:0) Maximum sector number
dh Maximum head number
dl Number of drives

Definition at line 227 of file int13.c.

References BDA_NUM_DRIVES, BDA_SEG, i386_regs::ch, i386_regs::cl, int13_drive::cylinders, DBG, i386_regs::dh, i386_regs::dl, get_real, int13_drive::heads, i386_all_regs::regs, and int13_drive::sectors_per_track.

Referenced by int13().

00228                                                                {
00229         unsigned int max_cylinder = drive->cylinders - 1;
00230         unsigned int max_head = drive->heads - 1;
00231         unsigned int max_sector = drive->sectors_per_track; /* sic */
00232 
00233         DBG ( "Get drive parameters\n" );
00234 
00235         ix86->regs.ch = ( max_cylinder & 0xff );
00236         ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
00237         ix86->regs.dh = max_head;
00238         get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
00239         return 0;
00240 }

static int int13_get_disk_type ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 15 - Get disk type.

Parameters:
drive Emulated drive
Return values:
ah Type code
cx:dx Sector count
status Status code / disk type

Definition at line 250 of file int13.c.

References int13_drive::blockdev, block_device::blocks, i386_regs::cx, DBG, i386_regs::dx, INT13_DISK_TYPE_HDD, and i386_all_regs::regs.

Referenced by int13().

00251                                                               {
00252         uint32_t blocks;
00253 
00254         DBG ( "Get disk type\n" );
00255         blocks = ( ( drive->blockdev->blocks <= 0xffffffffUL ) ?
00256                    drive->blockdev->blocks : 0xffffffffUL );
00257         ix86->regs.cx = ( blocks >> 16 );
00258         ix86->regs.dx = ( blocks & 0xffff );
00259         return INT13_DISK_TYPE_HDD;
00260 }

static int int13_extension_check ( struct int13_drive *drive  __unused,
struct i386_all_regs ix86 
) [static]

INT 13, 41 - Extensions installation check.

Parameters:
drive Emulated drive
bx 0x55aa
Return values:
bx 0xaa55
cx Extensions API support bitmap
status Status code / API version

Definition at line 271 of file int13.c.

References i386_regs::bx, i386_regs::cx, DBG, INT13_EXTENSION_LINEAR, INT13_EXTENSION_VER_1_X, INT13_STATUS_INVALID, and i386_all_regs::regs.

Referenced by int13().

00272                                                                 {
00273         if ( ix86->regs.bx == 0x55aa ) {
00274                 DBG ( "INT 13 extensions installation check\n" );
00275                 ix86->regs.bx = 0xaa55;
00276                 ix86->regs.cx = INT13_EXTENSION_LINEAR;
00277                 return INT13_EXTENSION_VER_1_X;
00278         } else {
00279                 return -INT13_STATUS_INVALID;
00280         }
00281 }

static int int13_extended_rw ( struct int13_drive drive,
struct i386_all_regs ix86,
int(*)(struct block_device *blockdev, uint64_t block, unsigned long count, userptr_t buffer)  io 
) [static]

Extended read / write.

Parameters:
drive Emulated drive
ds:si Disk address packet
io Read / write method
Return values:
status Status code

Definition at line 291 of file int13.c.

References int13_drive::blockdev, int13_disk_address::buffer, copy_from_real, int13_disk_address::count, DBG, i386_seg_regs::ds, INT13_STATUS_READ_ERROR, int13_disk_address::lba, segoff::offset, real_to_user(), i386_all_regs::regs, segoff::segment, i386_all_regs::segs, i386_regs::si, and strerror().

Referenced by int13_extended_read(), and int13_extended_write().

00296                                                                    {
00297         struct block_device *blockdev = drive->blockdev;
00298         struct int13_disk_address addr;
00299         uint64_t lba;
00300         unsigned long count;
00301         userptr_t buffer;
00302         int rc;
00303 
00304         /* Read parameters from disk address structure */
00305         copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr ));
00306         lba = addr.lba;
00307         count = addr.count;
00308         buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset );
00309 
00310         DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba,
00311               addr.buffer.segment, addr.buffer.offset, count );
00312         
00313         /* Read from / write to block device */
00314         if ( ( rc = io ( blockdev, lba, count, buffer ) ) != 0 ) {
00315                 DBG ( "INT 13 failed: %s\n", strerror ( rc ) );
00316                 return -INT13_STATUS_READ_ERROR;
00317         }
00318 
00319         return 0;
00320 }

static int int13_extended_read ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 42 - Extended read.

Parameters:
drive Emulated drive
ds:si Disk address packet
Return values:
status Status code

Definition at line 329 of file int13.c.

References int13_drive::blockdev, DBG, int13_extended_rw(), block_device::op, and block_device_operations::read.

Referenced by int13().

00330                                                               {
00331         DBG ( "Extended read: " );
00332         return int13_extended_rw ( drive, ix86, drive->blockdev->op->read );
00333 }

static int int13_extended_write ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 43 - Extended write.

Parameters:
drive Emulated drive
ds:si Disk address packet
Return values:
status Status code

Definition at line 342 of file int13.c.

References int13_drive::blockdev, DBG, int13_extended_rw(), block_device::op, and block_device_operations::write.

Referenced by int13().

00343                                                                {
00344         DBG ( "Extended write: " );
00345         return int13_extended_rw ( drive, ix86, drive->blockdev->op->write );
00346 }

static int int13_get_extended_parameters ( struct int13_drive drive,
struct i386_all_regs ix86 
) [static]

INT 13, 48 - Get extended parameters.

Parameters:
drive Emulated drive
ds:si Drive parameter table
Return values:
status Status code

Definition at line 355 of file int13.c.

References block_device::blksize, int13_drive::blockdev, block_device::blocks, int13_disk_parameters::bufsize, copy_to_real, int13_drive::cylinders, int13_disk_parameters::cylinders, DBG, i386_seg_regs::ds, int13_disk_parameters::flags, int13_drive::heads, INT13_FL_DMA_TRANSPARENT, i386_all_regs::regs, int13_drive::sectors_per_track, i386_all_regs::segs, and i386_regs::si.

Referenced by int13().

00356                                                                         {
00357         struct int13_disk_parameters params = {
00358                 .bufsize = sizeof ( params ),
00359                 .flags = INT13_FL_DMA_TRANSPARENT,
00360                 .cylinders = drive->cylinders,
00361                 .heads = drive->heads,
00362                 .sectors_per_track = drive->sectors_per_track,
00363                 .sectors = drive->blockdev->blocks,
00364                 .sector_size = drive->blockdev->blksize,
00365         };
00366         
00367         DBG ( "Get extended drive parameters to %04x:%04x\n",
00368               ix86->segs.ds, ix86->regs.si );
00369 
00370         copy_to_real ( ix86->segs.ds, ix86->regs.si, &params,
00371                        sizeof ( params ) );
00372         return 0;
00373 }

static __asmcall void int13 ( struct i386_all_regs ix86  )  [static]

INT 13 handler.

Definition at line 379 of file int13.c.

References i386_regs::ah, i386_regs::ax, CF, DBG, i386_regs::dl, int13_drive::drive, i386_all_regs::flags, int13_check_num_drives(), int13_extended_read(), INT13_EXTENDED_READ, int13_extended_write(), INT13_EXTENDED_WRITE, int13_extension_check(), INT13_EXTENSION_CHECK, int13_get_disk_type(), INT13_GET_DISK_TYPE, int13_get_extended_parameters(), INT13_GET_EXTENDED_PARAMETERS, int13_get_last_status(), INT13_GET_LAST_STATUS, int13_get_parameters(), INT13_GET_PARAMETERS, int13_read_sectors(), INT13_READ_SECTORS, int13_reset(), INT13_RESET, INT13_STATUS_INVALID, int13_write_sectors(), INT13_WRITE_SECTORS, int13_drive::last_status, int13_drive::list, list_for_each_entry, int13_drive::natural_drive, OF, and i386_all_regs::regs.

Referenced by hook_int13().

00379                                                            {
00380         int command = ix86->regs.ah;
00381         unsigned int bios_drive = ix86->regs.dl;
00382         struct int13_drive *drive;
00383         int status;
00384 
00385         /* Check BIOS hasn't killed off our drive */
00386         int13_check_num_drives();
00387 
00388         list_for_each_entry ( drive, &drives, list ) {
00389 
00390                 if ( bios_drive != drive->drive ) {
00391                         /* Remap any accesses to this drive's natural number */
00392                         if ( bios_drive == drive->natural_drive ) {
00393                                 DBG ( "INT 13,%04x (%02x) remapped to "
00394                                       "(%02x)\n", ix86->regs.ax,
00395                                       bios_drive, drive->drive );
00396                                 ix86->regs.dl = drive->drive;
00397                                 return;
00398                         }
00399                         continue;
00400                 }
00401                 
00402                 DBG ( "INT 13,%04x (%02x): ", ix86->regs.ax, drive->drive );
00403 
00404                 switch ( command ) {
00405                 case INT13_RESET:
00406                         status = int13_reset ( drive, ix86 );
00407                         break;
00408                 case INT13_GET_LAST_STATUS:
00409                         status = int13_get_last_status ( drive, ix86 );
00410                         break;
00411                 case INT13_READ_SECTORS:
00412                         status = int13_read_sectors ( drive, ix86 );
00413                         break;
00414                 case INT13_WRITE_SECTORS:
00415                         status = int13_write_sectors ( drive, ix86 );
00416                         break;
00417                 case INT13_GET_PARAMETERS:
00418                         status = int13_get_parameters ( drive, ix86 );
00419                         break;
00420                 case INT13_GET_DISK_TYPE:
00421                         status = int13_get_disk_type ( drive, ix86 );
00422                         break;
00423                 case INT13_EXTENSION_CHECK:
00424                         status = int13_extension_check ( drive, ix86 );
00425                         break;
00426                 case INT13_EXTENDED_READ:
00427                         status = int13_extended_read ( drive, ix86 );
00428                         break;
00429                 case INT13_EXTENDED_WRITE:
00430                         status = int13_extended_write ( drive, ix86 );
00431                         break;
00432                 case INT13_GET_EXTENDED_PARAMETERS:
00433                         status = int13_get_extended_parameters ( drive, ix86 );
00434                         break;
00435                 default:
00436                         DBG ( "*** Unrecognised INT 13 ***\n" );
00437                         status = -INT13_STATUS_INVALID;
00438                         break;
00439                 }
00440 
00441                 /* Store status for INT 13,01 */
00442                 drive->last_status = status;
00443 
00444                 /* Negative status indicates an error */
00445                 if ( status < 0 ) {
00446                         status = -status;
00447                         DBG ( "INT 13 returning failure status %x\n", status );
00448                 } else {
00449                         ix86->flags &= ~CF;
00450                 }
00451                 ix86->regs.ah = status;
00452 
00453                 /* Set OF to indicate to wrapper not to chain this call */
00454                 ix86->flags |= OF;
00455 
00456                 return;
00457         }
00458 }

static void hook_int13 ( void   )  [static]

Hook INT 13 handler.

Definition at line 464 of file int13.c.

References __asm__(), BDA_NUM_DRIVES, BDA_SEG, hook_bios_interrupt(), int13(), int13_vector, int13_wrapper(), and TEXT16_CODE.

Referenced by register_int13_drive().

00464                                 {
00465         /* Assembly wrapper to call int13().  int13() sets OF if we
00466          * should not chain to the previous handler.  (The wrapper
00467          * clears CF and OF before calling int13()).
00468          */
00469         __asm__  __volatile__ (
00470                TEXT16_CODE ( "\nint13_wrapper:\n\t"
00471                              /* Preserve %ax and %dx for future reference */
00472                              "pushw %%bp\n\t"
00473                              "movw %%sp, %%bp\n\t"                           
00474                              "pushw %%ax\n\t"
00475                              "pushw %%dx\n\t"
00476                              /* Clear OF, set CF, call int13() */
00477                              "orb $0, %%al\n\t" 
00478                              "stc\n\t"
00479                              "pushl %0\n\t"
00480                              "pushw %%cs\n\t"
00481                              "call prot_call\n\t"
00482                              /* Chain if OF not set */
00483                              "jo 1f\n\t"
00484                              "pushfw\n\t"
00485                              "lcall *%%cs:int13_vector\n\t"
00486                              "\n1:\n\t"
00487                              /* Overwrite flags for iret */
00488                              "pushfw\n\t"
00489                              "popw 6(%%bp)\n\t"
00490                              /* Fix up %dl:
00491                               *
00492                               * INT 13,15 : do nothing
00493                               * INT 13,08 : load with number of drives
00494                               * all others: restore original value
00495                               */
00496                              "cmpb $0x15, -1(%%bp)\n\t"
00497                              "je 2f\n\t"
00498                              "movb -4(%%bp), %%dl\n\t"
00499                              "cmpb $0x08, -1(%%bp)\n\t"
00500                              "jne 2f\n\t"
00501                              "pushw %%ds\n\t"
00502                              "pushw %1\n\t"
00503                              "popw %%ds\n\t"
00504                              "movb %c2, %%dl\n\t"
00505                              "popw %%ds\n\t"
00506                              /* Return */
00507                              "\n2:\n\t"
00508                              "movw %%bp, %%sp\n\t"
00509                              "popw %%bp\n\t"
00510                              "iret\n\t" )
00511                : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
00512 
00513         hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
00514                               &int13_vector );
00515 }

static void unhook_int13 ( void   )  [static]

Unhook INT 13 handler.

Definition at line 520 of file int13.c.

References int13_vector, int13_wrapper(), and unhook_bios_interrupt().

Referenced by unregister_int13_drive().

00520                                   {
00521         unhook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
00522                                 &int13_vector );
00523 }

static void guess_int13_geometry ( struct int13_drive drive  )  [static]

Guess INT 13 drive geometry.

Parameters:
drive Emulated drive
Guesses the drive geometry by inspecting the partition table.

Definition at line 532 of file int13.c.

References assert, block_device::blksize, int13_drive::blockdev, block_device::blocks, partition_table_entry::chs_end, int13_drive::cylinders, DBG, int13_drive::heads, INT13_BLKSIZE, block_device::op, PART_HEAD, PART_SECTOR, master_boot_record::partitions, block_device_operations::read, int13_drive::sectors_per_track, partition_table_entry::type, ULONG_MAX, and virt_to_user().

Referenced by register_int13_drive().

00532                                                                {
00533         struct master_boot_record mbr;
00534         struct partition_table_entry *partition;
00535         unsigned int guessed_heads = 255;
00536         unsigned int guessed_sectors_per_track = 63;
00537         unsigned long blocks;
00538         unsigned long blocks_per_cyl;
00539         unsigned int i;
00540 
00541         /* Don't even try when the blksize is invalid for C/H/S access */
00542         if ( drive->blockdev->blksize != INT13_BLKSIZE )
00543                 return;
00544 
00545         /* Scan through partition table and modify guesses for heads
00546          * and sectors_per_track if we find any used partitions.
00547          */
00548         if ( drive->blockdev->op->read ( drive->blockdev, 0, 1,
00549                                          virt_to_user ( &mbr ) ) == 0 ) {
00550                 for ( i = 0 ; i < 4 ; i++ ) {
00551                         partition = &mbr.partitions[i];
00552                         if ( ! partition->type )
00553                                 continue;
00554                         guessed_heads =
00555                                 ( PART_HEAD ( partition->chs_end ) + 1 );
00556                         guessed_sectors_per_track = 
00557                                 PART_SECTOR ( partition->chs_end );
00558                         DBG ( "Guessing C/H/S xx/%d/%d based on partition "
00559                               "%d\n", guessed_heads,
00560                               guessed_sectors_per_track, ( i + 1 ) );
00561                 }
00562         } else {
00563                 DBG ( "Could not read partition table to guess geometry\n" );
00564         }
00565 
00566         /* Apply guesses if no geometry already specified */
00567         if ( ! drive->heads )
00568                 drive->heads = guessed_heads;
00569         if ( ! drive->sectors_per_track )
00570                 drive->sectors_per_track = guessed_sectors_per_track;
00571         if ( ! drive->cylinders ) {
00572                 /* Avoid attempting a 64-bit divide on a 32-bit system */
00573                 blocks = ( ( drive->blockdev->blocks <= ULONG_MAX ) ?
00574                            drive->blockdev->blocks : ULONG_MAX );
00575                 blocks_per_cyl = ( drive->heads * drive->sectors_per_track );
00576                 assert ( blocks_per_cyl != 0 );
00577                 drive->cylinders = ( blocks / blocks_per_cyl );
00578                 if ( drive->cylinders > 1024 )
00579                         drive->cylinders = 1024;
00580         }
00581 }

void register_int13_drive ( struct int13_drive drive  ) 

Register INT 13 emulated drive.

Parameters:
drive Emulated drive
Registers the drive with the INT 13 emulation subsystem, and hooks the INT 13 interrupt vector (if not already hooked).

The underlying block device must be valid. A drive number and geometry will be assigned if left blank.

Definition at line 594 of file int13.c.

References BDA_NUM_DRIVES, BDA_SEG, int13_drive::cylinders, DBG, int13_drive::drive, get_real, guess_int13_geometry(), int13_drive::heads, hook_int13(), int13_set_num_drives(), int13_drive::list, list_add, list_empty(), int13_drive::natural_drive, num_drives, and int13_drive::sectors_per_track.

Referenced by aoeboot(), eltorito_exec(), ib_srpboot(), and iscsiboot().

00594                                                         {
00595         uint8_t num_drives;
00596 
00597         /* Give drive a default geometry if none specified */
00598         guess_int13_geometry ( drive );
00599 
00600         /* Assign natural drive number */
00601         get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
00602         drive->natural_drive = ( num_drives | 0x80 );
00603 
00604         /* Assign drive number */
00605         if ( ( drive->drive & 0xff ) == 0xff ) {
00606                 /* Drive number == -1 => use natural drive number */
00607                 drive->drive = drive->natural_drive;
00608         } else {
00609                 /* Use specified drive number (+0x80 if necessary) */
00610                 drive->drive |= 0x80;
00611         }
00612 
00613         DBG ( "Registered INT13 drive %02x (naturally %02x) with C/H/S "
00614               "geometry %d/%d/%d\n", drive->drive, drive->natural_drive,
00615               drive->cylinders, drive->heads, drive->sectors_per_track );
00616 
00617         /* Hook INT 13 vector if not already hooked */
00618         if ( list_empty ( &drives ) )
00619                 hook_int13();
00620 
00621         /* Add to list of emulated drives */
00622         list_add ( &drive->list, &drives );
00623 
00624         /* Update BIOS drive count */
00625         int13_set_num_drives();
00626 }

void unregister_int13_drive ( struct int13_drive drive  ) 

Unregister INT 13 emulated drive.

Parameters:
drive Emulated drive
Unregisters the drive from the INT 13 emulation subsystem. If this is the last emulated drive, the INT 13 vector is unhooked (if possible).

Definition at line 637 of file int13.c.

References DBG, int13_drive::drive, int13_drive::list, list_del, list_empty(), and unhook_int13().

Referenced by aoeboot(), eltorito_exec(), ib_srpboot(), and iscsiboot().

00637                                                           {
00638         /* Remove from list of emulated drives */
00639         list_del ( &drive->list );
00640 
00641         /* Should adjust BIOS drive count, but it's difficult to do so
00642          * reliably.
00643          */
00644 
00645         DBG ( "Unregistered INT13 drive %02x\n", drive->drive );
00646 
00647         /* Unhook INT 13 vector if no more drives */
00648         if ( list_empty ( &drives ) )
00649                 unhook_int13();
00650 }

int int13_boot ( unsigned int  drive  ) 

Attempt to boot from an INT 13 drive.

Parameters:
drive Drive number
Return values:
rc Return status code
This boots from the specified INT 13 drive by loading the Master Boot Record to 0000:7c00 and jumping to it. INT 18 is hooked to capture an attempt by the MBR to boot the next device. (This is the closest thing to a return path from an MBR).

Note that this function can never return success, by definition.

Definition at line 665 of file int13.c.

References __asm__(), be16_to_cpu, call_bootsector(), cpu_to_be16, DBG, ECANCELED, EIO, ENOEXEC, get_memmap(), REAL_CODE, and strerror().

Referenced by aoeboot(), ib_srpboot(), and iscsiboot().

00665                                       {
00666         struct memory_map memmap;
00667         int status, signature;
00668         int discard_c, discard_d;
00669         int rc;
00670 
00671         DBG ( "Booting from INT 13 drive %02x\n", drive );
00672 
00673         /* Use INT 13 to read the boot sector */
00674         __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
00675                                            "pushw $0\n\t"
00676                                            "popw %%es\n\t"
00677                                            "stc\n\t"
00678                                            "sti\n\t"
00679                                            "int $0x13\n\t"
00680                                            "sti\n\t" /* BIOS bugs */
00681                                            "jc 1f\n\t"
00682                                            "xorl %%eax, %%eax\n\t"
00683                                            "\n1:\n\t"
00684                                            "movzwl %%es:0x7dfe, %%ebx\n\t"
00685                                            "popw %%es\n\t" )
00686                                : "=a" ( status ), "=b" ( signature ),
00687                                  "=c" ( discard_c ), "=d" ( discard_d )
00688                                : "a" ( 0x0201 ), "b" ( 0x7c00 ),
00689                                  "c" ( 1 ), "d" ( drive ) );
00690         if ( status )
00691                 return -EIO;
00692 
00693         /* Check signature is correct */
00694         if ( signature != be16_to_cpu ( 0x55aa ) ) {
00695                 DBG ( "Invalid disk signature %#04x (should be 0x55aa)\n",
00696                       cpu_to_be16 ( signature ) );
00697                 return -ENOEXEC;
00698         }
00699 
00700         /* Dump out memory map prior to boot, if memmap debugging is
00701          * enabled.  Not required for program flow, but we have so
00702          * many problems that turn out to be memory-map related that
00703          * it's worth doing.
00704          */
00705         get_memmap ( &memmap );
00706 
00707         /* Jump to boot sector */
00708         if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
00709                 DBG ( "INT 13 drive %02x boot returned: %s\n",
00710                       drive, strerror ( rc ) );
00711                 return rc;
00712         }
00713 
00714         return -ECANCELED; /* -EIMPOSSIBLE */
00715 }


Variable Documentation

uint8_t num_drives [static]

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.

Definition at line 61 of file int13.c.

Referenced by int13_check_num_drives(), int13_set_num_drives(), and register_int13_drive().


Generated on Tue Apr 6 20:01:13 2010 for gPXE by  doxygen 1.5.7.1