X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Fide.c;h=bf9524563054db854ea9a3d2765dc7c1e03179da;hp=eb07a625e39b326897d1ee7753b97a3917108634;hb=afb2a35b2e15ba0fa932c4e49a3678f958a4502a;hpb=86fb0d26700ecdd5967013c43d70a5e77f2d0a7c diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index eb07a62..bf95245 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -22,10 +22,11 @@ #include #include #include +#include #include "ide-types.h" #include "atapi-types.h" -#ifndef DEBUG_IDE +#ifndef CONFIG_DEBUG_IDE #undef PrintDebug #define PrintDebug(fmt, args...) #endif @@ -95,18 +96,6 @@ static inline const char * dma_port_to_str(uint16_t port) { } -static const char * ide_dev_type_strs[] = {"NONE", "HARDDISK", "CDROM" }; - - -static inline const char * device_type_to_str(v3_ide_dev_type_t type) { - if (type > 2) { - return NULL; - } - - return ide_dev_type_strs[type]; -} - - struct ide_cd_state { struct atapi_sense_data sense; @@ -131,11 +120,11 @@ struct ide_hd_state { struct ide_drive { // Command Registers - v3_ide_dev_type_t drive_type; + v3_block_type_t drive_type; union { - struct v3_ide_cd_ops * cd_ops; - struct v3_ide_hd_ops * hd_ops; + struct v3_cd_ops * cd_ops; + struct v3_hd_ops * hd_ops; }; @@ -159,7 +148,6 @@ struct ide_drive { uint8_t data_buf[DATA_BUFFER_SIZE]; - uint32_t num_cylinders; uint32_t num_heads; uint32_t num_sectors; @@ -292,9 +280,9 @@ 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); - channel->dma_status.int_gen = 1; - v3_raise_irq(dev->vm, channel->irq); + // PrintError("Raising IDE Interrupt %d\n", channel->irq); + channel->dma_status.int_gen = 1; + v3_raise_irq(dev->vm, channel->irq); } } @@ -305,7 +293,7 @@ static void drive_reset(struct ide_drive * drive) { PrintDebug("Resetting drive %s\n", drive->model); - if (drive->drive_type == IDE_CDROM) { + if (drive->drive_type == BLOCK_CDROM) { drive->cylinder = 0xeb14; } else { drive->cylinder = 0x0000; @@ -365,6 +353,37 @@ static int dma_write(struct vm_device * dev, struct ide_channel * channel); #include "ata.h" +#ifdef CONFIG_DEBUG_IDE +static void print_prd_table(struct vm_device * dev, struct ide_channel * channel) { + struct ide_dma_prd prd_entry; + int index = 0; + + PrintDebug("Dumping PRD table\n"); + + while (1) { + uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * index); + int ret; + + ret = read_guest_pa_memory(dev->vm, prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry); + + if (ret != sizeof(struct ide_dma_prd)) { + PrintError("Could not read PRD\n"); + return; + } + + PrintDebug("\tPRD Addr: %x, PRD Len: %d, EOT: %d\n", + prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + + if (prd_entry.end_of_table) { + break; + } + + index++; + } + + return; +} +#endif /* IO Operations */ static int dma_read(struct vm_device * dev, struct ide_channel * channel) { @@ -376,6 +395,9 @@ static int dma_read(struct vm_device * dev, struct ide_channel * channel) { // Read in the data buffer.... // Read a sector/block at a time until the prd entry is full. +#ifdef CONFIG_DEBUG_IDE + print_prd_table(dev, channel); +#endif PrintDebug("DMA read for %d bytes\n", bytes_left); @@ -385,80 +407,91 @@ static int dma_read(struct vm_device * dev, struct ide_channel * channel) { uint_t prd_bytes_left = 0; uint_t prd_offset = 0; int ret; - + PrintDebug("PRD table address = %x\n", channel->dma_prd_addr); - + ret = read_guest_pa_memory(dev->vm, prd_entry_addr, sizeof(struct ide_dma_prd), (void *)&prd_entry); - + if (ret != sizeof(struct ide_dma_prd)) { PrintError("Could not read PRD\n"); return -1; } - + PrintDebug("PRD Addr: %x, PRD Len: %d, EOT: %d\n", prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); - + // loop through the PRD data.... - + prd_bytes_left = prd_entry.size; - - + + while (prd_bytes_left > 0) { uint_t bytes_to_write = 0; - - if (drive->drive_type == IDE_DISK) { - bytes_to_write = (prd_bytes_left > IDE_SECTOR_SIZE) ? IDE_SECTOR_SIZE : prd_bytes_left; - - + + if (drive->drive_type == BLOCK_DISK) { + bytes_to_write = (prd_bytes_left > HD_SECTOR_SIZE) ? HD_SECTOR_SIZE : prd_bytes_left; + + if (ata_read(dev, channel, drive->data_buf, 1) == -1) { PrintError("Failed to read next disk sector\n"); return -1; } - } else if (drive->drive_type == IDE_CDROM) { - bytes_to_write = (prd_bytes_left > ATAPI_BLOCK_SIZE) ? ATAPI_BLOCK_SIZE : prd_bytes_left; - - if (atapi_read_chunk(dev, channel) == -1) { - PrintError("Failed to read next disk sector\n"); + } else if (drive->drive_type == BLOCK_CDROM) { + if (atapi_cmd_is_data_op(drive->cd_state.atapi_cmd)) { + bytes_to_write = (prd_bytes_left > ATAPI_BLOCK_SIZE) ? ATAPI_BLOCK_SIZE : prd_bytes_left; + + if (atapi_read_chunk(dev, channel) == -1) { + PrintError("Failed to read next disk sector\n"); + return -1; + } + } else { + PrintDebug("DMA of command packet\n"); + PrintError("How does this work???\n"); return -1; + bytes_to_write = (prd_bytes_left > bytes_left) ? bytes_left : prd_bytes_left; + prd_bytes_left = bytes_to_write; } } - + PrintDebug("Writing DMA data to guest Memory ptr=%p, len=%d\n", (void *)(addr_t)(prd_entry.base_addr + prd_offset), bytes_to_write); drive->current_lba++; - + ret = write_guest_pa_memory(dev->vm, prd_entry.base_addr + prd_offset, bytes_to_write, drive->data_buf); - + if (ret != bytes_to_write) { PrintError("Failed to copy data into guest memory... (ret=%d)\n", ret); return -1; } PrintDebug("\t DMA ret=%d, (prd_bytes_left=%d) (bytes_left=%d)\n", ret, prd_bytes_left, bytes_left); - + drive->transfer_index += ret; prd_bytes_left -= ret; prd_offset += ret; bytes_left -= ret; - } - - channel->dma_tbl_index++; - - if (drive->drive_type == IDE_DISK) { - if (drive->transfer_index % IDE_SECTOR_SIZE) { + + channel->dma_tbl_index++; + + if (drive->drive_type == BLOCK_DISK) { + if (drive->transfer_index % HD_SECTOR_SIZE) { PrintError("We currently don't handle sectors that span PRD descriptors\n"); return -1; } - } else if (drive->drive_type == IDE_CDROM) { - if (drive->transfer_index % ATAPI_BLOCK_SIZE) { - PrintError("We currently don't handle ATAPI BLOCKS that span PRD descriptors\n"); - return -1; + } else if (drive->drive_type == BLOCK_CDROM) { + if (atapi_cmd_is_data_op(drive->cd_state.atapi_cmd)) { + if (drive->transfer_index % ATAPI_BLOCK_SIZE) { + PrintError("We currently don't handle ATAPI BLOCKS that span PRD descriptors\n"); + PrintError("transfer_index=%d, transfer_length=%d\n", + drive->transfer_index, drive->transfer_length); + return -1; + } } } - - + + if ((prd_entry.end_of_table == 1) && (bytes_left > 0)) { PrintError("DMA table not large enough for data transfer...\n"); return -1; @@ -527,7 +560,7 @@ static int dma_write(struct vm_device * dev, struct ide_channel * channel) { uint_t bytes_to_write = 0; - bytes_to_write = (prd_bytes_left > IDE_SECTOR_SIZE) ? IDE_SECTOR_SIZE : prd_bytes_left; + bytes_to_write = (prd_bytes_left > HD_SECTOR_SIZE) ? HD_SECTOR_SIZE : prd_bytes_left; ret = read_guest_pa_memory(dev->vm, prd_entry.base_addr + prd_offset, bytes_to_write, drive->data_buf); @@ -555,7 +588,7 @@ static int dma_write(struct vm_device * dev, struct ide_channel * channel) { channel->dma_tbl_index++; - if (drive->transfer_index % IDE_SECTOR_SIZE) { + if (drive->transfer_index % HD_SECTOR_SIZE) { PrintError("We currently don't handle sectors that span PRD descriptors\n"); return -1; } @@ -593,7 +626,8 @@ static int dma_write(struct vm_device * dev, struct ide_channel * channel) { #define DMA_CHANNEL_FLAG 0x08 -static int write_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { +static int write_dma_port(ushort_t port, void * src, uint_t length, void * private_data) { + struct vm_device * dev = (struct vm_device *)private_data; struct ide_internal * ide = (struct ide_internal *)(dev->private_data); uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1); uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3; @@ -675,7 +709,8 @@ static int write_dma_port(ushort_t port, void * src, uint_t length, struct vm_de } -static int read_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { +static int read_dma_port(ushort_t port, void * dst, uint_t length, void * private_data) { + struct vm_device * dev = (struct vm_device *)private_data; struct ide_internal * ide = (struct ide_internal *)(dev->private_data); uint16_t port_offset = port & (DMA_CHANNEL_FLAG - 1); uint_t channel_flag = (port & DMA_CHANNEL_FLAG) >> 3; @@ -745,7 +780,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de switch (channel->cmd_reg) { case 0xa1: // ATAPI Identify Device Packet - if (drive->drive_type != IDE_CDROM) { + if (drive->drive_type != BLOCK_CDROM) { drive_reset(drive); // JRL: Should we abort here? @@ -761,7 +796,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de } break; case 0xec: // Identify Device - if (drive->drive_type != IDE_DISK) { + if (drive->drive_type != BLOCK_DISK) { drive_reset(drive); // JRL: Should we abort here? @@ -777,7 +812,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de break; case 0xa0: // ATAPI Command Packet - if (drive->drive_type != IDE_CDROM) { + if (drive->drive_type != BLOCK_CDROM) { ide_abort_command(dev, channel); } @@ -824,7 +859,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de drive->hd_state.cur_sector_num = 1; - drive->transfer_length = sect_cnt * IDE_SECTOR_SIZE; + drive->transfer_length = sect_cnt * HD_SECTOR_SIZE; drive->transfer_index = 0; if (channel->dma_status.active == 1) { @@ -847,7 +882,7 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de drive->hd_state.cur_sector_num = 1; - drive->transfer_length = sect_cnt * IDE_SECTOR_SIZE; + drive->transfer_length = sect_cnt * HD_SECTOR_SIZE; drive->transfer_index = 0; if (channel->dma_status.active == 1) { @@ -967,7 +1002,7 @@ 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) { struct ide_drive * drive = get_selected_drive(channel); - int data_offset = drive->transfer_index % IDE_SECTOR_SIZE; + int data_offset = drive->transfer_index % HD_SECTOR_SIZE; @@ -1004,7 +1039,7 @@ static int read_hd_data(uint8_t * dst, uint_t length, struct vm_device * dev, st * cur_sector_num is configured depending on the operation we are currently running * We also trigger an interrupt if this is the last byte to transfer, regardless of sector count */ - if (((drive->transfer_index % (IDE_SECTOR_SIZE * drive->hd_state.cur_sector_num)) == 0) || + if (((drive->transfer_index % (HD_SECTOR_SIZE * drive->hd_state.cur_sector_num)) == 0) || (drive->transfer_index == drive->transfer_length)) { if (drive->transfer_index < drive->transfer_length) { // An increment is complete, but there is still more data to be transferred... @@ -1124,19 +1159,19 @@ static int ide_read_data_port(ushort_t port, void * dst, uint_t length, struct v struct ide_channel * channel = get_selected_channel(ide, port); struct ide_drive * drive = get_selected_drive(channel); - // PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length); + PrintDebug("IDE: Reading Data Port %x (len=%d)\n", port, length); if ((channel->cmd_reg == 0xec) || (channel->cmd_reg == 0xa1)) { return read_drive_id((uint8_t *)dst, length, dev, channel); } - if (drive->drive_type == IDE_CDROM) { + if (drive->drive_type == BLOCK_CDROM) { if (read_cd_data((uint8_t *)dst, length, dev, channel) == -1) { PrintError("IDE: Could not read CD Data\n"); return -1; } - } else if (drive->drive_type == IDE_DISK) { + } else if (drive->drive_type == BLOCK_DISK) { if (read_hd_data((uint8_t *)dst, length, dev, channel) == -1) { PrintError("IDE: Could not read HD Data\n"); return -1; @@ -1215,7 +1250,7 @@ static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_de drive = get_selected_drive(channel); // Selecting a non-present device is a no-no - if (drive->drive_type == IDE_NONE) { + if (drive->drive_type == BLOCK_NONE) { PrintDebug("Attempting to select a non-present drive\n"); channel->error_reg.abort = 1; channel->status.error = 1; @@ -1252,7 +1287,7 @@ static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_dev // if no drive is present just return 0 + reserved bits - if (drive->drive_type == IDE_NONE) { + if (drive->drive_type == BLOCK_NONE) { if ((port == PRI_DRV_SEL_PORT) || (port == SEC_DRV_SEL_PORT)) { *(uint8_t *)dst = 0xa0; @@ -1323,7 +1358,7 @@ static void init_drive(struct ide_drive * drive) { drive->sector_num = 0x01; drive->cylinder = 0x0000; - drive->drive_type = IDE_NONE; + drive->drive_type = BLOCK_NONE; memset(drive->model, 0, sizeof(drive->model)); @@ -1362,7 +1397,7 @@ static void init_channel(struct ide_channel * channel) { } -static int pci_config_update(struct pci_device * pci_dev, uint_t reg_num, int length) { +static int pci_config_update(uint_t reg_num, void * src, uint_t length, void * private_data) { PrintDebug("PCI Config Update\n"); PrintDebug("\t\tInterupt register (Dev=%s), irq=%d\n", pci_dev->name, pci_dev->config_header.intr_line); @@ -1390,10 +1425,64 @@ static int init_ide_state(struct vm_device * dev) { -static int init_ide(struct vm_device * dev) { - struct ide_internal * ide = (struct ide_internal *)(dev->private_data); +static int ide_free(struct vm_device * dev) { + // unhook io ports.... + // deregister from PCI? + return 0; +} + + +static struct v3_device_ops dev_ops = { + .free = ide_free, + .reset = NULL, + .start = NULL, + .stop = NULL, +}; + + + +static int ide_init(struct guest_info * vm, void * cfg_data) { + struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal)); + struct ide_cfg * cfg = (struct ide_cfg *)(cfg_data); + PrintDebug("IDE: Initializing IDE\n"); + memset(ide, 0, sizeof(struct ide_internal)); + + + if (cfg->pci != NULL) { + if (cfg->southbridge == NULL) { + PrintError("PCI Enabled BUT southbridge is NULL\n"); + return -1; + } + + ide->pci_bus = v3_find_dev(vm, (char *)cfg->pci); + + if (ide->pci_bus == NULL) { + PrintError("Could not find PCI device\n"); + return -1; + } + + struct vm_device * southbridge = v3_find_dev(vm, cfg->southbridge); + + if (!southbridge) { + PrintError("Could not find southbridge\n"); + return -1; + } + + ide->southbridge = (struct v3_southbridge *)(southbridge->private_data); + } + + + PrintDebug("IDE: Creating IDE bus x 2\n"); + + struct vm_device * dev = v3_allocate_device("IDE", &dev_ops, ide); + + if (v3_attach_device(vm, dev) == -1) { + PrintError("Could not attach device %s\n", "IDE"); + return -1; + } + if (init_ide_state(dev) == -1) { PrintError("Failed to initialize IDE state\n"); @@ -1467,12 +1556,14 @@ static int init_ide(struct vm_device * dev) { } bars[4].type = PCI_BAR_IO; - bars[4].default_base_port = PRI_DEFAULT_DMA_PORT; + // bars[4].default_base_port = PRI_DEFAULT_DMA_PORT; + bars[4].default_base_port = -1; bars[4].num_ports = 16; bars[4].io_read = read_dma_port; bars[4].io_write = write_dma_port; - + bars[4].private_data = dev; + pci_dev = v3_pci_register_device(ide->pci_bus, PCI_STD_DEVICE, 0, sb_pci->dev_num, 1, "PIIX3_IDE", bars, pci_config_update, NULL, NULL, dev); @@ -1492,9 +1583,9 @@ static int init_ide(struct vm_device * dev) { pci_dev->config_header.device_id = 0x7010; pci_dev->config_header.revision = 0x00; - pci_dev->config_header.prog_if = 0x80; - pci_dev->config_header.subclass = 0x01; - pci_dev->config_header.class = 0x01; + pci_dev->config_header.prog_if = 0x80; // Master IDE device + pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_IDE; + pci_dev->config_header.class = PCI_CLASS_STORAGE; pci_dev->config_header.command = 0; pci_dev->config_header.status = 0x0280; @@ -1510,44 +1601,13 @@ static int init_ide(struct vm_device * dev) { } -static int deinit_ide(struct vm_device * dev) { - // unhook io ports.... - // deregister from PCI? - return 0; -} +device_register("IDE", ide_init) -static struct vm_device_ops dev_ops = { - .init = init_ide, - .deinit = deinit_ide, - .reset = NULL, - .start = NULL, - .stop = NULL, -}; -struct vm_device * v3_create_ide(struct vm_device * pci_bus, struct vm_device * southbridge_dev) { - struct ide_internal * ide = (struct ide_internal *)V3_Malloc(sizeof(struct ide_internal)); - - memset(ide, 0, sizeof(struct ide_internal)); - struct vm_device * device = v3_create_device("IDE", &dev_ops, ide); - if (pci_bus != NULL) { - if (southbridge_dev == NULL) { - PrintError("PCI Enabled BUT southbridge is NULL\n"); - return NULL; - } - - ide->pci_bus = pci_bus; - ide->southbridge = (struct v3_southbridge *)(southbridge_dev->private_data); - } - - - PrintDebug("IDE: Creating IDE bus x 2\n"); - - return device; -} @@ -1558,7 +1618,7 @@ int v3_ide_get_geometry(struct vm_device * ide_dev, int channel_num, int drive_n struct ide_channel * channel = &(ide->channels[channel_num]); struct ide_drive * drive = &(channel->drives[drive_num]); - if (drive->drive_type == IDE_NONE) { + if (drive->drive_type == BLOCK_NONE) { return -1; } @@ -1576,7 +1636,7 @@ int v3_ide_register_cdrom(struct vm_device * ide_dev, uint_t bus_num, uint_t drive_num, char * dev_name, - struct v3_ide_cd_ops * ops, + struct v3_cd_ops * ops, void * private_data) { struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data); @@ -1589,7 +1649,7 @@ int v3_ide_register_cdrom(struct vm_device * ide_dev, channel = &(ide->channels[bus_num]); drive = &(channel->drives[drive_num]); - if (drive->drive_type != IDE_NONE) { + if (drive->drive_type != BLOCK_NONE) { PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num); return -1; } @@ -1601,7 +1661,7 @@ int v3_ide_register_cdrom(struct vm_device * ide_dev, } - drive->drive_type = IDE_CDROM; + drive->drive_type = BLOCK_CDROM; drive->cd_ops = ops; @@ -1620,7 +1680,7 @@ int v3_ide_register_harddisk(struct vm_device * ide_dev, uint_t bus_num, uint_t drive_num, char * dev_name, - struct v3_ide_hd_ops * ops, + struct v3_hd_ops * ops, void * private_data) { struct ide_internal * ide = (struct ide_internal *)(ide_dev->private_data); @@ -1633,14 +1693,14 @@ int v3_ide_register_harddisk(struct vm_device * ide_dev, channel = &(ide->channels[bus_num]); drive = &(channel->drives[drive_num]); - if (drive->drive_type != IDE_NONE) { + if (drive->drive_type != BLOCK_NONE) { PrintError("Device slot (bus=%d, drive=%d) already occupied\n", bus_num, drive_num); return -1; } strncpy(drive->model, dev_name, sizeof(drive->model) - 1); - drive->drive_type = IDE_DISK; + drive->drive_type = BLOCK_DISK; drive->hd_state.accessed = 0; drive->hd_state.mult_sector_num = 1;