Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


IDE hard drive works past grub
Jack Lange [Sat, 4 Apr 2009 01:25:07 +0000 (20:25 -0500)]
palacios/include/devices/ide.h
palacios/src/devices/ata.h [new file with mode: 0644]
palacios/src/devices/atapi.h
palacios/src/devices/ide-types.h
palacios/src/devices/ide.c
palacios/src/devices/ram_hd.c

index e0356b2..98c91ce 100644 (file)
 #define ATAPI_BLOCK_SIZE 2048
 #define IDE_SECTOR_SIZE 512
 
-typedef enum {IDE_DISK, IDE_CDROM, IDE_NONE} v3_ide_dev_type_t;
+typedef enum {IDE_NONE, IDE_DISK, IDE_CDROM} v3_ide_dev_type_t;
 
 struct v3_ide_cd_ops {
     uint32_t (*get_capacity)(void * private_data);
     // Reads always operate on 2048 byte blocks
-    int (*read)(uint8_t * buf, int count, int lba, void * private_data);
+    int (*read)(uint8_t * buf, int block_count, uint64_t lba, void * private_data);
 
 };
 
 
 struct v3_ide_hd_ops {
-    uint32_t (*get_capacity)(void * private_data);
+    uint64_t (*get_capacity)(void * private_data);
     // Reads always operate on 2048 byte blocks
-    int (*read)(uint8_t * buf, int count, int lba, void * private_data);    
+    int (*read)(uint8_t * buf, int sector_count, uint64_t lba, void * private_data);
 
 };
 
diff --git a/palacios/src/devices/ata.h b/palacios/src/devices/ata.h
new file mode 100644 (file)
index 0000000..b759f0b
--- /dev/null
@@ -0,0 +1,192 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+static void ata_identify_device(struct ide_drive * drive) {
+    struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
+    const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
+    const char* firmware = "ALPHA1  ";
+
+    drive->transfer_length = 512;
+    drive->transfer_index = 0;
+
+
+    memset(drive_id->buf, 0, sizeof(drive_id->buf));
+
+    drive_id->fixed_drive = 1;
+    drive_id->removable_media = 0;
+
+    // Black magic...
+    drive_id->disk_speed1 = 1;
+    drive_id->disk_speed3 = 1;
+
+    drive_id->cdrom_flag = 0;
+
+    // Make it the simplest drive possible (1 head, 1 cyl, 1 sect/track)
+    drive_id->num_cylinders = 1;
+    drive_id->num_heads = 1;
+    drive_id->bytes_per_track = IDE_SECTOR_SIZE;
+    drive_id->bytes_per_sector = IDE_SECTOR_SIZE;
+    drive_id->sectors_per_track = 1;
+
+
+    // These buffers do not contain a terminating "\0"
+    memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
+    memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
+    memcpy(drive_id->model_num, drive->model, 40);
+
+    // 32 bits access
+    drive_id->dword_io = 1;
+
+    // enable DMA access
+    drive_id->dma_enable = 1;
+
+    // enable LBA access
+    drive_id->lba_enable = 1;
+    
+    // Drive Capacity (28 bit LBA)
+    drive_id->lba_capacity = drive->hd_ops->get_capacity(drive->private_data);
+    
+    // Drive Capacity (48 bit LBA)
+    drive_id->lba_capacity_2 = drive->hd_ops->get_capacity(drive->private_data);
+
+    drive_id->rw_multiples = 0x80ff;
+
+    // words 64-70, 54-58 valid
+    drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
+
+    // copied from CFA540A
+    drive_id->buf[63] = 0x0103; // variable (DMA stuff)
+    //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
+    
+    //    drive_id->buf[64] = 0x0001; // PIO
+    drive_id->buf[65] = 0x00b4;
+    drive_id->buf[66] = 0x00b4;
+    drive_id->buf[67] = 0x012c;
+    drive_id->buf[68] = 0x00b4;
+
+    drive_id->buf[71] = 30; // faked
+    drive_id->buf[72] = 30; // faked
+
+    //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
+    drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
+
+    drive_id->buf[83] |= 0x0400; // supports 48 bit LBA
+
+
+    drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
+}
+
+
+static int ata_read(struct vm_device * dev, struct ide_channel * channel) {
+    struct ide_drive * drive = get_selected_drive(channel);
+
+    if (drive->hd_state.accessed == 0) {
+       drive->current_lba = 0;
+       drive->hd_state.accessed = 1;
+    }
+
+    int ret = drive->hd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data);
+    
+    if (ret == -1) {
+       PrintError("IDE: Error reading HD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
+       return -1;
+    }
+
+    return 0;
+}
+
+
+
+// 28 bit LBA
+static int ata_read_sectors(struct vm_device * dev, struct ide_channel * channel) {
+    struct ide_drive * drive = get_selected_drive(channel);
+    // The if the sector count == 0 then read 256 sectors (cast up to handle that value)
+    uint32_t sect_cnt = (drive->sector_count == 0) ? 256 : drive->sector_count;
+
+    union {
+       uint32_t addr;
+       uint8_t buf[4];
+    } __attribute__((packed)) lba_addr;
+
+    /* LBA addr bits:
+       0-8: sector number reg  (drive->lba0)
+       8-16: low cylinder reg (drive->lba1)
+       16-24: high cylinder reg (drive->lba2)
+       24-28:  low 4 bits of drive_head reg (channel->drive_head.head_num)
+     */
+
+    lba_addr.buf[0] = drive->lba0;
+    lba_addr.buf[1] = drive->lba1;
+    lba_addr.buf[2] = drive->lba2;
+    lba_addr.buf[3] = channel->drive_head.lba3;
+
+    PrintDebug("LBA Address %d\n", drive->lba0);
+    PrintDebug("sector_num %d\n", drive->sector_num);
+
+
+    if (lba_addr.addr + (sect_cnt * IDE_SECTOR_SIZE) > 
+       drive->hd_ops->get_capacity(drive->private_data)) {
+       PrintError("IDE: request size exceeds disk capacity (lba=%d) (sect_cnt=%d) (ReadEnd=%d) (capacity=%p)\n", 
+                  lba_addr.addr, sect_cnt, 
+                  lba_addr.addr + (sect_cnt * IDE_SECTOR_SIZE),
+                  (void *)(addr_t)(drive->hd_ops->get_capacity(drive->private_data)));
+       ide_abort_command(dev, channel);
+       return 0;
+    }
+
+    drive->current_lba = lba_addr.addr;
+    
+    if (ata_read(dev, channel) == -1) {
+       PrintError("Could not read disk sector\n");
+       return -1;
+    }
+
+    drive->transfer_length = sect_cnt * IDE_SECTOR_SIZE;
+    drive->transfer_index = 0;
+
+    channel->status.busy = 0;
+    channel->status.ready = 0;
+    channel->status.write_fault = 0;
+    channel->status.data_req = 1;
+    channel->status.error = 0;
+
+    drive->irq_flags.io_dir = 1;
+    drive->irq_flags.c_d = 0;
+    drive->irq_flags.rel = 0;
+
+
+    ide_raise_irq(dev, channel);
+
+    PrintDebug("Returning from read sectors\n");
+
+    return 0;
+}
+
+
+// 48 bit LBA
+static int ata_read_sectors_ext(struct vm_device * dev, struct ide_channel * channel) {
+    //struct ide_drive * drive = get_selected_drive(channel);
+    // The if the sector count == 0 then read 256 sectors (cast up to handle that value)
+    //uint32_t sector_count = (drive->sector_count == 0) ? 256 : drive->sector_count;
+
+    PrintError("Extended Sector read not implemented\n");
+
+    return -1;
+}
index 3407101..acc90ff 100644 (file)
@@ -128,10 +128,10 @@ static void atapi_cmd_nop(struct vm_device * dev, struct ide_channel * channel)
 static int atapi_read_chunk(struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
 
-    int ret = drive->cd_ops->read(drive->data_buf, ATAPI_BLOCK_SIZE, drive->cd_state.current_lba, drive->private_data);
-       
+    int ret = drive->cd_ops->read(drive->data_buf, 1, drive->current_lba, drive->private_data);
+    
     if (ret == -1) {
-       PrintError("IDE: Error reading CD block (LBA=%x)\n", drive->cd_state.current_lba);
+       PrintError("IDE: Error reading CD block (LBA=%p)\n", (void *)(addr_t)(drive->current_lba));
        return -1;
     }
 
@@ -147,7 +147,7 @@ static int atapi_update_data_buf(struct vm_device * dev, struct ide_channel * ch
        case 0xa8: // read(12)
 
            // Update lba address to point to next block
-           drive->cd_state.current_lba++;
+           drive->current_lba++;
 
            // read the next block
            return atapi_read_chunk(dev, channel);
@@ -188,7 +188,7 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) {
        
     //    PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba);
     
-    drive->cd_state.current_lba = lba;
+    drive->current_lba = lba;
        
     // Update the request length value in the cylinder registers
        
index 3ae9966..5cbb7c7 100644 (file)
@@ -54,6 +54,12 @@ struct ide_drive_head_reg {
            uint_t lba_mode      : 1;
            uint_t rsvd2         : 1;
        } __attribute__((packed));
+
+       struct {
+           uint_t lba3      : 4;
+           uint_t rsvd3     : 4;
+       } __attribute__((packed));
+       
     } __attribute__((packed));
 } __attribute__((packed));
 
index 3605050..197d903 100644 (file)
@@ -90,7 +90,7 @@ static inline const char * dma_port_to_str(uint16_t port) {
 }
 
 
-static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"};
+static const char * ide_dev_type_strs[] = {"NONE", "HARDDISK", "CDROM" };
 
 
 static inline const char * device_type_to_str(v3_ide_dev_type_t type) {
@@ -105,13 +105,13 @@ static inline const char * device_type_to_str(v3_ide_dev_type_t type) {
 
 struct ide_cd_state {
     struct atapi_sense_data sense;
-    uint_t current_lba;
+
     uint8_t atapi_cmd;
     struct atapi_error_recovery err_recovery;
 };
 
 struct ide_hd_state {
-
+    int accessed;
 };
 
 struct ide_drive {
@@ -139,6 +139,7 @@ struct ide_drive {
     // calculated for easy access
     uint_t transfer_length;
 
+    uint64_t current_lba;
 
     // We have a local data buffer that we use for IO port accesses
     uint8_t data_buf[DATA_BUFFER_SIZE];
@@ -154,24 +155,23 @@ struct ide_drive {
     union {
        uint8_t sector_num;               // 0x1f3,0x173
        uint8_t lba0;
-    };
+    } __attribute__((packed));
 
     union {
        uint16_t cylinder;
        uint16_t lba12;
-
-
+       
        struct {
            uint8_t cylinder_low;       // 0x1f4,0x174
            uint8_t cylinder_high;      // 0x1f5,0x175
        } __attribute__((packed));
-
+       
        struct {
            uint8_t lba1;
            uint8_t lba2;
        } __attribute__((packed));
-
-
+       
+       
        // The transfer length requested by the CPU 
        uint16_t req_len;
     } __attribute__((packed));
@@ -282,11 +282,14 @@ static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel)
 static void drive_reset(struct ide_drive * drive) {
     drive->sector_count = 0x01;
     drive->sector_num = 0x01;
+
+    PrintDebug("Resetting drive %s\n", drive->model);
     
     if (drive->drive_type == IDE_CDROM) {
        drive->cylinder = 0xeb14;
     } else {
        drive->cylinder = 0x0000;
+       //drive->hd_state.accessed = 0;
     }
 
 
@@ -332,85 +335,15 @@ static void ide_abort_command(struct vm_device * dev, struct ide_channel * chann
 
 
 
-static void ide_identify_device(struct ide_drive * drive) {
-    struct ide_drive_id * drive_id = (struct ide_drive_id *)(drive->data_buf);
-    const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
-    const char* firmware = "ALPHA1  ";
-
-    drive->transfer_length = 512;
-    drive->transfer_index = 0;
-
-
-    memset(drive_id->buf, 0, sizeof(drive_id->buf));
-
-    drive_id->fixed_drive = 1;
-    drive_id->removable_media = 0;
-
-    // Black magic...
-    drive_id->disk_speed1 = 1;
-    drive_id->disk_speed3 = 1;
-
-    drive_id->cdrom_flag = 0;
-
-    // Make it the simplest drive possible (1 head, 1 cyl, 1 sect/track)
-    drive_id->num_cylinders = 1;
-    drive_id->num_heads = 1;
-    drive_id->bytes_per_track = IDE_SECTOR_SIZE;
-    drive_id->bytes_per_sector = IDE_SECTOR_SIZE;
-    drive_id->sectors_per_track = 1;
-
-
-    // These buffers do not contain a terminating "\0"
-    memcpy(drive_id->serial_num, serial_number, strlen(serial_number));
-    memcpy(drive_id->firmware_rev, firmware, strlen(firmware));
-    memcpy(drive_id->model_num, drive->model, 40);
-
-    // 32 bits access
-    drive_id->dword_io = 1;
-
-    // enable DMA access
-    drive_id->dma_enable = 1;
-
-    // enable LBA access
-    drive_id->lba_enable = 1;
-    
-    // Drive Capacity
-    drive_id->lba_capacity = drive->hd_ops->get_capacity(drive->private_data);
-
-    drive_id->rw_multiples = 0x80ff;
-
-    // words 64-70, 54-58 valid
-    drive_id->field_valid = 0x0007; // DMA + pkg cmd valid
-
-    // copied from CFA540A
-    drive_id->buf[63] = 0x0103; // variable (DMA stuff)
-    //drive_id->buf[63] = 0x0000; // variable (DMA stuff)
-    
-    //    drive_id->buf[64] = 0x0001; // PIO
-    drive_id->buf[65] = 0x00b4;
-    drive_id->buf[66] = 0x00b4;
-    drive_id->buf[67] = 0x012c;
-    drive_id->buf[68] = 0x00b4;
-
-    drive_id->buf[71] = 30; // faked
-    drive_id->buf[72] = 30; // faked
-
-    //    drive_id->buf[80] = 0x1e; // supports up to ATA/ATAPI-4
-    drive_id->major_rev_num = 0x0040; // supports up to ATA/ATAPI-6
-
-    drive_id->dma_ultra = 0x2020; // Ultra_DMA_Mode_5_Selected | Ultra_DMA_Mode_5_Supported;
-}
-
-
-
-
-
 
 
 
 /* ATAPI functions */
 #include "atapi.h"
 
+/* ATA functions */
+#include "ata.h"
+
 
 
 /* IO Operations */
@@ -643,7 +576,39 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
     channel->cmd_reg = *(uint8_t *)src;
     
     switch (channel->cmd_reg) {
-       
+
+       case 0xa1: // ATAPI Identify Device Packet
+           if (drive->drive_type != IDE_CDROM) {
+               drive_reset(drive);
+
+               // JRL: Should we abort here?
+               ide_abort_command(dev, channel);
+           } else {
+               
+               atapi_identify_device(drive);
+               
+               channel->error_reg.val = 0;
+               channel->status.val = 0x58; // ready, data_req, seek_complete
+           
+               ide_raise_irq(dev, channel);
+           }
+           break;
+       case 0xec: // Identify Device
+           if (drive->drive_type != IDE_DISK) {
+               drive_reset(drive);
+
+               // JRL: Should we abort here?
+               ide_abort_command(dev, channel);
+           } else {
+               ata_identify_device(drive);
+
+               channel->error_reg.val = 0;
+               channel->status.val = 0x58;
+
+               ide_raise_irq(dev, channel);
+           }
+           break;
+
        case 0xa0: // ATAPI Command Packet
            if (drive->drive_type != IDE_CDROM) {
                ide_abort_command(dev, channel);
@@ -661,30 +626,21 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
            drive->transfer_index = 0;
 
            break;
-       case 0xa1: // ATAPI Identify Device Packet
-           atapi_identify_device(drive);
 
-           channel->error_reg.val = 0;
-           channel->status.val = 0x58; // ready, data_req, seek_complete
-           
-           ide_raise_irq(dev, channel);
+       case 0x20: // Read Sectors with Retry
+       case 0x21: // Read Sectors without Retry
+           if (ata_read_sectors(dev, channel) == -1) {
+               PrintError("Error reading sectors\n");
+               return -1;
+           }
            break;
-       case 0xec: // Identify Device
-           if (drive->drive_type != IDE_DISK) {
-               drive_reset(drive);
-
-               // JRL: Should we abort here?
-               ide_abort_command(dev, channel);
-           } else {
-               ide_identify_device(drive);
 
-               channel->error_reg.val = 0;
-               channel->status.val = 0x58;
-
-               ide_raise_irq(dev, channel);
+       case 0x24: // Read Sectors Extended
+           if (ata_read_sectors_ext(dev, channel) == -1) {
+               PrintError("Error reading extended sectors\n");
+               return -1;
            }
            break;
-
        case 0xef: // Set Features
            // Prior to this the features register has been written to. 
            // This command tells the drive to check if the new value is supported (the value is drive specific)
@@ -701,6 +657,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
            
            ide_raise_irq(dev, channel);
            break;
+
        default:
            PrintError("Unimplemented IDE command (%x)\n", channel->cmd_reg);
            return -1;
@@ -745,15 +702,70 @@ static int write_data_port(ushort_t port, void * src, uint_t length, struct vm_d
 
 
 static int read_hd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
-    PrintError("Harddrive data port read not implemented\n");
-    return -1;
+    struct ide_drive * drive = get_selected_drive(channel);
+    int data_offset = drive->transfer_index % IDE_SECTOR_SIZE;
+
+
+
+    if (drive->transfer_index >= drive->transfer_length) {
+       PrintError("Buffer overrun... (xfer_len=%d) (cur_idx=%x) (post_idx=%d)\n",
+                  drive->transfer_length, drive->transfer_index,
+                  drive->transfer_index + length);
+       return -1;
+    }
+
+    
+    if ((data_offset == 0) && (drive->transfer_index > 0)) {
+       drive->current_lba++;
+
+       if (ata_read(dev, channel) == -1) {
+           PrintError("Could not read next disk sector\n");
+           return -1;
+       }
+    }
+
+    /*
+      PrintDebug("Reading HD Data (Val=%x), (len=%d) (offset=%d)\n", 
+      *(uint32_t *)(drive->data_buf + data_offset), 
+      length, data_offset);
+    */
+    memcpy(dst, drive->data_buf + data_offset, length);
+
+    drive->transfer_index += length;
+
+    if ((drive->transfer_index % IDE_SECTOR_SIZE) == 0) {
+       if (drive->transfer_index < drive->transfer_length) {
+           // An increment is complete, but there is still more data to be transferred...
+           PrintDebug("Integral Complete, still transferring more sectors\n");
+           channel->status.data_req = 1;
+
+           drive->irq_flags.c_d = 0;
+       } else {
+           PrintDebug("Final Sector Transferred\n");
+           // This was the final read of the request
+           channel->status.data_req = 0;
+
+           
+           drive->irq_flags.c_d = 1;
+           drive->irq_flags.rel = 0;
+       }
+
+       channel->status.ready = 1;
+       drive->irq_flags.io_dir = 1;
+       channel->status.busy = 0;
+
+       ide_raise_irq(dev, channel);
+    }
+
+
+    return length;
 }
 
 
 
 static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
-    int data_offset = drive->transfer_index % DATA_BUFFER_SIZE;
+    int data_offset = drive->transfer_index % ATAPI_BLOCK_SIZE;
     int req_offset = drive->transfer_index % drive->req_len;
     
     if (drive->cd_state.atapi_cmd != 0x28) {
@@ -770,14 +782,8 @@ static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, st
 
 
     if ((data_offset == 0) && (drive->transfer_index > 0)) {
-       
-       if (drive->drive_type == IDE_CDROM) {
-           if (atapi_update_data_buf(dev, channel) == -1) {
-               PrintError("Could not update CDROM data buffer\n");
-               return -1;
-           } 
-       } else {
-           PrintError("IDE Harddrives not implemented\n");
+       if (atapi_update_data_buf(dev, channel) == -1) {
+           PrintError("Could not update CDROM data buffer\n");
            return -1;
        }
     }
@@ -786,6 +792,8 @@ static int read_cd_data(uint8_t * dst, uint_t length, struct vm_device * dev, st
     
     drive->transfer_index += length;
 
+
+    // Should the req_offset be recalculated here?????
     if ((req_offset == 0) && (drive->transfer_index > 0)) {
        if (drive->transfer_index < drive->transfer_length) {
            // An increment is complete, but there is still more data to be transferred...
@@ -904,21 +912,25 @@ static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_de
 
        case PRI_SECT_CNT_PORT:
        case SEC_SECT_CNT_PORT:
-           drive->sector_count = *(uint8_t *)src;
+           channel->drives[0].sector_count = *(uint8_t *)src;
+           channel->drives[1].sector_count = *(uint8_t *)src;
            break;
 
        case PRI_SECT_NUM_PORT:
        case SEC_SECT_NUM_PORT:
-           drive->sector_num = *(uint8_t *)src;
-
+           channel->drives[0].sector_num = *(uint8_t *)src;
+           channel->drives[1].sector_num = *(uint8_t *)src;
+           break;
        case PRI_CYL_LOW_PORT:
        case SEC_CYL_LOW_PORT:
-           drive->cylinder_low = *(uint8_t *)src;
+           channel->drives[0].cylinder_low = *(uint8_t *)src;
+           channel->drives[1].cylinder_low = *(uint8_t *)src;
            break;
 
        case PRI_CYL_HIGH_PORT:
        case SEC_CYL_HIGH_PORT:
-           drive->cylinder_high = *(uint8_t *)src;
+           channel->drives[0].cylinder_high = *(uint8_t *)src;
+           channel->drives[1].cylinder_high = *(uint8_t *)src;
            break;
 
        case PRI_DRV_SEL_PORT:
@@ -1049,7 +1061,6 @@ static void init_drive(struct ide_drive * drive) {
     memset(drive->data_buf, 0, sizeof(drive->data_buf));
 
 
-
     drive->private_data = NULL;
     drive->cd_ops = NULL;
 }
@@ -1315,6 +1326,8 @@ int v3_ide_register_harddisk(struct vm_device * ide_dev,
 
     drive->drive_type = IDE_DISK;
 
+    drive->hd_state.accessed = 0;
+
     drive->hd_ops = ops;
 
     drive->private_data = private_data;
index 86554d6..3129ec5 100644 (file)
@@ -34,29 +34,28 @@ struct hd_state {
 
 
 // HDs always read 2048 byte blocks... ?
-static int hd_read(uint8_t * buf, int count, int lba,  void * private_data) {
+static int hd_read(uint8_t * buf, int sector_count, uint64_t lba,  void * private_data) {
     struct vm_device * hd_dev = (struct vm_device *)private_data;
     struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
     int offset = lba * IDE_SECTOR_SIZE;
-    int length = ((offset + count) > hd->capacity) ? (hd->capacity - offset) : count;
+    int length = sector_count * IDE_SECTOR_SIZE;
 
-    PrintDebug("Reading RAM HD at (LBA=%d) offset %d (length=%d)\n", lba, offset, length);
+    PrintDebug("Reading RAM HD at (LBA=%d) offset %d (length=%d)\n", (uint32_t)lba, offset, length);
 
     memcpy(buf, (uint8_t *)(hd->disk_image + offset), length);
 
-    // Pad out the rest of the buffer with 0's
-    //    memset(buf + length, 0, IDE_SECTOR_SIZE - length);
+
 
     return 0;
 }
 
 
-static uint32_t hd_get_capacity(void * private_data) {
+static uint64_t hd_get_capacity(void * private_data) {
     struct vm_device * hd_dev = (struct vm_device *)private_data;
     struct hd_state * hd = (struct hd_state *)(hd_dev->private_data);
     PrintDebug("Querying RAM HD capacity (bytes=%d) (ret = %d)\n", 
-              hd->capacity, (hd->capacity + IDE_SECTOR_SIZE - 1) / IDE_SECTOR_SIZE);
-    return (hd->capacity + IDE_SECTOR_SIZE - 1) / IDE_SECTOR_SIZE;
+              hd->capacity, hd->capacity  / IDE_SECTOR_SIZE);
+    return hd->capacity / IDE_SECTOR_SIZE;
 }
 
 static struct v3_ide_hd_ops hd_ops = {
@@ -91,7 +90,14 @@ static struct vm_device_ops dev_ops = {
 struct vm_device * v3_create_ram_hd(struct vm_device * ide, 
                                    uint_t bus, uint_t drive, 
                                    addr_t ramdisk, uint32_t size) {
-    struct hd_state * hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
+    struct hd_state * hd = NULL;
+
+    if (size % IDE_SECTOR_SIZE) {
+       PrintError("HD image must be an integral of sector size (IDE_SECTOR_SIZE=%d)\n", IDE_SECTOR_SIZE);
+       return NULL;
+    }
+
+    hd = (struct hd_state *)V3_Malloc(sizeof(struct hd_state));
 
     PrintDebug("Registering Ram HDD at %p (size=%d)\n", (void *)ramdisk, size);