summaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx/vmx.c
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2020-09-23 18:50:46 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2020-09-28 13:57:29 +0200
commitb936d3eb92b7c1258805bebecc7eaac0c8a51b7f (patch)
tree17366cfba22b260da80a4b8cb44987ca1c1ab230 /arch/x86/kvm/vmx/vmx.c
parentKVM: VMX: Rename vmx_*_supported() helpers to cpu_has_vmx_*() (diff)
downloadlinux-b936d3eb92b7c1258805bebecc7eaac0c8a51b7f.tar.xz
linux-b936d3eb92b7c1258805bebecc7eaac0c8a51b7f.zip
KVM: VMX: Unconditionally clear CPUID.INVPCID if !CPUID.PCID
If PCID is not exposed to the guest, clear INVPCID in the guest's CPUID even if the VMCS INVPCID enable is not supported. This will allow consolidating the secondary execution control adjustment code without having to special case INVPCID. Technically, this fixes a bug where !CPUID.PCID && CPUID.INVCPID would result in unexpected guest behavior (#UD instead of #GP/#PF), but KVM doesn't support exposing INVPCID if it's not supported in the VMCS, i.e. such a config is broken/bogus no matter what. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Message-Id: <20200923165048.20486-3-sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx/vmx.c')
-rw-r--r--arch/x86/kvm/vmx/vmx.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 96adc964afed..641e5ef513ae 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4158,16 +4158,22 @@ static void vmx_compute_secondary_exec_control(struct vcpu_vmx *vmx)
}
}
+ /*
+ * Expose INVPCID if and only if PCID is also exposed to the guest.
+ * INVPCID takes a #UD when it's disabled in the VMCS, but a #GP or #PF
+ * if CR4.PCIDE=0. Enumerating CPUID.INVPCID=1 would lead to incorrect
+ * behavior from the guest perspective (it would expect #GP or #PF).
+ */
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_PCID))
+ guest_cpuid_clear(vcpu, X86_FEATURE_INVPCID);
+
if (cpu_has_vmx_invpcid()) {
/* Exposing INVPCID only when PCID is exposed */
bool invpcid_enabled =
- guest_cpuid_has(vcpu, X86_FEATURE_INVPCID) &&
- guest_cpuid_has(vcpu, X86_FEATURE_PCID);
+ guest_cpuid_has(vcpu, X86_FEATURE_INVPCID);
- if (!invpcid_enabled) {
+ if (!invpcid_enabled)
exec_control &= ~SECONDARY_EXEC_ENABLE_INVPCID;
- guest_cpuid_clear(vcpu, X86_FEATURE_INVPCID);
- }
if (nested) {
if (invpcid_enabled)