From: Jack Lange Date: Thu, 2 Apr 2009 01:27:48 +0000 (-0500) Subject: broken DMA that should be working X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=a3843aa9457ed5a02159fd5a83620426b0a0f3fe broken DMA that should be working Maybe if there was an actual spec that people could, you know, download and look at this would be easier... --- diff --git a/palacios/include/devices/ide.h b/palacios/include/devices/ide.h index d70ac4b..4dce588 100644 --- a/palacios/include/devices/ide.h +++ b/palacios/include/devices/ide.h @@ -29,7 +29,7 @@ typedef enum {IDE_DISK, IDE_CDROM, IDE_NONE} 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 lba, void * private_data); + int (*read)(uint8_t * buf, int count, int lba, void * private_data); }; diff --git a/palacios/include/devices/pci.h b/palacios/include/devices/pci.h index d39eae3..6727e44 100644 --- a/palacios/include/devices/pci.h +++ b/palacios/include/devices/pci.h @@ -114,7 +114,7 @@ v3_pci_register_device(struct vm_device * pci, int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length), int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled), int (*ext_rom_update)(struct pci_device *pci_dev), - void * private_data); + struct vm_device * dev); #endif diff --git a/palacios/src/devices/atapi.h b/palacios/src/devices/atapi.h index 5af6729..3d98a75 100644 --- a/palacios/src/devices/atapi.h +++ b/palacios/src/devices/atapi.h @@ -129,8 +129,8 @@ 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, drive->cd_state.current_lba, drive->private_data); - + int ret = drive->cd_ops->read(drive->data_buf, ATAPI_BLOCK_SIZE, drive->cd_state.current_lba, drive->private_data); + if (ret == -1) { PrintError("IDE: Error reading CD block (LBA=%x)\n", drive->cd_state.current_lba); return -1; @@ -166,35 +166,41 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) { struct atapi_read10_cmd * cmd = (struct atapi_read10_cmd *)(drive->data_buf); uint32_t lba = be_to_le_32(cmd->lba); uint16_t xfer_len = be_to_le_16(cmd->xfer_len); - + + PrintDebug("READ10: XferLen=%d\n", xfer_len); + /* Check if cd is ready * if not: atapi_cmd_error(... ATAPI_SEN_NOT_RDY, ASC_MEDIA_NOT_PRESENT) */ - + if (xfer_len == 0) { atapi_cmd_nop(dev, channel); return 0; } - if ((lba + xfer_len) > drive->cd_ops->get_capacity(drive->private_data)) { + if (lba + xfer_len > drive->cd_ops->get_capacity(drive->private_data)) { + PrintError("IDE: xfer len exceeded capacity (lba=%d) (xfer_len=%d) (ReadEnd=%d) (capacity=%d)\n", + lba, xfer_len, lba + xfer_len, + drive->cd_ops->get_capacity(drive->private_data)); atapi_cmd_error(dev, channel, ATAPI_SEN_ILL_REQ, ASC_LOG_BLK_OOR); ide_raise_irq(dev, channel); - return 0;} - + return 0; + } + // PrintDebug("Reading %d blocks from LBA 0x%x\n", xfer_len, lba); - + drive->cd_state.current_lba = lba; - + // Update the request length value in the cylinder registers - + if (atapi_read_chunk(dev, channel) == -1) { PrintError("IDE: Could not read initial chunk from CD\n"); - return -1; + return -1; } - + drive->transfer_length = xfer_len * ATAPI_BLOCK_SIZE; drive->transfer_index = 0; - + // Length of ATAPI buffer sits in cylinder registers // This is weird... The host sets this value to say what it would like to transfer, // if it is larger than the correct size, the device shrinks it to the correct size @@ -202,7 +208,7 @@ static int atapi_read10(struct vm_device * dev, struct ide_channel * channel) { PrintError("Could not update initial request length\n"); return -1; } - + ide_raise_irq(dev, channel); return 0; @@ -536,8 +542,9 @@ static void atapi_identify_device(struct ide_drive * drive) { 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[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; diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index a9d88aa..43858a4 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include "ide-types.h" @@ -50,19 +51,9 @@ #define SEC_ADDR_REG_PORT 0x377 -#define PRI_DMA_CMD_PORT 0xc000 -#define PRI_DMA_STATUS_PORT 0xc002 -#define PRI_DMA_PRD_PORT0 0xc004 -#define PRI_DMA_PRD_PORT1 0xc005 -#define PRI_DMA_PRD_PORT2 0xc006 -#define PRI_DMA_PRD_PORT3 0xc007 +#define PRI_DEFAULT_DMA_PORT 0xc000 +#define SEC_DEFAULT_DMA_PORT 0xc008 -#define SEC_DMA_CMD_PORT 0xc008 -#define SEC_DMA_STATUS_PORT 0xc00a -#define SEC_DMA_PRD_PORT0 0xc00c -#define SEC_DMA_PRD_PORT1 0xc00d -#define SEC_DMA_PRD_PORT2 0xc00e -#define SEC_DMA_PRD_PORT3 0xc00f #define DATA_BUFFER_SIZE 2048 @@ -75,14 +66,8 @@ static const char * ide_sec_port_strs[] = {"SEC_DATA", "SEC_FEATURES", "SEC_SECT "SEC_CYL_LOW", "SEC_CYL_HIGH", "SEC_DRV_SEL", "SEC_CMD", "SEC_CTRL", "SEC_ADDR_REG"}; -static const char * ide_dma_port_strs[] = {"PRI_DMA_CMD", NULL, - "PRI_DMA_STATUS", NULL, - "PRI_DMA_PRD0", "PRI_DMA_PRD1", - "PRI_DMA_PRD2", "PRI_DMA_PRD3", - "SEC_DMA_CMD", NULL, - "SEC_DMA_STATUS", NULL, - "SEC_DMA_PRD0","SEC_DMA_PRD1", - "SEC_DMA_PRD2","SEC_DMA_PRD3"}; +static const char * ide_dma_port_strs[] = {"DMA_CMD", NULL, "DMA_STATUS", NULL, + "DMA_PRD0", "DMA_PRD1", "DMA_PRD2", "DMA_PRD3"}; @@ -95,13 +80,15 @@ static inline const char * io_port_to_str(uint16_t port) { return ide_pri_port_strs[port - PRI_CTRL_PORT + 8]; } else if ((port == SEC_CTRL_PORT) || (port == SEC_ADDR_REG_PORT)) { return ide_sec_port_strs[port - SEC_CTRL_PORT + 8]; - } else if ((port >= PRI_DMA_CMD_PORT) && (port <= SEC_DMA_PRD_PORT3)) { - return ide_dma_port_strs[port - PRI_DMA_CMD_PORT]; } return NULL; } +static inline const char * dma_port_to_str(uint16_t port) { + return ide_dma_port_strs[port & 0x7]; +} + static const char * ide_dev_type_strs[] = {"HARDDISK", "CDROM", "NONE"}; @@ -189,10 +176,6 @@ struct ide_drive { uint16_t req_len; } __attribute__((packed)); - struct ide_dma_cmd_reg dma_cmd; - struct ide_dma_status_reg dma_status; - uint32_t dma_prd_addr; - }; @@ -216,6 +199,11 @@ struct ide_channel { // Control Registers struct ide_ctrl_reg ctrl_reg; // [write] 0x3f6,0x376 + + struct ide_dma_cmd_reg dma_cmd; + struct ide_dma_status_reg dma_status; + uint32_t dma_prd_addr; + uint_t dma_tbl_index; }; @@ -279,6 +267,8 @@ static inline int is_lba_enabled(struct ide_channel * channel) { 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); } } @@ -340,45 +330,166 @@ static void ide_abort_command(struct vm_device * dev, struct ide_channel * chann #include "atapi.h" -static int write_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { - struct ide_internal * ide = (struct ide_internal *)(dev->private_data); - struct ide_channel * channel = get_selected_channel(ide, port); + +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; + uint32_t prd_entry_addr = channel->dma_prd_addr + (sizeof(struct ide_dma_prd) * channel->dma_tbl_index); + int ret; - if (length != 1) { - PrintError("IDE: Invalid Write length on IDE port %x\n", port); + + 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("IDE: Writing DMA Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)src); + PrintDebug("PRD Addr: %x, PDR Len: %d, EOT: %d\n", prd_entry.base_addr, prd_entry.size, prd_entry.end_of_table); + + ret = write_guest_pa_memory(dev->vm, prd_entry.base_addr, prd_entry.size, drive->data_buf); + + if (ret != prd_entry.size) { + PrintError("Failed to copy data into guest memory... (ret=%d)\n", ret); + return -1; + } + + channel->status.busy = 0; + channel->status.ready = 1; + channel->status.data_req = 0; + channel->status.error = 0; + channel->status.seek_complete = 1; + + /* + drive->irq_flags.io_dir = 1; + drive->irq_flags.c_d = 1; + drive->irq_flags.rel = 0; + */ + + + // set DMA status + channel->dma_status.active = 0; + channel->dma_status.err = 1; + channel->dma_status.int_gen = 1; + + ide_raise_irq(dev, channel); + + return 0; +} + + +static int dma_write(struct vm_device * dev, struct ide_channel * channel) { + // unsupported + PrintError("DMA writes currently not supported\n"); + return -1; +} + + +/* + * This is an ugly ugly ugly way to differentiate between the first and second DMA channels + */ + +static int write_dma_port(ushort_t port_offset, void * src, uint_t length, struct vm_device * dev, struct ide_channel * channel); +static int read_dma_port(ushort_t port_offset, void * dst, uint_t length, struct vm_device * dev, struct ide_channel * channel); + + +static int write_pri_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + PrintDebug("IDE: Writing PRI DMA Port %x (%s) (val=%x)\n", port, dma_port_to_str(port & 0x7), *(uint32_t *)src); + return write_dma_port(port & 0x7, src, length, dev, &(ide->channels[0])); +} + +static int write_sec_dma_port(ushort_t port, void * src, uint_t length, struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + PrintDebug("IDE: Writing SEC DMA Port %x (%s) (val=%x)\n", port, dma_port_to_str(port & 0x7), *(uint32_t *)src); + return write_dma_port(port & 0x7, src, length, dev, &(ide->channels[1])); +} + + +static int read_pri_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + PrintDebug("IDE: Reading PRI DMA Port %x (%s)\n", port, dma_port_to_str(port & 0x7)); + return read_dma_port(port & 0x7, dst, length, dev, &(ide->channels[0])); +} + +static int read_sec_dma_port(ushort_t port, void * dst, uint_t length, struct vm_device * dev) { + struct ide_internal * ide = (struct ide_internal *)(dev->private_data); + PrintDebug("IDE: Reading SEC DMA Port %x (%s)\n", port, dma_port_to_str(port & 0x7)); + return read_dma_port(port & 0x7, dst, length, dev, &(ide->channels[1])); +} + + +#define DMA_CMD_PORT 0x00 +#define DMA_STATUS_PORT 0x02 +#define DMA_PRD_PORT0 0x04 +#define DMA_PRD_PORT1 0x05 +#define DMA_PRD_PORT2 0x06 +#define DMA_PRD_PORT3 0x07 + + +static int write_dma_port(ushort_t port_offset, void * src, uint_t length, + struct vm_device * dev, struct ide_channel * channel) { + + switch (port_offset) { + case DMA_CMD_PORT: + channel->dma_cmd.val = *(uint8_t *)src; + + if (channel->dma_cmd.start == 0) { + channel->dma_tbl_index = 0; + } else { + channel->dma_status.active = 1; + + if (channel->dma_cmd.read == 1) { + // DMA Read + if (dma_read(dev, channel) == -1) { + PrintError("Failed DMA Read\n"); + return -1; + } + } else { + // DMA write + if (dma_write(dev, channel) == -1) { + PrintError("Failed DMA Write\n"); + return -1; + } + } + } - switch (port) { - case PRI_DMA_CMD_PORT: - case SEC_DMA_CMD_PORT: - drive->dma_cmd.val = *(uint8_t *)src; break; + + case DMA_STATUS_PORT: + if (length != 1) { + PrintError("Invalid read length for DMA status port\n"); + return -1; + } - case PRI_DMA_STATUS_PORT: - case SEC_DMA_STATUS_PORT: - drive->dma_status.val = *(uint8_t *)src; + channel->dma_status.val = *(uint8_t *)src; break; + + case DMA_PRD_PORT0: + case DMA_PRD_PORT1: + case DMA_PRD_PORT2: + case DMA_PRD_PORT3: { + uint_t addr_index = port_offset & 0x3; + uint8_t * addr_buf = (uint8_t *)&(channel->dma_prd_addr); + int i = 0; + + if (addr_index + length > 4) { + PrintError("DMA Port space overrun port=%x len=%d\n", port_offset, length); + return -1; + } + + for (i = 0; i < length; i++) { + addr_buf[addr_index + i] = *((uint8_t *)src + i); + } + + PrintDebug("Writing PRD Port %x (val=%x)\n", port_offset, channel->dma_prd_addr); - case PRI_DMA_PRD_PORT0: - case PRI_DMA_PRD_PORT1: - case PRI_DMA_PRD_PORT2: - case PRI_DMA_PRD_PORT3: - case SEC_DMA_PRD_PORT0: - case SEC_DMA_PRD_PORT1: - case SEC_DMA_PRD_PORT2: - case SEC_DMA_PRD_PORT3: { - uint_t addr_index = port & 0x3; - uint8_t * addr_buf = (uint8_t *)&(drive->dma_prd_addr); - - addr_buf[addr_index] = *(uint8_t *)src; break; } default: - PrintError("IDE: Invalid DMA Port (%x)\n", port); + PrintError("IDE: Invalid DMA Port (%s)\n", dma_port_to_str(port_offset)); return -1; } @@ -386,49 +497,48 @@ 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) { - struct ide_internal * ide = (struct ide_internal *)(dev->private_data); - struct ide_channel * channel = get_selected_channel(ide, port); - struct ide_drive * drive = get_selected_drive(channel); - - if (length != 1) { - PrintError("IDE: Invalid Write length on IDE port %x\n", port); - return -1; - } +static int read_dma_port(ushort_t port_offset, void * dst, uint_t length, + struct vm_device * dev, struct ide_channel * channel) { + switch (port_offset) { + case DMA_CMD_PORT: + *(uint8_t *)dst = channel->dma_cmd.val; + break; + case DMA_STATUS_PORT: + if (length != 1) { + PrintError("Invalid read length for DMA status port\n"); + return -1; + } - switch (port) { - case PRI_DMA_CMD_PORT: - case SEC_DMA_CMD_PORT: - *(uint8_t *)dst = drive->dma_cmd.val; + *(uint8_t *)dst = channel->dma_status.val; break; - case PRI_DMA_STATUS_PORT: - case SEC_DMA_STATUS_PORT: - *(uint8_t *)dst = drive->dma_status.val; - break; + case DMA_PRD_PORT0: + case DMA_PRD_PORT1: + case DMA_PRD_PORT2: + case DMA_PRD_PORT3: { + uint_t addr_index = port_offset & 0x3; + uint8_t * addr_buf = (uint8_t *)&(channel->dma_prd_addr); + int i = 0; + + if (addr_index + length > 4) { + PrintError("DMA Port space overrun port=%x len=%d\n", port_offset, length); + return -1; + } + + for (i = 0; i < length; i++) { + *((uint8_t *)dst + i) = addr_buf[addr_index + i]; + } - case PRI_DMA_PRD_PORT0: - case PRI_DMA_PRD_PORT1: - case PRI_DMA_PRD_PORT2: - case PRI_DMA_PRD_PORT3: - case SEC_DMA_PRD_PORT0: - case SEC_DMA_PRD_PORT1: - case SEC_DMA_PRD_PORT2: - case SEC_DMA_PRD_PORT3: { - uint_t addr_index = port & 0x3; - uint8_t * addr_buf = (uint8_t *)&(drive->dma_prd_addr); - - *(uint8_t *)dst = addr_buf[addr_index]; break; } default: - PrintError("IDE: Invalid DMA Port (%x)\n", port); + PrintError("IDE: Invalid DMA Port (%s)\n", dma_port_to_str(port_offset)); return -1; } - PrintDebug("IDE: Reading DMA Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)dst); + PrintDebug("\tval=%x\n", *(uint32_t *)dst); return length; } @@ -487,6 +597,23 @@ static int write_cmd_port(ushort_t port, void * src, uint_t length, struct vm_de 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) + // Common is that bit0=DMA enable + // If valid the drive raises an interrupt, if not it aborts. + + // Do some checking here... + + channel->status.busy = 0; + channel->status.write_fault = 0; + channel->status.error = 0; + channel->status.ready = 1; + channel->status.seek_complete = 1; + + ide_raise_irq(dev, channel); + break; default: PrintError("Unimplemented IDE command (%x)\n", channel->cmd_reg); return -1; @@ -667,7 +794,6 @@ static int write_port_std(ushort_t port, void * src, uint_t length, struct vm_de PrintDebug("IDE: Writing Standard Port %x (%s) (val=%x)\n", port, io_port_to_str(port), *(uint8_t *)src); - switch (port) { // reset and interrupt enable case PRI_CTRL_PORT: @@ -744,10 +870,9 @@ static int read_port_std(ushort_t port, void * dst, uint_t length, struct vm_dev PrintError("Invalid Read length on IDE port %x\n", port); return -1; } - + PrintDebug("IDE: Reading Standard Port %x (%s)\n", port, io_port_to_str(port)); - if ((port == PRI_ADDR_REG_PORT) || (port == SEC_ADDR_REG_PORT)) { // unused, return 0xff @@ -836,9 +961,7 @@ static void init_drive(struct ide_drive * drive) { drive->transfer_length = 0; memset(drive->data_buf, 0, sizeof(drive->data_buf)); - drive->dma_cmd.val = 0; - drive->dma_status.val = 0; - drive->dma_prd_addr = 0; + drive->private_data = NULL; drive->cd_ops = NULL; @@ -854,18 +977,23 @@ static void init_channel(struct ide_channel * channel) { channel->ctrl_reg.val = 0x08; + channel->dma_cmd.val = 0; + channel->dma_status.val = 0; + channel->dma_prd_addr = 0; + channel->dma_tbl_index = 0; + for (i = 0; i < 2; i++) { init_drive(&(channel->drives[i])); } } -/* + static int pci_config_update(struct pci_device * pci_dev, uint_t reg_num, int length) { - PrintError("IDE does not handle PCI config updates\n"); - return -1; + PrintDebug("Interupt register (Dev=%s), irq=%d\n", pci_dev->name, pci_dev->config_header.intr_line); + + return 0; } -*/ static int init_ide_state(struct vm_device * dev) { struct ide_internal * ide = (struct ide_internal *)(dev->private_data); @@ -885,13 +1013,19 @@ static int init_ide_state(struct vm_device * dev) { bars[4].type = PCI_BAR_IO; - bars[4].default_base_port = PRI_DMA_CMD_PORT + (i * 0x8); + bars[4].default_base_port = PRI_DEFAULT_DMA_PORT + (i * 0x8); bars[4].num_ports = 8; - bars[4].io_read = read_dma_port; - bars[4].io_write = write_dma_port; + + if (i == 0) { + bars[4].io_read = read_pri_dma_port; + bars[4].io_write = write_pri_dma_port; + } else { + bars[4].io_read = read_sec_dma_port; + bars[4].io_write = write_sec_dma_port; + } pci_dev = v3_pci_register_device(ide->pci, PCI_STD_DEVICE, 0, "V3_IDE", -1, bars, - NULL, NULL, NULL, dev); + pci_config_update, NULL, NULL, dev); if (pci_dev == NULL) { PrintError("Failed to register IDE BUS %d with PCI\n", i); @@ -905,6 +1039,9 @@ static int init_ide_state(struct vm_device * dev) { pci_dev->config_header.revision = 0x8f07; pci_dev->config_header.subclass = 0x01; pci_dev->config_header.class = 0x01; + + pci_dev->config_header.intr_line = PRI_DEFAULT_IRQ + i; + pci_dev->config_header.intr_pin = 1; } @@ -943,8 +1080,6 @@ static int init_ide(struct vm_device * dev) { } - - v3_dev_hook_io(dev, PRI_DATA_PORT, &ide_read_data_port, &write_data_port); v3_dev_hook_io(dev, PRI_FEATURES_PORT, @@ -993,36 +1128,6 @@ static int init_ide(struct vm_device * dev) { v3_dev_hook_io(dev, PRI_ADDR_REG_PORT, &read_port_std, &write_port_std); - - /* - - v3_dev_hook_io(dev, PRI_DMA_CMD_PORT, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, PRI_DMA_STATUS_PORT, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, PRI_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - - - v3_dev_hook_io(dev, SEC_DMA_CMD_PORT, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, SEC_DMA_STATUS_PORT, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - v3_dev_hook_io(dev, SEC_DMA_PRD_PORT0, - &read_dma_port, &write_dma_port); - */ return 0; } diff --git a/palacios/src/devices/pci.c b/palacios/src/devices/pci.c index 964cd48..14ad96b 100644 --- a/palacios/src/devices/pci.c +++ b/palacios/src/devices/pci.c @@ -355,16 +355,18 @@ static inline int is_cfg_reg_writable(uchar_t header_type, int reg_num) { static int bar_update(struct pci_device * pci, int bar_num, uint32_t new_val) { struct v3_pci_bar * bar = &(pci->bar[bar_num]); - PrintError("Updating BAR Register (Dev=%s) (bar=%d) (val=%x)\n", - pci->name, bar_num, new_val); + PrintError("Updating BAR Register (Dev=%s) (bar=%d) (old_val=%x) (new_val=%x)\n", + pci->name, bar_num, bar->val, new_val); switch (bar->type) { case PCI_BAR_IO: { int i = 0; + + PrintError("\tRehooking %d IO ports from base %x to %x\n", + bar->num_ports, PCI_IO_BASE(bar->val), PCI_IO_BASE(new_val)); // only do this if pci device is enabled.... for (i = 0; i < bar->num_ports; i++) { - PrintDebug("Rehooking IO Port %x\n", PCI_IO_BASE(bar->val) + i); v3_dev_unhook_io(pci->vm_dev, PCI_IO_BASE(bar->val) + i); @@ -379,7 +381,6 @@ static int bar_update(struct pci_device * pci, int bar_num, uint32_t new_val) { case PCI_BAR_NONE: { PrintError("Reprogramming an unsupported BAR register (Dev=%s) (bar=%d) (val=%x)\n", pci->name, bar_num, new_val); - bar->val = new_val; break; } default: @@ -421,27 +422,33 @@ static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_d for (i = 0; i < length; i++) { uint_t cur_reg = reg_num + i; - + if (is_cfg_reg_writable(pci_dev->config_header.header_type, cur_reg)) { pci_dev->config_space[cur_reg] = *(uint8_t *)((uint8_t *)src + i); if ((cur_reg >= 0x10) && (cur_reg < 0x28)) { - // BAR Reg - int bar_reg = (cur_reg & ~0x3) - 0x10; + // BAR Register Update + int bar_reg = ((cur_reg & ~0x3) - 0x10) / 4; pci_dev->bar_update_flag = 1; pci_dev->bar[bar_reg].updated = 1; - PrintDebug("Updating BAR register\n"); + // PrintDebug("Updating BAR register %d\n", bar_reg); } else if ((cur_reg >= 0x30) && (cur_reg < 0x34)) { + // Extension ROM update + pci_dev->ext_rom_update_flag = 1; } else if (cur_reg == 0x04) { // COMMAND update uint8_t command = *((uint8_t *)src + i); + PrintError("command update for %s old=%x new=%x\n", + pci_dev->name, + pci_dev->config_space[cur_reg],command); + pci_dev->config_space[cur_reg] = command; - + if (pci_dev->cmd_update) { pci_dev->cmd_update(pci_dev, (command & 0x01), (command & 0x02)); } @@ -464,6 +471,7 @@ static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_d int bar_offset = 0x10 + 4 * i; *(uint32_t *)(pci_dev->config_space + bar_offset) &= pci_dev->bar[i].mask; + // check special flags.... // bar_update if (bar_update(pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) { @@ -670,6 +678,7 @@ static inline int init_bars(struct pci_device * pci_dev) { return -1; } else if (pci_dev->bar[i].type == PCI_BAR_NONE) { pci_dev->bar[i].val = 0x00000000; + pci_dev->bar[i].mask = 0x00000000; // This ensures that all updates will be dropped *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val; } else { PrintError("Invalid BAR type for bar #%d\n", i); @@ -691,7 +700,7 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci, int (*config_update)(struct pci_device * pci_dev, uint_t reg_num, int length), int (*cmd_update)(struct pci_device *pci_dev, uchar_t io_enabled, uchar_t mem_enabled), int (*ext_rom_update)(struct pci_device * pci_dev), - void * private_data) { + struct vm_device * dev) { struct pci_internal * pci_state = (struct pci_internal *)pci->private_data; struct pci_bus * bus = &(pci_state->bus_list[bus_num]); @@ -739,14 +748,13 @@ struct pci_device * v3_pci_register_device(struct vm_device * pci, pci_dev->dev_num = dev_num; strncpy(pci_dev->name, name, sizeof(pci_dev->name)); - pci_dev->vm_dev = pci; + pci_dev->vm_dev = dev; // register update callbacks pci_dev->config_update = config_update; pci_dev->cmd_update = cmd_update; pci_dev->ext_rom_update = ext_rom_update; - pci_dev->priv_data = private_data; //copy bars