KVM: VMX: Move skip_emulated_instruction out of nested_vmx_check_vmcs12
authorKyle Huey <me@kylehuey.com>
Tue, 29 Nov 2016 20:40:39 +0000 (12:40 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 8 Dec 2016 14:31:04 +0000 (15:31 +0100)
We can't return both the pass/fail boolean for the vmcs and the upcoming
continue/exit-to-userspace boolean for skip_emulated_instruction out of
nested_vmx_check_vmcs, so move skip_emulated_instruction out of it instead.

Additionally, VMENTER/VMRESUME only trigger singlestep exceptions when
they advance the IP to the following instruction, not when they a) succeed,
b) fail MSR validation or c) throw an exception. Add a separate call to
skip_emulated_instruction that will later not be converted to the variant
that checks the singlestep flag.

Signed-off-by: Kyle Huey <khuey@kylehuey.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/vmx.c

index f2f9cf595c07e8a443d4dde15a28d895bb068441..f4f6304f9583a24527264fa254ad14e7e4587a37 100644 (file)
@@ -7324,7 +7324,6 @@ static int nested_vmx_check_vmcs12(struct kvm_vcpu *vcpu)
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        if (vmx->nested.current_vmptr == -1ull) {
                nested_vmx_failInvalid(vcpu);
-               skip_emulated_instruction(vcpu);
                return 0;
        }
        return 1;
@@ -7338,9 +7337,13 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
        u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
        gva_t gva = 0;
 
-       if (!nested_vmx_check_permission(vcpu) ||
-           !nested_vmx_check_vmcs12(vcpu))
+       if (!nested_vmx_check_permission(vcpu))
+               return 1;
+
+       if (!nested_vmx_check_vmcs12(vcpu)) {
+               skip_emulated_instruction(vcpu);
                return 1;
+       }
 
        /* Decode instruction info and find the field to read */
        field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf));
@@ -7388,10 +7391,14 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu)
        u64 field_value = 0;
        struct x86_exception e;
 
-       if (!nested_vmx_check_permission(vcpu) ||
-           !nested_vmx_check_vmcs12(vcpu))
+       if (!nested_vmx_check_permission(vcpu))
                return 1;
 
+       if (!nested_vmx_check_vmcs12(vcpu)) {
+               skip_emulated_instruction(vcpu);
+               return 1;
+       }
+
        if (vmx_instruction_info & (1u << 10))
                field_value = kvm_register_readl(vcpu,
                        (((vmx_instruction_info) >> 3) & 0xf));
@@ -10046,11 +10053,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        bool ia32e;
        u32 msr_entry_idx;
 
-       if (!nested_vmx_check_permission(vcpu) ||
-           !nested_vmx_check_vmcs12(vcpu))
+       if (!nested_vmx_check_permission(vcpu))
                return 1;
 
-       skip_emulated_instruction(vcpu);
+       if (!nested_vmx_check_vmcs12(vcpu))
+               goto out;
+
        vmcs12 = get_vmcs12(vcpu);
 
        if (enable_shadow_vmcs)
@@ -10070,33 +10078,33 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                nested_vmx_failValid(vcpu,
                        launch ? VMXERR_VMLAUNCH_NONCLEAR_VMCS
                               : VMXERR_VMRESUME_NONLAUNCHED_VMCS);
-               return 1;
+               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);
-               return 1;
+               goto out;
        }
 
        if (!nested_get_vmcs12_pages(vcpu, vmcs12)) {
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               return 1;
+               goto out;
        }
 
        if (nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12)) {
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               return 1;
+               goto out;
        }
 
        if (nested_vmx_check_apicv_controls(vcpu, vmcs12)) {
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               return 1;
+               goto out;
        }
 
        if (nested_vmx_check_msr_switch_controls(vcpu, vmcs12)) {
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               return 1;
+               goto out;
        }
 
        if (!vmx_control_verify(vmcs12->cpu_based_vm_exec_control,
@@ -10116,26 +10124,26 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                                vmx->nested.nested_vmx_entry_ctls_high))
        {
                nested_vmx_failValid(vcpu, VMXERR_ENTRY_INVALID_CONTROL_FIELD);
-               return 1;
+               goto out;
        }
 
        if (((vmcs12->host_cr0 & VMXON_CR0_ALWAYSON) != VMXON_CR0_ALWAYSON) ||
            ((vmcs12->host_cr4 & VMXON_CR4_ALWAYSON) != VMXON_CR4_ALWAYSON)) {
                nested_vmx_failValid(vcpu,
                        VMXERR_ENTRY_INVALID_HOST_STATE_FIELD);
-               return 1;
+               goto out;
        }
 
        if (!nested_cr0_valid(vcpu, vmcs12->guest_cr0) ||
            ((vmcs12->guest_cr4 & VMXON_CR4_ALWAYSON) != VMXON_CR4_ALWAYSON)) {
                nested_vmx_entry_failure(vcpu, vmcs12,
                        EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
-               return 1;
+               goto out;
        }
        if (vmcs12->vmcs_link_pointer != -1ull) {
                nested_vmx_entry_failure(vcpu, vmcs12,
                        EXIT_REASON_INVALID_STATE, ENTRY_FAIL_VMCS_LINK_PTR);
-               return 1;
+               goto out;
        }
 
        /*
@@ -10155,7 +10163,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                     ia32e != !!(vmcs12->guest_ia32_efer & EFER_LME))) {
                        nested_vmx_entry_failure(vcpu, vmcs12,
                                EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
-                       return 1;
+                       goto out;
                }
        }
 
@@ -10173,7 +10181,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
                    ia32e != !!(vmcs12->host_ia32_efer & EFER_LME)) {
                        nested_vmx_entry_failure(vcpu, vmcs12,
                                EXIT_REASON_INVALID_STATE, ENTRY_FAIL_DEFAULT);
-                       return 1;
+                       goto out;
                }
        }
 
@@ -10186,6 +10194,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (!vmcs02)
                return -ENOMEM;
 
+       skip_emulated_instruction(vcpu);
        enter_guest_mode(vcpu);
 
        if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
@@ -10227,6 +10236,10 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
         * the success flag) when L2 exits (see nested_vmx_vmexit()).
         */
        return 1;
+
+out:
+       skip_emulated_instruction(vcpu);
+       return 1;
 }
 
 /*