aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/process.c
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2012-10-05 07:31:20 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2012-10-17 09:33:31 -0400
commitc34501d21b005a6e363386a19519bd11cf92a67c (patch)
treec17d7a800d21418ef12d635a8275ebb063e2816a /arch/arm64/kernel/process.c
parentddffeb8c4d0331609ef2581d84de4d763607bd37 (diff)
arm64: Use generic kernel_thread() implementation
This patch enables CONFIG_GENERIC_KERNEL_THREAD on arm64, changes copy_threads to cope with kernel threads creation and adapts ret_from_fork accordingly. The arm64-specific kernel_thread implementation is no longer needed. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel/process.c')
-rw-r--r--arch/arm64/kernel/process.c77
1 files changed, 24 insertions, 53 deletions
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index f22965ea1cfc..bf615e212c6c 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -240,27 +240,35 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
240 struct pt_regs *childregs = task_pt_regs(p); 240 struct pt_regs *childregs = task_pt_regs(p);
241 unsigned long tls = p->thread.tp_value; 241 unsigned long tls = p->thread.tp_value;
242 242
243 *childregs = *regs; 243 memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
244 childregs->regs[0] = 0;
245 244
246 if (is_compat_thread(task_thread_info(p))) 245 if (likely(regs)) {
247 childregs->compat_sp = stack_start; 246 *childregs = *regs;
248 else { 247 childregs->regs[0] = 0;
248 if (is_compat_thread(task_thread_info(p))) {
249 childregs->compat_sp = stack_start;
250 } else {
251 /*
252 * Read the current TLS pointer from tpidr_el0 as it may be
253 * out-of-sync with the saved value.
254 */
255 asm("mrs %0, tpidr_el0" : "=r" (tls));
256 childregs->sp = stack_start;
257 }
249 /* 258 /*
250 * Read the current TLS pointer from tpidr_el0 as it may be 259 * If a TLS pointer was passed to clone (4th argument), use it
251 * out-of-sync with the saved value. 260 * for the new thread.
252 */ 261 */
253 asm("mrs %0, tpidr_el0" : "=r" (tls)); 262 if (clone_flags & CLONE_SETTLS)
254 childregs->sp = stack_start; 263 tls = regs->regs[3];
264 } else {
265 memset(childregs, 0, sizeof(struct pt_regs));
266 childregs->pstate = PSR_MODE_EL1h;
267 p->thread.cpu_context.x19 = stack_start;
268 p->thread.cpu_context.x20 = stk_sz;
255 } 269 }
256
257 memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
258 p->thread.cpu_context.sp = (unsigned long)childregs;
259 p->thread.cpu_context.pc = (unsigned long)ret_from_fork; 270 p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
260 271 p->thread.cpu_context.sp = (unsigned long)childregs;
261 /* If a TLS pointer was passed to clone, use that for the new thread. */
262 if (clone_flags & CLONE_SETTLS)
263 tls = regs->regs[3];
264 p->thread.tp_value = tls; 272 p->thread.tp_value = tls;
265 273
266 ptrace_hw_copy_thread(p); 274 ptrace_hw_copy_thread(p);
@@ -327,43 +335,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
327} 335}
328EXPORT_SYMBOL(dump_fpu); 336EXPORT_SYMBOL(dump_fpu);
329 337
330/*
331 * Shuffle the argument into the correct register before calling the
332 * thread function. x1 is the thread argument, x2 is the pointer to
333 * the thread function, and x3 points to the exit function.
334 */
335extern void kernel_thread_helper(void);
336asm( ".section .text\n"
337" .align\n"
338" .type kernel_thread_helper, #function\n"
339"kernel_thread_helper:\n"
340" mov x0, x1\n"
341" mov x30, x3\n"
342" br x2\n"
343" .size kernel_thread_helper, . - kernel_thread_helper\n"
344" .previous");
345
346#define kernel_thread_exit do_exit
347
348/*
349 * Create a kernel thread.
350 */
351pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
352{
353 struct pt_regs regs;
354
355 memset(&regs, 0, sizeof(regs));
356
357 regs.regs[1] = (unsigned long)arg;
358 regs.regs[2] = (unsigned long)fn;
359 regs.regs[3] = (unsigned long)kernel_thread_exit;
360 regs.pc = (unsigned long)kernel_thread_helper;
361 regs.pstate = PSR_MODE_EL1h;
362
363 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
364}
365EXPORT_SYMBOL(kernel_thread);
366
367unsigned long get_wchan(struct task_struct *p) 338unsigned long get_wchan(struct task_struct *p)
368{ 339{
369 struct stackframe frame; 340 struct stackframe frame;