Add fixed-bar-N properties to PCIDevice to allow the guest address of an individual PCI BAR to be explicitly specified. The properties are available for PCI BARs 0 through 5 and accept QEMU size values, for example fixed-bar-0=0x40000000 or fixed-bar-0=64G.
e.g. -device some-device,fixed-bar-0=<addr>[,fixed-bar-1=<addr>]... During realize, validate that each specified BAR exists and is a memory BAR, and reject fixed BAR configuration for hot-plugged devices. The fixed BAR properties are only supported on machine types that implement fixed BAR placement. Add the `pci_fixed_bar_supported` MachineClass flag to advertise this support, and reject fixed BAR properties on machine types that do not set it. Signed-off-by: Tushar Dave <[email protected]> --- hw/pci/pci.c | 71 +++++++++++++++++++++++++++++++++++++ include/hw/core/boards.h | 3 ++ include/hw/pci/pci_device.h | 7 ++++ 3 files changed, 81 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2d2fe02c68..e9ae0d5648 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -89,6 +89,18 @@ static const Property pci_props[] = { DEFINE_PROP_STRING("romfile", PCIDevice, romfile), DEFINE_PROP_UINT32("romsize", PCIDevice, romsize, UINT32_MAX), DEFINE_PROP_INT32("rombar", PCIDevice, rom_bar, -1), + DEFINE_PROP_SIZE("fixed-bar-0", PCIDevice, fixed_bar_addr[0], + PCI_BAR_UNMAPPED), + DEFINE_PROP_SIZE("fixed-bar-1", PCIDevice, fixed_bar_addr[1], + PCI_BAR_UNMAPPED), + DEFINE_PROP_SIZE("fixed-bar-2", PCIDevice, fixed_bar_addr[2], + PCI_BAR_UNMAPPED), + DEFINE_PROP_SIZE("fixed-bar-3", PCIDevice, fixed_bar_addr[3], + PCI_BAR_UNMAPPED), + DEFINE_PROP_SIZE("fixed-bar-4", PCIDevice, fixed_bar_addr[4], + PCI_BAR_UNMAPPED), + DEFINE_PROP_SIZE("fixed-bar-5", PCIDevice, fixed_bar_addr[5], + PCI_BAR_UNMAPPED), DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present, QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false), DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present, @@ -228,6 +240,58 @@ static void pci_bus_unrealize(BusState *qbus) vmstate_unregister(NULL, &vmstate_pcibus, bus); } +static bool pci_dev_has_fixed_bar(PCIDevice *pci_dev) +{ + int i; + + for (i = 0; i < PCI_NUM_REGIONS - 1; i++) { + if (pci_dev->fixed_bar_addr[i] != PCI_BAR_UNMAPPED) { + return true; + } + } + return false; +} + +static void pci_check_fixed_bars(PCIDevice *pci_dev, Error **errp) +{ + PCIIORegion *r; + int i; + + if (!pci_dev_has_fixed_bar(pci_dev)) { + return; + } + + if (!MACHINE_GET_CLASS(qdev_get_machine())->pci_fixed_bar_supported) { + error_setg(errp, "fixed BAR placement is not supported by this " + "machine type"); + return; + } + + if (DEVICE(pci_dev)->hotplugged) { + error_setg(errp, "fixed BAR placement is not supported on " + "hot-plugged devices"); + return; + } + + for (i = 0; i < PCI_NUM_REGIONS - 1; i++) { + if (pci_dev->fixed_bar_addr[i] == PCI_BAR_UNMAPPED) { + continue; + } + + r = &pci_dev->io_regions[i]; + if (!r->size) { + error_setg(errp, "fixed-bar-%d: bar%d does not exist on %s", + i, i, pci_dev->name); + return; + } + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { + error_setg(errp, "fixed-bar-%d: bar%d on %s is an I/O BAR, " + "not a memory BAR", i, i, pci_dev->name); + return; + } + } +} + static int pcibus_num(PCIBus *bus) { if (pci_bus_is_root(bus)) { @@ -2399,6 +2463,13 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) is_default_rom = true; } + pci_check_fixed_bars(pci_dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + pci_qdev_unrealize(DEVICE(pci_dev)); + return; + } + pci_add_option_rom(pci_dev, is_default_rom, &local_err); if (local_err) { error_propagate(errp, local_err); diff --git a/include/hw/core/boards.h b/include/hw/core/boards.h index d0e4ad9820..8092634eb3 100644 --- a/include/hw/core/boards.h +++ b/include/hw/core/boards.h @@ -242,6 +242,8 @@ typedef struct { * is not needed. * @numa_mem_supported: * true if '--numa node.mem' option is supported and false otherwise + * @pci_fixed_bar_supported: + * true if the machine supports fixed PCI BAR placement and false otherwise * @hotplug_allowed: * If the hook is provided, then it'll be called for each device * hotplug to check whether the device hotplug is allowed. Return @@ -317,6 +319,7 @@ struct MachineClass { bool ignore_boot_device_suffixes; bool nvdimm_supported; bool numa_mem_supported; + bool pci_fixed_bar_supported; bool auto_enable_numa; bool cpu_cluster_has_numa_boundary; SMPCompatProps smp_props; diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h index 5cac6e1688..db4a003ae3 100644 --- a/include/hw/pci/pci_device.h +++ b/include/hw/pci/pci_device.h @@ -187,6 +187,13 @@ struct PCIDevice { uint32_t max_bounce_buffer_size; char *sriov_pf; + + /* + * fixed_bar_addr[N] holds the guest address configured via the + * fixed-bar-N property for memory BAR N. PCI_BAR_UNMAPPED means + * the BAR's address is not fixed. + */ + uint64_t fixed_bar_addr[PCI_NUM_REGIONS - 1]; }; static inline int pci_intx(PCIDevice *pci_dev) -- 2.34.1
