All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
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	[thread overview]
Message-ID: <1503521038-21073-3-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1503521038-21073-1-git-send-email-pbonzini@redhat.com>

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 <pbonzini@redhat.com>
---
 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

  parent reply	other threads:[~2017-08-23 20:44 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-23 20:43 [RFC PATCH 0/4] KVM: x86: allow overwriting L2 reinjected exception with L1 vmexit Paolo Bonzini
2017-08-23 20:43 ` [PATCH 1/4] KVM: nVMX: move vmentry tasks from prepare_vmcs12 to enter_vmx_non_root_mode Paolo Bonzini
2017-08-23 21:25   ` Jim Mattson
2017-08-23 21:47     ` Paolo Bonzini
2017-08-23 20:43 ` Paolo Bonzini [this message]
2017-08-23 20:43 ` [PATCH 3/4] KVM: x86: pass struct kvm_queued_exception to kvm_multiple_exception Paolo Bonzini
2017-08-23 20:43 ` [PATCH 4/4] KVM: x86: allow overwriting L2 reinjected exception with L1 vmexit Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1503521038-21073-3-git-send-email-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=david@redhat.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rkrcmar@redhat.com \
    --cc=wanpeng.li@hotmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.