static int data_port_read(ushort_t port, void * dst, uint_t length, struct vm_device * vmdev) {
struct pci_internal * pci_state = (struct pci_internal *)(vmdev->private_data);
struct pci_device * pci_dev = NULL;
- uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
+ uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3);
int i;
if (pci_state->addr_reg.bus_num != 0) {
int i = 0;
for (i = 0; i < length; i++) {
- *(uint8_t *)dst = 0xff;
+ *((uint8_t *)dst + i) = 0xff;
}
return length;
}
-static int bar_update(struct pci_device * pci, int bar_num) {
- PrintError("Bar Updates not handled (bar=%d)\n", bar_num);
- return -1;
+static int bar_update(struct pci_device * pci, int bar_num, uint32_t new_val) {
+ struct v3_pci_bar * bar = &(pci->bar[bar_num]);
+
+ PrintDebug("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;
+
+ PrintDebug("\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++) {
+
+ v3_dev_unhook_io(pci->vm_dev, PCI_IO_BASE(bar->val) + i);
+
+ v3_dev_hook_io(pci->vm_dev, PCI_IO_BASE(new_val) + i,
+ bar->io_read, bar->io_write);
+ }
+
+ bar->val = new_val;
+
+ break;
+ }
+ case PCI_BAR_NONE: {
+ PrintDebug("Reprogramming an unsupported BAR register (Dev=%s) (bar=%d) (val=%x)\n",
+ pci->name, bar_num, new_val);
+ break;
+ }
+ default:
+ PrintError("Invalid Bar Reg updated (bar=%d)\n", bar_num);
+ return -1;
+ }
+
+ return 0;
}
static int data_port_write(ushort_t port, void * src, uint_t length, struct vm_device * vmdev) {
struct pci_internal * pci_state = (struct pci_internal *)vmdev->private_data;
struct pci_device * pci_dev = NULL;
- uint_t reg_num = pci_state->addr_reg.reg_num + (port & 0x3);
+ uint_t reg_num = (pci_state->addr_reg.reg_num << 2) + (port & 0x3);
int i;
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));
}
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) == -1) {
+ if (bar_update(pci_dev, i, *(uint32_t *)(pci_dev->config_space + bar_offset)) == -1) {
PrintError("PCI Device %s: Bar update Error Bar=%d\n", pci_dev->name, i);
return -1;
}
if (pci_dev->bar[i].type == PCI_BAR_IO) {
int j = 0;
pci_dev->bar[i].mask = (~((pci_dev->bar[i].num_ports) - 1)) | 0x01;
-
- *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask;
- *(uint32_t *)(pci_dev->config_space + bar_offset) |= 0x00000001;
+
+ pci_dev->bar[i].val = pci_dev->bar[i].default_base_port & pci_dev->bar[i].mask;
+ pci_dev->bar[i].val |= 0x00000001;
for (j = 0; j < pci_dev->bar[i].num_ports; j++) {
// hook IO
}
}
+ *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val;
+
} else if (pci_dev->bar[i].type == PCI_BAR_MEM32) {
pci_dev->bar[i].mask = ~((pci_dev->bar[i].num_pages << 12) - 1);
pci_dev->bar[i].mask |= 0xf; // preserve the configuration flags
- *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask;
+ pci_dev->bar[i].val = pci_dev->bar[i].default_base_addr & pci_dev->bar[i].mask;
// hook memory
if (pci_dev->bar[i].mem_read) {
*/
} else {
// set the prefetchable flag...
- *(uint8_t *)(pci_dev->config_space + bar_offset) |= 0x00000008;
+ pci_dev->bar[i].val |= 0x00000008;
}
+
+ *(uint32_t *)(pci_dev->config_space + bar_offset) = pci_dev->bar[i].val;
+
} else if (pci_dev->bar[i].type == PCI_BAR_MEM16) {
PrintError("16 Bit memory ranges not supported (reg: %d)\n", i);
return -1;
} else if (pci_dev->bar[i].type == PCI_BAR_NONE) {
- *(uint32_t *)(pci_dev->config_space + bar_offset) = 0x00000000;
+ 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);
return -1;
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]);
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