]> Pileus Git - ~andy/linux/blobdiff - arch/x86/kernel/process_64.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
[~andy/linux] / arch / x86 / kernel / process_64.c
index 8a6d20ce19784ee96362cbaaa29c696497122a6a..16c6365e2b867c883805061f533349751f9bfbf0 100644 (file)
@@ -146,29 +146,18 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls)
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long sp,
-               unsigned long unused,
+               unsigned long arg,
        struct task_struct *p, struct pt_regs *regs)
 {
        int err;
        struct pt_regs *childregs;
        struct task_struct *me = current;
 
-       childregs = ((struct pt_regs *)
-                       (THREAD_SIZE + task_stack_page(p))) - 1;
-       *childregs = *regs;
-
-       childregs->ax = 0;
-       if (user_mode(regs))
-               childregs->sp = sp;
-       else
-               childregs->sp = (unsigned long)childregs;
-
+       p->thread.sp0 = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+       childregs = task_pt_regs(p);
        p->thread.sp = (unsigned long) childregs;
-       p->thread.sp0 = (unsigned long) (childregs+1);
        p->thread.usersp = me->thread.usersp;
-
        set_tsk_thread_flag(p, TIF_FORK);
-
        p->fpu_counter = 0;
        p->thread.io_bitmap_ptr = NULL;
 
@@ -178,6 +167,24 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs;
        savesegment(es, p->thread.es);
        savesegment(ds, p->thread.ds);
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
+
+       if (unlikely(!regs)) {
+               /* kernel thread */
+               memset(childregs, 0, sizeof(struct pt_regs));
+               childregs->sp = (unsigned long)childregs;
+               childregs->ss = __KERNEL_DS;
+               childregs->bx = sp; /* function */
+               childregs->bp = arg;
+               childregs->orig_ax = -1;
+               childregs->cs = __KERNEL_CS | get_kernel_rpl();
+               childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_BIT1;
+               return 0;
+       }
+       *childregs = *regs;
+
+       childregs->ax = 0;
+       childregs->sp = sp;
 
        err = -ENOMEM;
        memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));