]> Pileus Git - ~andy/linux/blobdiff - arch/x86/kernel/process_64.c
Merge branch 'linus' into tracing/hw-breakpoints
[~andy/linux] / arch / x86 / kernel / process_64.c
index b751a41392b1b997d3c9a3235ba85b2372bdf7a3..89c46f1259d39ae1d306ba2c6aaec533372cd968 100644 (file)
@@ -14,8 +14,6 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
-#include <stdarg.h>
-
 #include <linux/stackprotector.h>
 #include <linux/cpu.h>
 #include <linux/errno.h>
@@ -32,7 +30,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
-#include <linux/random.h>
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
@@ -55,6 +52,8 @@
 #include <asm/idle.h>
 #include <asm/syscalls.h>
 #include <asm/ds.h>
+#include <asm/debugreg.h>
+#include <asm/hw_breakpoint.h>
 
 asmlinkage extern void ret_from_fork(void);
 
@@ -248,6 +247,8 @@ void release_thread(struct task_struct *dead_task)
                        BUG();
                }
        }
+       if (unlikely(dead_task->thread.debugreg7))
+               flush_thread_hw_breakpoint(dead_task);
 }
 
 static inline void set_32bit_tls(struct task_struct *t, int tls, u32 addr)
@@ -303,12 +304,18 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
 
        p->thread.fs = me->thread.fs;
        p->thread.gs = me->thread.gs;
+       p->thread.io_bitmap_ptr = NULL;
 
        savesegment(gs, p->thread.gsindex);
        savesegment(fs, p->thread.fsindex);
        savesegment(es, p->thread.es);
        savesegment(ds, p->thread.ds);
 
+       err = -ENOMEM;
+       if (unlikely(test_tsk_thread_flag(me, TIF_DEBUG)))
+               if (copy_thread_hw_breakpoint(me, p, clone_flags))
+                       goto out;
+
        if (unlikely(test_tsk_thread_flag(me, TIF_IO_BITMAP))) {
                p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
                if (!p->thread.io_bitmap_ptr) {
@@ -335,7 +342,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
                        goto out;
        }
 
-       ds_copy_thread(p, me);
+       clear_tsk_thread_flag(p, TIF_DS_AREA_MSR);
+       p->thread.ds_ctx = NULL;
 
        clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
        p->thread.debugctlmsr = 0;
@@ -346,6 +354,9 @@ out:
                kfree(p->thread.io_bitmap_ptr);
                p->thread.io_bitmap_max = 0;
        }
+       if (err)
+               flush_thread_hw_breakpoint(p);
+
        return err;
 }
 
@@ -428,7 +439,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         * done before math_state_restore, so the TS bit is up
         * to date.
         */
-       arch_leave_lazy_cpu_mode();
+       arch_end_context_switch(next_p);
 
        /*
         * Switch FS and GS.
@@ -491,6 +502,24 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
         */
        if (tsk_used_math(next_p) && next_p->fpu_counter > 5)
                math_state_restore();
+       /*
+        * There's a problem with moving the arch_install_thread_hw_breakpoint()
+        * call before current is updated.  Suppose a kernel breakpoint is
+        * triggered in between the two, the hw-breakpoint handler will see that
+        * the 'current' task does not have TIF_DEBUG flag set and will think it
+        * is leftover from an old task (lazy switching) and will erase it. Then
+        * until the next context switch, no user-breakpoints will be installed.
+        *
+        * The real problem is that it's impossible to update both current and
+        * physical debug registers at the same instant, so there will always be
+        * a window in which they disagree and a breakpoint might get triggered.
+        * Since we use lazy switching, we are forced to assume that a
+        * disagreement means that current is correct and the exception is due
+        * to lazy debug register switching.
+        */
+       if (unlikely(test_tsk_thread_flag(next_p, TIF_DEBUG)))
+               arch_install_thread_hw_breakpoint(next_p);
+
        return prev_p;
 }
 
@@ -660,15 +689,3 @@ long sys_arch_prctl(int code, unsigned long addr)
        return do_arch_prctl(current, code, addr);
 }
 
-unsigned long arch_align_stack(unsigned long sp)
-{
-       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
-               sp -= get_random_int() % 8192;
-       return sp & ~0xf;
-}
-
-unsigned long arch_randomize_brk(struct mm_struct *mm)
-{
-       unsigned long range_end = mm->brk + 0x02000000;
-       return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
-}