diff options
Diffstat (limited to '1-2-kvm-vmx-Reinstate-support-for-CPUs-without-virtual-NMI.patch')
-rw-r--r-- | 1-2-kvm-vmx-Reinstate-support-for-CPUs-without-virtual-NMI.patch | 296 |
1 files changed, 0 insertions, 296 deletions
diff --git a/1-2-kvm-vmx-Reinstate-support-for-CPUs-without-virtual-NMI.patch b/1-2-kvm-vmx-Reinstate-support-for-CPUs-without-virtual-NMI.patch deleted file mode 100644 index ca079af42..000000000 --- a/1-2-kvm-vmx-Reinstate-support-for-CPUs-without-virtual-NMI.patch +++ /dev/null @@ -1,296 +0,0 @@ -From patchwork Mon Nov 6 12:31:12 2017 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -Subject: [1/2] kvm: vmx: Reinstate support for CPUs without virtual NMI -From: Paolo Bonzini <pbonzini@redhat.com> -X-Patchwork-Id: 10043403 -Message-Id: <1509971473-74491-2-git-send-email-pbonzini@redhat.com> -To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org -Cc: rkrcmar@redhat.com, stable@vger.kernel.org -Date: Mon, 6 Nov 2017 13:31:12 +0100 - -This is more or less a revert of commit 2c82878b0cb3 ("KVM: VMX: require -virtual NMI support", 2017-03-27); it turns out that Core 2 Duo machines -only had virtual NMIs in some SKUs. - -The revert is not trivial because in the meanwhile there have been several -fixes to nested NMI injection. Therefore, the entire vNMI state is moved -to struct loaded_vmcs. - -Another change compared to before the patch is a simplification here: - - if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked && - !(is_guest_mode(vcpu) && nested_cpu_has_virtual_nmis( - get_vmcs12(vcpu))))) { - -The final condition here is always true (because nested_cpu_has_virtual_nmis -is always false) and is removed. - -Fixes: 2c82878b0cb38fd516fd612c67852a6bbf282003 -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1490803 -Cc: stable@vger.kernel.org -Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> ---- - arch/x86/kvm/vmx.c | 150 +++++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 106 insertions(+), 44 deletions(-) - -diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c -index e6c8ffa84968..d6b3b12ae1e2 100644 ---- a/arch/x86/kvm/vmx.c -+++ b/arch/x86/kvm/vmx.c -@@ -202,6 +202,10 @@ struct loaded_vmcs { - bool nmi_known_unmasked; - unsigned long vmcs_host_cr3; /* May not match real cr3 */ - unsigned long vmcs_host_cr4; /* May not match real cr4 */ -+ /* Support for vnmi-less CPUs */ -+ int soft_vnmi_blocked; -+ ktime_t entry_time; -+ s64 vnmi_blocked_time; - struct list_head loaded_vmcss_on_cpu_link; - }; - -@@ -1291,6 +1295,11 @@ static inline bool cpu_has_vmx_invpcid(void) - SECONDARY_EXEC_ENABLE_INVPCID; - } - -+static inline bool cpu_has_virtual_nmis(void) -+{ -+ return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; -+} -+ - static inline bool cpu_has_vmx_wbinvd_exit(void) - { - return vmcs_config.cpu_based_2nd_exec_ctrl & -@@ -1348,11 +1357,6 @@ static inline bool nested_cpu_has2(struct vmcs12 *vmcs12, u32 bit) - (vmcs12->secondary_vm_exec_control & bit); - } - --static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12) --{ -- return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS; --} -- - static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12) - { - return vmcs12->pin_based_vm_exec_control & -@@ -3712,9 +3716,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) - &_vmexit_control) < 0) - return -EIO; - -- min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING | -- PIN_BASED_VIRTUAL_NMIS; -- opt = PIN_BASED_POSTED_INTR | PIN_BASED_VMX_PREEMPTION_TIMER; -+ min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; -+ opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR | -+ PIN_BASED_VMX_PREEMPTION_TIMER; - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, - &_pin_based_exec_control) < 0) - return -EIO; -@@ -5669,7 +5673,8 @@ static void enable_irq_window(struct kvm_vcpu *vcpu) - - static void enable_nmi_window(struct kvm_vcpu *vcpu) - { -- if (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) { -+ if (!cpu_has_virtual_nmis() || -+ vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_STI) { - enable_irq_window(vcpu); - return; - } -@@ -5709,6 +5714,19 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu) - { - struct vcpu_vmx *vmx = to_vmx(vcpu); - -+ if (!cpu_has_virtual_nmis()) { -+ /* -+ * Tracking the NMI-blocked state in software is built upon -+ * finding the next open IRQ window. This, in turn, depends on -+ * well-behaving guests: They have to keep IRQs disabled at -+ * least as long as the NMI handler runs. Otherwise we may -+ * cause NMI nesting, maybe breaking the guest. But as this is -+ * highly unlikely, we can live with the residual risk. -+ */ -+ vmx->loaded_vmcs->soft_vnmi_blocked = 1; -+ vmx->loaded_vmcs->vnmi_blocked_time = 0; -+ } -+ - ++vcpu->stat.nmi_injections; - vmx->loaded_vmcs->nmi_known_unmasked = false; - -@@ -5727,6 +5745,8 @@ static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu) - struct vcpu_vmx *vmx = to_vmx(vcpu); - bool masked; - -+ if (!cpu_has_virtual_nmis()) -+ return vmx->loaded_vmcs->soft_vnmi_blocked; - if (vmx->loaded_vmcs->nmi_known_unmasked) - return false; - masked = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI; -@@ -5738,13 +5758,20 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked) - { - struct vcpu_vmx *vmx = to_vmx(vcpu); - -- vmx->loaded_vmcs->nmi_known_unmasked = !masked; -- if (masked) -- vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, -- GUEST_INTR_STATE_NMI); -- else -- vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, -- GUEST_INTR_STATE_NMI); -+ if (!cpu_has_virtual_nmis()) { -+ if (vmx->loaded_vmcs->soft_vnmi_blocked != masked) { -+ vmx->loaded_vmcs->soft_vnmi_blocked = masked; -+ vmx->loaded_vmcs->vnmi_blocked_time = 0; -+ } -+ } else { -+ vmx->loaded_vmcs->nmi_known_unmasked = !masked; -+ if (masked) -+ vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, -+ GUEST_INTR_STATE_NMI); -+ else -+ vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO, -+ GUEST_INTR_STATE_NMI); -+ } - } - - static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) -@@ -5752,6 +5779,10 @@ static int vmx_nmi_allowed(struct kvm_vcpu *vcpu) - if (to_vmx(vcpu)->nested.nested_run_pending) - return 0; - -+ if (!cpu_has_virtual_nmis() && -+ to_vmx(vcpu)->loaded_vmcs->soft_vnmi_blocked) -+ return 0; -+ - return !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & - (GUEST_INTR_STATE_MOV_SS | GUEST_INTR_STATE_STI - | GUEST_INTR_STATE_NMI)); -@@ -6479,6 +6510,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) - * AAK134, BY25. - */ - if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && -+ cpu_has_virtual_nmis() && - (exit_qualification & INTR_INFO_UNBLOCK_NMI)) - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI); - -@@ -6965,7 +6997,7 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx) - } - - /* Create a new VMCS */ -- item = kmalloc(sizeof(struct vmcs02_list), GFP_KERNEL); -+ item = kzalloc(sizeof(struct vmcs02_list), GFP_KERNEL); - if (!item) - return NULL; - item->vmcs02.vmcs = alloc_vmcs(); -@@ -7982,6 +8014,7 @@ static int handle_pml_full(struct kvm_vcpu *vcpu) - * "blocked by NMI" bit has to be set before next VM entry. - */ - if (!(to_vmx(vcpu)->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && -+ cpu_has_virtual_nmis() && - (exit_qualification & INTR_INFO_UNBLOCK_NMI)) - vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, - GUEST_INTR_STATE_NMI); -@@ -8826,6 +8859,25 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) - return 0; - } - -+ if (unlikely(!cpu_has_virtual_nmis() && -+ vmx->loaded_vmcs->soft_vnmi_blocked)) { -+ if (vmx_interrupt_allowed(vcpu)) { -+ vmx->loaded_vmcs->soft_vnmi_blocked = 0; -+ } else if (vmx->loaded_vmcs->vnmi_blocked_time > 1000000000LL && -+ vcpu->arch.nmi_pending) { -+ /* -+ * This CPU don't support us in finding the end of an -+ * NMI-blocked window if the guest runs with IRQs -+ * disabled. So we pull the trigger after 1 s of -+ * futile waiting, but inform the user about this. -+ */ -+ printk(KERN_WARNING "%s: Breaking out of NMI-blocked " -+ "state on VCPU %d after 1 s timeout\n", -+ __func__, vcpu->vcpu_id); -+ vmx->loaded_vmcs->soft_vnmi_blocked = 0; -+ } -+ } -+ - if (exit_reason < kvm_vmx_max_exit_handlers - && kvm_vmx_exit_handlers[exit_reason]) - return kvm_vmx_exit_handlers[exit_reason](vcpu); -@@ -9108,33 +9160,38 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx) - - idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK; - -- if (vmx->loaded_vmcs->nmi_known_unmasked) -- return; -- /* -- * Can't use vmx->exit_intr_info since we're not sure what -- * the exit reason is. -- */ -- exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); -- unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; -- vector = exit_intr_info & INTR_INFO_VECTOR_MASK; -- /* -- * SDM 3: 27.7.1.2 (September 2008) -- * Re-set bit "block by NMI" before VM entry if vmexit caused by -- * a guest IRET fault. -- * SDM 3: 23.2.2 (September 2008) -- * Bit 12 is undefined in any of the following cases: -- * If the VM exit sets the valid bit in the IDT-vectoring -- * information field. -- * If the VM exit is due to a double fault. -- */ -- if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi && -- vector != DF_VECTOR && !idtv_info_valid) -- vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, -- GUEST_INTR_STATE_NMI); -- else -- vmx->loaded_vmcs->nmi_known_unmasked = -- !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) -- & GUEST_INTR_STATE_NMI); -+ if (cpu_has_virtual_nmis()) { -+ if (vmx->loaded_vmcs->nmi_known_unmasked) -+ return; -+ /* -+ * Can't use vmx->exit_intr_info since we're not sure what -+ * the exit reason is. -+ */ -+ exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO); -+ unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0; -+ vector = exit_intr_info & INTR_INFO_VECTOR_MASK; -+ /* -+ * SDM 3: 27.7.1.2 (September 2008) -+ * Re-set bit "block by NMI" before VM entry if vmexit caused by -+ * a guest IRET fault. -+ * SDM 3: 23.2.2 (September 2008) -+ * Bit 12 is undefined in any of the following cases: -+ * If the VM exit sets the valid bit in the IDT-vectoring -+ * information field. -+ * If the VM exit is due to a double fault. -+ */ -+ if ((exit_intr_info & INTR_INFO_VALID_MASK) && unblock_nmi && -+ vector != DF_VECTOR && !idtv_info_valid) -+ vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, -+ GUEST_INTR_STATE_NMI); -+ else -+ vmx->loaded_vmcs->nmi_known_unmasked = -+ !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) -+ & GUEST_INTR_STATE_NMI); -+ } else if (unlikely(vmx->loaded_vmcs->soft_vnmi_blocked)) -+ vmx->loaded_vmcs->vnmi_blocked_time += -+ ktime_to_ns(ktime_sub(ktime_get(), -+ vmx->loaded_vmcs->entry_time)); - } - - static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, -@@ -9251,6 +9308,11 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) - struct vcpu_vmx *vmx = to_vmx(vcpu); - unsigned long debugctlmsr, cr3, cr4; - -+ /* Record the guest's net vcpu time for enforced NMI injections. */ -+ if (unlikely(!cpu_has_virtual_nmis() && -+ vmx->loaded_vmcs->soft_vnmi_blocked)) -+ vmx->loaded_vmcs->entry_time = ktime_get(); -+ - /* Don't enter VMX if guest state is invalid, let the exit handler - start emulation until we arrive back to a valid state */ - if (vmx->emulation_required) |