aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
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
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')
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/processor.h5
-rw-r--r--arch/arm64/kernel/entry.S5
-rw-r--r--arch/arm64/kernel/process.c77
4 files changed, 29 insertions, 59 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7ff68c946073..4077b71b1258 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -6,6 +6,7 @@ config ARM64
6 select GENERIC_IOMAP 6 select GENERIC_IOMAP
7 select GENERIC_IRQ_PROBE 7 select GENERIC_IRQ_PROBE
8 select GENERIC_IRQ_SHOW 8 select GENERIC_IRQ_SHOW
9 select GENERIC_KERNEL_THREAD
9 select GENERIC_SMP_IDLE_THREAD 10 select GENERIC_SMP_IDLE_THREAD
10 select GENERIC_TIME_VSYSCALL 11 select GENERIC_TIME_VSYSCALL
11 select HARDIRQS_SW_RESEND 12 select HARDIRQS_SW_RESEND
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 39a208a392f7..d6331acaf64e 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -136,11 +136,6 @@ unsigned long get_wchan(struct task_struct *p);
136extern struct task_struct *cpu_switch_to(struct task_struct *prev, 136extern struct task_struct *cpu_switch_to(struct task_struct *prev,
137 struct task_struct *next); 137 struct task_struct *next);
138 138
139/*
140 * Create a new kernel thread
141 */
142extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
143
144#define task_pt_regs(p) \ 139#define task_pt_regs(p) \
145 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) 140 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
146 141
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index a6f3f7da6880..08db8972ebcc 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -611,7 +611,10 @@ ENDPROC(ret_to_user)
611 */ 611 */
612ENTRY(ret_from_fork) 612ENTRY(ret_from_fork)
613 bl schedule_tail 613 bl schedule_tail
614 get_thread_info tsk 614 cbz x19, 1f // not a kernel thread
615 mov x0, x20
616 blr x19
6171: get_thread_info tsk
615 b ret_to_user 618 b ret_to_user
616ENDPROC(ret_from_fork) 619ENDPROC(ret_from_fork)
617 620
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;