Commit 9e14f828 authored by Al Viro's avatar Al Viro

arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 38b983b3
...@@ -49,6 +49,7 @@ config ARM ...@@ -49,6 +49,7 @@ config ARM
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
select GENERIC_KERNEL_THREAD
help help
The ARM series is a line of low-power-consumption RISC chip designs The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and licensed by ARM Ltd and targeted at embedded applications and
......
...@@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p); ...@@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier() #define cpu_relax() barrier()
#endif #endif
/*
* Create a new kernel thread
*/
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
#define task_pt_regs(p) \ #define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
......
...@@ -91,6 +91,18 @@ ENTRY(ret_from_fork) ...@@ -91,6 +91,18 @@ ENTRY(ret_from_fork)
b ret_slow_syscall b ret_slow_syscall
ENDPROC(ret_from_fork) ENDPROC(ret_from_fork)
ENTRY(ret_from_kernel_thread)
UNWIND(.fnstart)
UNWIND(.cantunwind)
bl schedule_tail
mov r0, r4
adr lr, BSYM(1f) @ kernel threads should not exit
mov pc, r5
1: bl do_exit
nop
UNWIND(.fnend)
ENDPROC(ret_from_kernel_thread)
.equ NR_syscalls,0 .equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1 #define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S" #include "calls.S"
......
...@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task) ...@@ -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_fork(void) __asm__("ret_from_fork");
asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
int int
copy_thread(unsigned long clone_flags, unsigned long stack_start, copy_thread(unsigned long clone_flags, unsigned long stack_start,
...@@ -381,13 +382,20 @@ 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 thread_info *thread = task_thread_info(p);
struct pt_regs *childregs = task_pt_regs(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)); 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.sp = (unsigned long)childregs;
thread->cpu_context.pc = (unsigned long)ret_from_fork;
clear_ptrace_hw_breakpoint(p); clear_ptrace_hw_breakpoint(p);
...@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp) ...@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
} }
EXPORT_SYMBOL(dump_fpu); 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) unsigned long get_wchan(struct task_struct *p)
{ {
struct stackframe frame; struct stackframe frame;
......
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