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
[palacios.git] / palacios / src / devices / ata.h
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;
+}