[PATCH v3 2/5] ACRN:DM:PCI: Load rom_file and map it into PCI ROMbar


Zhao, Yakui
 

PCI ROM is the firmware specific to PCI device and it is provided by
the device vendor. The PCI rom resides in 0x30 offset of PCI config space.
This can be used to check whether the PCI rom exists. And when it exists,
it can load the firmware from the addr that is obtained from ROM bar addr.

For the user-vm, it will try to load the rom_file for the given PCI device and
enable the VM to access the firmware that is defined in rom_file.

BTW: The emulated rom_file is converted from efi image by using EfiRom. It has
no dependency on the ROM bar of physical PCI devices. Of course if the physical
PCI devices supports the ROM bar, the rom_file can also be dumped from the PCI
rom.

Now this is limited to PCI display device.

V2->V3: Add the function of pci_load_rombar/pci_release_rombar to handle the
rombar in course of passthrough_init/deinit.

Signed-off-by: Zhao Yakui <yakui.zhao@...>
---
devicemodel/hw/pci/passthrough.c | 124 +++++++++++++++++++++++++++++++
devicemodel/include/passthru.h | 4 +-
2 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/devicemodel/hw/pci/passthrough.c b/devicemodel/hw/pci/passthrough.c
index 4c227aea9..c8675621c 100644
--- a/devicemodel/hw/pci/passthrough.c
+++ b/devicemodel/hw/pci/passthrough.c
@@ -174,6 +174,113 @@ static inline int ptdev_msix_pba_bar(struct passthru_dev *ptdev)
return ptdev->dev->msix.pba_bar;
}

+static void
+pci_load_rombar(struct vmctx *ctx, struct pci_vdev *dev, char *rom_file)
+{
+ FILE *fp;
+ int file_size, rom_size;
+ uint8_t rom_header[4];
+ size_t read_size;
+ char *rom_buffer;
+ struct passthru_dev *ptdev;
+ uint64_t bar_addr;
+
+ /*
+ * It is unnecessary to check dev & dev->arg again as it is already
+ * checked in caller.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+ fp = fopen(rom_file, "rb");
+ if (fp == NULL) {
+ pr_warn("Fail to open %s rom_file\n", rom_file);
+ ptdev->need_rombar = false;
+ } else {
+ rom_buffer = NULL;
+ read_size = fread(rom_header, 1, 4, fp);
+ file_size = 0;
+ if (read_size != 4)
+ pr_warn("%s: Fail to read rom_header\n", __func__);
+
+ if ((rom_header[0] == 0x55) && (rom_header[1] == 0xaa)) {
+ /* check file size */
+ fseek(fp, 0, SEEK_END);
+ file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if (file_size > (2048 * 1024)) {
+ pr_warn("Rom file is too big.\n");
+ ptdev->need_rombar = false;
+ }
+ } else {
+ pr_warn("Incorrect Rom file format\n");
+ ptdev->need_rombar = false;
+ }
+ if (ptdev->need_rombar) {
+ rom_size = ALIGN_UP(file_size, 4096);
+ /* round up to a power of 2 */
+ if ((rom_size & (rom_size - 1)) != 0)
+ rom_size = 1UL << fls(rom_size);
+
+ if (posix_memalign((void **)&rom_buffer, 4096, rom_size) == 0) {
+ ptdev->rom_buffer = rom_buffer;
+ read_size = fread(rom_buffer, 1, file_size, fp);
+ if (read_size != file_size) {
+ pr_warn("%s: read size is different with rom_size\n", __func__);
+ }
+ pci_emul_alloc_bar(dev, PCI_ROMBAR, PCIBAR_ROM, rom_size);
+
+ /* Setup the EPT mapping for ROM bar */
+ bar_addr = dev->bar[PCI_ROMBAR].addr;
+ if (vm_map_memseg_vma(ctx, rom_size, bar_addr,
+ (uint64_t)rom_buffer, PROT_READ)) {
+ pr_err("%s: Fail to map ROM bar\n", __func__);
+ free(rom_buffer);
+ ptdev->need_rombar = false;
+ dev->bar[PCI_ROMBAR].addr = 0;
+ dev->bar[PCI_ROMBAR].size = 0;
+ } else {
+ /* Update the enable flag */
+ pci_set_cfgdata32(dev, PCIR_BIOS, (bar_addr | PCIM_BIOS_ENABLE));
+ }
+ } else {
+ ptdev->need_rombar = false;
+ pr_err("Fail to allocate buffer for rom_file\n");
+ }
+ }
+ fclose(fp);
+ }
+ return;
+}
+
+static void
+pci_release_rombar(struct vmctx *ctx, struct pci_vdev *dev)
+{
+ int error;
+ struct acrn_vm_memmap rom_unmap;
+ struct passthru_dev *ptdev;
+
+ /*
+ * As it is already checked in caller, it is unnecessary to
+ * check dev and dev->arg again.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+
+ rom_unmap.user_vm_pa = dev->bar[PCI_ROMBAR].addr;
+ rom_unmap.len = dev->bar[PCI_ROMBAR].size;
+ /* remove the EPT mapping for PCI_rombar.
+ * WA: Use ACRN_MEMMAP_MMIO to del the mapping
+ */
+ rom_unmap.type = ACRN_MEMMAP_MMIO;
+ error = ioctl(ctx->fd, ACRN_IOCTL_UNSET_MEMSEG, &rom_unmap);
+ if (error) {
+ pr_err("%s: unset_memseg ioctl() returned an error: %s\n",
+ __func__, errormsg(errno));
+ }
+ free(ptdev->rom_buffer);
+ ptdev->rom_buffer = NULL;
+ ptdev->need_rombar = false;
+ return;
+}
+
static int
cfginitbar(struct vmctx *ctx, struct passthru_dev *ptdev)
{
@@ -600,6 +707,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
struct acrn_pcidev pcidev = {};
uint16_t vendor = 0, device = 0;
uint8_t class = 0;
+ char rom_file[256];

ptdev = NULL;
error = -EINVAL;
@@ -615,6 +723,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
return -EINVAL;
}

+ memset(rom_file, 0, sizeof(rom_file));
while ((opt = strsep(&opts, ",")) != NULL) {
if (!strncmp(opt, "keep_gsi", 8))
keep_gsi = true;
@@ -711,6 +820,16 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
error = ACRN_PTDEV_IRQ_MSI;
}

+ if (class != 3) {
+ if (ptdev->need_rombar) {
+ pr_warn("Virtual PCI rom is only supported for GPU device\n");
+ ptdev->need_rombar = false;
+ }
+ }
+
+ if (ptdev->need_rombar)
+ pci_load_rombar(ctx, dev, rom_file);
+
if (is_intel_graphics_dev(dev)) {
if (is_rtvm) {
pr_err("%s RTVM doesn't support GVT-D.", __func__);
@@ -805,6 +924,11 @@ passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
vm_reset_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq, false);
}

+ if (ptdev->need_rombar) {
+ pci_release_rombar(ctx, dev);
+ ptdev->need_rombar = false;
+ }
+
if (ptdev)
phys_bdf = ptdev->phys_bdf;

diff --git a/devicemodel/include/passthru.h b/devicemodel/include/passthru.h
index 7f693913e..655a17000 100644
--- a/devicemodel/include/passthru.h
+++ b/devicemodel/include/passthru.h
@@ -16,7 +16,7 @@

struct passthru_dev {
struct pci_vdev *dev;
- struct pcibar bar[PCI_BARMAX + 1];
+ struct pcibar bar[PCI_BARMAX + 2];
struct {
int capoff;
} msi;
@@ -36,6 +36,8 @@ struct passthru_dev {
*/
bool need_reset;
bool d3hot_reset;
+ bool need_rombar;
+ char *rom_buffer;
bool (*has_virt_pcicfg_regs)(int offset);
};

--
2.25.1


Yu Wang
 

On Tue, Sep 20, 2022 at 09:56:49AM +0800, Zhao Yakui wrote:
PCI ROM is the firmware specific to PCI device and it is provided by
the device vendor. The PCI rom resides in 0x30 offset of PCI config space.
This can be used to check whether the PCI rom exists. And when it exists,
it can load the firmware from the addr that is obtained from ROM bar addr.

For the user-vm, it will try to load the rom_file for the given PCI device and
enable the VM to access the firmware that is defined in rom_file.

BTW: The emulated rom_file is converted from efi image by using EfiRom. It has
no dependency on the ROM bar of physical PCI devices. Of course if the physical
PCI devices supports the ROM bar, the rom_file can also be dumped from the PCI
rom.

Now this is limited to PCI display device.

V2->V3: Add the function of pci_load_rombar/pci_release_rombar to handle the
rombar in course of passthrough_init/deinit.

Signed-off-by: Zhao Yakui <yakui.zhao@...>
---
devicemodel/hw/pci/passthrough.c | 124 +++++++++++++++++++++++++++++++
devicemodel/include/passthru.h | 4 +-
2 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/devicemodel/hw/pci/passthrough.c b/devicemodel/hw/pci/passthrough.c
index 4c227aea9..c8675621c 100644
--- a/devicemodel/hw/pci/passthrough.c
+++ b/devicemodel/hw/pci/passthrough.c
@@ -174,6 +174,113 @@ static inline int ptdev_msix_pba_bar(struct passthru_dev *ptdev)
return ptdev->dev->msix.pba_bar;
}

+static void
+pci_load_rombar(struct vmctx *ctx, struct pci_vdev *dev, char *rom_file)
Let's keep the verb-object fashion.

load_pci_rombar

Others are LGTM.

Acked-by: Wang, Yu1 <yu1.wang@...>

+{
+ FILE *fp;
+ int file_size, rom_size;
+ uint8_t rom_header[4];
+ size_t read_size;
+ char *rom_buffer;
+ struct passthru_dev *ptdev;
+ uint64_t bar_addr;
+
+ /*
+ * It is unnecessary to check dev & dev->arg again as it is already
+ * checked in caller.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+ fp = fopen(rom_file, "rb");
+ if (fp == NULL) {
+ pr_warn("Fail to open %s rom_file\n", rom_file);
+ ptdev->need_rombar = false;
+ } else {
+ rom_buffer = NULL;
+ read_size = fread(rom_header, 1, 4, fp);
+ file_size = 0;
+ if (read_size != 4)
+ pr_warn("%s: Fail to read rom_header\n", __func__);
+
+ if ((rom_header[0] == 0x55) && (rom_header[1] == 0xaa)) {
+ /* check file size */
+ fseek(fp, 0, SEEK_END);
+ file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if (file_size > (2048 * 1024)) {
+ pr_warn("Rom file is too big.\n");
+ ptdev->need_rombar = false;
+ }
+ } else {
+ pr_warn("Incorrect Rom file format\n");
+ ptdev->need_rombar = false;
+ }
+ if (ptdev->need_rombar) {
+ rom_size = ALIGN_UP(file_size, 4096);
+ /* round up to a power of 2 */
+ if ((rom_size & (rom_size - 1)) != 0)
+ rom_size = 1UL << fls(rom_size);
+
+ if (posix_memalign((void **)&rom_buffer, 4096, rom_size) == 0) {
+ ptdev->rom_buffer = rom_buffer;
+ read_size = fread(rom_buffer, 1, file_size, fp);
+ if (read_size != file_size) {
+ pr_warn("%s: read size is different with rom_size\n", __func__);
+ }
+ pci_emul_alloc_bar(dev, PCI_ROMBAR, PCIBAR_ROM, rom_size);
+
+ /* Setup the EPT mapping for ROM bar */
+ bar_addr = dev->bar[PCI_ROMBAR].addr;
+ if (vm_map_memseg_vma(ctx, rom_size, bar_addr,
+ (uint64_t)rom_buffer, PROT_READ)) {
+ pr_err("%s: Fail to map ROM bar\n", __func__);
+ free(rom_buffer);
+ ptdev->need_rombar = false;
+ dev->bar[PCI_ROMBAR].addr = 0;
+ dev->bar[PCI_ROMBAR].size = 0;
+ } else {
+ /* Update the enable flag */
+ pci_set_cfgdata32(dev, PCIR_BIOS, (bar_addr | PCIM_BIOS_ENABLE));
+ }
+ } else {
+ ptdev->need_rombar = false;
+ pr_err("Fail to allocate buffer for rom_file\n");
+ }
+ }
+ fclose(fp);
+ }
+ return;
+}
+
+static void
+pci_release_rombar(struct vmctx *ctx, struct pci_vdev *dev)
+{
+ int error;
+ struct acrn_vm_memmap rom_unmap;
+ struct passthru_dev *ptdev;
+
+ /*
+ * As it is already checked in caller, it is unnecessary to
+ * check dev and dev->arg again.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+
+ rom_unmap.user_vm_pa = dev->bar[PCI_ROMBAR].addr;
+ rom_unmap.len = dev->bar[PCI_ROMBAR].size;
+ /* remove the EPT mapping for PCI_rombar.
+ * WA: Use ACRN_MEMMAP_MMIO to del the mapping
+ */
+ rom_unmap.type = ACRN_MEMMAP_MMIO;
+ error = ioctl(ctx->fd, ACRN_IOCTL_UNSET_MEMSEG, &rom_unmap);
+ if (error) {
+ pr_err("%s: unset_memseg ioctl() returned an error: %s\n",
+ __func__, errormsg(errno));
+ }
+ free(ptdev->rom_buffer);
+ ptdev->rom_buffer = NULL;
+ ptdev->need_rombar = false;
+ return;
+}
+
static int
cfginitbar(struct vmctx *ctx, struct passthru_dev *ptdev)
{
@@ -600,6 +707,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
struct acrn_pcidev pcidev = {};
uint16_t vendor = 0, device = 0;
uint8_t class = 0;
+ char rom_file[256];

ptdev = NULL;
error = -EINVAL;
@@ -615,6 +723,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
return -EINVAL;
}

+ memset(rom_file, 0, sizeof(rom_file));
while ((opt = strsep(&opts, ",")) != NULL) {
if (!strncmp(opt, "keep_gsi", 8))
keep_gsi = true;
@@ -711,6 +820,16 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
error = ACRN_PTDEV_IRQ_MSI;
}

+ if (class != 3) {
+ if (ptdev->need_rombar) {
+ pr_warn("Virtual PCI rom is only supported for GPU device\n");
+ ptdev->need_rombar = false;
+ }
+ }
+
+ if (ptdev->need_rombar)
+ pci_load_rombar(ctx, dev, rom_file);
+
if (is_intel_graphics_dev(dev)) {
if (is_rtvm) {
pr_err("%s RTVM doesn't support GVT-D.", __func__);
@@ -805,6 +924,11 @@ passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
vm_reset_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq, false);
}

+ if (ptdev->need_rombar) {
+ pci_release_rombar(ctx, dev);
+ ptdev->need_rombar = false;
+ }
+
if (ptdev)
phys_bdf = ptdev->phys_bdf;

diff --git a/devicemodel/include/passthru.h b/devicemodel/include/passthru.h
index 7f693913e..655a17000 100644
--- a/devicemodel/include/passthru.h
+++ b/devicemodel/include/passthru.h
@@ -16,7 +16,7 @@

struct passthru_dev {
struct pci_vdev *dev;
- struct pcibar bar[PCI_BARMAX + 1];
+ struct pcibar bar[PCI_BARMAX + 2];
struct {
int capoff;
} msi;
@@ -36,6 +36,8 @@ struct passthru_dev {
*/
bool need_reset;
bool d3hot_reset;
+ bool need_rombar;
+ char *rom_buffer;
bool (*has_virt_pcicfg_regs)(int offset);
};

--
2.25.1


Zhao, Yakui
 

On 2022/9/20 9:47, Yu Wang wrote:
On Tue, Sep 20, 2022 at 09:56:49AM +0800, Zhao Yakui wrote:
PCI ROM is the firmware specific to PCI device and it is provided by
the device vendor. The PCI rom resides in 0x30 offset of PCI config space.
This can be used to check whether the PCI rom exists. And when it exists,
it can load the firmware from the addr that is obtained from ROM bar addr.

For the user-vm, it will try to load the rom_file for the given PCI device and
enable the VM to access the firmware that is defined in rom_file.

BTW: The emulated rom_file is converted from efi image by using EfiRom. It has
no dependency on the ROM bar of physical PCI devices. Of course if the physical
PCI devices supports the ROM bar, the rom_file can also be dumped from the PCI
rom.

Now this is limited to PCI display device.

V2->V3: Add the function of pci_load_rombar/pci_release_rombar to handle the
rombar in course of passthrough_init/deinit.

Signed-off-by: Zhao Yakui <yakui.zhao@...>
---
devicemodel/hw/pci/passthrough.c | 124 +++++++++++++++++++++++++++++++
devicemodel/include/passthru.h | 4 +-
2 files changed, 127 insertions(+), 1 deletion(-)

diff --git a/devicemodel/hw/pci/passthrough.c b/devicemodel/hw/pci/passthrough.c
index 4c227aea9..c8675621c 100644
--- a/devicemodel/hw/pci/passthrough.c
+++ b/devicemodel/hw/pci/passthrough.c
@@ -174,6 +174,113 @@ static inline int ptdev_msix_pba_bar(struct passthru_dev *ptdev)
return ptdev->dev->msix.pba_bar;
}
+static void
+pci_load_rombar(struct vmctx *ctx, struct pci_vdev *dev, char *rom_file)
Let's keep the verb-object fashion.
load_pci_rombar
Others are LGTM.
Thanks for the review.
It will be changed in PR.

Acked-by: Wang, Yu1 <yu1.wang@...>

+{
+ FILE *fp;
+ int file_size, rom_size;
+ uint8_t rom_header[4];
+ size_t read_size;
+ char *rom_buffer;
+ struct passthru_dev *ptdev;
+ uint64_t bar_addr;
+
+ /*
+ * It is unnecessary to check dev & dev->arg again as it is already
+ * checked in caller.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+ fp = fopen(rom_file, "rb");
+ if (fp == NULL) {
+ pr_warn("Fail to open %s rom_file\n", rom_file);
+ ptdev->need_rombar = false;
+ } else {
+ rom_buffer = NULL;
+ read_size = fread(rom_header, 1, 4, fp);
+ file_size = 0;
+ if (read_size != 4)
+ pr_warn("%s: Fail to read rom_header\n", __func__);
+
+ if ((rom_header[0] == 0x55) && (rom_header[1] == 0xaa)) {
+ /* check file size */
+ fseek(fp, 0, SEEK_END);
+ file_size = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if (file_size > (2048 * 1024)) {
+ pr_warn("Rom file is too big.\n");
+ ptdev->need_rombar = false;
+ }
+ } else {
+ pr_warn("Incorrect Rom file format\n");
+ ptdev->need_rombar = false;
+ }
+ if (ptdev->need_rombar) {
+ rom_size = ALIGN_UP(file_size, 4096);
+ /* round up to a power of 2 */
+ if ((rom_size & (rom_size - 1)) != 0)
+ rom_size = 1UL << fls(rom_size);
+
+ if (posix_memalign((void **)&rom_buffer, 4096, rom_size) == 0) {
+ ptdev->rom_buffer = rom_buffer;
+ read_size = fread(rom_buffer, 1, file_size, fp);
+ if (read_size != file_size) {
+ pr_warn("%s: read size is different with rom_size\n", __func__);
+ }
+ pci_emul_alloc_bar(dev, PCI_ROMBAR, PCIBAR_ROM, rom_size);
+
+ /* Setup the EPT mapping for ROM bar */
+ bar_addr = dev->bar[PCI_ROMBAR].addr;
+ if (vm_map_memseg_vma(ctx, rom_size, bar_addr,
+ (uint64_t)rom_buffer, PROT_READ)) {
+ pr_err("%s: Fail to map ROM bar\n", __func__);
+ free(rom_buffer);
+ ptdev->need_rombar = false;
+ dev->bar[PCI_ROMBAR].addr = 0;
+ dev->bar[PCI_ROMBAR].size = 0;
+ } else {
+ /* Update the enable flag */
+ pci_set_cfgdata32(dev, PCIR_BIOS, (bar_addr | PCIM_BIOS_ENABLE));
+ }
+ } else {
+ ptdev->need_rombar = false;
+ pr_err("Fail to allocate buffer for rom_file\n");
+ }
+ }
+ fclose(fp);
+ }
+ return;
+}
+
+static void
+pci_release_rombar(struct vmctx *ctx, struct pci_vdev *dev)
+{
+ int error;
+ struct acrn_vm_memmap rom_unmap;
+ struct passthru_dev *ptdev;
+
+ /*
+ * As it is already checked in caller, it is unnecessary to
+ * check dev and dev->arg again.
+ */
+ ptdev = (struct passthru_dev *) dev->arg;
+
+ rom_unmap.user_vm_pa = dev->bar[PCI_ROMBAR].addr;
+ rom_unmap.len = dev->bar[PCI_ROMBAR].size;
+ /* remove the EPT mapping for PCI_rombar.
+ * WA: Use ACRN_MEMMAP_MMIO to del the mapping
+ */
+ rom_unmap.type = ACRN_MEMMAP_MMIO;
+ error = ioctl(ctx->fd, ACRN_IOCTL_UNSET_MEMSEG, &rom_unmap);
+ if (error) {
+ pr_err("%s: unset_memseg ioctl() returned an error: %s\n",
+ __func__, errormsg(errno));
+ }
+ free(ptdev->rom_buffer);
+ ptdev->rom_buffer = NULL;
+ ptdev->need_rombar = false;
+ return;
+}
+
static int
cfginitbar(struct vmctx *ctx, struct passthru_dev *ptdev)
{
@@ -600,6 +707,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
struct acrn_pcidev pcidev = {};
uint16_t vendor = 0, device = 0;
uint8_t class = 0;
+ char rom_file[256];
ptdev = NULL;
error = -EINVAL;
@@ -615,6 +723,7 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
return -EINVAL;
}
+ memset(rom_file, 0, sizeof(rom_file));
while ((opt = strsep(&opts, ",")) != NULL) {
if (!strncmp(opt, "keep_gsi", 8))
keep_gsi = true;
@@ -711,6 +820,16 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
error = ACRN_PTDEV_IRQ_MSI;
}
+ if (class != 3) {
+ if (ptdev->need_rombar) {
+ pr_warn("Virtual PCI rom is only supported for GPU device\n");
+ ptdev->need_rombar = false;
+ }
+ }
+
+ if (ptdev->need_rombar)
+ pci_load_rombar(ctx, dev, rom_file);
+
if (is_intel_graphics_dev(dev)) {
if (is_rtvm) {
pr_err("%s RTVM doesn't support GVT-D.", __func__);
@@ -805,6 +924,11 @@ passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
vm_reset_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq, false);
}
+ if (ptdev->need_rombar) {
+ pci_release_rombar(ctx, dev);
+ ptdev->need_rombar = false;
+ }
+
if (ptdev)
phys_bdf = ptdev->phys_bdf;
diff --git a/devicemodel/include/passthru.h b/devicemodel/include/passthru.h
index 7f693913e..655a17000 100644
--- a/devicemodel/include/passthru.h
+++ b/devicemodel/include/passthru.h
@@ -16,7 +16,7 @@
struct passthru_dev {
struct pci_vdev *dev;
- struct pcibar bar[PCI_BARMAX + 1];
+ struct pcibar bar[PCI_BARMAX + 2];
struct {
int capoff;
} msi;
@@ -36,6 +36,8 @@ struct passthru_dev {
*/
bool need_reset;
bool d3hot_reset;
+ bool need_rombar;
+ char *rom_buffer;
bool (*has_virt_pcicfg_regs)(int offset);
};
--
2.25.1