Commit 384151a9 authored by Russell King's avatar Russell King

[ARM] Avoid using clone syscall from kernel_thread()

Don't issue a system call from kernel_thread(), but call do_fork()
directly.  This avoids all the unnecessary syscall overhead.
parent 13a69a2e
......@@ -312,8 +312,8 @@ void release_thread(struct task_struct *dead_task)
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
int
copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
unsigned long unused, struct task_struct *p, struct pt_regs *regs)
copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *thread = p->thread_info;
struct pt_regs *childregs;
......@@ -321,7 +321,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1;
*childregs = *regs;
childregs->ARM_r0 = 0;
childregs->ARM_sp = esp;
childregs->ARM_sp = stack_start;
memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
thread->cpu_context.sp = (unsigned long)childregs;
......@@ -373,33 +373,35 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
}
/*
* This is the mechanism for creating a new kernel thread.
*
* NOTE! Only a kernel-only process(ie the swapper or direct descendants
* who haven't done an "execve()") should use this: it will work within
* a system call from a "real" process, but the process memory space will
* not be free'd until both the parent and the child have exited.
* Shuffle the argument into the correct register before calling the
* thread function. r1 is the thread argument, r2 is the pointer to
* the thread function, and r3 points to the exit function.
*/
extern void kernel_thread_helper(void);
asm( ".align\n"
" .type kernel_thread_helper, #function\n"
"kernel_thread_helper:\n"
" mov r0, r1\n"
" mov lr, r3\n"
" mov pc, r2\n"
" .size kernel_thread_helper, . - kernel_thread_helper");
/*
* Create a kernel thread.
*/
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
register unsigned int r0 asm("r0") = flags | CLONE_VM | CLONE_UNTRACED;
register unsigned int r1 asm("r1") = 0;
register pid_t __ret asm("r0");
__asm__ __volatile__(
__syscall(clone)" @ kernel_thread sys_clone \n\
movs %0, r0 @ if we are the child \n\
bne 1f \n\
mov fp, #0 @ ensure that fp is zero \n\
mov r0, %4 \n\
mov lr, pc \n\
mov pc, %3 \n\
b sys_exit \n\
1: "
: "=r" (__ret)
: "0" (r0), "r" (r1), "r" (fn), "r" (arg)
: "lr");
return __ret;
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.ARM_r1 = (unsigned long)arg;
regs.ARM_r2 = (unsigned long)fn;
regs.ARM_r3 = (unsigned long)do_exit;
regs.ARM_pc = (unsigned long)kernel_thread_helper;
regs.ARM_cpsr = SVC_MODE;
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment