summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2006-05-20 17:33:32 +0200
committerMichael Brown2006-05-20 17:33:32 +0200
commitca2519cea3dc36ca75fc34c00d051fe012a078ba (patch)
treef9c3b9d104a9c914999ad2eb794756d53d07a9bc
parentAdded missing @file block (diff)
downloadipxe-ca2519cea3dc36ca75fc34c00d051fe012a078ba.tar.gz
ipxe-ca2519cea3dc36ca75fc34c00d051fe012a078ba.tar.xz
ipxe-ca2519cea3dc36ca75fc34c00d051fe012a078ba.zip
Refactored to reduce code size; now down from 1304 to 1105 bytes.
Tidied up debug messages; the log now contains one line per INT 13 operation, looking like INT 13,08 (80): Get drive parameters INT 13,02 (80): Read: C/H/S 0/47/14 = LBA 0xb9e <-> 1084:0000 (count 106)
-rw-r--r--src/arch/i386/interface/pcbios/int13.c218
1 files changed, 98 insertions, 120 deletions
diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c
index d87428f7f..8df4c7973 100644
--- a/src/arch/i386/interface/pcbios/int13.c
+++ b/src/arch/i386/interface/pcbios/int13.c
@@ -65,113 +65,85 @@ extern void int13_exec_fail ( void );
static LIST_HEAD ( drives );
/**
- * Convert CHS address to linear address
+ * INT 13, 00 - Reset disk system
*
* @v drive Emulated drive
- * @v ch Low bits of cylinder number
- * @v cl (bits 7:6) High bits of cylinder number
- * @v cl (bits 5:0) Sector number
- * @v dh Head number
- * @ret lba LBA address
- *
+ * @ret status Status code
*/
-static unsigned long chs_to_lba ( struct int13_drive *drive,
- struct i386_all_regs *ix86 ) {
- unsigned int cylinder;
- unsigned int head;
- unsigned int sector;
- unsigned long lba;
-
- cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 8 ) | ix86->regs.ch );
- head = ix86->regs.dh;
- sector = ( ix86->regs.cl & 0x3f );
-
- assert ( cylinder < drive->cylinders );
- assert ( head < drive->heads );
- assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) );
-
- lba = ( ( ( ( cylinder * drive->heads ) + head )
- * drive->sectors_per_track ) + sector - 1 );
-
- DBG ( "C/H/S address %x/%x/%x -> LBA %lx\n",
- cylinder, head, sector, lba );
-
- return lba;
+static int int13_reset ( struct int13_drive *drive __unused,
+ struct i386_all_regs *ix86 __unused ) {
+ DBG ( "Reset drive\n" );
+ return 0;
}
/**
- * Read from drive to real-mode data buffer
+ * INT 13, 01 - Get status of last operation
*
* @v drive Emulated drive
- * @v lba LBA starting sector number
- * @v data Data buffer
- * @v count Number of sectors to read
* @ret status Status code
*/
-static int int13_read ( struct int13_drive *drive, uint64_t lba,
- struct segoff data, unsigned long count ) {
- struct block_device *blockdev = drive->blockdev;
- userptr_t buffer = real_to_user ( data.segment, data.offset );
- int rc;
-
- DBG ( "Read %lx sectors from %llx to %04x:%04x\n", count,
- ( unsigned long long ) lba, data.segment, data.offset );
-
- if ( ( rc = blockdev->read ( blockdev, lba, count, buffer ) ) != 0 )
- return INT13_STATUS_READ_ERROR;
-
- return 0;
+static int int13_get_last_status ( struct int13_drive *drive,
+ struct i386_all_regs *ix86 __unused ) {
+ DBG ( "Get status of last operation\n" );
+ return drive->last_status;
}
/**
- * Write from real-mode data buffer to drive
+ * Read / write sectors
*
* @v drive Emulated drive
- * @v lba LBA starting sector number
- * @v data Data buffer
- * @v count Number of sectors to read
+ * @v al Number of sectors to read or write (must be nonzero)
+ * @v ch Low bits of cylinder number
+ * @v cl (bits 7:6) High bits of cylinder number
+ * @v cl (bits 5:0) Sector number
+ * @v dh Head number
+ * @v es:bx Data buffer
+ * @v io Read / write method
* @ret status Status code
+ * @ret al Number of sectors read or written
*/
-static int int13_write ( struct int13_drive *drive, uint64_t lba,
- struct segoff data, unsigned long count ) {
+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 ) ) {
struct block_device *blockdev = drive->blockdev;
- userptr_t buffer = real_to_user ( data.segment, data.offset );
- int rc;
+ unsigned int cylinder, head, sector;
+ unsigned long lba;
+ unsigned int count;
+ userptr_t buffer;
- DBG ( "Write %lx sectors from %04x:%04x to %llx\n", count,
- data.segment, data.offset, ( unsigned long long ) lba );
+ /* Calculate parameters */
+ cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 8 ) | ix86->regs.ch );
+ assert ( cylinder < drive->cylinders );
+ head = ix86->regs.dh;
+ assert ( head < drive->heads );
+ sector = ( ix86->regs.cl & 0x3f );
+ assert ( ( sector >= 1 ) && ( sector <= drive->sectors_per_track ) );
+ lba = ( ( ( ( cylinder * drive->heads ) + head )
+ * drive->sectors_per_track ) + sector - 1 );
+ count = ix86->regs.al;
+ buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );
- if ( ( rc = blockdev->write ( blockdev, lba, count, buffer ) ) != 0 )
- return INT13_STATUS_WRITE_ERROR;
+ DBG ( "C/H/S %d/%d/%d = LBA %#lx <-> %04x:%04x (count %d)\n", cylinder,
+ head, sector, lba, ix86->segs.es, ix86->regs.bx, count );
- return 0;
-}
+ /* Validate blocksize */
+ if ( blockdev->blksize != INT13_BLKSIZE ) {
+ DBG ( "Invalid blocksize (%zd) for non-extended read/write\n",
+ blockdev->blksize );
+ return INT13_STATUS_INVALID;
+ }
+
+ /* Read from / write to block device */
+ if ( io ( blockdev, lba, count, buffer ) != 0 )
+ return INT13_STATUS_READ_ERROR;
-/**
- * INT 13, 00 - Reset disk system
- *
- * @v drive Emulated drive
- * @ret status Status code
- */
-static int int13_reset ( struct int13_drive *drive __unused,
- struct i386_all_regs *ix86 __unused ) {
- DBG ( "Reset drive\n" );
return 0;
}
/**
- * INT 13, 01 - Get status of last operation
- *
- * @v drive Emulated drive
- * @ret status Status code
- */
-static int int13_get_last_status ( struct int13_drive *drive,
- struct i386_all_regs *ix86 __unused ) {
- DBG ( "Get status of last operation\n" );
- return drive->last_status;
-}
-
-/**
* INT 13, 02 - Read sectors
*
* @v drive Emulated drive
@@ -186,20 +158,8 @@ static int int13_get_last_status ( struct int13_drive *drive,
*/
static int int13_read_sectors ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
- unsigned long lba = chs_to_lba ( drive, ix86 );
- unsigned int count = ix86->regs.al;
- struct segoff data = {
- .segment = ix86->segs.es,
- .offset = ix86->regs.bx,
- };
-
- if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
- DBG ( "Invalid blocksize (%zd) for non-extended read\n",
- drive->blockdev->blksize );
- return INT13_STATUS_INVALID;
- }
-
- return int13_read ( drive, lba, data, count );
+ DBG ( "Read: " );
+ return int13_rw_sectors ( drive, ix86, drive->blockdev->read );
}
/**
@@ -217,20 +177,8 @@ static int int13_read_sectors ( struct int13_drive *drive,
*/
static int int13_write_sectors ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
- unsigned long lba = chs_to_lba ( drive, ix86 );
- unsigned int count = ix86->regs.al;
- struct segoff data = {
- .segment = ix86->segs.es,
- .offset = ix86->regs.bx,
- };
-
- if ( drive->blockdev->blksize != INT13_BLKSIZE ) {
- DBG ( "Invalid blocksize (%zd) for non-extended write\n",
- drive->blockdev->blksize );
- return INT13_STATUS_INVALID;
- }
-
- return int13_write ( drive, lba, data, count );
+ DBG ( "Write: " );
+ return int13_rw_sectors ( drive, ix86, drive->blockdev->write );
}
/**
@@ -281,6 +229,42 @@ static int int13_extension_check ( struct int13_drive *drive __unused,
}
/**
+ * Extended read / write
+ *
+ * @v drive Emulated drive
+ * @v ds:si Disk address packet
+ * @v io Read / write method
+ * @ret status Status code
+ */
+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 ) ) {
+ struct block_device *blockdev = drive->blockdev;
+ struct int13_disk_address addr;
+ uint64_t lba;
+ unsigned long count;
+ userptr_t buffer;
+
+ /* Read parameters from disk address structure */
+ copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, sizeof ( addr ));
+ lba = addr.lba;
+ count = addr.count;
+ buffer = real_to_user ( addr.buffer.segment, addr.buffer.offset );
+
+ DBG ( "LBA %#llx <-> %04x:%04x (count %ld)\n", (unsigned long long)lba,
+ addr.buffer.segment, addr.buffer.offset, count );
+
+ /* Read from / write to block device */
+ if ( io ( blockdev, lba, count, buffer ) != 0 )
+ return INT13_STATUS_READ_ERROR;
+
+ return 0;
+}
+
+/**
* INT 13, 42 - Extended read
*
* @v drive Emulated drive
@@ -289,11 +273,8 @@ static int int13_extension_check ( struct int13_drive *drive __unused,
*/
static int int13_extended_read ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
- struct int13_disk_address addr;
-
- copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
- sizeof ( addr ) );
- return int13_read ( drive, addr.lba, addr.buffer, addr.count );
+ DBG ( "Extended read: " );
+ return int13_extended_rw ( drive, ix86, drive->blockdev->read );
}
/**
@@ -305,11 +286,8 @@ static int int13_extended_read ( struct int13_drive *drive,
*/
static int int13_extended_write ( struct int13_drive *drive,
struct i386_all_regs *ix86 ) {
- struct int13_disk_address addr;
-
- copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si,
- sizeof ( addr ) );
- return int13_write ( drive, addr.lba, addr.buffer, addr.count );
+ DBG ( "Extended write: " );
+ return int13_extended_rw ( drive, ix86, drive->blockdev->write );
}
/**
@@ -351,7 +329,7 @@ static void int13 ( struct i386_all_regs *ix86 ) {
if ( drive->drive != ix86->regs.dl )
continue;
- DBG ( "INT 13, %02x on drive %02x\n", ix86->regs.ah,
+ DBG ( "INT 13,%02x (%02x): ", ix86->regs.ah,
ix86->regs.dl );
switch ( ix86->regs.ah ) {