]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
kvm: nVMX: Split VMCS checks from nested_vmx_run()
authorJim Mattson <jmattson@google.com>
Wed, 30 Nov 2016 20:03:46 +0000 (12:03 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 15 Feb 2017 13:56:35 +0000 (14:56 +0100)
The checks performed on the contents of the vmcs12 are extracted from
nested_vmx_run so that they can be used to validate a vmcs12 that has
been restored from a checkpoint.

Signed-off-by: Jim Mattson <jmattson@google.com>
[Change prepare_vmcs02 and nested_vmx_load_cr3's last argument to u32,
 to match check_vmentry_postreqs.  Update comments for singlestep
 handling. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx.c

index 650f34336fada5ca51f2e393762175c733450a64..71df7411959fee96be4c49b00e4b82d85b9fa5f2 100644 (file)
@@ -10035,7 +10035,7 @@ static bool nested_cr3_valid(struct kvm_vcpu *vcpu, unsigned long val)
  * is assigned to entry_failure_code on failure.
  */
 static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept,
-                              unsigned long *entry_failure_code)
+                              u32 *entry_failure_code)
 {
        if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) {
                if (!nested_cr3_valid(vcpu, cr3)) {
@@ -10075,7 +10075,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool ne
  * is assigned to entry_failure_code on failure.
  */
 static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
-                         bool from_vmentry, unsigned long *entry_failure_code)
+                         bool from_vmentry, u32 *entry_failure_code)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 exec_control;
@@ -10411,68 +10411,22 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        return 0;
 }
 
-/*
- * nested_vmx_run() handles a nested entry, i.e., a VMLAUNCH or VMRESUME on L1
- * for running an L2 nested guest.
- */
-static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
+static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 {
-       struct vmcs12 *vmcs12;
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       int cpu;
-       struct loaded_vmcs *vmcs02;
-       bool ia32e;
-       u32 msr_entry_idx;
-       unsigned long exit_qualification;
-
-       if (!nested_vmx_check_permission(vcpu))
-               return 1;
-
-       if (!nested_vmx_check_vmcs12(vcpu))
-               goto out;
-
-       vmcs12 = get_vmcs12(vcpu);
-
-       if (enable_shadow_vmcs)
-               copy_shadow_to_vmcs12(vmx);
-
-       /*
-        * The nested entry process starts with enforcing various prerequisites
-        * on vmcs12 as required by the Intel SDM, and act appropriately when
-        * they fail: As the SDM explains, some conditions should cause the
-        * instruction to fail, while others will cause the instruction to seem
-        * to succeed, but return an EXIT_REASON_INVALID_STATE.
-        * To speed up the normal (success) code path, we should avoid checking
-        * for misconfigurations which will anyway be caught by the processor
-        * when using the merged vmcs02.
-        */
-       if (vmcs12->launch_state == launch) {
-               nested_vmx_failValid(vcpu,
-                       launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS
-                              : VMXERR_VMRESUME_NONLAUNCHED_VMCS);
-               goto out;
-       }
 
        if (vmcs12->guest_activity_state != GUEST_ACTIVITY_ACTIVE &&
-           vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT) {
-               nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               goto out;
-       }
+           vmcs12->guest_activity_state != GUEST_ACTIVITY_HLT)
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
-       if (nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12)) {
-               nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               goto out;
-       }
+       if (nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12))
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
-       if (nested_vmx_check_apicv_controls(vcpu, vmcs12)) {
-               nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               goto out;
-       }
+       if (nested_vmx_check_apicv_controls(vcpu, vmcs12))
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
-       if (nested_vmx_check_msr_switch_controls(vcpu, vmcs12)) {
-               nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               goto out;
-       }
+       if (nested_vmx_check_msr_switch_controls(vcpu, vmcs12))
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
        if (!vmx_control_verify(vmcs12->cpu_based_vm_exec_control,
                                vmx->nested.nested_vmx_procbased_ctls_low,
@@ -10489,28 +10443,30 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
            !vmx_control_verify(vmcs12->vm_entry_controls,
                                vmx->nested.nested_vmx_entry_ctls_low,
                                vmx->nested.nested_vmx_entry_ctls_high))
-       {
-               nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               goto out;
-       }
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
        if (!nested_host_cr0_valid(vcpu, vmcs12->host_cr0) ||
            !nested_host_cr4_valid(vcpu, vmcs12->host_cr4) ||
-           !nested_cr3_valid(vcpu, vmcs12->host_cr3)) {
-               nested_vmx_failValid(vcpu,
-                       VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
-               goto out;
-       }
+           !nested_cr3_valid(vcpu, vmcs12->host_cr3))
+               return VMXERR_ENTRY_INVALID_HOST_STATE_FIELD;
+
+       return 0;
+}
+
+static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
+                                 u32 *exit_qual)
+{
+       bool ia32e;
+
+       *exit_qual = ENTRY_FAIL_DEFAULT;
 
        if (!nested_guest_cr0_valid(vcpu, vmcs12->guest_cr0) ||
-           !nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4)) {
-               nested_vmx_entry_failure(vcpu, vmcs12,
-                       EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
+           !nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4))
                return 1;
-       }
-       if (vmcs12->vmcs_link_pointer != -1ull) {
-               nested_vmx_entry_failure(vcpu, vmcs12,
-                       EXIT_REASON_INVALID_STATE, ENTRY_FAIL_VMCS_LINK_PTR);
+
+       if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_SHADOW_VMCS) &&
+           vmcs12->vmcs_link_pointer != -1ull) {
+               *exit_qual = ENTRY_FAIL_VMCS_LINK_PTR;
                return 1;
        }
 
@@ -10523,16 +10479,14 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
         *   to bit 8 (LME) if bit 31 in the CR0 field (corresponding to
         *   CR0.PG) is 1.
         */
-       if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER) {
+       if (to_vmx(vcpu)->nested.nested_run_pending &&
+           (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) {
                ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
                if (!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer) ||
                    ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA) ||
                    ((vmcs12->guest_cr0 & X86_CR0_PG) &&
-                    ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME))) {
-                       nested_vmx_entry_failure(vcpu, vmcs12,
-                               EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
+                    ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME)))
                        return 1;
-               }
        }
 
        /*
@@ -10546,11 +10500,75 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                         VM_EXIT_HOST_ADDR_SPACE_SIZE) != 0;
                if (!kvm_valid_efer(vcpu, vmcs12->host_ia32_efer) ||
                    ia32e != !!(vmcs12->host_ia32_efer & EFER_LMA) ||
-                   ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) {
-                       nested_vmx_entry_failure(vcpu, vmcs12,
-                               EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
+                   ia32e != !!(vmcs12->host_ia32_efer & EFER_LME))
                        return 1;
-               }
+       }
+
+       return 0;
+}
+
+/*
+ * nested_vmx_run() handles a nested entry, i.e., a VMLAUNCH or VMRESUME on L1
+ * for running an L2 nested guest.
+ */
+static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
+{
+       struct vmcs12 *vmcs12;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       int cpu;
+       struct loaded_vmcs *vmcs02;
+       u32 msr_entry_idx;
+       u32 exit_qual;
+       int ret;
+
+       if (!nested_vmx_check_permission(vcpu))
+               return 1;
+
+       if (!nested_vmx_check_vmcs12(vcpu))
+               goto out;
+
+       vmcs12 = get_vmcs12(vcpu);
+
+       if (enable_shadow_vmcs)
+               copy_shadow_to_vmcs12(vmx);
+
+       /*
+        * The nested entry process starts with enforcing various prerequisites
+        * on vmcs12 as required by the Intel SDM, and act appropriately when
+        * they fail: As the SDM explains, some conditions should cause the
+        * instruction to fail, while others will cause the instruction to seem
+        * to succeed, but return an EXIT_REASON_INVALID_STATE.
+        * To speed up the normal (success) code path, we should avoid checking
+        * for misconfigurations which will anyway be caught by the processor
+        * when using the merged vmcs02.
+        */
+       if (vmcs12->launch_state == launch) {
+               nested_vmx_failValid(vcpu,
+                       launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS
+                              : VMXERR_VMRESUME_NONLAUNCHED_VMCS);
+               goto out;
+       }
+
+       ret = check_vmentry_prereqs(vcpu, vmcs12);
+       if (ret) {
+               nested_vmx_failValid(vcpu, ret);
+               goto out;
+       }
+
+       /*
+        * After this point, the trap flag no longer triggers a singlestep trap
+        * on the vm entry instructions; don't call kvm_skip_emulated_instruction.
+        * This is not 100% correct; for performance reasons, we delegate most
+        * of the checks on host state to the processor.  If those fail,
+        * the singlestep trap is missed.
+        */
+       skip_emulated_instruction(vcpu);
+
+       ret = check_vmentry_postreqs(vcpu, vmcs12, &exit_qual);
+       if (ret) {
+               nested_vmx_entry_failure(vcpu, vmcs12,
+                                        EXIT_REASON_INVALID_STATE, exit_qual);
+               return 1;
        }
 
        /*
@@ -10562,12 +10580,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (!vmcs02)
                return -ENOMEM;
 
-       /*
-        * After this point, the trap flag no longer triggers a singlestep trap
-        * on the vm entry instructions. Don't call
-        * kvm_skip_emulated_instruction.
-        */
-       skip_emulated_instruction(vcpu);
        enter_guest_mode(vcpu);
 
        if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
@@ -10582,11 +10594,11 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
 
        vmx_segment_cache_clear(vmx);
 
-       if (prepare_vmcs02(vcpu, vmcs12, true, &exit_qualification)) {
+       if (prepare_vmcs02(vcpu, vmcs12, true, &exit_qual)) {
                leave_guest_mode(vcpu);
                vmx_load_vmcs01(vcpu);
                nested_vmx_entry_failure(vcpu, vmcs12,
-                               EXIT_REASON_INVALID_STATE, exit_qualification);
+                               EXIT_REASON_INVALID_STATE, exit_qual);
                return 1;
        }
 
@@ -10937,7 +10949,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
                                   struct vmcs12 *vmcs12)
 {
        struct kvm_segment seg;
-       unsigned long entry_failure_code;
+       u32 entry_failure_code;
 
        if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER)
                vcpu->arch.efer = vmcs12->host_ia32_efer;