>From 2b5621e0a504c821125d24475ee83d9e1cf24e96 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 26 Jul 2022 09:20:37 -0700 Subject: [PATCH 1/2] KVM: x86: Add CPUID cache for frequent X86_FEATURE_* guest lookups Implement a small "cache" for expediting guest_cpuid_has() lookups of frequently used features. Guest CPUID lookups are slow, especially if the associated leaf has no entry, as KVM uses a linear walk of all CPUID entries to find the associated leaf, e.g. adding a guest_cpuid_has() lookup in the VM-Enter path is slow enough that it shows up on perf traces. Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/cpuid.c | 9 +++++++++ arch/x86/kvm/cpuid.h | 28 ++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index e8281d64a431..8cdb5c46815d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -759,6 +759,7 @@ struct kvm_vcpu_arch { int cpuid_nent; struct kvm_cpuid_entry2 *cpuid_entries; u32 kvm_cpuid_base; + u32 kvm_cpuid_x86_feature_cache; u64 reserved_gpa_bits; int maxphyaddr; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 75dcf7a72605..27b25fdb4335 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -377,6 +377,12 @@ u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu) return rsvd_bits(cpuid_maxphyaddr(vcpu), 63); } +#define kvm_cpuid_cache_update(__vcpu, x86_feature) \ +do { \ + if (__guest_cpuid_has(__vcpu, x86_feature)) \ + (__vcpu)->arch.kvm_cpuid_x86_feature_cache |= BIT(KVM_CACHED_ ## x86_feature); \ +} while (0) + static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2, int nent) { @@ -412,6 +418,9 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2, vcpu->arch.cpuid_entries = e2; vcpu->arch.cpuid_nent = nent; + /* Update the cache before doing anything else. */ + vcpu->arch.kvm_cpuid_x86_feature_cache = 0; + kvm_update_kvm_cpuid_base(vcpu); kvm_vcpu_after_set_cpuid(vcpu); diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index b1658c0de847..49009d16022a 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -85,8 +85,21 @@ static __always_inline u32 *guest_cpuid_get_register(struct kvm_vcpu *vcpu, return __cpuid_entry_get_reg(entry, cpuid.reg); } -static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu, - unsigned int x86_feature) +enum kvm_cpuid_cached_feature { + NR_KVM_CACHED_X86_FEATURES, +}; + +static __always_inline int guest_cpuid_get_cache_bit(unsigned int x86_feature) +{ + int cache_bytes = sizeof((struct kvm_vcpu_arch *)0)->kvm_cpuid_x86_feature_cache; + + BUILD_BUG_ON(NR_KVM_CACHED_X86_FEATURES > cache_bytes * BITS_PER_BYTE); + + return NR_KVM_CACHED_X86_FEATURES; +} + +static __always_inline bool __guest_cpuid_has(struct kvm_vcpu *vcpu, + unsigned int x86_feature) { u32 *reg; @@ -97,6 +110,17 @@ static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu, return *reg & __feature_bit(x86_feature); } +static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu, + unsigned int x86_feature) +{ + int cache_bit = guest_cpuid_get_cache_bit(x86_feature); + + if (cache_bit != NR_KVM_CACHED_X86_FEATURES) + return vcpu->arch.kvm_cpuid_x86_feature_cache & BIT(cache_bit); + + return __guest_cpuid_has(vcpu, x86_feature); +} + static __always_inline void guest_cpuid_clear(struct kvm_vcpu *vcpu, unsigned int x86_feature) { base-commit: 1a4d88a361af4f2e91861d632c6a1fe87a9665c2 -- 2.37.1.455.g008518b4e5-goog