Merge branch 'kvm-fix-svm-races' into kvm-master
[linux-block.git] / arch / x86 / kvm / svm / nested.c
index c9e7b86350d6bb0035c055a1709a1b6d754f4edc..fb204eaa8bb3924063a2f78e63bc98ffc450bb7f 100644 (file)
@@ -51,6 +51,23 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
        nested_svm_vmexit(svm);
 }
 
+static void svm_inject_page_fault_nested(struct kvm_vcpu *vcpu, struct x86_exception *fault)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       WARN_ON(!is_guest_mode(vcpu));
+
+       if (vmcb_is_intercept(&svm->nested.ctl, INTERCEPT_EXCEPTION_OFFSET + PF_VECTOR) &&
+          !svm->nested.nested_run_pending) {
+               svm->vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + PF_VECTOR;
+               svm->vmcb->control.exit_code_hi = 0;
+               svm->vmcb->control.exit_info_1 = fault->error_code;
+               svm->vmcb->control.exit_info_2 = fault->address;
+               nested_svm_vmexit(svm);
+       } else {
+               kvm_inject_page_fault(vcpu, fault);
+       }
+}
+
 static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -58,7 +75,7 @@ static u64 nested_svm_get_tdp_pdptr(struct kvm_vcpu *vcpu, int index)
        u64 pdpte;
        int ret;
 
-       ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(__sme_clr(cr3)), &pdpte,
+       ret = kvm_vcpu_read_guest_page(vcpu, gpa_to_gfn(cr3), &pdpte,
                                       offset_in_page(cr3) + index * 8, 8);
        if (ret)
                return 0;
@@ -199,6 +216,10 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
 static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
+
+       if (WARN_ON(!is_guest_mode(vcpu)))
+               return true;
+
        if (!nested_svm_vmrun_msrpm(svm)) {
                vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                vcpu->run->internal.suberror =
@@ -227,6 +248,7 @@ static bool nested_vmcb_check_controls(struct vmcb_control_area *control)
 
 static bool nested_vmcb_check_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
 {
+       struct kvm_vcpu *vcpu = &svm->vcpu;
        bool vmcb12_lma;
 
        /*
@@ -247,21 +269,13 @@ static bool nested_vmcb_check_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
 
        vmcb12_lma = (vmcb12->save.efer & EFER_LME) && (vmcb12->save.cr0 & X86_CR0_PG);
 
-       if (!vmcb12_lma) {
-               if (vmcb12->save.cr4 & X86_CR4_PAE) {
-                       if (vmcb12->save.cr3 & MSR_CR3_LEGACY_PAE_RESERVED_MASK)
-                               return false;
-               } else {
-                       if (vmcb12->save.cr3 & MSR_CR3_LEGACY_RESERVED_MASK)
-                               return false;
-               }
-       } else {
+       if (vmcb12_lma) {
                if (!(vmcb12->save.cr4 & X86_CR4_PAE) ||
                    !(vmcb12->save.cr0 & X86_CR0_PE) ||
-                   (vmcb12->save.cr3 & MSR_CR3_LONG_MBZ_MASK))
+                   kvm_vcpu_is_illegal_gpa(vcpu, vmcb12->save.cr3))
                        return false;
        }
-       if (kvm_valid_cr4(&svm->vcpu, vmcb12->save.cr4))
+       if (!kvm_is_valid_cr4(&svm->vcpu, vmcb12->save.cr4))
                return false;
 
        return true;
@@ -355,7 +369,7 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm)
 static int nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
                               bool nested_npt)
 {
-       if (cr3 & rsvd_bits(cpuid_maxphyaddr(vcpu), 63))
+       if (kvm_vcpu_is_illegal_gpa(vcpu, cr3))
                return -EINVAL;
 
        if (!nested_npt && is_pae_paging(vcpu) &&
@@ -388,7 +402,7 @@ static void nested_prepare_vmcb_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
        svm->vmcb->save.ds = vmcb12->save.ds;
        svm->vmcb->save.gdtr = vmcb12->save.gdtr;
        svm->vmcb->save.idtr = vmcb12->save.idtr;
-       kvm_set_rflags(&svm->vcpu, vmcb12->save.rflags);
+       kvm_set_rflags(&svm->vcpu, vmcb12->save.rflags | X86_EFLAGS_FIXED);
 
        /*
         * Force-set EFER_SVME even though it is checked earlier on the
@@ -408,8 +422,8 @@ static void nested_prepare_vmcb_save(struct vcpu_svm *svm, struct vmcb *vmcb12)
        svm->vmcb->save.rax = vmcb12->save.rax;
        svm->vmcb->save.rsp = vmcb12->save.rsp;
        svm->vmcb->save.rip = vmcb12->save.rip;
-       svm->vmcb->save.dr7 = vmcb12->save.dr7;
-       svm->vcpu.arch.dr6  = vmcb12->save.dr6;
+       svm->vmcb->save.dr7 = vmcb12->save.dr7 | DR7_FIXED_1;
+       svm->vcpu.arch.dr6  = vmcb12->save.dr6 | DR6_ACTIVE_LOW;
        svm->vmcb->save.cpl = vmcb12->save.cpl;
 }
 
@@ -453,15 +467,32 @@ int enter_svm_guest_mode(struct vcpu_svm *svm, u64 vmcb12_gpa,
 {
        int ret;
 
+       trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb12_gpa,
+                              vmcb12->save.rip,
+                              vmcb12->control.int_ctl,
+                              vmcb12->control.event_inj,
+                              vmcb12->control.nested_ctl);
+
+       trace_kvm_nested_intercepts(vmcb12->control.intercepts[INTERCEPT_CR] & 0xffff,
+                                   vmcb12->control.intercepts[INTERCEPT_CR] >> 16,
+                                   vmcb12->control.intercepts[INTERCEPT_EXCEPTION],
+                                   vmcb12->control.intercepts[INTERCEPT_WORD3],
+                                   vmcb12->control.intercepts[INTERCEPT_WORD4],
+                                   vmcb12->control.intercepts[INTERCEPT_WORD5]);
+
+
        svm->nested.vmcb12_gpa = vmcb12_gpa;
-       nested_prepare_vmcb_save(svm, vmcb12);
        nested_prepare_vmcb_control(svm);
+       nested_prepare_vmcb_save(svm, vmcb12);
 
        ret = nested_svm_load_cr3(&svm->vcpu, vmcb12->save.cr3,
                                  nested_npt_enabled(svm));
        if (ret)
                return ret;
 
+       if (!npt_enabled)
+               svm->vcpu.arch.mmu->inject_page_fault = svm_inject_page_fault_nested;
+
        svm_set_gif(svm, true);
 
        return 0;
@@ -508,18 +539,6 @@ int nested_svm_vmrun(struct vcpu_svm *svm)
                goto out;
        }
 
-       trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb12_gpa,
-                              vmcb12->save.rip,
-                              vmcb12->control.int_ctl,
-                              vmcb12->control.event_inj,
-                              vmcb12->control.nested_ctl);
-
-       trace_kvm_nested_intercepts(vmcb12->control.intercepts[INTERCEPT_CR] & 0xffff,
-                                   vmcb12->control.intercepts[INTERCEPT_CR] >> 16,
-                                   vmcb12->control.intercepts[INTERCEPT_EXCEPTION],
-                                   vmcb12->control.intercepts[INTERCEPT_WORD3],
-                                   vmcb12->control.intercepts[INTERCEPT_WORD4],
-                                   vmcb12->control.intercepts[INTERCEPT_WORD5]);
 
        /* Clear internal status */
        kvm_clear_exception_queue(&svm->vcpu);
@@ -611,6 +630,8 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
        svm->nested.vmcb12_gpa = 0;
        WARN_ON_ONCE(svm->nested.nested_run_pending);
 
+       kvm_clear_request(KVM_REQ_GET_NESTED_STATE_PAGES, &svm->vcpu);
+
        /* in case we halted in L2 */
        svm->vcpu.arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
@@ -676,13 +697,14 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
        svm->vmcb->save.gdtr = hsave->save.gdtr;
        svm->vmcb->save.idtr = hsave->save.idtr;
        kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
+       kvm_set_rflags(&svm->vcpu, hsave->save.rflags | X86_EFLAGS_FIXED);
        svm_set_efer(&svm->vcpu, hsave->save.efer);
        svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
        svm_set_cr4(&svm->vcpu, hsave->save.cr4);
        kvm_rax_write(&svm->vcpu, hsave->save.rax);
        kvm_rsp_write(&svm->vcpu, hsave->save.rsp);
        kvm_rip_write(&svm->vcpu, hsave->save.rip);
-       svm->vmcb->save.dr7 = 0;
+       svm->vmcb->save.dr7 = DR7_FIXED_1;
        svm->vmcb->save.cpl = 0;
        svm->vmcb->control.exit_int_info = 0;
 
@@ -769,6 +791,7 @@ void svm_leave_nested(struct vcpu_svm *svm)
                leave_guest_mode(&svm->vcpu);
                copy_vmcb_control_area(&vmcb->control, &hsave->control);
                nested_svm_uninit_mmu_context(&svm->vcpu);
+               vmcb_mark_all_dirty(svm->vmcb);
        }
 
        kvm_clear_request(KVM_REQ_GET_NESTED_STATE_PAGES, &svm->vcpu);
@@ -1211,6 +1234,10 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
         * in the registers, the save area of the nested state instead
         * contains saved L1 state.
         */
+
+       svm->nested.nested_run_pending =
+               !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
+
        copy_vmcb_control_area(&hsave->control, &svm->vmcb->control);
        hsave->save = *save;