arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
38b983b346
commit
9e14f828ee
4 changed files with 26 additions and 67 deletions
|
@ -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);
|
||||||
#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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
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(®s, 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, ®s, 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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue