Messages in this thread | | | Date | Wed, 13 Mar 2024 09:14:59 +0800 | Subject | Re: [PATCH v3 2/2] kvm/cpuid: set proper GuestPhysBits in CPUID.0x80000008 | From | Xiaoyao Li <> |
| |
On 3/13/2024 9:06 AM, Tao Su wrote: > On Mon, Mar 11, 2024 at 11:41:17AM +0100, Gerd Hoffmann wrote: >> The AMD 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 below. Hardware always returns zero >> here. >> >> Use the GuestPhysBits field to communicate the max addressable GPA to >> the guest. Typically this is identical to the max effective GPA, except >> in case the CPU supports MAXPHYADDR > 48 but does not support 5-level >> TDP. >> >> GuestPhysBits is set only in case TDP is enabled, otherwise it is left >> at zero. >> >> GuestPhysBits will be used by the guest firmware to make sure resources >> like PCI bars are mapped into the addressable GPA. >> >> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> >> --- >> arch/x86/kvm/mmu.h | 2 ++ >> arch/x86/kvm/cpuid.c | 31 +++++++++++++++++++++++++++++-- >> arch/x86/kvm/mmu/mmu.c | 5 +++++ >> 3 files changed, 36 insertions(+), 2 deletions(-) >> >> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h >> index 60f21bb4c27b..b410a227c601 100644 >> --- a/arch/x86/kvm/mmu.h >> +++ b/arch/x86/kvm/mmu.h >> @@ -100,6 +100,8 @@ static inline u8 kvm_get_shadow_phys_bits(void) >> return boot_cpu_data.x86_phys_bits; >> } >> >> +u8 kvm_mmu_get_max_tdp_level(void); >> + >> void kvm_mmu_set_mmio_spte_mask(u64 mmio_value, u64 mmio_mask, u64 access_mask); >> void kvm_mmu_set_me_spte_mask(u64 me_value, u64 me_mask); >> void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only); >> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c >> index c638b5fb2144..cd627dead9ce 100644 >> --- a/arch/x86/kvm/cpuid.c >> +++ b/arch/x86/kvm/cpuid.c >> @@ -1221,8 +1221,22 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) >> entry->eax = entry->ebx = entry->ecx = 0; >> break; >> case 0x80000008: { >> + /* >> + * GuestPhysAddrSize (EAX[23:16]) is intended for software >> + * use. >> + * >> + * KVM's ABI is to report the effective MAXPHYADDR for the >> + * guest in PhysAddrSize (phys_as), and the maximum >> + * *addressable* GPA in GuestPhysAddrSize (g_phys_as). >> + * >> + * GuestPhysAddrSize is valid if and only if TDP is enabled, >> + * in which case the max GPA that can be addressed by KVM may >> + * be less than the max GPA that can be legally generated by >> + * the guest, e.g. if MAXPHYADDR>48 but the CPU doesn't >> + * support 5-level TDP. >> + */ >> unsigned int virt_as = max((entry->eax >> 8) & 0xff, 48U); >> - unsigned int phys_as; >> + unsigned int phys_as, g_phys_as; >> >> if (!tdp_enabled) { >> /* >> @@ -1232,11 +1246,24 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) >> * for memory encryption affect shadow paging, too. >> */ >> phys_as = boot_cpu_data.x86_phys_bits; >> + g_phys_as = 0; >> } else { >> + /* >> + * If TDP is enabled, the effective guest MAXPHYADDR >> + * is the same as the raw bare metal MAXPHYADDR, as >> + * reductions to HPAs don't affect GPAs. The max >> + * addressable GPA is the same as the max effective >> + * GPA, except that it's capped at 48 bits if 5-level >> + * TDP isn't supported (hardware processes bits 51:48 >> + * only when walking the fifth level page table). >> + */ >> phys_as = entry->eax & 0xff; >> + g_phys_as = phys_as; >> + if (kvm_mmu_get_max_tdp_level() < 5) >> + g_phys_as = min(g_phys_as, 48); >> } >> >> - entry->eax = phys_as | (virt_as << 8); >> + entry->eax = phys_as | (virt_as << 8) | (g_phys_as << 16); > > When g_phys_as==phys_as, I would suggest advertising g_phys_as==0, > otherwise application can easily know whether it is in a VM, I’m > concerned this could be abused by application.
IMO, this should be protected by userspace VMM, e.g., QEMU to set actual g_phys_as. On KVM side, KVM only reports the capability to userspace.
>> entry->ecx &= ~(GENMASK(31, 16) | GENMASK(11, 8)); >> entry->edx = 0; >> cpuid_entry_override(entry, CPUID_8000_0008_EBX); >> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c >> index 2d6cdeab1f8a..ffd32400fd8c 100644 >> --- a/arch/x86/kvm/mmu/mmu.c >> +++ b/arch/x86/kvm/mmu/mmu.c >> @@ -5267,6 +5267,11 @@ static inline int kvm_mmu_get_tdp_level(struct kvm_vcpu *vcpu) >> return max_tdp_level; >> } >> >> +u8 kvm_mmu_get_max_tdp_level(void) >> +{ >> + return tdp_root_level ? tdp_root_level : max_tdp_level; >> +} >> + >> static union kvm_mmu_page_role >> kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu, >> union kvm_cpu_role cpu_role) >> -- >> 2.44.0 >> >> >
| |