Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932745AbdHWUoJ (ORCPT ); Wed, 23 Aug 2017 16:44:09 -0400 Received: from mail-wr0-f193.google.com ([209.85.128.193]:38210 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932639AbdHWUoG (ORCPT ); Wed, 23 Aug 2017 16:44:06 -0400 From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: wanpeng.li@hotmail.com, david@redhat.com, rkrcmar@redhat.com, jmattson@google.com Subject: [PATCH 2/4] KVM: nVMX: fill nested IDT-vectored event info on all L2->L0 exits Date: Wed, 23 Aug 2017 22:43:56 +0200 Message-Id: <1503521038-21073-3-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1503521038-21073-1-git-send-email-pbonzini@redhat.com> References: <1503521038-21073-1-git-send-email-pbonzini@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6374 Lines: 190 vcpu->arch.exception currently contains the vmcs02 IDT-vectored info through the entire execution of the vmexit. This makes it harder to keep that information safe when vcpu->arch.exception is reused for an exception that happens while L0 handles a vmexit. When this happens, there are two cases: - the exception causes a vmexit to L1; in that case, the exception in the IDT-vectored info is not reinjected; vcpu->arch.exception is reused to build the VM-exit interruption info. - the exception doesn't cause a vmexit to L1; in that case, vcpu->arch.exception is changed to a double fault which is injected normally into L2 via KVM_REQ_EVENT. We want to discard vcpu->arch.exception in the first case. To prepare for that, prepare the vmcs12 IDT-vectored info early. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 127 +++++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 01c29b6af254..f8ef38094acc 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9073,11 +9073,76 @@ static void __vmx_complete_interrupts(struct kvm_vcpu *vcpu, } } -static void vmx_complete_interrupts(struct vcpu_vmx *vmx) +static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu, + struct vmcs12 *vmcs12) +{ + u32 idt_vectoring; + unsigned int nr; + + if (vcpu->arch.exception.pending && vcpu->arch.exception.reinject) { + nr = vcpu->arch.exception.nr; + idt_vectoring = nr | VECTORING_INFO_VALID_MASK; + + if (kvm_exception_is_soft(nr)) { + vmcs12->vm_exit_instruction_len = + vcpu->arch.event_exit_inst_len; + idt_vectoring |= INTR_TYPE_SOFT_EXCEPTION; + } else + idt_vectoring |= INTR_TYPE_HARD_EXCEPTION; + + if (vcpu->arch.exception.has_error_code) { + idt_vectoring |= VECTORING_INFO_DELIVER_CODE_MASK; + vmcs12->idt_vectoring_error_code = + vcpu->arch.exception.error_code; + } + + vmcs12->idt_vectoring_info_field = idt_vectoring; + } else if (vcpu->arch.nmi_injected) { + vmcs12->idt_vectoring_info_field = + INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR; + } else if (vcpu->arch.interrupt.pending) { + nr = vcpu->arch.interrupt.nr; + idt_vectoring = nr | VECTORING_INFO_VALID_MASK; + + if (vcpu->arch.interrupt.soft) { + idt_vectoring |= INTR_TYPE_SOFT_INTR; + vmcs12->vm_entry_instruction_len = + vcpu->arch.event_exit_inst_len; + } else + idt_vectoring |= INTR_TYPE_EXT_INTR; + + vmcs12->idt_vectoring_info_field = idt_vectoring; + } +} + +static void vmx_complete_interrupts(struct kvm_vcpu *vcpu) { + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct vmcs12 *vmcs12; + __vmx_complete_interrupts(&vmx->vcpu, vmx->idt_vectoring_info, VM_EXIT_INSTRUCTION_LEN, IDT_VECTORING_ERROR_CODE); + + if (!is_guest_mode(vcpu)) + return; + + /* + * Nested vmexit during event delivery, move the IDT-vectored event + * fields to _both_ vcpu->arch and VMCS12. If we exit to L1, having it + * in VMCS12 makes it easier to reuse vcpu->arch for a non-reinjected + * exception and error code; if we stay in L2, the vmcs12 writes go + * unnoticed. + */ + + vmcs12 = get_vmcs12(vcpu); + vmcs12->idt_vectoring_info_field = 0; + vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); + + if ((vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) && + !(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) + vmcs12_save_pending_event(vcpu, vmcs12); } static void vmx_cancel_injection(struct kvm_vcpu *vcpu) @@ -9343,7 +9408,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx_complete_atomic_exit(vmx); vmx_recover_nmi_blocking(vmx); - vmx_complete_interrupts(vmx); + vmx_complete_interrupts(vcpu); } STACK_FRAME_NON_STANDARD(vmx_vcpu_run); @@ -10887,48 +10952,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) vcpu->arch.cr4_guest_owned_bits)); } -static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12) -{ - u32 idt_vectoring; - unsigned int nr; - - if (vcpu->arch.exception.pending && vcpu->arch.exception.reinject) { - nr = vcpu->arch.exception.nr; - idt_vectoring = nr | VECTORING_INFO_VALID_MASK; - - if (kvm_exception_is_soft(nr)) { - vmcs12->vm_exit_instruction_len = - vcpu->arch.event_exit_inst_len; - idt_vectoring |= INTR_TYPE_SOFT_EXCEPTION; - } else - idt_vectoring |= INTR_TYPE_HARD_EXCEPTION; - - if (vcpu->arch.exception.has_error_code) { - idt_vectoring |= VECTORING_INFO_DELIVER_CODE_MASK; - vmcs12->idt_vectoring_error_code = - vcpu->arch.exception.error_code; - } - - vmcs12->idt_vectoring_info_field = idt_vectoring; - } else if (vcpu->arch.nmi_injected) { - vmcs12->idt_vectoring_info_field = - INTR_TYPE_NMI_INTR | INTR_INFO_VALID_MASK | NMI_VECTOR; - } else if (vcpu->arch.interrupt.pending) { - nr = vcpu->arch.interrupt.nr; - idt_vectoring = nr | VECTORING_INFO_VALID_MASK; - - if (vcpu->arch.interrupt.soft) { - idt_vectoring |= INTR_TYPE_SOFT_INTR; - vmcs12->vm_entry_instruction_len = - vcpu->arch.event_exit_inst_len; - } else - idt_vectoring |= INTR_TYPE_EXT_INTR; - - vmcs12->idt_vectoring_info_field = idt_vectoring; - } -} - static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -11123,21 +11146,9 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmcs12->exit_qualification = exit_qualification; vmcs12->vm_exit_intr_info = exit_intr_info; - vmcs12->idt_vectoring_info_field = 0; - vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); - vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - - if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) { - /* - * Transfer the event that L0 or L1 may wanted to inject into - * L2 to IDT_VECTORING_INFO_FIELD. - */ - vmcs12_save_pending_event(vcpu, vmcs12); - } - /* - * Drop what we picked up for L2 via vmx_complete_interrupts. It is - * preserved above and would only end up incorrectly in L1. + * Clear these, they are already in vmcs12 via exit interruption info + * or IDT-vectored event info. */ vcpu->arch.nmi_injected = false; kvm_clear_exception_queue(vcpu); -- 1.8.3.1