diff --git a/devicemodel/hw/pci/core.c b/devicemodel/hw/pci/core.c index 190e1ecc6..1b400add8 100644 --- a/devicemodel/hw/pci/core.c +++ b/devicemodel/hw/pci/core.c @@ -594,9 +594,11 @@ memen(struct pci_vdev *dev) * the address range decoded by the BAR register. */ static void -update_bar_address(struct pci_vdev *dev, uint64_t addr, int idx, int type) +update_bar_address(struct vmctx *ctx, struct pci_vdev *dev, uint64_t addr, + int idx, int type) { bool decode; + uint64_t orig_addr = dev->bar[idx].addr; if (dev->bar[idx].type == PCIBAR_IO) decode = porten(dev); @@ -625,6 +627,10 @@ update_bar_address(struct pci_vdev *dev, uint64_t addr, int idx, int type) if (decode) register_bar(dev, idx); + + /* update bar mapping */ + if (dev->dev_ops->vdev_update_bar_map) + dev->dev_ops->vdev_update_bar_map(ctx, dev, idx, orig_addr); } int @@ -2136,7 +2142,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func, * Register the new BAR value for interception */ if (addr != dev->bar[idx].addr) { - update_bar_address(dev, addr, idx, + update_bar_address(ctx, dev, addr, idx, PCIBAR_IO); } break; @@ -2144,7 +2150,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func, addr = bar = *eax & mask; bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32; if (addr != dev->bar[idx].addr) { - update_bar_address(dev, addr, idx, + update_bar_address(ctx, dev, addr, idx, PCIBAR_MEM32); } break; @@ -2153,7 +2159,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func, bar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 | PCIM_BAR_MEM_PREFETCH; if (addr != (uint32_t)dev->bar[idx].addr) { - update_bar_address(dev, addr, idx, + update_bar_address(ctx, dev, addr, idx, PCIBAR_MEM64); } break; @@ -2163,7 +2169,7 @@ pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func, addr = ((uint64_t)*eax << 32) & mask; bar = addr >> 32; if (bar != dev->bar[idx - 1].addr >> 32) { - update_bar_address(dev, addr, idx - 1, + update_bar_address(ctx, dev, addr, idx - 1, PCIBAR_MEMHI64); } break; diff --git a/devicemodel/hw/pci/passthrough.c b/devicemodel/hw/pci/passthrough.c index f60efb0e3..00e19ef54 100644 --- a/devicemodel/hw/pci/passthrough.c +++ b/devicemodel/hw/pci/passthrough.c @@ -938,6 +938,39 @@ passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts) vm_unassign_ptdev(ctx, bus, slot, func); } +static void +passthru_update_bar_map(struct vmctx *ctx, struct pci_vdev *dev, + int idx, uint64_t orig_addr) +{ + struct passthru_dev *ptdev; + + if (!dev->arg) { + warnx("%s: passthru_dev is NULL", __func__); + return; + } + + ptdev = (struct passthru_dev *)dev->arg; + + if (ptdev->bar[idx].size == 0 || + idx == ptdev_msix_table_bar(ptdev) || + ptdev->bar[idx].type == PCIBAR_IO) + return; + + if (dev->bar[idx].addr + dev->bar[idx].size > PCI_EMUL_MEMLIMIT64 || + orig_addr + dev->bar[idx].size > PCI_EMUL_MEMLIMIT64) + return; + + vm_unmap_ptdev_mmio(ctx, ptdev->sel.bus, + ptdev->sel.dev, ptdev->sel.func, + orig_addr, ptdev->bar[idx].size, + ptdev->bar[idx].addr); + + vm_map_ptdev_mmio(ctx, ptdev->sel.bus, + ptdev->sel.dev, ptdev->sel.func, + dev->bar[idx].addr, ptdev->bar[idx].size, + ptdev->bar[idx].addr); +} + /* bind pin info for pass-through device */ static void passthru_bind_irq(struct vmctx *ctx, struct pci_vdev *dev) @@ -1767,6 +1800,7 @@ struct pci_vdev_ops passthru = { .vdev_barwrite = passthru_write, .vdev_barread = passthru_read, .vdev_phys_access = passthru_bind_irq, + .vdev_update_bar_map = passthru_update_bar_map, .vdev_write_dsdt = passthru_write_dsdt, }; DEFINE_PCI_DEVTYPE(passthru); diff --git a/devicemodel/include/pci_core.h b/devicemodel/include/pci_core.h index bbe55fd7d..da68ade26 100644 --- a/devicemodel/include/pci_core.h +++ b/devicemodel/include/pci_core.h @@ -64,6 +64,11 @@ struct pci_vdev_ops { /* ops related to physical resources */ void (*vdev_phys_access)(struct vmctx *ctx, struct pci_vdev *dev); + /* update BAR map callback */ + void (*vdev_update_bar_map)(struct vmctx *ctx, + struct pci_vdev *dev, int idx, + uint64_t orig_addr); + /* config space read/write callbacks */ int (*vdev_cfgwrite)(struct vmctx *ctx, int vcpu, struct pci_vdev *pi, int offset,