kvm: nVMX: Refactor nested_vmx_run()
authorJim Mattson <jmattson@google.com>
Wed, 30 Nov 2016 20:03:47 +0000 (12:03 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 15 Feb 2017 13:56:36 +0000 (14:56 +0100)
Nested_vmx_run is split into two parts: the part that handles the
VMLAUNCH/VMRESUME instruction, and the part that modifies the vcpu state
to transition from VMX root mode to VMX non-root mode. The latter will
be used when restoring the checkpointed state of a vCPU that was in VMX
operation when a snapshot was taken.

Signed-off-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx.c

index 71df7411959fee96be4c49b00e4b82d85b9fa5f2..bca60665d55dea174ee293f14cf3472ac2cd6710 100644 (file)
@@ -10507,6 +10507,65 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        return 0;
 }
 
+static int enter_vmx_non_root_mode(struct kvm_vcpu *vcpu, bool from_vmentry)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       struct loaded_vmcs *vmcs02;
+       int cpu;
+       u32 msr_entry_idx;
+       u32 exit_qual;
+
+       vmcs02 = nested_get_current_vmcs02(vmx);
+       if (!vmcs02)
+               return -ENOMEM;
+
+       enter_guest_mode(vcpu);
+
+       if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
+               vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
+
+       cpu = get_cpu();
+       vmx->loaded_vmcs = vmcs02;
+       vmx_vcpu_put(vcpu);
+       vmx_vcpu_load(vcpu, cpu);
+       vcpu->cpu = cpu;
+       put_cpu();
+
+       vmx_segment_cache_clear(vmx);
+
+       if (prepare_vmcs02(vcpu, vmcs12, from_vmentry, &exit_qual)) {
+               leave_guest_mode(vcpu);
+               vmx_load_vmcs01(vcpu);
+               nested_vmx_entry_failure(vcpu, vmcs12,
+                                        EXIT_REASON_INVALID_STATE, exit_qual);
+               return 1;
+       }
+
+       nested_get_vmcs12_pages(vcpu, vmcs12);
+
+       msr_entry_idx = nested_vmx_load_msr(vcpu,
+                                           vmcs12->vm_entry_msr_load_addr,
+                                           vmcs12->vm_entry_msr_load_count);
+       if (msr_entry_idx) {
+               leave_guest_mode(vcpu);
+               vmx_load_vmcs01(vcpu);
+               nested_vmx_entry_failure(vcpu, vmcs12,
+                               EXIT_REASON_MSR_LOAD_FAIL, msr_entry_idx);
+               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
+        * returned as far as L1 is concerned. It will only return (and set
+        * the success flag) when L2 exits (see nested_vmx_vmexit()).
+        */
+       return 0;
+}
+
 /*
  * nested_vmx_run() handles a nested entry, i.e., a VMLAUNCH or VMRESUME on L1
  * for running an L2 nested guest.
@@ -10515,9 +10574,6 @@ 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;
 
@@ -10576,58 +10632,15 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
         * the nested entry.
         */
 
-       vmcs02 = nested_get_current_vmcs02(vmx);
-       if (!vmcs02)
-               return -ENOMEM;
-
-       enter_guest_mode(vcpu);
-
-       if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
-               vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
-
-       cpu = get_cpu();
-       vmx->loaded_vmcs = vmcs02;
-       vmx_vcpu_put(vcpu);
-       vmx_vcpu_load(vcpu, cpu);
-       vcpu->cpu = cpu;
-       put_cpu();
-
-       vmx_segment_cache_clear(vmx);
-
-       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_qual);
-               return 1;
-       }
-
-       nested_get_vmcs12_pages(vcpu, vmcs12);
-
-       msr_entry_idx = nested_vmx_load_msr(vcpu,
-                                           vmcs12->vm_entry_msr_load_addr,
-                                           vmcs12->vm_entry_msr_load_count);
-       if (msr_entry_idx) {
-               leave_guest_mode(vcpu);
-               vmx_load_vmcs01(vcpu);
-               nested_vmx_entry_failure(vcpu, vmcs12,
-                               EXIT_REASON_MSR_LOAD_FAIL, msr_entry_idx);
-               return 1;
-       }
-
-       vmcs12->launch_state = 1;
+       ret = enter_vmx_non_root_mode(vcpu, true);
+       if (ret)
+               return ret;
 
        if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT)
                return kvm_vcpu_halt(vcpu);
 
        vmx->nested.nested_run_pending = 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
-        * returned as far as L1 is concerned. It will only return (and set
-        * the success flag) when L2 exits (see nested_vmx_vmexit()).
-        */
        return 1;
 
 out: