]> Pileus Git - ~andy/linux/blobdiff - arch/arm/kernel/process.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
[~andy/linux] / arch / arm / kernel / process.c
index 04eea22d7958637f17456c7e2f37ac7b71e8e182..f98c17ff1957cc921c1e7a7459802f03e539a8de 100644 (file)
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
 }
 
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
 
 int
 copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        struct thread_info *thread = task_thread_info(p);
        struct pt_regs *childregs = task_pt_regs(p);
 
-       *childregs = *regs;
-       childregs->ARM_r0 = 0;
-       childregs->ARM_sp = stack_start;
-
        memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
+
+       if (likely(regs)) {
+               *childregs = *regs;
+               childregs->ARM_r0 = 0;
+               childregs->ARM_sp = stack_start;
+               thread->cpu_context.pc = (unsigned long)ret_from_fork;
+       } else {
+               thread->cpu_context.r4 = stk_sz;
+               thread->cpu_context.r5 = stack_start;
+               thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
+               childregs->ARM_cpsr = SVC_MODE;
+       }
        thread->cpu_context.sp = (unsigned long)childregs;
-       thread->cpu_context.pc = (unsigned long)ret_from_fork;
 
        clear_ptrace_hw_breakpoint(p);
 
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
 }
 EXPORT_SYMBOL(dump_fpu);
 
-/*
- * Shuffle the argument into the correct register before calling the
- * thread function.  r4 is the thread argument, r5 is the pointer to
- * the thread function, and r6 points to the exit function.
- */
-extern void kernel_thread_helper(void);
-asm(   ".pushsection .text\n"
-"      .align\n"
-"      .type   kernel_thread_helper, #function\n"
-"kernel_thread_helper:\n"
-#ifdef CONFIG_TRACE_IRQFLAGS
-"      bl      trace_hardirqs_on\n"
-#endif
-"      msr     cpsr_c, r7\n"
-"      mov     r0, r4\n"
-"      mov     lr, r6\n"
-"      mov     pc, r5\n"
-"      .size   kernel_thread_helper, . - kernel_thread_helper\n"
-"      .popsection");
-
-#ifdef CONFIG_ARM_UNWIND
-extern void kernel_thread_exit(long code);
-asm(   ".pushsection .text\n"
-"      .align\n"
-"      .type   kernel_thread_exit, #function\n"
-"kernel_thread_exit:\n"
-"      .fnstart\n"
-"      .cantunwind\n"
-"      bl      do_exit\n"
-"      nop\n"
-"      .fnend\n"
-"      .size   kernel_thread_exit, . - kernel_thread_exit\n"
-"      .popsection");
-#else
-#define kernel_thread_exit     do_exit
-#endif
-
-/*
- * Create a kernel thread.
- */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.ARM_r4 = (unsigned long)arg;
-       regs.ARM_r5 = (unsigned long)fn;
-       regs.ARM_r6 = (unsigned long)kernel_thread_exit;
-       regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
-       regs.ARM_pc = (unsigned long)kernel_thread_helper;
-       regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
-
-       return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
 unsigned long get_wchan(struct task_struct *p)
 {
        struct stackframe frame;