Skip to content

Commit 7ea3457

Browse files
committed
KVM: x86: Replace guts of "governed" features with comprehensive cpu_caps
Replace the internals of the governed features framework with a more comprehensive "guest CPU capabilities" implementation, i.e. with a guest version of kvm_cpu_caps. Keep the skeleton of governed features around for now as vmx_adjust_sec_exec_control() relies on detecting governed features to do the right thing for XSAVES, and switching all guest feature queries to guest_cpu_cap_has() requires subtle and non-trivial changes, i.e. is best done as a standalone change. Tracking *all* guest capabilities that KVM cares will allow excising the poorly named "governed features" framework, and effectively optimizes all KVM queries of guest capabilities, i.e. doesn't require making a subjective decision as to whether or not a feature is worth "governing", and doesn't require adding the code to do so. The cost of tracking all features is currently 92 bytes per vCPU on 64-bit kernels: 100 bytes for cpu_caps versus 8 bytes for governed_features. That cost is well worth paying even if the only benefit was eliminating the "governed features" terminology. And practically speaking, the real cost is zero unless those 92 bytes pushes the size of vcpu_vmx or vcpu_svm into a new order-N allocation, and if that happens there are better ways to reduce the footprint of kvm_vcpu_arch, e.g. making the PMU and/or MTRR state separate allocations. Suggested-by: Maxim Levitsky <[email protected]> Reviewed-by: Binbin Wu <[email protected]> Reviewed-by: Maxim Levitsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 2c5e168 commit 7ea3457

File tree

4 files changed

+45
-42
lines changed

4 files changed

+45
-42
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,23 @@ struct kvm_queued_exception {
739739
bool has_payload;
740740
};
741741

742+
/*
743+
* Hardware-defined CPUID leafs that are either scattered by the kernel or are
744+
* unknown to the kernel, but need to be directly used by KVM. Note, these
745+
* word values conflict with the kernel's "bug" caps, but KVM doesn't use those.
746+
*/
747+
enum kvm_only_cpuid_leafs {
748+
CPUID_12_EAX = NCAPINTS,
749+
CPUID_7_1_EDX,
750+
CPUID_8000_0007_EDX,
751+
CPUID_8000_0022_EAX,
752+
CPUID_7_2_EDX,
753+
CPUID_24_0_EBX,
754+
NR_KVM_CPU_CAPS,
755+
756+
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS,
757+
};
758+
742759
struct kvm_vcpu_arch {
743760
/*
744761
* rip and regs accesses must go through
@@ -857,23 +874,20 @@ struct kvm_vcpu_arch {
857874
bool is_amd_compatible;
858875

859876
/*
860-
* FIXME: Drop this macro and use KVM_NR_GOVERNED_FEATURES directly
861-
* when "struct kvm_vcpu_arch" is no longer defined in an
862-
* arch/x86/include/asm header. The max is mostly arbitrary, i.e.
863-
* can be increased as necessary.
864-
*/
865-
#define KVM_MAX_NR_GOVERNED_FEATURES BITS_PER_LONG
866-
867-
/*
868-
* Track whether or not the guest is allowed to use features that are
869-
* governed by KVM, where "governed" means KVM needs to manage state
870-
* and/or explicitly enable the feature in hardware. Typically, but
871-
* not always, governed features can be used by the guest if and only
872-
* if both KVM and userspace want to expose the feature to the guest.
877+
* cpu_caps holds the effective guest capabilities, i.e. the features
878+
* the vCPU is allowed to use. Typically, but not always, features can
879+
* be used by the guest if and only if both KVM and userspace want to
880+
* expose the feature to the guest.
881+
*
882+
* A common exception is for virtualization holes, i.e. when KVM can't
883+
* prevent the guest from using a feature, in which case the vCPU "has"
884+
* the feature regardless of what KVM or userspace desires.
885+
*
886+
* Note, features that don't require KVM involvement in any way are
887+
* NOT enforced/sanitized by KVM, i.e. are taken verbatim from the
888+
* guest CPUID provided by userspace.
873889
*/
874-
struct {
875-
DECLARE_BITMAP(enabled, KVM_MAX_NR_GOVERNED_FEATURES);
876-
} governed_features;
890+
u32 cpu_caps[NR_KVM_CPU_CAPS];
877891

878892
u64 reserved_gpa_bits;
879893
int maxphyaddr;

arch/x86/kvm/cpuid.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
360360
struct kvm_cpuid_entry2 *best;
361361
bool allow_gbpages;
362362

363-
BUILD_BUG_ON(KVM_NR_GOVERNED_FEATURES > KVM_MAX_NR_GOVERNED_FEATURES);
364-
bitmap_zero(vcpu->arch.governed_features.enabled,
365-
KVM_MAX_NR_GOVERNED_FEATURES);
363+
memset(vcpu->arch.cpu_caps, 0, sizeof(vcpu->arch.cpu_caps));
366364

367365
kvm_update_cpuid_runtime(vcpu);
368366

@@ -446,17 +444,26 @@ u64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu)
446444
static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
447445
int nent)
448446
{
447+
u32 vcpu_caps[NR_KVM_CPU_CAPS];
449448
int r;
450449

451450
/*
452451
* Swap the existing (old) entries with the incoming (new) entries in
453452
* order to massage the new entries, e.g. to account for dynamic bits
454453
* that KVM controls, without clobbering the current guest CPUID, which
455454
* KVM needs to preserve in order to unwind on failure.
455+
*
456+
* Similarly, save the vCPU's current cpu_caps so that the capabilities
457+
* can be updated alongside the CPUID entries when performing runtime
458+
* updates. Full initialization is done if and only if the vCPU hasn't
459+
* run, i.e. only if userspace is potentially changing CPUID features.
456460
*/
457461
swap(vcpu->arch.cpuid_entries, e2);
458462
swap(vcpu->arch.cpuid_nent, nent);
459463

464+
memcpy(vcpu_caps, vcpu->arch.cpu_caps, sizeof(vcpu_caps));
465+
BUILD_BUG_ON(sizeof(vcpu_caps) != sizeof(vcpu->arch.cpu_caps));
466+
460467
/*
461468
* KVM does not correctly handle changing guest CPUID after KVM_RUN, as
462469
* MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
@@ -497,6 +504,7 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
497504
return 0;
498505

499506
err:
507+
memcpy(vcpu->arch.cpu_caps, vcpu_caps, sizeof(vcpu_caps));
500508
swap(vcpu->arch.cpuid_entries, e2);
501509
swap(vcpu->arch.cpuid_nent, nent);
502510
return r;

arch/x86/kvm/cpuid.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,9 @@ static __always_inline bool kvm_is_governed_feature(unsigned int x86_feature)
241241
static __always_inline void guest_cpu_cap_set(struct kvm_vcpu *vcpu,
242242
unsigned int x86_feature)
243243
{
244-
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
244+
unsigned int x86_leaf = __feature_leaf(x86_feature);
245245

246-
__set_bit(kvm_governed_feature_index(x86_feature),
247-
vcpu->arch.governed_features.enabled);
246+
vcpu->arch.cpu_caps[x86_leaf] |= __feature_bit(x86_feature);
248247
}
249248

250249
static __always_inline void guest_cpu_cap_check_and_set(struct kvm_vcpu *vcpu,
@@ -257,10 +256,9 @@ static __always_inline void guest_cpu_cap_check_and_set(struct kvm_vcpu *vcpu,
257256
static __always_inline bool guest_cpu_cap_has(struct kvm_vcpu *vcpu,
258257
unsigned int x86_feature)
259258
{
260-
BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
259+
unsigned int x86_leaf = __feature_leaf(x86_feature);
261260

262-
return test_bit(kvm_governed_feature_index(x86_feature),
263-
vcpu->arch.governed_features.enabled);
261+
return vcpu->arch.cpu_caps[x86_leaf] & __feature_bit(x86_feature);
264262
}
265263

266264
static inline bool kvm_vcpu_is_legal_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)

arch/x86/kvm/reverse_cpuid.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,6 @@
66
#include <asm/cpufeature.h>
77
#include <asm/cpufeatures.h>
88

9-
/*
10-
* Hardware-defined CPUID leafs that are either scattered by the kernel or are
11-
* unknown to the kernel, but need to be directly used by KVM. Note, these
12-
* word values conflict with the kernel's "bug" caps, but KVM doesn't use those.
13-
*/
14-
enum kvm_only_cpuid_leafs {
15-
CPUID_12_EAX = NCAPINTS,
16-
CPUID_7_1_EDX,
17-
CPUID_8000_0007_EDX,
18-
CPUID_8000_0022_EAX,
19-
CPUID_7_2_EDX,
20-
CPUID_24_0_EBX,
21-
NR_KVM_CPU_CAPS,
22-
23-
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS,
24-
};
25-
269
/*
2710
* Define a KVM-only feature flag.
2811
*

0 commit comments

Comments
 (0)