aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-09-09 21:31:07 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-30 22:21:36 -0400
commit9e14f828ee4a7a4a98703e380d180717a579fb35 (patch)
treece7554478f9abf5de5f47760ebff548485762142 /arch/arm/kernel
parent38b983b3461e7d3c64a981e2338bb34605c46f30 (diff)
arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/entry-common.S12
-rw-r--r--arch/arm/kernel/process.c75
2 files changed, 25 insertions, 62 deletions
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 978eac57e04..9a48b7a577e 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -91,6 +91,18 @@ ENTRY(ret_from_fork)
91 b ret_slow_syscall 91 b ret_slow_syscall
92ENDPROC(ret_from_fork) 92ENDPROC(ret_from_fork)
93 93
94ENTRY(ret_from_kernel_thread)
95 UNWIND(.fnstart)
96 UNWIND(.cantunwind)
97 bl schedule_tail
98 mov r0, r4
99 adr lr, BSYM(1f) @ kernel threads should not exit
100 mov pc, r5
1011: bl do_exit
102 nop
103 UNWIND(.fnend)
104ENDPROC(ret_from_kernel_thread)
105
94 .equ NR_syscalls,0 106 .equ NR_syscalls,0
95#define CALL(x) .equ NR_syscalls,NR_syscalls+1 107#define CALL(x) .equ NR_syscalls,NR_syscalls+1
96#include "calls.S" 108#include "calls.S"
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 693b744fd57..c10e4395bc4 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
373} 373}
374 374
375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); 375asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
376asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
376 377
377int 378int
378copy_thread(unsigned long clone_flags, unsigned long stack_start, 379copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
381 struct thread_info *thread = task_thread_info(p); 382 struct thread_info *thread = task_thread_info(p);
382 struct pt_regs *childregs = task_pt_regs(p); 383 struct pt_regs *childregs = task_pt_regs(p);
383 384
384 *childregs = *regs;
385 childregs->ARM_r0 = 0;
386 childregs->ARM_sp = stack_start;
387
388 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); 385 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
386
387 if (likely(regs)) {
388 *childregs = *regs;
389 childregs->ARM_r0 = 0;
390 childregs->ARM_sp = stack_start;
391 thread->cpu_context.pc = (unsigned long)ret_from_fork;
392 } else {
393 thread->cpu_context.r4 = stk_sz;
394 thread->cpu_context.r5 = stack_start;
395 thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
396 childregs->ARM_cpsr = SVC_MODE;
397 }
389 thread->cpu_context.sp = (unsigned long)childregs; 398 thread->cpu_context.sp = (unsigned long)childregs;
390 thread->cpu_context.pc = (unsigned long)ret_from_fork;
391 399
392 clear_ptrace_hw_breakpoint(p); 400 clear_ptrace_hw_breakpoint(p);
393 401
@@ -423,63 +431,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
423} 431}
424EXPORT_SYMBOL(dump_fpu); 432EXPORT_SYMBOL(dump_fpu);
425 433
426/*
427 * Shuffle the argument into the correct register before calling the
428 * thread function. r4 is the thread argument, r5 is the pointer to
429 * the thread function, and r6 points to the exit function.
430 */
431extern void kernel_thread_helper(void);
432asm( ".pushsection .text\n"
433" .align\n"
434" .type kernel_thread_helper, #function\n"
435"kernel_thread_helper:\n"
436#ifdef CONFIG_TRACE_IRQFLAGS
437" bl trace_hardirqs_on\n"
438#endif
439" msr cpsr_c, r7\n"
440" mov r0, r4\n"
441" mov lr, r6\n"
442" mov pc, r5\n"
443" .size kernel_thread_helper, . - kernel_thread_helper\n"
444" .popsection");
445
446#ifdef CONFIG_ARM_UNWIND
447extern void kernel_thread_exit(long code);
448asm( ".pushsection .text\n"
449" .align\n"
450" .type kernel_thread_exit, #function\n"
451"kernel_thread_exit:\n"
452" .fnstart\n"
453" .cantunwind\n"
454" bl do_exit\n"
455" nop\n"
456" .fnend\n"
457" .size kernel_thread_exit, . - kernel_thread_exit\n"
458" .popsection");
459#else
460#define kernel_thread_exit do_exit
461#endif
462
463/*
464 * Create a kernel thread.
465 */
466pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
467{
468 struct pt_regs regs;
469
470 memset(&regs, 0, sizeof(regs));
471
472 regs.ARM_r4 = (unsigned long)arg;
473 regs.ARM_r5 = (unsigned long)fn;
474 regs.ARM_r6 = (unsigned long)kernel_thread_exit;
475 regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
476 regs.ARM_pc = (unsigned long)kernel_thread_helper;
477 regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;
478
479 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
480}
481EXPORT_SYMBOL(kernel_thread);
482
483unsigned long get_wchan(struct task_struct *p) 434unsigned long get_wchan(struct task_struct *p)
484{ 435{
485 struct stackframe frame; 436 struct stackframe frame;