Add a highmem-mmio-base property to override the base of the virt machine's high PCIe MMIO window, alongside the existing highmem-mmio-size:
-machine virt,highmem-mmio-base=<addr>,highmem-mmio-size=<size> Some PCI devices require MMIO resources to be placed within a specific address range that cannot be satisfied by the default placement. The configured base is validated to be non-zero, aligned to highmem-mmio-size, non-overlapping with the existing high memory layout, and within the configured physical address space. Signed-off-by: Tushar Dave <[email protected]> --- hw/arm/virt.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index cb9cd2d25c..47653b8753 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2515,9 +2515,34 @@ static void virt_set_high_memmap(VirtMachineState *vms, for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) { region_enabled = virt_get_high_memmap_enabled(vms, i); - region_base = ROUND_UP(base, extended_memmap[i].size); region_size = extended_memmap[i].size; + if (i == VIRT_HIGH_PCIE_MMIO && extended_memmap[i].base) { + region_base = extended_memmap[i].base; + + if (region_base < base) { + error_report("highmem-mmio-base 0x%"PRIx64" overlaps prior " + "high memory layout (must be >= 0x%"PRIx64")", + region_base, base); + exit(1); + } + if (region_base % region_size != 0) { + error_report("highmem-mmio-base 0x%"PRIx64" must be " + "aligned to highmem-mmio-size 0x%"PRIx64, + region_base, region_size); + exit(1); + } + if (region_base + region_size > BIT_ULL(pa_bits)) { + error_report("highmem-mmio-base + highmem-mmio-size " + "[0x%"PRIx64", 0x%"PRIx64") exceeds %d-bit PA " + "space", region_base, + region_base + region_size, pa_bits); + exit(1); + } + } else { + region_base = ROUND_UP(base, region_size); + } + vms->memmap[i].base = region_base; vms->memmap[i].size = region_size; @@ -3418,6 +3443,33 @@ static void virt_set_highmem_mmio_size(Object *obj, Visitor *v, extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size; } +static void virt_get_highmem_mmio_base(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + uint64_t base = extended_memmap[VIRT_HIGH_PCIE_MMIO].base; + + visit_type_size(v, name, &base, errp); +} + +static void virt_set_highmem_mmio_base(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + uint64_t base; + + if (!visit_type_size(v, name, &base, errp)) { + return; + } + + if (base == 0) { + error_setg(errp, "highmem-mmio-base cannot be 0"); + return; + } + + extended_memmap[VIRT_HIGH_PCIE_MMIO].base = base; +} + static char *virt_get_msi(Object *obj, Error **errp) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -4285,6 +4337,14 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data) "Set the high memory region size " "for PCI MMIO"); + object_class_property_add(oc, "highmem-mmio-base", "size", + virt_get_highmem_mmio_base, + virt_set_highmem_mmio_base, + NULL, NULL); + object_class_property_set_description(oc, "highmem-mmio-base", + "Set the high memory region base " + "for PCI MMIO"); + object_class_property_add(oc, "virtio-mmio-transports", "uint8", virt_get_virtio_transports, virt_set_virtio_transports, -- 2.34.1
