Skip to content

Commit 4276441

Browse files
committed
KVM: x86: Add a framework for enabling KVM-governed x86 features
Introduce yet another X86_FEATURE flag framework to manage and cache KVM governed features (for lack of a better name). "Governed" in this case means that KVM has some level of involvement and/or vested interest in whether or not an X86_FEATURE can be used by the guest. The intent of the framework is twofold: to simplify caching of guest CPUID flags that KVM needs to frequently query, and to add clarity to such caching, e.g. it isn't immediately obvious that SVM's bundle of flags for "optional nested SVM features" track whether or not a flag is exposed to L1. Begrudgingly define KVM_MAX_NR_GOVERNED_FEATURES for the size of the bitmap to avoid exposing governed_features.h in arch/x86/include/asm/, but add a FIXME to call out that it can and should be cleaned up once "struct kvm_vcpu_arch" is no longer expose to the kernel at large. Cc: Zeng Guang <guang.zeng@intel.com> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com> Reviewed-by: Kai Huang <kai.huang@intel.com> Reviewed-by: Yuan Yao <yuan.yao@intel.com> Link: https://lore.kernel.org/r/20230815203653.519297-2-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 392a532 commit 4276441

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,25 @@ struct kvm_vcpu_arch {
831831
struct kvm_cpuid_entry2 *cpuid_entries;
832832
struct kvm_hypervisor_cpuid kvm_cpuid;
833833

834+
/*
835+
* FIXME: Drop this macro and use KVM_NR_GOVERNED_FEATURES directly
836+
* when "struct kvm_vcpu_arch" is no longer defined in an
837+
* arch/x86/include/asm header. The max is mostly arbitrary, i.e.
838+
* can be increased as necessary.
839+
*/
840+
#define KVM_MAX_NR_GOVERNED_FEATURES BITS_PER_LONG
841+
842+
/*
843+
* Track whether or not the guest is allowed to use features that are
844+
* governed by KVM, where "governed" means KVM needs to manage state
845+
* and/or explicitly enable the feature in hardware. Typically, but
846+
* not always, governed features can be used by the guest if and only
847+
* if both KVM and userspace want to expose the feature to the guest.
848+
*/
849+
struct {
850+
DECLARE_BITMAP(enabled, KVM_MAX_NR_GOVERNED_FEATURES);
851+
} governed_features;
852+
834853
u64 reserved_gpa_bits;
835854
int maxphyaddr;
836855

arch/x86/kvm/cpuid.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
313313
struct kvm_lapic *apic = vcpu->arch.apic;
314314
struct kvm_cpuid_entry2 *best;
315315

316+
BUILD_BUG_ON(KVM_NR_GOVERNED_FEATURES > KVM_MAX_NR_GOVERNED_FEATURES);
317+
bitmap_zero(vcpu->arch.governed_features.enabled,
318+
KVM_MAX_NR_GOVERNED_FEATURES);
319+
316320
best = kvm_find_cpuid_entry(vcpu, 1);
317321
if (best && apic) {
318322
if (cpuid_entry_has(best, X86_FEATURE_TSC_DEADLINE_TIMER))

arch/x86/kvm/cpuid.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,50 @@ static __always_inline bool guest_pv_has(struct kvm_vcpu *vcpu,
232232
return vcpu->arch.pv_cpuid.features & (1u << kvm_feature);
233233
}
234234

235+
enum kvm_governed_features {
236+
#define KVM_GOVERNED_FEATURE(x) KVM_GOVERNED_##x,
237+
#include "governed_features.h"
238+
KVM_NR_GOVERNED_FEATURES
239+
};
240+
241+
static __always_inline int kvm_governed_feature_index(unsigned int x86_feature)
242+
{
243+
switch (x86_feature) {
244+
#define KVM_GOVERNED_FEATURE(x) case x: return KVM_GOVERNED_##x;
245+
#include "governed_features.h"
246+
default:
247+
return -1;
248+
}
249+
}
250+
251+
static __always_inline bool kvm_is_governed_feature(unsigned int x86_feature)
252+
{
253+
return kvm_governed_feature_index(x86_feature) >= 0;
254+
}
255+
256+
static __always_inline void kvm_governed_feature_set(struct kvm_vcpu *vcpu,
257+
unsigned int x86_feature)
258+
{
259+
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
260+
261+
__set_bit(kvm_governed_feature_index(x86_feature),
262+
vcpu->arch.governed_features.enabled);
263+
}
264+
265+
static __always_inline void kvm_governed_feature_check_and_set(struct kvm_vcpu *vcpu,
266+
unsigned int x86_feature)
267+
{
268+
if (kvm_cpu_cap_has(x86_feature) && guest_cpuid_has(vcpu, x86_feature))
269+
kvm_governed_feature_set(vcpu, x86_feature);
270+
}
271+
272+
static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu,
273+
unsigned int x86_feature)
274+
{
275+
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
276+
277+
return test_bit(kvm_governed_feature_index(x86_feature),
278+
vcpu->arch.governed_features.enabled);
279+
}
280+
235281
#endif

arch/x86/kvm/governed_features.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#if !defined(KVM_GOVERNED_FEATURE) || defined(KVM_GOVERNED_X86_FEATURE)
3+
BUILD_BUG()
4+
#endif
5+
6+
#define KVM_GOVERNED_X86_FEATURE(x) KVM_GOVERNED_FEATURE(X86_FEATURE_##x)
7+
8+
#undef KVM_GOVERNED_X86_FEATURE
9+
#undef KVM_GOVERNED_FEATURE

0 commit comments

Comments
 (0)