On Wed, 20 May 2026 18:56:32 +0900
Akihiko Odaki <[email protected]> wrote:
> Remove the lower bound of the Highmem IO Regions' addresses for the
> latest machine version to increase the chance to fit the regions in the
> PA space.
>
> The lower bound was especially problematic when using virt-install on
> Apple M2. virt-install 5.0.0 adds multiple pcie-root-port devices that
it looks like with this patch everything would move down,
with 'small' but, VIRT_HIGH_PCIE_MMIO that still won't fit into M2 PA and
will get disabled.
Is it intended (perhaps it should be mentioned in patch)
> require sufficient space in the ECAM region. However, the Highmem ECAM
> region did not fit in the limited PA space on the hardware, and the ECAM
> region size was limited to 16 MiB. If virt-install had added more than
> 16 devices to the root bridge, the region overflowed, which prevented
> edk2-stable202505 from scanning PCI devices, including the boot disk,
> causing boot failures.
>
> Ideally, a virtual machine with more than 16 devices added to the root
> bridge should just work so that users and management layers do not have
> to care whether they use constrained hardware.
>
> The base address of the Highmem IO Regions was fixed when commit
> f90747c4e8fb ("hw/arm/virt: GICv3 DT node with one or two redistributor
> regions") added the first Highmem IO Region. Later, commit 957e32cffa57
> ("hw/arm/virt: Dynamic memory map depending on RAM requirements")
> allowed moving the Highmem IO Regions to higher addresses to accommodate
> RAM more than 255 GiB, but the lower bound remained to keep the legacy
> memory map.
>
> Remove the lower bound for the latest machine version to accommodate
> more devices with the root bridge. Keeping the lower bound for the old
> machine versions ensures the compatibility is still maintained.
>
> The hardcoded memory map in tests/qtest/libqos/generic-pcihost.c is also
> updated.
>
> Signed-off-by: Akihiko Odaki <[email protected]>
> Reviewed-by: Eric Auger <[email protected]>
> ---
> include/hw/arm/virt.h | 1 +
> hw/arm/virt.c | 17 +++++++++++------
> tests/qtest/libqos/generic-pcihost.c | 2 +-
> 3 files changed, 13 insertions(+), 7 deletions(-)
>
> diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
> index 3ba33b4bd274..6c8ba8f3185b 100644
> --- a/include/hw/arm/virt.h
> +++ b/include/hw/arm/virt.h
> @@ -142,6 +142,7 @@ typedef enum VirtGICType {
>
> struct VirtMachineClass {
> MachineClass parent;
> + hwaddr min_highmem_base;
> bool no_tcg_its;
> bool no_highmem_compact;
> bool no_kvm_steal_time;
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index b090233893c5..78a85a966ad7 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -229,8 +229,7 @@ static const MemMapEntry base_memmap[] = {
> * Highmem IO Regions: This memory map is floating, located after the RAM.
> * Each MemMapEntry base (GPA) will be dynamically computed, depending on the
> * top of the RAM, so that its base get the same alignment as the size,
> - * ie. a 512GiB entry will be aligned on a 512GiB boundary. If there is
> - * less than 256GiB of RAM, the floating area starts at the 256GiB mark.
> + * ie. a 512GiB entry will be aligned on a 512GiB boundary.
> * Note the extended_memmap is sized so that it eventually also includes the
> * base_memmap entries (VIRT_HIGH_GIC_REDIST2 index is greater than the last
> * index of base_memmap).
> @@ -2479,6 +2478,7 @@ static void virt_set_high_memmap(VirtMachineState *vms,
> static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
> {
> MachineState *ms = MACHINE(vms);
> + VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
> hwaddr base, device_memory_base, device_memory_size, memtop;
> int i;
>
> @@ -2505,8 +2505,7 @@ static void virt_set_memmap(VirtMachineState *vms, int
> pa_bits)
> /*
> * We compute the base of the high IO region depending on the
> * amount of initial and device memory. The device memory start/size
> - * is aligned on 1GiB. We never put the high IO region below 256GiB
> - * so that if maxram_size is < 255GiB we keep the legacy memory map.
> + * is aligned on 1GiB.
> * The device region size assumes 1GiB page max alignment per slot.
> */
> device_memory_base =
> @@ -2524,8 +2523,8 @@ static void virt_set_memmap(VirtMachineState *vms, int
> pa_bits)
> error_report("maxmem/slots too huge");
> exit(EXIT_FAILURE);
> }
> - if (base < vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES) {
> - base = vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES;
> + if (base < vmc->min_highmem_base) {
> + base = vmc->min_highmem_base;
> }
>
> /* We know for sure that at least the memory fits in the PA space */
> @@ -4367,6 +4366,12 @@ static void virt_machine_11_0_options(MachineClass *mc)
> virt_machine_11_1_options(mc);
> compat_props_add(mc->compat_props, hw_compat_11_0, hw_compat_11_0_len);
> vmc->hvf_no_kernel_irqchip_default = true;
> +
> + /*
> + * Do not put the high IO region below 256GiB so that if maxram_size is
> + * < 255GiB we keep the legacy memory map.
> + */
> + vmc->min_highmem_base = base_memmap[VIRT_MEM].base +
> LEGACY_RAMLIMIT_BYTES;
> }
> DEFINE_VIRT_MACHINE(11, 0)
>
> diff --git a/tests/qtest/libqos/generic-pcihost.c
> b/tests/qtest/libqos/generic-pcihost.c
> index b77617524cac..287e8445ec5b 100644
> --- a/tests/qtest/libqos/generic-pcihost.c
> +++ b/tests/qtest/libqos/generic-pcihost.c
> @@ -210,7 +210,7 @@ void qpci_init_generic(QGenericPCIBus *qpci, QTestState
> *qts,
> qpci->bus.pio_limit = 0x10000;
> qpci->bus.mmio_alloc_ptr = 0x10000000;
> qpci->bus.mmio_limit = 0x2eff0000;
> - qpci->ecam_alloc_ptr = 0x4010000000;
> + qpci->ecam_alloc_ptr = 0x90000000;
>
> qpci->obj.get_driver = qpci_generic_get_driver;
> }
>