From: Jack Lange <jarusl@cs.northwestern.edu>
Date: Fri, 3 Apr 2009 18:07:43 +0000 (-0500)
Subject: Added intial cut at IDE disk support
X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=4659d019e2f65b9397e2289a9add28a3adf47cf8;p=palacios.releases.git

Added intial cut at IDE disk support
---

diff --git a/palacios/build/Makefile b/palacios/build/Makefile
index f243949..46fcc40 100644
--- a/palacios/build/Makefile
+++ b/palacios/build/Makefile
@@ -331,6 +331,7 @@ DEVICES_OBJS := \
 	devices/para_net.o \
 	devices/ide.o \
 	devices/ram_cd.o \
+	devices/ram_hd.o \
 
 #	devices/cdrom.o \
 #	devices/ramdisk.o \
diff --git a/palacios/include/devices/ide.h b/palacios/include/devices/ide.h
index 4dce588..e0356b2 100644
--- a/palacios/include/devices/ide.h
+++ b/palacios/include/devices/ide.h
@@ -24,6 +24,9 @@
 #include <palacios/vm_dev.h>
 
 
+#define ATAPI_BLOCK_SIZE 2048
+#define IDE_SECTOR_SIZE 512
+
 typedef enum {IDE_DISK, IDE_CDROM, IDE_NONE} v3_ide_dev_type_t;
 
 struct v3_ide_cd_ops {
@@ -35,7 +38,9 @@ struct v3_ide_cd_ops {
 
 
 struct v3_ide_hd_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);    
 
 };
 
diff --git a/palacios/include/devices/ram_hd.h b/palacios/include/devices/ram_hd.h
new file mode 100644
index 0000000..77adf3e
--- /dev/null
+++ b/palacios/include/devices/ram_hd.h
@@ -0,0 +1,36 @@
+/* 
+ * 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".
+ */
+
+#ifndef __DEVICES_RAM_HD_H__
+#define __DEVICES_RAM_HD_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vm_dev.h>
+
+
+struct vm_device * v3_create_ram_hd(struct vm_device * ide, 
+				    uint_t bus, uint_t drive, 
+				    addr_t ramdisk, uint32_t size);
+
+
+
+#endif
+
+#endif
diff --git a/palacios/src/devices/atapi.h b/palacios/src/devices/atapi.h
index 3d98a75..3407101 100644
--- a/palacios/src/devices/atapi.h
+++ b/palacios/src/devices/atapi.h
@@ -18,7 +18,6 @@
  */
 
 #define ATAPI_PACKET_SIZE 12
-#define ATAPI_BLOCK_SIZE 2048
 
 #include "atapi-types.h"
 
diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c
index 43858a4..3605050 100644
--- a/palacios/src/devices/ide.c
+++ b/palacios/src/devices/ide.c
@@ -216,6 +216,10 @@ struct ide_internal {
 
 
 
+
+
+/* Utility functions */
+
 static inline uint16_t be_to_le_16(const uint16_t val) {
     uint8_t * buf = (uint8_t *)&val;
     return (buf[0] << 8) | (buf[1]) ;
@@ -265,6 +269,7 @@ static inline int is_lba_enabled(struct ide_channel * channel) {
 }
 
 
+/* Drive Commands */
 static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel) {
     if (channel->ctrl_reg.irq_disable == 0) {
 	PrintDebug("Raising IDE Interrupt %d\n", channel->irq);
@@ -326,11 +331,89 @@ static void ide_abort_command(struct vm_device * dev, struct ide_channel * chann
 }
 
 
-// Include the ATAPI interface handlers
+
+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"
 
 
 
+/* IO Operations */
 static int dma_read(struct vm_device * dev, struct ide_channel * channel) {
     struct ide_drive * drive = get_selected_drive(channel);
     struct ide_dma_prd prd_entry;
@@ -593,8 +676,12 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de
 		// JRL: Should we abort here?
 		ide_abort_command(dev, channel);
 	    } else {
-		PrintError("IDE Disks currently not implemented\n");
-		return -1;
+		ide_identify_device(drive);
+
+		channel->error_reg.val = 0;
+		channel->status.val = 0x58;
+
+		ide_raise_irq(dev, channel);
 	    }
 	    break;
 
@@ -1234,3 +1321,6 @@ int v3_ide_register_harddisk(struct vm_device * ide_dev,
 
     return 0;
 }
+
+
+
diff --git a/palacios/src/devices/ram_hd.c b/palacios/src/devices/ram_hd.c
new file mode 100644
index 0000000..86554d6
--- /dev/null
+++ b/palacios/src/devices/ram_hd.c
@@ -0,0 +1,108 @@
+/* 
+ * 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".
+ */
+
+#include <palacios/vmm.h>
+#include <devices/ram_hd.h>
+#include <devices/ide.h>
+
+
+struct hd_state {
+    addr_t disk_image;
+    uint32_t capacity; // in bytes
+
+    struct vm_device * ide;
+
+    uint_t bus;
+    uint_t drive;
+};
+
+
+// HDs always read 2048 byte blocks... ?
+static int hd_read(uint8_t * buf, int count, int 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;
+
+    PrintDebug("Reading RAM HD at (LBA=%d) offset %d (length=%d)\n", 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) {
+    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;
+}
+
+static struct v3_ide_hd_ops hd_ops = {
+    .read = hd_read, 
+    .get_capacity = hd_get_capacity,
+};
+
+
+static int hd_init(struct vm_device * dev) {
+    struct hd_state * hd = (struct hd_state *)(dev->private_data);
+
+    if (v3_ide_register_harddisk(hd->ide, hd->bus, hd->drive, "V3-RAM-HD", &hd_ops, dev) == -1) {
+	return -1;
+    }
+    
+    return 0;
+}
+
+
+static int hd_deinit(struct vm_device * dev) {
+    return 0;
+}
+
+static struct vm_device_ops dev_ops = {
+    .init = hd_init, 
+    .deinit = hd_deinit,
+    .reset = NULL,
+    .start = NULL,
+    .stop = NULL,
+};
+
+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));
+
+    PrintDebug("Registering Ram HDD at %p (size=%d)\n", (void *)ramdisk, size);
+
+    hd->disk_image = ramdisk;
+    hd->capacity = size;
+
+    hd->ide = ide;
+    hd->bus = bus;
+    hd->drive = drive;
+	
+    struct vm_device * hd_dev = v3_create_device("RAM-HD", &dev_ops, hd);
+
+    return hd_dev;
+}
diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c
index be73f33..75e7834 100644
--- a/palacios/src/palacios/vmm_config.c
+++ b/palacios/src/palacios/vmm_config.c
@@ -35,6 +35,7 @@
 #include <devices/generic.h>
 #include <devices/ide.h>
 #include <devices/ram_cd.h>
+#include <devices/ram_hd.h>
 #include <devices/bochs_debug.h>
 #include <devices/os_debug.h>
 #include <devices/apic.h>
@@ -280,7 +281,8 @@ static int setup_memory_map(struct guest_info * info, struct v3_vm_config * conf
 
 static int setup_devices(struct guest_info * info, struct v3_vm_config * config_ptr) {
     struct vm_device * ide = NULL;
-    struct vm_device * ram_cd = NULL;
+    //    struct vm_device * ram_cd = NULL;
+    struct vm_device * ram_hd = NULL;
     struct vm_device * pci = v3_create_pci();
     struct vm_device * nvram = v3_create_nvram();
     //struct vm_device * timer = v3_create_timer();
@@ -303,7 +305,10 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_
 
     if (use_ramdisk) {
 	PrintDebug("Creating Ramdisk\n");
-	ram_cd = v3_create_ram_cd(ide, 0, 0, 
+	//	ram_cd = v3_create_ram_cd(ide, 0, 0, 
+	//			  (addr_t)(config_ptr->ramdisk), 
+	//			  config_ptr->ramdisk_size);
+	ram_hd = v3_create_ram_hd(ide, 0, 0, 
 				  (addr_t)(config_ptr->ramdisk), 
 				  config_ptr->ramdisk_size);
     }
@@ -333,7 +338,8 @@ static int setup_devices(struct guest_info * info, struct v3_vm_config * config_
     v3_attach_device(info, ide);
 
     if (use_ramdisk) {
-	v3_attach_device(info, ram_cd);
+	//	v3_attach_device(info, ram_cd);
+	v3_attach_device(info, ram_hd);
     }
 
     if (use_generic) {