#include "types.h" // u8
#include "farptr.h" // GET_FARVAR
#include "config.h" // CONFIG_*
+#include "disk.h" // struct chs_s
-
-/****************************************************************
- * Interupt vector table
- ****************************************************************/
-
-struct rmode_IVT {
+struct segoff_s {
union {
struct {
u16 offset;
u16 seg;
};
u32 segoff;
- } ivec[256];
+ };
+};
+#define SEGOFF(s,o) ({struct segoff_s __so; __so.offset=(o); __so.seg=(s); __so;})
+
+
+/****************************************************************
+ * Interupt vector table
+ ****************************************************************/
+
+struct rmode_IVT {
+ struct segoff_s ivec[256];
};
#define GET_IVT(vector) \
u16 sector_count;
// Virtual device
- u16 heads;
- u16 cylinders;
- u16 spt;
+ struct chs_s lchs;
};
struct fdpt_s {
// Stack space available for code that needs it.
u8 extra_stack[512] __aligned(8);
+
+ u8 cdemu_buf[2048 * !!CONFIG_CDROM_EMU];
} PACKED;
// The initial size and location of EBDA
cdemu_1308(struct bregs *regs, u8 device)
{
u16 ebda_seg = get_ebda_seg();
- u16 nlc = GET_EBDA2(ebda_seg, cdemu.cylinders) - 1;
- u16 nlh = GET_EBDA2(ebda_seg, cdemu.heads) - 1;
- u16 nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
+ u16 nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders) - 1;
+ u16 nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads) - 1;
+ u16 nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
regs->al = 0x00;
regs->bl = 0x00;
SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
- SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.cylinders));
- SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.spt));
- SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.heads));
+ SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
+ SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
+ SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
// If we have to terminate emulation
if (regs->al == 0x00) {
switch (media) {
case 0x01: // 1.2M floppy
- SET_EBDA2(ebda_seg, cdemu.spt, 15);
- SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
- SET_EBDA2(ebda_seg, cdemu.heads, 2);
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
break;
case 0x02: // 1.44M floppy
- SET_EBDA2(ebda_seg, cdemu.spt, 18);
- SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
- SET_EBDA2(ebda_seg, cdemu.heads, 2);
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
break;
case 0x03: // 2.88M floppy
- SET_EBDA2(ebda_seg, cdemu.spt, 36);
- SET_EBDA2(ebda_seg, cdemu.cylinders, 80);
- SET_EBDA2(ebda_seg, cdemu.heads, 2);
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
break;
}
} else {
u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
- SET_EBDA2(ebda_seg, cdemu.spt, sptcyl & 0x3f);
- SET_EBDA2(ebda_seg, cdemu.cylinders, ((sptcyl<<2)&0x300) + cyllow + 1);
- SET_EBDA2(ebda_seg, cdemu.heads, heads + 1);
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
+ , ((sptcyl<<2)&0x300) + cyllow + 1);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
}
// everything is ok, so from now on, the emulation is active
if (!dop.command)
// If verify or seek
status = 0;
- if (dop.command == CMD_CDEMU_READ)
- status = cdrom_read_512(&dop);
- else if (dop.command == CMD_CDROM_READ)
+ if (dop.command == CMD_CDROM_READ)
status = cdrom_read(&dop);
else
status = ata_cmd_data(&dop);
irq_disable();
// Update count with total sectors transferred.
- SET_FARVAR(op_seg, op_far->count, GET_EBDA(sector_count));
+ if (dop.command)
+ SET_FARVAR(op_seg, op_far->count, GET_EBDA(sector_count));
if (status)
dprintf(1, "disk_op cmd %d error %d!\n", dop.command, status);
// Obtain the requested disk lba from an old-style chs request.
static int
-legacy_lba(struct bregs *regs, struct disk_op_s *op, u16 nlc, u16 nlh, u16 nlspt)
+legacy_lba(struct bregs *regs, u16 lchs_seg, struct chs_s *lchs_far)
{
- op->count = regs->al;
+ u8 count = regs->al;
u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
u16 sector = regs->cl & 0x3f;
u16 head = regs->dh;
- if (op->count > 128 || op->count == 0 || sector == 0) {
+ if (count > 128 || count == 0 || sector == 0) {
dprintf(1, "int13_harddisk: function %02x, parameter out of range!\n"
, regs->ah);
disk_ret(regs, DISK_RET_EPARAM);
return -1;
}
+ u16 nlc = GET_FARVAR(lchs_seg, lchs_far->cylinders);
+ u16 nlh = GET_FARVAR(lchs_seg, lchs_far->heads);
+ u16 nlspt = GET_FARVAR(lchs_seg, lchs_far->spt);
+
// sanity check on cyl heads, sec
if (cylinder >= nlc || head >= nlh || sector > nlspt) {
dprintf(1, "int13_harddisk: function %02x, parameters out of"
}
// translate lchs to lba
- op->lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
- + (u32)sector - 1);
-
- u16 segment = regs->es;
- u16 offset = regs->bx;
- op->buf_fl = MAKE_FLATPTR(segment, offset);
-
- return 0;
+ return (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+ + (u32)sector - 1);
}
// Perform read/write/verify using old-style chs accesses
struct disk_op_s dop;
dop.driveid = device;
dop.command = command;
- u16 nlc = GET_GLOBAL(ATA.devices[device].lchs.cylinders);
- u16 nlh = GET_GLOBAL(ATA.devices[device].lchs.heads);
- u16 nlspt = GET_GLOBAL(ATA.devices[device].lchs.spt);
- int ret = legacy_lba(regs, &dop, nlc, nlh, nlspt);
- if (ret)
+ int lba = legacy_lba(regs, get_global_seg(), &ATA.devices[device].lchs);
+ if (lba < 0)
return;
+ dop.lba = lba;
+ dop.count = regs->al;
+ dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
int status = send_disk_op(&dop);
{
struct disk_op_s dop;
dop.driveid = device;
- dop.command = (command == ATA_CMD_READ_SECTORS ? CMD_CDEMU_READ : 0);
+ dop.command = (command == ATA_CMD_READ_SECTORS ? CMD_CDROM_READ : 0);
u16 ebda_seg = get_ebda_seg();
- u16 nlc = GET_EBDA2(ebda_seg, cdemu.cylinders);
- u16 nlh = GET_EBDA2(ebda_seg, cdemu.heads);
- u16 nlspt = GET_EBDA2(ebda_seg, cdemu.spt);
- int ret = legacy_lba(regs, &dop, nlc, nlh, nlspt);
- if (ret)
+ int vlba = legacy_lba(
+ regs, ebda_seg
+ , (void*)offsetof(struct extended_bios_data_area_s, cdemu.lchs));
+ if (vlba < 0)
return;
- dop.lba += GET_EBDA2(ebda_seg, cdemu.ilba) * 4;
+ dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + vlba / 4;
+ u8 count = regs->al;
+ u8 *cdbuf_far = (void*)offsetof(struct extended_bios_data_area_s, cdemu_buf);
+ u8 *dest_far = (void*)(regs->bx+0);
+ regs->al = 0;
- int status = send_disk_op(&dop);
+ if (vlba & 3) {
+ dop.count = 1;
+ dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
+ int status = send_disk_op(&dop);
+ if (status)
+ goto fail;
+ u8 thiscount = 4 - (vlba & 3);
+ if (thiscount > count)
+ thiscount = count;
+ count -= thiscount;
+ memcpy_far(regs->es, dest_far
+ , ebda_seg, cdbuf_far + (vlba & 3) * 512
+ , thiscount * 512);
+ dest_far += thiscount * 512;
+ regs->al += thiscount;
+ dop.lba++;
+ }
- regs->al = dop.count;
+ if (count > 3) {
+ dop.count = count / 4;
+ dop.buf_fl = MAKE_FLATPTR(regs->es, dest_far);
+ int status = send_disk_op(&dop);
+ regs->al += dop.count * 4;
+ if (status)
+ goto fail;
+ u8 thiscount = count & ~3;
+ count &= 3;
+ dest_far += thiscount * 512;
+ dop.lba += thiscount / 4;
+ }
- if (status) {
- disk_ret(regs, DISK_RET_EBADTRACK);
- return;
+ if (count) {
+ dop.count = 1;
+ dop.buf_fl = MAKE_FLATPTR(ebda_seg, cdbuf_far);
+ int status = send_disk_op(&dop);
+ if (status)
+ goto fail;
+ u8 thiscount = count;
+ memcpy_far(regs->es, dest_far, ebda_seg, cdbuf_far, thiscount * 512);
+ regs->al += thiscount;
}
+
disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+fail:
+ disk_ret(regs, DISK_RET_EBADTRACK);
}
// Perform read/write/verify using new-style "int13ext" accesses.