KVM: SVM: Emulate nRIP feature when reinjecting INT3
[safe/jmp/linux-2.6] / arch / x86 / kvm / svm.c
index f9da35b..468ff6e 100644 (file)
@@ -47,6 +47,7 @@ MODULE_LICENSE("GPL");
 #define SVM_FEATURE_NPT  (1 << 0)
 #define SVM_FEATURE_LBRV (1 << 1)
 #define SVM_FEATURE_SVML (1 << 2)
+#define SVM_FEATURE_NRIP (1 << 3)
 #define SVM_FEATURE_PAUSE_FILTER (1 << 10)
 
 #define NESTED_EXIT_HOST       0       /* Exit handled on host level */
@@ -110,6 +111,9 @@ struct vcpu_svm {
        struct nested_state nested;
 
        bool nmi_singlestep;
+
+       unsigned int3_injected;
+       unsigned long int3_rip;
 };
 
 /* enable NPT for AMD64 and X86 with PAE */
@@ -129,6 +133,7 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
 
 static int nested_svm_exit_handled(struct vcpu_svm *svm);
+static int nested_svm_intercept(struct vcpu_svm *svm);
 static int nested_svm_vmexit(struct vcpu_svm *svm);
 static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
                                      bool has_error_code, u32 error_code);
@@ -235,23 +240,6 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
        vcpu->arch.efer = efer;
 }
 
-static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
-                               bool has_error_code, u32 error_code)
-{
-       struct vcpu_svm *svm = to_svm(vcpu);
-
-       /* If we are within a nested VM we'd better #VMEXIT and let the
-          guest handle the exception */
-       if (nested_svm_check_exception(svm, nr, has_error_code, error_code))
-               return;
-
-       svm->vmcb->control.event_inj = nr
-               | SVM_EVTINJ_VALID
-               | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0)
-               | SVM_EVTINJ_TYPE_EXEPT;
-       svm->vmcb->control.event_inj_err = error_code;
-}
-
 static int is_external_interrupt(u32 info)
 {
        info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
@@ -264,7 +252,7 @@ static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
        u32 ret = 0;
 
        if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
-               ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS;
+               ret |= KVM_X86_SHADOW_INT_STI | KVM_X86_SHADOW_INT_MOV_SS;
        return ret & mask;
 }
 
@@ -297,6 +285,39 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
        svm_set_interrupt_shadow(vcpu, 0);
 }
 
+static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
+                               bool has_error_code, u32 error_code)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       /* If we are within a nested VM we'd better #VMEXIT and let the
+          guest handle the exception */
+       if (nested_svm_check_exception(svm, nr, has_error_code, error_code))
+               return;
+
+       if (nr == BP_VECTOR && !svm_has(SVM_FEATURE_NRIP)) {
+               unsigned long rip, old_rip = kvm_rip_read(&svm->vcpu);
+
+               /*
+                * For guest debugging where we have to reinject #BP if some
+                * INT3 is guest-owned:
+                * Emulate nRIP by moving RIP forward. Will fail if injection
+                * raises a fault that is not intercepted. Still better than
+                * failing in all cases.
+                */
+               skip_emulated_instruction(&svm->vcpu);
+               rip = kvm_rip_read(&svm->vcpu);
+               svm->int3_rip = rip + svm->vmcb->save.cs.base;
+               svm->int3_injected = rip - old_rip;
+       }
+
+       svm->vmcb->control.event_inj = nr
+               | SVM_EVTINJ_VALID
+               | (has_error_code ? SVM_EVTINJ_VALID_ERR : 0)
+               | SVM_EVTINJ_TYPE_EXEPT;
+       svm->vmcb->control.event_inj_err = error_code;
+}
+
 static int has_svm(void)
 {
        const char *msg;
@@ -978,6 +999,7 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 
 static void update_cr0_intercept(struct vcpu_svm *svm)
 {
+       struct vmcb *vmcb = svm->vmcb;
        ulong gcr0 = svm->vcpu.arch.cr0;
        u64 *hcr0 = &svm->vmcb->save.cr0;
 
@@ -989,11 +1011,25 @@ static void update_cr0_intercept(struct vcpu_svm *svm)
 
 
        if (gcr0 == *hcr0 && svm->vcpu.fpu_active) {
-               svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
-               svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+               vmcb->control.intercept_cr_read &= ~INTERCEPT_CR0_MASK;
+               vmcb->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+               if (is_nested(svm)) {
+                       struct vmcb *hsave = svm->nested.hsave;
+
+                       hsave->control.intercept_cr_read  &= ~INTERCEPT_CR0_MASK;
+                       hsave->control.intercept_cr_write &= ~INTERCEPT_CR0_MASK;
+                       vmcb->control.intercept_cr_read  |= svm->nested.intercept_cr_read;
+                       vmcb->control.intercept_cr_write |= svm->nested.intercept_cr_write;
+               }
        } else {
                svm->vmcb->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
                svm->vmcb->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
+               if (is_nested(svm)) {
+                       struct vmcb *hsave = svm->nested.hsave;
+
+                       hsave->control.intercept_cr_read |= INTERCEPT_CR0_MASK;
+                       hsave->control.intercept_cr_write |= INTERCEPT_CR0_MASK;
+               }
        }
 }
 
@@ -1268,7 +1304,22 @@ static int ud_interception(struct vcpu_svm *svm)
 static void svm_fpu_activate(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
-       svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+       u32 excp;
+
+       if (is_nested(svm)) {
+               u32 h_excp, n_excp;
+
+               h_excp  = svm->nested.hsave->control.intercept_exceptions;
+               n_excp  = svm->nested.intercept_exceptions;
+               h_excp &= ~(1 << NM_VECTOR);
+               excp    = h_excp | n_excp;
+       } else {
+               excp  = svm->vmcb->control.intercept_exceptions;
+               excp &= ~(1 << NM_VECTOR);
+       }
+
+       svm->vmcb->control.intercept_exceptions = excp;
+
        svm->vcpu.fpu_active = 1;
        update_cr0_intercept(svm);
 }
@@ -1384,6 +1435,8 @@ static int nested_svm_check_permissions(struct vcpu_svm *svm)
 static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
                                      bool has_error_code, u32 error_code)
 {
+       int vmexit;
+
        if (!is_nested(svm))
                return 0;
 
@@ -1392,19 +1445,24 @@ static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
        svm->vmcb->control.exit_info_1 = error_code;
        svm->vmcb->control.exit_info_2 = svm->vcpu.arch.cr2;
 
-       return nested_svm_exit_handled(svm);
+       vmexit = nested_svm_intercept(svm);
+       if (vmexit == NESTED_EXIT_DONE)
+               svm->nested.exit_required = true;
+
+       return vmexit;
 }
 
-static inline int nested_svm_intr(struct vcpu_svm *svm)
+/* This function returns true if it is save to enable the irq window */
+static inline bool nested_svm_intr(struct vcpu_svm *svm)
 {
        if (!is_nested(svm))
-               return 0;
+               return true;
 
        if (!(svm->vcpu.arch.hflags & HF_VINTR_MASK))
-               return 0;
+               return true;
 
        if (!(svm->vcpu.arch.hflags & HF_HIF_MASK))
-               return 0;
+               return false;
 
        svm->vmcb->control.exit_code = SVM_EXIT_INTR;
 
@@ -1417,16 +1475,18 @@ static inline int nested_svm_intr(struct vcpu_svm *svm)
                 */
                svm->nested.exit_required = true;
                trace_kvm_nested_intr_vmexit(svm->vmcb->save.rip);
-               return 1;
+               return false;
        }
 
-       return 0;
+       return true;
 }
 
 static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
 {
        struct page *page;
 
+       might_sleep();
+
        page = gfn_to_page(svm->vcpu.kvm, gpa >> PAGE_SHIFT);
        if (is_error_page(page))
                goto error;
@@ -1452,19 +1512,13 @@ static bool nested_svm_exit_handled_msr(struct vcpu_svm *svm)
 {
        u32 param = svm->vmcb->control.exit_info_1 & 1;
        u32 msr = svm->vcpu.arch.regs[VCPU_REGS_RCX];
-       struct page *page;
        bool ret = false;
        u32 t0, t1;
-       u8 *msrpm;
+       u8 val;
 
        if (!(svm->nested.intercept & (1ULL << INTERCEPT_MSR_PROT)))
                return false;
 
-       msrpm = nested_svm_map(svm, svm->nested.vmcb_msrpm, &page);
-
-       if (!msrpm)
-               goto out;
-
        switch (msr) {
        case 0 ... 0x1fff:
                t0 = (msr * 2) % 8;
@@ -1485,11 +1539,10 @@ static bool nested_svm_exit_handled_msr(struct vcpu_svm *svm)
                goto out;
        }
 
-       ret = msrpm[t1] & ((1 << param) << t0);
+       if (!kvm_read_guest(svm->vcpu.kvm, svm->nested.vmcb_msrpm + t1, &val, 1))
+               ret = val & ((1 << param) << t0);
 
 out:
-       nested_svm_unmap(page);
-
        return ret;
 }
 
@@ -1511,6 +1564,9 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
                if (!npt_enabled)
                        return NESTED_EXIT_HOST;
                break;
+       case SVM_EXIT_EXCP_BASE + NM_VECTOR:
+               nm_interception(svm);
+               break;
        default:
                break;
        }
@@ -1521,7 +1577,7 @@ static int nested_svm_exit_special(struct vcpu_svm *svm)
 /*
  * If this function returns true, this #vmexit was already handled
  */
-static int nested_svm_exit_handled(struct vcpu_svm *svm)
+static int nested_svm_intercept(struct vcpu_svm *svm)
 {
        u32 exit_code = svm->vmcb->control.exit_code;
        int vmexit = NESTED_EXIT_HOST;
@@ -1567,9 +1623,17 @@ static int nested_svm_exit_handled(struct vcpu_svm *svm)
        }
        }
 
-       if (vmexit == NESTED_EXIT_DONE) {
+       return vmexit;
+}
+
+static int nested_svm_exit_handled(struct vcpu_svm *svm)
+{
+       int vmexit;
+
+       vmexit = nested_svm_intercept(svm);
+
+       if (vmexit == NESTED_EXIT_DONE)
                nested_svm_vmexit(svm);
-       }
 
        return vmexit;
 }
@@ -1623,6 +1687,9 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        if (!nested_vmcb)
                return 1;
 
+       /* Exit nested SVM mode */
+       svm->nested.vmcb = 0;
+
        /* Give the current vmcb to the guest */
        disable_gif(svm);
 
@@ -1632,9 +1699,13 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        nested_vmcb->save.ds     = vmcb->save.ds;
        nested_vmcb->save.gdtr   = vmcb->save.gdtr;
        nested_vmcb->save.idtr   = vmcb->save.idtr;
+       nested_vmcb->save.cr0    = kvm_read_cr0(&svm->vcpu);
        if (npt_enabled)
                nested_vmcb->save.cr3    = vmcb->save.cr3;
+       else
+               nested_vmcb->save.cr3    = svm->vcpu.arch.cr3;
        nested_vmcb->save.cr2    = vmcb->save.cr2;
+       nested_vmcb->save.cr4    = svm->vcpu.arch.cr4;
        nested_vmcb->save.rflags = vmcb->save.rflags;
        nested_vmcb->save.rip    = vmcb->save.rip;
        nested_vmcb->save.rsp    = vmcb->save.rsp;
@@ -1706,9 +1777,6 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
        svm->vmcb->save.cpl = 0;
        svm->vmcb->control.exit_int_info = 0;
 
-       /* Exit nested SVM mode */
-       svm->nested.vmcb = 0;
-
        nested_svm_unmap(page);
 
        kvm_mmu_reset_context(&svm->vcpu);
@@ -1743,14 +1811,14 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        struct vmcb *hsave = svm->nested.hsave;
        struct vmcb *vmcb = svm->vmcb;
        struct page *page;
+       u64 vmcb_gpa;
+
+       vmcb_gpa = svm->vmcb->save.rax;
 
        nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
        if (!nested_vmcb)
                return false;
 
-       /* nested_vmcb is our indicator if nested SVM is activated */
-       svm->nested.vmcb = svm->vmcb->save.rax;
-
        trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, svm->nested.vmcb,
                               nested_vmcb->save.rip,
                               nested_vmcb->control.int_ctl,
@@ -1818,21 +1886,6 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        svm->vmcb->save.dr6 = nested_vmcb->save.dr6;
        svm->vmcb->save.cpl = nested_vmcb->save.cpl;
 
-       /* We don't want a nested guest to be more powerful than the guest,
-          so all intercepts are ORed */
-       svm->vmcb->control.intercept_cr_read |=
-               nested_vmcb->control.intercept_cr_read;
-       svm->vmcb->control.intercept_cr_write |=
-               nested_vmcb->control.intercept_cr_write;
-       svm->vmcb->control.intercept_dr_read |=
-               nested_vmcb->control.intercept_dr_read;
-       svm->vmcb->control.intercept_dr_write |=
-               nested_vmcb->control.intercept_dr_write;
-       svm->vmcb->control.intercept_exceptions |=
-               nested_vmcb->control.intercept_exceptions;
-
-       svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
-
        svm->nested.vmcb_msrpm = nested_vmcb->control.msrpm_base_pa;
 
        /* cache intercepts */
@@ -1850,6 +1903,28 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
        else
                svm->vcpu.arch.hflags &= ~HF_VINTR_MASK;
 
+       if (svm->vcpu.arch.hflags & HF_VINTR_MASK) {
+               /* We only want the cr8 intercept bits of the guest */
+               svm->vmcb->control.intercept_cr_read &= ~INTERCEPT_CR8_MASK;
+               svm->vmcb->control.intercept_cr_write &= ~INTERCEPT_CR8_MASK;
+       }
+
+       /* We don't want a nested guest to be more powerful than the guest,
+          so all intercepts are ORed */
+       svm->vmcb->control.intercept_cr_read |=
+               nested_vmcb->control.intercept_cr_read;
+       svm->vmcb->control.intercept_cr_write |=
+               nested_vmcb->control.intercept_cr_write;
+       svm->vmcb->control.intercept_dr_read |=
+               nested_vmcb->control.intercept_dr_read;
+       svm->vmcb->control.intercept_dr_write |=
+               nested_vmcb->control.intercept_dr_write;
+       svm->vmcb->control.intercept_exceptions |=
+               nested_vmcb->control.intercept_exceptions;
+
+       svm->vmcb->control.intercept |= nested_vmcb->control.intercept;
+
+       svm->vmcb->control.lbr_ctl = nested_vmcb->control.lbr_ctl;
        svm->vmcb->control.int_vector = nested_vmcb->control.int_vector;
        svm->vmcb->control.int_state = nested_vmcb->control.int_state;
        svm->vmcb->control.tsc_offset += nested_vmcb->control.tsc_offset;
@@ -1858,6 +1933,9 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
 
        nested_svm_unmap(page);
 
+       /* nested_vmcb is our indicator if nested SVM is activated */
+       svm->nested.vmcb = vmcb_gpa;
+
        enable_gif(svm);
 
        return true;
@@ -2512,6 +2590,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        if (irr == -1)
                return;
 
@@ -2569,13 +2650,11 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       nested_svm_intr(svm);
-
        /* In case GIF=0 we can't rely on the CPU to tell us when
         * GIF becomes 1, because that's a separate STGI/VMRUN intercept.
         * The next time we get that intercept, this function will be
         * called again though and we'll get the vintr intercept. */
-       if (gif_set(svm)) {
+       if (gif_set(svm) && nested_svm_intr(svm)) {
                svm_set_vintr(svm);
                svm_inject_irq(svm, 0x0);
        }
@@ -2615,6 +2694,9 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        if (!(svm->vmcb->control.intercept_cr_write & INTERCEPT_CR8_MASK)) {
                int cr8 = svm->vmcb->control.int_ctl & V_TPR_MASK;
                kvm_set_cr8(vcpu, cr8);
@@ -2626,6 +2708,9 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
        struct vcpu_svm *svm = to_svm(vcpu);
        u64 cr8;
 
+       if (is_nested(svm) && (vcpu->arch.hflags & HF_VINTR_MASK))
+               return;
+
        cr8 = kvm_get_cr8(vcpu);
        svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
        svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK;
@@ -2636,6 +2721,9 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
        u8 vector;
        int type;
        u32 exitintinfo = svm->vmcb->control.exit_int_info;
+       unsigned int3_injected = svm->int3_injected;
+
+       svm->int3_injected = 0;
 
        if (svm->vcpu.arch.hflags & HF_IRET_MASK)
                svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
@@ -2655,12 +2743,21 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
                svm->vcpu.arch.nmi_injected = true;
                break;
        case SVM_EXITINTINFO_TYPE_EXEPT:
-               /* In case of software exception do not reinject an exception
-                  vector, but re-execute and instruction instead */
                if (is_nested(svm))
                        break;
-               if (kvm_exception_is_soft(vector))
+               /*
+                * In case of software exceptions, do not reinject the vector,
+                * but re-execute the instruction instead. Rewind RIP first
+                * if we emulated INT3 before.
+                */
+               if (kvm_exception_is_soft(vector)) {
+                       if (vector == BP_VECTOR && int3_injected &&
+                           kvm_is_linear_rip(&svm->vcpu, svm->int3_rip))
+                               kvm_rip_write(&svm->vcpu,
+                                             kvm_rip_read(&svm->vcpu) -
+                                             int3_injected);
                        break;
+               }
                if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) {
                        u32 err = svm->vmcb->control.exit_int_info_err;
                        kvm_queue_exception_e(&svm->vcpu, vector, err);
@@ -2947,8 +3044,10 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
 
-       update_cr0_intercept(svm);
        svm->vmcb->control.intercept_exceptions |= 1 << NM_VECTOR;
+       if (is_nested(svm))
+               svm->nested.hsave->control.intercept_exceptions |= 1 << NM_VECTOR;
+       update_cr0_intercept(svm);
 }
 
 static struct kvm_x86_ops svm_x86_ops = {