Skip to content

Commit e592ec6

Browse files
committed
KVM: x86: Initialize guest cpu_caps based on KVM support
Constrain all guest cpu_caps based on KVM support instead of constraining only the few features that KVM _currently_ needs to verify are actually supported by KVM. The intent of cpu_caps is to track what the guest is actually capable of using, not the raw, unfiltered CPUID values that the guest sees. I.e. KVM should always consult it's only support when making decisions based on guest CPUID, and the only reason KVM has historically made the checks opt-in was due to lack of centralized tracking. Suggested-by: Maxim Levitsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent d4b9ff3 commit e592ec6

File tree

4 files changed

+16
-26
lines changed

4 files changed

+16
-26
lines changed

arch/x86/kvm/cpuid.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@ static u32 cpuid_get_reg_unsafe(struct kvm_cpuid_entry2 *entry, u32 reg)
376376
}
377377
}
378378

379+
static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func,
380+
bool include_partially_emulated);
381+
379382
void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
380383
{
381384
struct kvm_lapic *apic = vcpu->arch.apic;
@@ -394,6 +397,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
394397
*/
395398
for (i = 0; i < NR_KVM_CPU_CAPS; i++) {
396399
const struct cpuid_reg cpuid = reverse_cpuid[i];
400+
struct kvm_cpuid_entry2 emulated;
397401

398402
if (!cpuid.function)
399403
continue;
@@ -402,7 +406,16 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
402406
if (!entry)
403407
continue;
404408

405-
vcpu->arch.cpu_caps[i] = cpuid_get_reg_unsafe(entry, cpuid.reg);
409+
cpuid_func_emulated(&emulated, cpuid.function, true);
410+
411+
/*
412+
* A vCPU has a feature if it's supported by KVM and is enabled
413+
* in guest CPUID. Note, this includes features that are
414+
* supported by KVM but aren't advertised to userspace!
415+
*/
416+
vcpu->arch.cpu_caps[i] = kvm_cpu_caps[i] |
417+
cpuid_get_reg_unsafe(&emulated, cpuid.reg);
418+
vcpu->arch.cpu_caps[i] &= cpuid_get_reg_unsafe(entry, cpuid.reg);
406419
}
407420

408421
kvm_update_cpuid_runtime(vcpu);

arch/x86/kvm/cpuid.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,6 @@ static __always_inline void guest_cpu_cap_change(struct kvm_vcpu *vcpu,
264264
guest_cpu_cap_clear(vcpu, x86_feature);
265265
}
266266

267-
static __always_inline void guest_cpu_cap_constrain(struct kvm_vcpu *vcpu,
268-
unsigned int x86_feature)
269-
{
270-
if (!kvm_cpu_cap_has(x86_feature))
271-
guest_cpu_cap_clear(vcpu, x86_feature);
272-
}
273-
274267
static __always_inline bool guest_cpu_cap_has(struct kvm_vcpu *vcpu,
275268
unsigned int x86_feature)
276269
{

arch/x86/kvm/svm/svm.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4406,24 +4406,13 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
44064406
boot_cpu_has(X86_FEATURE_XSAVES) &&
44074407
guest_cpuid_has(vcpu, X86_FEATURE_XSAVE));
44084408

4409-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_NRIPS);
4410-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_TSCRATEMSR);
4411-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_LBRV);
4412-
44134409
/*
44144410
* Intercept VMLOAD if the vCPU model is Intel in order to emulate that
44154411
* VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
44164412
* SVM on Intel is bonkers and extremely unlikely to work).
44174413
*/
44184414
if (guest_cpuid_is_intel_compatible(vcpu))
44194415
guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
4420-
else
4421-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
4422-
4423-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_PAUSEFILTER);
4424-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_PFTHRESHOLD);
4425-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_VGIF);
4426-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_VNMI);
44274416

44284417
svm_recalc_instruction_intercepts(vcpu, svm);
44294418

arch/x86/kvm/vmx/vmx.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7828,15 +7828,10 @@ void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
78287828
* to the guest. XSAVES depends on CR4.OSXSAVE, and CR4.OSXSAVE can be
78297829
* set if and only if XSAVE is supported.
78307830
*/
7831-
if (boot_cpu_has(X86_FEATURE_XSAVE) &&
7832-
guest_cpuid_has(vcpu, X86_FEATURE_XSAVE))
7833-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_XSAVES);
7834-
else
7831+
if (!boot_cpu_has(X86_FEATURE_XSAVE) ||
7832+
!guest_cpuid_has(vcpu, X86_FEATURE_XSAVE))
78357833
guest_cpu_cap_clear(vcpu, X86_FEATURE_XSAVES);
78367834

7837-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_VMX);
7838-
guest_cpu_cap_constrain(vcpu, X86_FEATURE_LAM);
7839-
78407835
vmx_setup_uret_msrs(vmx);
78417836

78427837
if (cpu_has_secondary_exec_ctrls())

0 commit comments

Comments
 (0)