Initial cd emulation code.
authorKevin O'Connor <kevin@koconnor.net>
Wed, 5 Mar 2008 00:45:04 +0000 (19:45 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Wed, 5 Mar 2008 00:45:04 +0000 (19:45 -0500)
Provides the int13 hooks - still a work in progress.

src/config.h
src/disk.c
src/disk.h

index a984e5c..a118c68 100644 (file)
@@ -6,7 +6,7 @@
 #define CONFIG_PS2_MOUSE 1
 #define CONFIG_ATA 1
 #define CONFIG_KBD_CALL_INT15_4F 1
-#define CONFIG_ELTORITO_BOOT 0
+#define CONFIG_ELTORITO_BOOT 1
 
 #define CONFIG_MAX_ATA_INTERFACES 4
 #define CONFIG_MAX_ATA_DEVICES  (CONFIG_MAX_ATA_INTERFACES*2)
index 74c1aca..832eee1 100644 (file)
@@ -109,6 +109,78 @@ basic_access(struct bregs *regs, u8 device, u16 command)
     disk_ret(regs, DISK_RET_SUCCESS);
 }
 
+static void
+emu_access(struct bregs *regs, u8 device, u16 command)
+{
+    u16 nbsectors   = regs->al;
+    u16 cylinder    = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
+    u16 sector      = regs->cl & 0x3f;
+    u16 head        = regs->dh;
+
+    if ((nbsectors > 128) || (nbsectors == 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;
+    // end lba on cd
+    u32 elba = (u32)(vlba+nbsectors-1)/4;
+    u32 count = elba-slba+1;
+    u32 lba = ilba+slba;
+
+    u16 segment = regs->es;
+    u16 offset  = regs->bx;
+
+    u8 atacmd[12];
+    memset(atacmd, 0, sizeof(atacmd));
+    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);
+
+    u8 status = ata_cmd_packet(device, (u32)atacmd, sizeof(atacmd)
+                               , before*512, count*2048L
+                               , ATA_DATA_IN, segment, offset);
+
+    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 = nbsectors;
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
 static void
 extended_access(struct bregs *regs, u8 device, u16 command)
 {
@@ -730,7 +802,7 @@ cdrom_wp(struct bregs *regs, u8 device)
     disk_ret(regs, DISK_RET_EWRITEPROTECT);
 }
 
-void
+static void
 cdrom_13(struct bregs *regs, u8 device)
 {
     //debug_stub(regs);
@@ -770,6 +842,113 @@ 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)
+{
+    emu_access(regs, device, 0);
+}
+
+// read disk drive parameters
+static void
+cdemu_1308(struct bregs *regs, u8 device)
+{
+    u16 nlc   = GET_EBDA(cdemu.vdevice.cylinders) - 1;
+    u16 nlh   = GET_EBDA(cdemu.vdevice.heads) - 1;
+    u16 nlspt = GET_EBDA(cdemu.vdevice.spt);
+
+    regs->al = 0x00;
+    regs->bl = 0x00;
+    regs->ch = nlc & 0xff;
+    regs->cl = ((nlc >> 2) & 0xc0) | (nlspt  & 0x3f);
+    regs->dh = nlh;
+    // FIXME ElTorito Various. should send the real count of drives 1 or 2
+    // FIXME ElTorito Harddisk. should send the HD count
+    regs->dl = 0x02;
+    u8 media = GET_EBDA(cdemu.media);
+    if (media <= 3)
+        regs->bl = media * 2;
+
+    regs->es = SEG_BIOS;
+    regs->di = (u16)&diskette_param_table2;
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+cdemu_13(struct bregs *regs)
+{
+    //debug_stub(regs);
+
+    u8 device  = GET_EBDA(cdemu.controller_index) * 2;
+    device += GET_EBDA(cdemu.device_spec);
+
+    switch (regs->ah) {
+    case 0x02: cdemu_1302(regs, device); break;
+    case 0x04: cdemu_1304(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;
+    }
+}
+
+struct eltorito_s {
+    u8 size;
+    u8 media;
+    u8 emulated_drive;
+    u8 controller_index;
+    u32 ilba;
+    u16 device_spec;
+    u16 buffer_segment;
+    u16 load_segment;
+    u16 sector_count;
+    u8 cylinders;
+    u8 sectors;
+    u8 heads;
+};
+
+#define SET_INT13ET(regs,var,val)                                      \
+    SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
+
+// ElTorito - Terminate disk emu
+static void
+cdemu_134b(struct bregs *regs)
+{
+    // FIXME ElTorito Hardcoded
+    SET_INT13ET(regs, size, 0x13);
+    SET_INT13ET(regs, media, GET_EBDA(cdemu.media));
+    SET_INT13ET(regs, emulated_drive, GET_EBDA(cdemu.emulated_drive));
+    SET_INT13ET(regs, controller_index, GET_EBDA(cdemu.controller_index));
+    SET_INT13ET(regs, ilba, GET_EBDA(cdemu.ilba));
+    SET_INT13ET(regs, device_spec, GET_EBDA(cdemu.device_spec));
+    SET_INT13ET(regs, buffer_segment, GET_EBDA(cdemu.buffer_segment));
+    SET_INT13ET(regs, load_segment, GET_EBDA(cdemu.load_segment));
+    SET_INT13ET(regs, sector_count, GET_EBDA(cdemu.sector_count));
+    SET_INT13ET(regs, cylinders, GET_EBDA(cdemu.vdevice.cylinders));
+    SET_INT13ET(regs, sectors, GET_EBDA(cdemu.vdevice.spt));
+    SET_INT13ET(regs, heads, GET_EBDA(cdemu.vdevice.heads));
+
+    // If we have to terminate emulation
+    if (regs->al == 0x00) {
+        // FIXME ElTorito Various. Should be handled accordingly to spec
+        SET_EBDA(cdemu.active, 0x00); // bye bye
+    }
+
+    disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+
 /****************************************************************
  * Entry points
  ****************************************************************/
@@ -835,17 +1014,24 @@ handle_40(struct bregs *regs)
 void VISIBLE
 handle_13(struct bregs *regs)
 {
-    //debug_enter(regs);
+    debug_enter(regs);
     u8 drive = regs->dl;
-    // XXX
-#if BX_ELTORITO_BOOT
-    if (regs->ah >= 0x4a || regs->ah <= 0x4d) {
-        int13_eltorito(regs);
-    } else if (cdemu_isactive() && cdrom_emulated_drive()) {
-        int13_cdemu(regs);
-    } else
-#endif
-        handle_legacy_disk(regs, drive);
+
+    if (CONFIG_ELTORITO_BOOT) {
+        if (regs->ah == 0x4b) {
+            cdemu_134b(regs);
+            goto done;
+        }
+        if (GET_EBDA(cdemu.active)) {
+            if (drive == GET_EBDA(cdemu.emulated_drive)) {
+                cdemu_13(regs);
+                goto done;
+            }
+            drive--;
+        }
+    }
+    handle_legacy_disk(regs, drive);
+done:
     debug_exit(regs);
 }
 
index beb4495..93e9756 100644 (file)
@@ -94,6 +94,7 @@ struct floppy_ext_dbt_s {
 };
 
 // floppy.c
+extern struct floppy_ext_dbt_s diskette_param_table2;
 void floppy_13(struct bregs *regs, u8 drive);
 void floppy_tick();