Skip to content

Commit

Permalink
Cleanup cdrom emulation.
Browse files Browse the repository at this point in the history
Remove 'header' param for ata_cmd_packet - the only code that uses it
    is cdrom emulation.  So, bury this detail in ata.c.
Introduce new helpers cdrom_read_emu and cdrom_read_512 for working
    with emulated cdrom drives.
Unify basic_access() and emu_access() - now basic_access() can read
    from cdrom drives.
  • Loading branch information
KevinOConnor committed Mar 23, 2008
1 parent 070231b commit aa2590c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 112 deletions.
58 changes: 46 additions & 12 deletions src/ata.c
Expand Up @@ -267,9 +267,9 @@ ata_transfer(struct ata_pio_command *cmd)
// 2 : BUSY bit set
// 3 : error
// 4 : not ready
int
ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
, u16 header, u32 length, void *far_buffer)
static inline int
__ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
, u16 header, u32 length, void *far_buffer)
{
DEBUGF("ata_cmd_packet d=%d cmdlen=%d h=%d l=%d buf=%p\n"
, biosid, cmdlen, header, length, far_buffer);
Expand Down Expand Up @@ -422,24 +422,58 @@ ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
}

int
cdrom_read(u16 biosid, u32 lba, u32 count, void *far_buffer, u16 skip)
ata_cmd_packet(u16 biosid, u8 *cmdbuf, u8 cmdlen
, u32 length, void *far_buffer)
{
u16 sectors = (count + 2048 - 1) / 2048;
return __ata_cmd_packet(biosid, cmdbuf, cmdlen, 0, length, far_buffer);
}

u8 atacmd[12];
memset(atacmd, 0, sizeof(atacmd));
atacmd[0]=0x28; // READ command
atacmd[7]=(sectors & 0xff00) >> 8; // Sectors
atacmd[8]=(sectors & 0x00ff); // Sectors
atacmd[2]=(lba & 0xff000000) >> 24; // LBA
static void
build_cdrom_cmd(u8 *atacmd, u32 lba, u16 count)
{
memset(atacmd, 0, 12);
atacmd[0]=0x28; // READ command
atacmd[7]=(count & 0xff00) >> 8; // Sectors
atacmd[8]=(count & 0x00ff); // Sectors
atacmd[2]=(lba & 0xff000000) >> 24; // LBA
atacmd[3]=(lba & 0x00ff0000) >> 16;
atacmd[4]=(lba & 0x0000ff00) >> 8;
atacmd[5]=(lba & 0x000000ff);
}

// Read sectors from the cdrom.
int
cdrom_read(u16 biosid, u32 lba, u32 count, void *far_buffer)
{
u8 atacmd[12];
build_cdrom_cmd(atacmd, lba, count);
return ata_cmd_packet(biosid, atacmd, sizeof(atacmd)
, skip, count, far_buffer);
, count*2048, far_buffer);
}

// Pretend the cdrom has 512 byte sectors (instead of 2048) and read
// sectors.
int
cdrom_read_512(u16 biosid, u32 vlba, u32 count, void *far_buffer)
{
u32 slba = vlba / 4;
u16 before = vlba % 4;
u32 elba = (vlba + count - 1) / 4;

u8 atacmd[12];
build_cdrom_cmd(atacmd, slba, elba - slba + 1);

int status = __ata_cmd_packet(biosid, atacmd, sizeof(atacmd)
, before*512, count*512, far_buffer);
if (status) {
SET_EBDA(ata.trsfsectors, 0);
return status;
}
SET_EBDA(ata.trsfsectors, count);
return 0;
}


// ---------------------------------------------------------------------------
// ATA/ATAPI driver : device detection
// ---------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/ata.h
Expand Up @@ -33,9 +33,9 @@ struct ata_pio_command {
void ata_reset(u16 device);
int ata_transfer(struct ata_pio_command *cmd);
int ata_cmd_packet(u16 device, u8 *cmdbuf, u8 cmdlen
, u16 header, u32 length, void *far_buffer);
int cdrom_read(u16 device, u32 lba, u32 count
, void *far_buffer, u16 skip);
, u32 length, void *far_buffer);
int cdrom_read(u16 device, u32 lba, u32 count, void *far_buffer);
int cdrom_read_512(u16 device, u32 lba, u32 count, void *far_buffer);
void ata_detect();

static inline int
Expand Down
43 changes: 20 additions & 23 deletions src/cdrom.c
Expand Up @@ -179,18 +179,13 @@ cdrom_13(struct bregs *regs, u8 device)
* CD emulation
****************************************************************/

// read disk sectors
static void
cdemu_1302(struct bregs *regs, u8 device)
{
emu_access(regs, device, ATA_CMD_READ_SECTORS);
}

// verify disk sectors
static void
cdemu_1304(struct bregs *regs, u8 device)
// Read a series of 512 byte sectors from the cdrom starting at the
// image offset.
inline int
cdrom_read_emu(u16 biosid, u32 vlba, u32 count, void *far_buffer)
{
emu_access(regs, device, 0);
u32 ilba = GET_EBDA(cdemu.ilba);
return cdrom_read_512(biosid, ilba * 4 + vlba, count, far_buffer);
}

// read disk drive parameters
Expand Down Expand Up @@ -228,9 +223,14 @@ cdemu_13(struct bregs *regs)
device += GET_EBDA(cdemu.device_spec);

switch (regs->ah) {
case 0x02: cdemu_1302(regs, device); break;
case 0x04: cdemu_1304(regs, device); break;
// These functions are the same as for hard disks
case 0x02:
case 0x04:
disk_13(regs, device);
break;

case 0x08: cdemu_1308(regs, device); break;

// XXX - All other calls get passed to standard CDROM functions.
default: cdrom_13(regs, device); break;
}
Expand Down Expand Up @@ -295,8 +295,7 @@ atapi_get_sense(u16 device, u8 *asc, u8 *ascq)
memset(atacmd, 0, sizeof(atacmd));
atacmd[0] = ATA_CMD_REQUEST_SENSE;
atacmd[4] = sizeof(buffer);
u16 ret = ata_cmd_packet(device, atacmd, sizeof(atacmd)
, 0, sizeof(buffer)
u16 ret = ata_cmd_packet(device, atacmd, sizeof(atacmd), sizeof(buffer)
, MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
if (ret != 0)
return 0x0002;
Expand Down Expand Up @@ -332,8 +331,7 @@ atapi_is_ready(u16 device)
DEBUGF("read capacity failed\n");
return -1;
}
u16 ret = ata_cmd_packet(device, packet, sizeof(packet)
, 0, sizeof(buf)
u16 ret = ata_cmd_packet(device, packet, sizeof(packet), sizeof(buf)
, MAKE_FARPTR(GET_SEG(SS), (u32)buf));
if (ret == 0)
break;
Expand Down Expand Up @@ -431,8 +429,8 @@ cdrom_boot()

// Read the Boot Record Volume Descriptor
u8 buffer[2048];
ret = cdrom_read(device, 0x11, 2048
, MAKE_FARPTR(GET_SEG(SS), (u32)buffer), 0);
ret = cdrom_read(device, 0x11, 1
, MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
if (ret)
return 3;

Expand All @@ -446,8 +444,8 @@ cdrom_boot()
u32 lba = *(u32*)&buffer[0x47];

// And we read the Boot Catalog
ret = cdrom_read(device, lba, 2048
, MAKE_FARPTR(GET_SEG(SS), (u32)buffer), 0);
ret = cdrom_read(device, lba, 1
, MAKE_FARPTR(GET_SEG(SS), (u32)buffer));
if (ret)
return 7;

Expand Down Expand Up @@ -484,8 +482,7 @@ cdrom_boot()
SET_EBDA(cdemu.ilba, lba);

// And we read the image in memory
ret = cdrom_read(device, lba, nbsectors*512
, MAKE_FARPTR(boot_segment, 0), 0);
ret = cdrom_read_emu(device, 0, nbsectors, MAKE_FARPTR(boot_segment, 0));
if (ret)
return 12;

Expand Down
103 changes: 30 additions & 73 deletions src/disk.c
Expand Up @@ -51,9 +51,18 @@ basic_access(struct bregs *regs, u8 device, u16 command)
return;
}

u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
u8 type = GET_EBDA(ata.devices[device].type);
u16 nlc, nlh, nlspt;
if (type == ATA_TYPE_ATA) {
nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
nlh = GET_EBDA(ata.devices[device].lchs.heads);
nlspt = GET_EBDA(ata.devices[device].lchs.spt);
} else {
// Must be cd emulation.
nlc = GET_EBDA(cdemu.vdevice.cylinders);
nlh = GET_EBDA(cdemu.vdevice.heads);
nlspt = GET_EBDA(cdemu.vdevice.spt);
}

// sanity check on cyl heads, sec
if (cylinder >= nlc || head >= nlh || sector > nlspt) {
Expand All @@ -70,93 +79,39 @@ basic_access(struct bregs *regs, u8 device, u16 command)
return;
}

u16 segment = regs->es;
u16 offset = regs->bx;

// translate lchs to lba
u32 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+ (u32)sector - 1);
irq_enable();
u8 status = ata_cmd_data(device, command, lba, count
, MAKE_FARPTR(segment, offset));
irq_disable();

// Set nb of sector transferred
regs->al = GET_EBDA(ata.trsfsectors);

if (status != 0) {
BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
disk_ret(regs, DISK_RET_EBADTRACK);
}
disk_ret(regs, DISK_RET_SUCCESS);
}

void
emu_access(struct bregs *regs, u8 device, u16 command)
{
u16 count = regs->al;
u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
u16 sector = regs->cl & 0x3f;
u16 head = regs->dh;

if ((count > 128) || (count == 0) || (sector == 0)) {
BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
, regs->ah);
disk_ret(regs, DISK_RET_EPARAM);
return;
}

u16 nlc = GET_EBDA(cdemu.vdevice.cylinders);
u16 nlh = GET_EBDA(cdemu.vdevice.heads);
u16 nlspt = GET_EBDA(cdemu.vdevice.spt);

// sanity check on cyl heads, sec
if ( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
BX_INFO("int13_harddisk: function %02x, parameters out of"
" range %04x/%04x/%04x!\n"
, regs->ah, cylinder, head, sector);
disk_ret(regs, DISK_RET_EPARAM);
return;
}

if (!command) {
// If verify or seek
disk_ret(regs, DISK_RET_SUCCESS);
return;
}

u32 ilba = GET_EBDA(cdemu.ilba);
// calculate the virtual lba inside the image
u32 vlba= (((((u32)cylinder*(u32)nlh)+(u32)head)*(u32)nlspt)
+((u32)(sector-1)));
// start lba on cd
u32 slba = (u32)vlba/4;
u16 before= (u16)vlba%4;
u32 lba = ilba + slba;

u16 segment = regs->es;
u16 offset = regs->bx;
void *far_buffer = MAKE_FARPTR(segment, offset);

irq_enable();
u8 status = cdrom_read(device, lba, count*512
, MAKE_FARPTR(segment, offset), before*512);

int status;
if (type == ATA_TYPE_ATA)
status = ata_cmd_data(device, command, lba, count, far_buffer);
else
status = cdrom_read_emu(device, lba, count, far_buffer);

irq_disable();

// Set nb of sector transferred
regs->al = GET_EBDA(ata.trsfsectors);

if (status != 0) {
BX_INFO("int13_harddisk: function %02x, error %02x !\n"
, regs->ah, status);
regs->al = 0;
disk_ret(regs, DISK_RET_EBADTRACK);
}
regs->al = count;
disk_ret(regs, DISK_RET_SUCCESS);
}

static void
extended_access(struct bregs *regs, u8 device, u16 command)
{
u16 count = GET_INT13EXT(regs, count);
u16 segment = GET_INT13EXT(regs, segment);
u16 offset = GET_INT13EXT(regs, offset);

// Can't use 64 bits lba
u32 lba = GET_INT13EXT(regs, lba2);
Expand Down Expand Up @@ -184,15 +139,17 @@ extended_access(struct bregs *regs, u8 device, u16 command)
return;
}

u16 segment = GET_INT13EXT(regs, segment);
u16 offset = GET_INT13EXT(regs, offset);
void *far_buffer = MAKE_FARPTR(segment, offset);

irq_enable();

u8 status;
if (type == ATA_TYPE_ATA)
status = ata_cmd_data(device, command, lba, count
, MAKE_FARPTR(segment, offset));
status = ata_cmd_data(device, command, lba, count, far_buffer);
else
status = cdrom_read(device, lba, count*2048
, MAKE_FARPTR(segment, offset), 0);
status = cdrom_read(device, lba, count, far_buffer);

irq_disable();

Expand Down
2 changes: 1 addition & 1 deletion src/disk.h
Expand Up @@ -111,11 +111,11 @@ void floppy_13(struct bregs *regs, u8 drive);
void floppy_tick();

// disk.c
void emu_access(struct bregs *regs, u8 device, u16 command);
void disk_13(struct bregs *regs, u8 device);
void disk_13XX(struct bregs *regs, u8 device);

// cdrom.c
int cdrom_read_emu(u16 device, u32 lba, u32 count, void *far_buffer);
void cdrom_13(struct bregs *regs, u8 device);
void cdemu_13(struct bregs *regs);
void cdemu_134b(struct bregs *regs);
Expand Down

0 comments on commit aa2590c

Please sign in to comment.