kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues
@ 2017-06-01 22:13 Jim Mattson
  2017-06-01 22:13 ` [PATCH 1/4] KVM: nVMX: Sequester all vmcs12 guest-state updates Jim Mattson
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Jim Mattson @ 2017-06-01 22:13 UTC (permalink / raw)
  To: kvm, nyh; +Cc: Jim Mattson

According to the Intel SDM, volume 3, section 26.7: VM-Entry Failures
During or After Loading Guest State,

  Although this process resembles that of a VM exit, many steps taken
  during a VM exit do not occur for these VM-entry failures:

  o Most VM-exit information fields are not updated (see step 1
    above).
  o The valid bit in the VM-entry interruption-information field is
    not cleared.
  o The guest-state area is not modified.
  o No MSRs are saved into the VM-exit MSR-store area.

"Step 1 above" indicates that information about the VM-entry failure
is only recorded in the exit reason and exit qualification fields.
*All other VM-exit information fields are unmodified.*

Moreover, the pseudo-code for VMLAUNCH/VMRESUME in section 30.3
indicates that the launch state of the VMCS is only set to "launched"
when the VM-entry succeeds.

The current nested_vmx_vmexit code does not sufficiently distinguish
VM-entry failure from a normal VM-exit, and therefore gets most of
these things wrong.

Jim Mattson (4):
  KVM: nVMX: Sequester all vmcs12 guest-state updates
  KVM: nVMX: Introduce update_vmcs12_vm_entry_controls
  KVM: nVMX: Introduce record_extra_vmcs12_exit_information
  KVM: nVMX: Don't set vmcs12 to "launched" when VMLAUNCH fails

 arch/x86/kvm/vmx.c | 112 +++++++++++++++++++++++++++++++++--------------------
 1 file changed, 69 insertions(+), 43 deletions(-)

-- 
2.13.0.219.gdb65acc882-goog

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] KVM: nVMX: Sequester all vmcs12 guest-state updates
  2017-06-01 22:13 [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues Jim Mattson
@ 2017-06-01 22:13 ` Jim Mattson
  2017-06-01 22:13 ` [PATCH 2/4] KVM: nVMX: Introduce update_vmcs12_vm_entry_controls Jim Mattson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Jim Mattson @ 2017-06-01 22:13 UTC (permalink / raw)
  To: kvm, nyh; +Cc: Jim Mattson

Rename sync_vmcs12 to save_vmcs12_guest_state and hoist out any code
that doesn't just update guest-state fields in vmcs12. Guest-state
fields are not updated on failed VM-entry, so move the call site into
the appropriate conditional block.

Fixes: 4704d0befb072 ("KVM: nVMX: Exiting from L2 to L1")
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 36 ++++++++++++++++--------------------
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ae66ebc7fb82..a01dd8bd712c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -10627,11 +10627,10 @@ static u32 vmx_get_preemption_timer_value(struct kvm_vcpu *vcpu)
 
 /*
  * Update the guest state fields of vmcs12 to reflect changes that
- * occurred while L2 was running. (The "IA-32e mode guest" bit of the
- * VM-entry controls is also updated, since this is really a guest
- * state bit.)
+ * occurred while L2 was running.
  */
-static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
+static void save_vmcs12_guest_state(struct kvm_vcpu *vcpu,
+				    struct vmcs12 *vmcs12)
 {
 	vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
 	vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
@@ -10686,13 +10685,9 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 	else
 		vmcs12->guest_activity_state = GUEST_ACTIVITY_ACTIVE;
 
-	if (nested_cpu_has_preemption_timer(vmcs12)) {
-		if (vmcs12->vm_exit_controls &
-		    VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
-			vmcs12->vmx_preemption_timer_value =
-				vmx_get_preemption_timer_value(vcpu);
-		hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
-	}
+	if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)
+		vmcs12->vmx_preemption_timer_value =
+			vmx_get_preemption_timer_value(vcpu);
 
 	/*
 	 * In some cases (usually, nested EPT), L2 is allowed to change its
@@ -10710,15 +10705,9 @@ static void sync_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 		vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
 	}
 
-	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
-
 	if (nested_cpu_has_vid(vmcs12))
 		vmcs12->guest_intr_status = vmcs_read16(GUEST_INTR_STATUS);
 
-	vmcs12->vm_entry_controls =
-		(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
-		(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
-
 	if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) {
 		kvm_get_dr(vcpu, 7, (unsigned long *)&vmcs12->guest_dr7);
 		vmcs12->guest_ia32_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
@@ -10752,9 +10741,6 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 			   u32 exit_reason, u32 exit_intr_info,
 			   unsigned long exit_qualification)
 {
-	/* update guest state fields: */
-	sync_vmcs12(vcpu, vmcs12);
-
 	/* update exit information fields: */
 
 	vmcs12->vm_exit_reason = exit_reason;
@@ -10770,7 +10756,14 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 	vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
 	vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
 
+	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+
+	vmcs12->vm_entry_controls =
+		(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
+		(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
+
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
+		save_vmcs12_guest_state(vcpu, vmcs12);
 		/* vm_entry_intr_info_field is cleared on exit. Emulate this
 		 * instead of reading the real value. */
 		vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK;
@@ -10944,6 +10937,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
 	/* trying to cancel vmlaunch/vmresume is a bug */
 	WARN_ON_ONCE(vmx->nested.nested_run_pending);
 
+	if (nested_cpu_has_preemption_timer(vmcs12))
+		hrtimer_cancel(&to_vmx(vcpu)->nested.preemption_timer);
+
 	leave_guest_mode(vcpu);
 	prepare_vmcs12(vcpu, vmcs12, exit_reason, exit_intr_info,
 		       exit_qualification);
-- 
2.13.0.219.gdb65acc882-goog

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] KVM: nVMX: Introduce update_vmcs12_vm_entry_controls
  2017-06-01 22:13 [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues Jim Mattson
  2017-06-01 22:13 ` [PATCH 1/4] KVM: nVMX: Sequester all vmcs12 guest-state updates Jim Mattson
@ 2017-06-01 22:13 ` Jim Mattson
  2017-06-01 22:13 ` [PATCH 3/4] KVM: nVMX: Introduce record_extra_vmcs12_exit_information Jim Mattson
  2017-06-01 22:13 ` [PATCH 4/4] KVM: nVMX: Don't set vmcs12 to "launched" when VMLAUNCH fails Jim Mattson
  3 siblings, 0 replies; 5+ messages in thread
From: Jim Mattson @ 2017-06-01 22:13 UTC (permalink / raw)
  To: kvm, nyh; +Cc: Jim Mattson

VM-entry controls are updated on a VM-exit, but not on a failed
VM-entry. Collect these updates in a new function, and call that
function from the appropriate conditional block.

Fixes: 4704d0befb072 ("KVM: nVMX: Exiting from L2 to L1")
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a01dd8bd712c..5059c6b45914 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -10727,6 +10727,28 @@ static void save_vmcs12_guest_state(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * Update the VM-entry control fields in vmcs12 after an emulated
+ * VM-exit (but not after a failed VM-entry).
+ */
+static void update_vmcs12_vm_entry_controls(struct kvm_vcpu *vcpu,
+					    struct vmcs12 *vmcs12)
+{
+	/*
+	 * The valid bit (bit 31) is cleared in the "VM-entry
+	 * interruption-information field" on VM-exit.
+	 */
+	vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK;
+
+	/*
+	 * The value of IA32_EFER.LMA is stored in the "IA-32e mode guest"
+	 * VM-entry control.
+	 */
+	vmcs12->vm_entry_controls =
+		(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
+		(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
+}
+
+/*
  * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits
  * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12),
  * and this function updates it to reflect the changes to the guest state while
@@ -10758,16 +10780,9 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 
 	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
 
-	vmcs12->vm_entry_controls =
-		(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
-		(vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE);
-
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
+		update_vmcs12_vm_entry_controls(vcpu, vmcs12);
 		save_vmcs12_guest_state(vcpu, vmcs12);
-		/* vm_entry_intr_info_field is cleared on exit. Emulate this
-		 * instead of reading the real value. */
-		vmcs12->vm_entry_intr_info_field &= ~INTR_INFO_VALID_MASK;
-
 		/*
 		 * Transfer the event that L0 or L1 may wanted to inject into
 		 * L2 to IDT_VECTORING_INFO_FIELD.
-- 
2.13.0.219.gdb65acc882-goog

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] KVM: nVMX: Introduce record_extra_vmcs12_exit_information
  2017-06-01 22:13 [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues Jim Mattson
  2017-06-01 22:13 ` [PATCH 1/4] KVM: nVMX: Sequester all vmcs12 guest-state updates Jim Mattson
  2017-06-01 22:13 ` [PATCH 2/4] KVM: nVMX: Introduce update_vmcs12_vm_entry_controls Jim Mattson
@ 2017-06-01 22:13 ` Jim Mattson
  2017-06-01 22:13 ` [PATCH 4/4] KVM: nVMX: Don't set vmcs12 to "launched" when VMLAUNCH fails Jim Mattson
  3 siblings, 0 replies; 5+ messages in thread
From: Jim Mattson @ 2017-06-01 22:13 UTC (permalink / raw)
  To: kvm, nyh; +Cc: Jim Mattson

Only the exit reason and exit qualification fields are written on a
failed VM-entry. Sequester the other exit-information field updates in
a separate function, and call it from the appropriate conditional
block.

Fixes: 4704d0befb072 ("KVM: nVMX: Exiting from L2 to L1")
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 54 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 5059c6b45914..4cddd6fab1c5 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -10531,6 +10531,7 @@ static void vmcs12_save_pending_event(struct kvm_vcpu *vcpu,
 	u32 idt_vectoring;
 	unsigned int nr;
 
+	vmcs12->idt_vectoring_info_field = 0;
 	if (vcpu->arch.exception.pending && vcpu->arch.exception.reinject) {
 		nr = vcpu->arch.exception.nr;
 		idt_vectoring = nr | VECTORING_INFO_VALID_MASK;
@@ -10749,6 +10750,34 @@ static void update_vmcs12_vm_entry_controls(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * Record information about the nature of the VM-exit in the VM-exit
+ * information fields of vmcs12. Note that this function assumes that
+ * all of the extra VM-exit information aside from the "VM-exit
+ * interruption information" is live in vmcs02.
+ */
+static void record_extra_vmcs12_exit_information(struct kvm_vcpu *vcpu,
+						 struct vmcs12 *vmcs12,
+						 u32 exit_intr_info)
+{
+	vmcs12->vm_exit_intr_info = exit_intr_info;
+	if ((vmcs12->vm_exit_intr_info &
+	     (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK)) ==
+	    (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK))
+		vmcs12->vm_exit_intr_error_code =
+			vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
+	vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+	vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+	/*
+	 * Transfer the event that L0 or L1 may want to inject into L2
+	 * to "IDT-vectoring information" and associated fields. Note
+	 * that this function may overwrite "VM-exit instruction
+	 * length."
+	 */
+	vmcs12_save_pending_event(vcpu, vmcs12);
+}
+
+/*
  * prepare_vmcs12 is part of what we need to do when the nested L2 guest exits
  * and we want to prepare to run its L1 parent. L1 keeps a vmcs for L2 (vmcs12),
  * and this function updates it to reflect the changes to the guest state while
@@ -10763,31 +10792,18 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 			   u32 exit_reason, u32 exit_intr_info,
 			   unsigned long exit_qualification)
 {
-	/* update exit information fields: */
-
+	/*
+	 * The exit reason and exit qualification are saved for failed
+	 * VM-entry as well as VM-exit.
+	 */
 	vmcs12->vm_exit_reason = exit_reason;
 	vmcs12->exit_qualification = exit_qualification;
 
-	vmcs12->vm_exit_intr_info = exit_intr_info;
-	if ((vmcs12->vm_exit_intr_info &
-	     (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK)) ==
-	    (INTR_INFO_VALID_MASK | INTR_INFO_DELIVER_CODE_MASK))
-		vmcs12->vm_exit_intr_error_code =
-			vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
-	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);
-
-	vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
-
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
 		update_vmcs12_vm_entry_controls(vcpu, vmcs12);
 		save_vmcs12_guest_state(vcpu, vmcs12);
-		/*
-		 * Transfer the event that L0 or L1 may wanted to inject into
-		 * L2 to IDT_VECTORING_INFO_FIELD.
-		 */
-		vmcs12_save_pending_event(vcpu, vmcs12);
+		record_extra_vmcs12_exit_information(vcpu, vmcs12,
+						     exit_intr_info);
 	}
 
 	/*
-- 
2.13.0.219.gdb65acc882-goog

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] KVM: nVMX: Don't set vmcs12 to "launched" when VMLAUNCH fails
  2017-06-01 22:13 [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues Jim Mattson
                   ` (2 preceding siblings ...)
  2017-06-01 22:13 ` [PATCH 3/4] KVM: nVMX: Introduce record_extra_vmcs12_exit_information Jim Mattson
@ 2017-06-01 22:13 ` Jim Mattson
  3 siblings, 0 replies; 5+ messages in thread
From: Jim Mattson @ 2017-06-01 22:13 UTC (permalink / raw)
  To: kvm, nyh; +Cc: Jim Mattson

The VMCS launch state is not set to "launched" unless the VMLAUNCH
actually succeeds. VMLAUNCH failure includes VM-entry failure during
or after loading guest state (i.e. VM-exits with bit 31 set in the
exit reason).

Note that this change does not address the related problem that a
failure to launch/resume vmcs02 (i.e. vmx->fail) is not handled
correctly.

Fixes: cd232ad02f002 ("KVM: nVMX: Implement VMLAUNCH and VMRESUME")
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/kvm/vmx.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 4cddd6fab1c5..1d308c5b89fd 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -10396,8 +10396,6 @@ static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
 		return 1;
 	}
 
-	vmcs12->launch_state = 1;
-
 	/*
 	 * Note no nested_vmx_succeed or nested_vmx_fail here. At this point
 	 * we are no longer running L1, and VMLAUNCH/VMRESUME has not yet
@@ -10800,6 +10798,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
 	vmcs12->exit_qualification = exit_qualification;
 
 	if (!(vmcs12->vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) {
+		vmcs12->launch_state = 1;
 		update_vmcs12_vm_entry_controls(vcpu, vmcs12);
 		save_vmcs12_guest_state(vcpu, vmcs12);
 		record_extra_vmcs12_exit_information(vcpu, vmcs12,
-- 
2.13.0.219.gdb65acc882-goog

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-06-01 22:13 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-06-01 22:13 [PATCH 0/4] KVM: nVMX: Fix some failed VM-entry issues Jim Mattson
2017-06-01 22:13 ` [PATCH 1/4] KVM: nVMX: Sequester all vmcs12 guest-state updates Jim Mattson
2017-06-01 22:13 ` [PATCH 2/4] KVM: nVMX: Introduce update_vmcs12_vm_entry_controls Jim Mattson
2017-06-01 22:13 ` [PATCH 3/4] KVM: nVMX: Introduce record_extra_vmcs12_exit_information Jim Mattson
2017-06-01 22:13 ` [PATCH 4/4] KVM: nVMX: Don't set vmcs12 to "launched" when VMLAUNCH fails Jim Mattson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).