KVM really has no business messing with the vCPU state. Nonetheless, it has become ABI for KVM to adjust certain bits of the VMX entry/exit control MSRs depending on the guest CPUID. Namely, the bits associated with the IA32_PERF_GLOBAL_CTRL and IA32_BNDCFGS MSRs were conditionally enabled if the guest CPUID allows for it. Allow userspace to opt-out of changes to VMX control MSRs by adding a new KVM quirk. Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Oliver Upton <oupton@xxxxxxxxxx> --- Documentation/virt/kvm/api.rst | 24 ++++++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/include/uapi/asm/kvm.h | 11 ++++++----- arch/x86/kvm/vmx/vmx.c | 3 +++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 8f7240e79cc0..9bb79ca9de89 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7127,6 +7127,30 @@ The valid bits in cap.args[0] are: Additionally, when this quirk is disabled, KVM clears CPUID.01H:ECX[bit 3] if IA32_MISC_ENABLE[bit 18] is cleared. + + KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS By default, KVM adjusts the values of + IA32_VMX_TRUE_ENTRY_CTLS and + IA32_VMX_TRUE_EXIT_CTLS MSRs under the + following conditions: + + - If CPUID.07H:EBX[bit 14] (MPX) is set, KVM + sets IA32_VMX_TRUE_ENTRY_CTLS[bit 48] + ('load IA32_BNDCFGS') and + IA32_VMX_TRUE_EXIT_CTLS[bit 55] + ('clear IA32_BNDCFGS'). Otherwise, these + corresponding MSR bits are cleared. + - If CPUID.0AH:EAX[bits 7:0] > 1, KVM sets + IA32_VMX_TRUE_ENTRY_CTLS[bit 45] + ('load IA32_PERF_GLOBAL_CTRL') and + IA32_VMX_TRUE_EXIT_CTLS[bit 44] + ('load IA32_PERF_GLOBAL_CTRL'). Otherwise, + these corresponding MSR bits are cleared. + + When this quirk is disabled, KVM will not + change the values of + IA32_VMX_TRUE_ENTRY_CTLS or + IA32_VMX_TRUE_EXIT_CTLS based on the + aforementioned CPUID bits. =================================== ============================================ 8. Other capabilities. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index bc3405565967..1b905e6c4760 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1968,6 +1968,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages); KVM_X86_QUIRK_CD_NW_CLEARED | \ KVM_X86_QUIRK_LAPIC_MMIO_HOLE | \ KVM_X86_QUIRK_OUT_7E_INC_RIP | \ - KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT) + KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT | \ + KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS) #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index bf6e96011dfe..acbab6a97fae 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -428,11 +428,12 @@ struct kvm_sync_regs { struct kvm_vcpu_events events; }; -#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) -#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) -#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) -#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) -#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) +#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) +#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) +#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2) +#define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) +#define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) +#define KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS (1 << 5) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 224ef4c19a5d..21b98bad1319 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7250,6 +7250,9 @@ void nested_vmx_entry_exit_ctls_update(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS)) + return; + if (kvm_mpx_supported()) { bool mpx_enabled = guest_cpuid_has(vcpu, X86_FEATURE_MPX); -- 2.35.1.574.g5d30c73bfb-goog