diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2012-10-05 07:31:20 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2012-10-17 09:33:31 -0400 |
commit | c34501d21b005a6e363386a19519bd11cf92a67c (patch) | |
tree | c17d7a800d21418ef12d635a8275ebb063e2816a /arch/arm64/kernel/process.c | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (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.c | 77 |
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 | } |
328 | EXPORT_SYMBOL(dump_fpu); | 336 | EXPORT_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 | */ | ||
335 | extern void kernel_thread_helper(void); | ||
336 | asm( ".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 | */ | ||
351 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
352 | { | ||
353 | struct pt_regs regs; | ||
354 | |||
355 | memset(®s, 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, ®s, 0, NULL, NULL); | ||
364 | } | ||
365 | EXPORT_SYMBOL(kernel_thread); | ||
366 | |||
367 | unsigned long get_wchan(struct task_struct *p) | 338 | unsigned long get_wchan(struct task_struct *p) |
368 | { | 339 | { |
369 | struct stackframe frame; | 340 | struct stackframe frame; |