x86, traps: converge do_debug handlers
[safe/jmp/linux-2.6] / arch / x86 / kernel / traps_32.c
index 7eb1203..953172a 100644 (file)
@@ -88,6 +88,20 @@ static inline void conditional_sti(struct pt_regs *regs)
                local_irq_enable();
 }
 
+static inline void preempt_conditional_sti(struct pt_regs *regs)
+{
+       inc_preempt_count();
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_enable();
+}
+
+static inline void preempt_conditional_cli(struct pt_regs *regs)
+{
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_disable();
+       dec_preempt_count();
+}
+
 static inline void
 die_if_kernel(const char *str, struct pt_regs *regs, long err)
 {
@@ -498,7 +512,7 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
 dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
-       unsigned int condition;
+       unsigned long condition;
        int si_code;
 
        get_debugreg(condition, 6);
@@ -512,9 +526,9 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
                                                SIGTRAP) == NOTIFY_STOP)
                return;
+
        /* It's safe to allow irq's after DR6 has been saved */
-       if (regs->flags & X86_EFLAGS_IF)
-               local_irq_enable();
+       preempt_conditional_sti(regs);
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
@@ -533,16 +547,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
         * kernel space (but re-enable TF when returning to user mode).
         */
        if (condition & DR_STEP) {
-               /*
-                * We already checked v86 mode above, so we can
-                * check for kernel mode by just checking the CPL
-                * of CS.
-                */
                if (!user_mode(regs))
                        goto clear_TF_reenable;
        }
 
-       si_code = get_si_code((unsigned long)condition);
+       si_code = get_si_code(condition);
        /* Ok, finally something we can handle */
        send_sigtrap(tsk, regs, error_code, si_code);
 
@@ -552,15 +561,18 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
         */
 clear_dr7:
        set_debugreg(0, 7);
+       preempt_conditional_cli(regs);
        return;
 
 debug_vm86:
        handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+       preempt_conditional_cli(regs);
        return;
 
 clear_TF_reenable:
        set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
        regs->flags &= ~X86_EFLAGS_TF;
+       preempt_conditional_cli(regs);
        return;
 }