aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/avr32/kernel/process.c')
-rw-r--r--arch/avr32/kernel/process.c67
1 files changed, 17 insertions, 50 deletions
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 1bb0a8abd79..07380c3a4f7 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -69,44 +69,6 @@ void machine_restart(char *cmd)
69} 69}
70 70
71/* 71/*
72 * PC is actually discarded when returning from a system call -- the
73 * return address must be stored in LR. This function will make sure
74 * LR points to do_exit before starting the thread.
75 *
76 * Also, when returning from fork(), r12 is 0, so we must copy the
77 * argument as well.
78 *
79 * r0 : The argument to the main thread function
80 * r1 : The address of do_exit
81 * r2 : The address of the main thread function
82 */
83asmlinkage extern void kernel_thread_helper(void);
84__asm__(" .type kernel_thread_helper, @function\n"
85 "kernel_thread_helper:\n"
86 " mov r12, r0\n"
87 " mov lr, r2\n"
88 " mov pc, r1\n"
89 " .size kernel_thread_helper, . - kernel_thread_helper");
90
91int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
92{
93 struct pt_regs regs;
94
95 memset(&regs, 0, sizeof(regs));
96
97 regs.r0 = (unsigned long)arg;
98 regs.r1 = (unsigned long)fn;
99 regs.r2 = (unsigned long)do_exit;
100 regs.lr = (unsigned long)kernel_thread_helper;
101 regs.pc = (unsigned long)kernel_thread_helper;
102 regs.sr = MODE_SUPERVISOR;
103
104 return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
105 0, &regs, 0, NULL, NULL);
106}
107EXPORT_SYMBOL(kernel_thread);
108
109/*
110 * Free current thread data structures etc 72 * Free current thread data structures etc
111 */ 73 */
112void exit_thread(void) 74void exit_thread(void)
@@ -332,26 +294,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
332} 294}
333 295
334asmlinkage void ret_from_fork(void); 296asmlinkage void ret_from_fork(void);
297asmlinkage void ret_from_kernel_thread(void);
298asmlinkage void syscall_return(void);
335 299
336int copy_thread(unsigned long clone_flags, unsigned long usp, 300int copy_thread(unsigned long clone_flags, unsigned long usp,
337 unsigned long unused, 301 unsigned long arg,
338 struct task_struct *p, struct pt_regs *regs) 302 struct task_struct *p, struct pt_regs *regs)
339{ 303{
340 struct pt_regs *childregs; 304 struct pt_regs *childregs = task_pt_regs(p);
341 305
342 childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1; 306 if (unlikely(!regs)) {
343 *childregs = *regs; 307 memset(childregs, 0, sizeof(struct pt_regs));
344 308 p->thread.cpu_context.r0 = arg;
345 if (user_mode(regs)) 309 p->thread.cpu_context.r1 = usp; /* fn */
310 p->thread.cpu_context.r2 = syscall_return;
311 p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
312 childregs->sr = MODE_SUPERVISOR;
313 } else {
314 *childregs = *regs;
346 childregs->sp = usp; 315 childregs->sp = usp;
347 else 316 childregs->r12 = 0; /* Set return value for child */
348 childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; 317 p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
349 318 }
350 childregs->r12 = 0; /* Set return value for child */
351 319
352 p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; 320 p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
353 p->thread.cpu_context.ksp = (unsigned long)childregs; 321 p->thread.cpu_context.ksp = (unsigned long)childregs;
354 p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
355 322
356 clear_tsk_thread_flag(p, TIF_DEBUG); 323 clear_tsk_thread_flag(p, TIF_DEBUG);
357 if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) 324 if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))