2
0
mirror of https://github.com/xcat2/xNBA.git synced 2024-12-23 19:51:46 +00:00

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)
This commit is contained in:
Michael Brown 2006-05-20 15:33:32 +00:00
parent af4aacb978
commit ca2519cea3

View File

@ -64,89 +64,6 @@ extern void int13_exec_fail ( void );
/** List of registered emulated drives */
static LIST_HEAD ( drives );
/**
* Convert CHS address to linear address
*
* @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
*
*/
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;
}
/**
* Read from drive to real-mode data buffer
*
* @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;
}
/**
* Write from real-mode data buffer to drive
*
* @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_write ( 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 ( "Write %lx sectors from %04x:%04x to %llx\n", count,
data.segment, data.offset, ( unsigned long long ) lba );
if ( ( rc = blockdev->write ( blockdev, lba, count, buffer ) ) != 0 )
return INT13_STATUS_WRITE_ERROR;
return 0;
}
/**
* INT 13, 00 - Reset disk system
*
@ -171,6 +88,61 @@ static int int13_get_last_status ( struct int13_drive *drive,
return drive->last_status;
}
/**
* Read / write sectors
*
* @v drive Emulated drive
* @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_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;
unsigned int cylinder, head, sector;
unsigned long lba;
unsigned int count;
userptr_t buffer;
/* 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 );
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 );
/* 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;
return 0;
}
/**
* INT 13, 02 - Read sectors
*
@ -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 );
}
/**
@ -280,6 +228,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
*
@ -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 ) {