Skip to content

Commit b628cb5

Browse files
kraxelsean-jc
authored andcommitted
KVM: x86: Advertise max mappable GPA in CPUID.0x80000008.GuestPhysBits
Use the GuestPhysBits field in CPUID.0x80000008 to communicate the max mappable GPA to userspace, i.e. the max GPA that is addressable by the CPU itself. Typically this is identical to the max effective GPA, except in the case where the CPU supports MAXPHYADDR > 48 but does not support 5-level TDP (the CPU consults bits 51:48 of the GPA only when walking the fifth level TDP page table entry). Enumerating the max mappable GPA via CPUID will allow guest firmware to map resources like PCI bars in the highest possible address space, while ensuring that the GPA is addressable by the CPU. Without precise knowledge about the max mappable GPA, the guest must assume that 5-level paging is unsupported and thus restrict its mappings to the lower 48 bits. Advertise the max mappable GPA via KVM_GET_SUPPORTED_CPUID as userspace doesn't have easy access to whether or not 5-level paging is supported, and to play nice with userspace VMMs that reflect the supported CPUID directly into the guest. AMD's APM (3.35) defines GuestPhysBits (EAX[23:16]) as: Maximum guest physical address size in bits. This number applies only to guests using nested paging. When this field is zero, refer to the PhysAddrSize field for the maximum guest physical address size. Tom Lendacky confirmed that the purpose of GuestPhysBits is software use and KVM can use it as described above. Real hardware always returns zero. Leave GuestPhysBits as '0' when TDP is disabled in order to comply with the APM's statement that GuestPhysBits "applies only to guest using nested paging". As above, guest firmware will likely create suboptimal mappings, but that is a very minor issue and not a functional concern. Signed-off-by: Gerd Hoffmann <[email protected]> Reviewed-by: Xiaoyao Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] [sean: massage changelog] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 6f5c960 commit b628cb5

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

arch/x86/kvm/cpuid.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,8 +1231,22 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
12311231
entry->eax = entry->ebx = entry->ecx = 0;
12321232
break;
12331233
case 0x80000008: {
1234+
/*
1235+
* GuestPhysAddrSize (EAX[23:16]) is intended for software
1236+
* use.
1237+
*
1238+
* KVM's ABI is to report the effective MAXPHYADDR for the
1239+
* guest in PhysAddrSize (phys_as), and the maximum
1240+
* *addressable* GPA in GuestPhysAddrSize (g_phys_as).
1241+
*
1242+
* GuestPhysAddrSize is valid if and only if TDP is enabled,
1243+
* in which case the max GPA that can be addressed by KVM may
1244+
* be less than the max GPA that can be legally generated by
1245+
* the guest, e.g. if MAXPHYADDR>48 but the CPU doesn't
1246+
* support 5-level TDP.
1247+
*/
12341248
unsigned int virt_as = max((entry->eax >> 8) & 0xff, 48U);
1235-
unsigned int phys_as;
1249+
unsigned int phys_as, g_phys_as;
12361250

12371251
/*
12381252
* If TDP (NPT) is disabled use the adjusted host MAXPHYADDR as
@@ -1241,15 +1255,23 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
12411255
* paging, too.
12421256
*
12431257
* If TDP is enabled, use the raw bare metal MAXPHYADDR as
1244-
* reductions to the HPAs do not affect GPAs.
1258+
* reductions to the HPAs do not affect GPAs. The max
1259+
* addressable GPA is the same as the max effective GPA, except
1260+
* that it's capped at 48 bits if 5-level TDP isn't supported
1261+
* (hardware processes bits 51:48 only when walking the fifth
1262+
* level page table).
12451263
*/
12461264
if (!tdp_enabled) {
12471265
phys_as = boot_cpu_data.x86_phys_bits;
1266+
g_phys_as = 0;
12481267
} else {
12491268
phys_as = entry->eax & 0xff;
1269+
g_phys_as = phys_as;
1270+
if (kvm_mmu_get_max_tdp_level() < 5)
1271+
g_phys_as = min(g_phys_as, 48);
12501272
}
12511273

1252-
entry->eax = phys_as | (virt_as << 8);
1274+
entry->eax = phys_as | (virt_as << 8) | (g_phys_as << 16);
12531275
entry->ecx &= ~(GENMASK(31, 16) | GENMASK(11, 8));
12541276
entry->edx = 0;
12551277
cpuid_entry_override(entry, CPUID_8000_0008_EBX);

arch/x86/kvm/mmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static inline u8 kvm_get_shadow_phys_bits(void)
100100
return boot_cpu_data.x86_phys_bits;
101101
}
102102

103+
u8 kvm_mmu_get_max_tdp_level(void);
104+
103105
void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask);
104106
void kvm_mmu_set_me_spte_mask(u64 me_value, u64 me_mask);
105107
void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only);

arch/x86/kvm/mmu/mmu.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5322,6 +5322,11 @@ static inline int kvm_mmu_get_tdp_level(struct kvm_vcpu *vcpu)
53225322
return max_tdp_level;
53235323
}
53245324

5325+
u8 kvm_mmu_get_max_tdp_level(void)
5326+
{
5327+
return tdp_root_level ? tdp_root_level : max_tdp_level;
5328+
}
5329+
53255330
static union kvm_mmu_page_role
53265331
kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu,
53275332
union kvm_cpu_role cpu_role)

0 commit comments

Comments
 (0)