Re: [PATCH v2 7/9] hw/i386: Reserve AMD IOMMU HT GPA range for Hygon
Zhao Liu <[email protected]>
| Newsgroups | org.nongnu.qemu-devel,org.kernel.vger.kvm |
|---|---|
| Message-ID | <[email protected]> |
On Mon, Aug 10, 2026 at 04:29:54PM +0800, Tina Zhang wrote: > Date: Mon, 10 Aug 2026 16:29:54 +0800 > From: Tina Zhang <[email protected]> > Subject: [PATCH v2 7/9] hw/i386: Reserve AMD IOMMU HT GPA range for Hygon > X-Mailer: git-send-email 2.43.7 > > pc_memory_init() avoids the AMD IOMMU HyperTransport range below 1 TiB > only for AMD vCPUs. Dhyana therefore allows RAM, hotplug address space, > or 64-bit PCI MMIO to overlap 0xfd00000000-0xffffffffff. > > Linux supports Dhyana platforms in the AMD IOMMU driver. The driver > reports this range as reserved unless the IOMMU advertises > FEATURE_HT_RANGE_IGNORE. A VFIO device cannot DMA to guest addresses > that QEMU places in the reserved range: VFIO_DMA_MAP may fail with > -EINVAL, or the IOMMU may report an INVALID_DEVICE_REQUEST fault. > > Apply the AMD IOMMU HT GPA layout to Hygon vCPUs. When the possible > address space reaches the reserved range, move RAM above 4 GiB to 1 TiB; > also expose the range as reserved in E820 when the vCPU can address it. > > Changing the GPA layout affects migration, so enable the Hygon behavior > through x-hygon-vendor-abi-fixes. pc-11.0 and older machine types retain > their previous Hygon layout. The existing enforce_amd_1tb_hole setting > continues to preserve the AMD layout of pc/q35 machine types through 7.0. > > Add functional tests for Dhyana with the current q35 machine type and > with pc-q35-11.0 compatibility. > > Signed-off-by: Yanjing Zhou <[email protected]> > Signed-off-by: Tina Zhang <[email protected]> > --- > hw/i386/pc.c | 18 ++++++--- > .../functional/x86_64/test_mem_addr_space.py | 37 +++++++++++++++++++ > 2 files changed, 50 insertions(+), 5 deletions(-) > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > index 2b4e322b2f..04aef6c267 100644 > --- a/hw/i386/pc.c > +++ b/hw/i386/pc.c > @@ -738,6 +738,12 @@ static hwaddr pc_max_used_gpa(PCMachineState *pcms, uint64_t pci_hole64_size) > #define AMD_ABOVE_1TB_START (AMD_HT_END + 1) > #define AMD_HT_SIZE (AMD_ABOVE_1TB_START - AMD_HT_START) > > +static bool x86_cpu_has_amd_iommu_ht_gpa_hole(const X86CPU *cpu) > +{ > + return IS_AMD_CPU(&cpu->env) || > + (IS_HYGON_CPU(&cpu->env) && cpu->hygon_vendor_abi_fixes); > +} > + > void pc_memory_init(PCMachineState *pcms, > MemoryRegion *system_memory, > MemoryRegion *rom_memory, > @@ -762,12 +768,14 @@ void pc_memory_init(PCMachineState *pcms, > linux_boot = (machine->kernel_filename != NULL); > > /* > - * The HyperTransport range close to the 1T boundary is unique to AMD > - * hosts with IOMMUs enabled. Restrict the ram-above-4g relocation > - * to above 1T to AMD vCPUs only. @enforce_amd_1tb_hole is only false in > - * older machine types (<= 7.0) for compatibility purposes. > + * The HyperTransport range close to the 1T boundary is reserved by the > + * AMD IOMMU GPA layout. Apply the ram-above-4g relocation only to vCPUs > + * that use that layout. @enforce_amd_1tb_hole preserves older AMD > + * machine types (<= 7.0), and x-hygon-vendor-abi-fixes preserves older > + * Hygon machine types (<= 11.0). ^^^^^^^ nit: <= 11.1. > */ And x-hygon-vendor-abi-fixes is not here, or maybe we can palce all checks in a single helper... > - if (IS_AMD_CPU(&cpu->env) && pcmc->enforce_amd_1tb_hole) { > + if (x86_cpu_has_amd_iommu_ht_gpa_hole(cpu) && > + pcmc->enforce_amd_1tb_hole) { ...for example: /* * The HyperTransport range close to the 1T boundary is unique to AMD & * Hygon hosts with IOMMUs enabled. Restrict the ram-above-4g relocation * to above 1T to AMD & Hygon vCPUs only. @enforce_amd_1tb_hole is only false * in older machine types (<= 7.0) and @x-hygon-vendor-abi-fixes is false in * machine types (<= 11.1), for compatibility purposes. */ static inline bool x86_cpu_has_iommu_ht_gpa_hole(PCMachineState *pcms, const X86CPU *cpu) { if (!pcmc->enforce_amd_1tb_hole) { return false; } return IS_AMD_CPU(&cpu->env) || (IS_HYGON_CPU(&cpu->env) && cpu->hygon_vendor_abi_fixes); } > /* Bail out if max possible address does not cross HT range */ > if (pc_max_used_gpa(pcms, pci_hole64_size) >= AMD_HT_START) { > x86ms->above_4g_mem_start = AMD_ABOVE_1TB_START; > diff --git a/tests/functional/x86_64/test_mem_addr_space.py b/tests/functional/x86_64/test_mem_addr_space.py > index 61b4a190b4..b80f9acd99 100755 > --- a/tests/functional/x86_64/test_mem_addr_space.py > +++ b/tests/functional/x86_64/test_mem_addr_space.py > @@ -208,6 +208,25 @@ def test_phybits_low_tcg_q35_71_amd(self): > self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1") > self.assertRegex(self.vm.get_log(), r'phys-bits too low') > > + def test_phybits_low_tcg_q35_hygon(self): like q35-7.1 AMD case, I think it's better to record the version in test name: def test_phybits_low_tcg_q35_112_hygon(self): > + """ > + Same as q35-7.1 AMD case except that here we check that Dhyana > + follows the same AMD IOMMU HT reserved GPA range on new machine > + types. > + """ > + self.ensure_64bit_binary() > + self.set_machine('q35') For compatibility checks, it's better to explicitly specify the version: self.set_machine('pc-q35-11.2') > + self.vm.add_args('-S', '-cpu', 'Dhyana,phys-bits=40', > + '-m', '512,slots=1,maxmem=976G', > + '-display', 'none', > + '-object', 'memory-backend-ram,id=mem1,size=1G', > + '-device', 'pc-dimm,id=vm0,memdev=mem1') > + self.vm.set_qmp_monitor(enabled=False) > + self.vm.launch() > + self.vm.wait() > + self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1") > + self.assertRegex(self.vm.get_log(), r'phys-bits too low') > + > def test_phybits_ok_tcg_q35_70_amd(self): > """ > Same as q35-7.0 AMD case except that here we check that QEMU can > @@ -225,6 +244,24 @@ def test_phybits_ok_tcg_q35_70_amd(self): > self.vm.shutdown() > self.assertNotRegex(self.vm.get_log(), r'phys-bits too low') > > + def test_phybits_ok_tcg_q35_110_hygon(self): test_phybits_ok_tcg_q35_111_hygon? > + """ > + Same as q35-7.1 Dhyana case except that here we check that the > + q35-11.0 compatibility setting keeps the old memory layout. q35-11.1. > + """ > + self.ensure_64bit_binary() > + self.set_machine('pc-q35-11.0') self.set_machine('pc-q35-11.1')? Thanks, Zhao