Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c34501d2 authored by Catalin Marinas's avatar Catalin Marinas
Browse files

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: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent ddffeb8c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ config ARM64
	select GENERIC_IOMAP
	select GENERIC_IRQ_PROBE
	select GENERIC_IRQ_SHOW
	select GENERIC_KERNEL_THREAD
	select GENERIC_SMP_IDLE_THREAD
	select GENERIC_TIME_VSYSCALL
	select HARDIRQS_SW_RESEND
+0 −5
Original line number Diff line number Diff line
@@ -136,11 +136,6 @@ unsigned long get_wchan(struct task_struct *p);
extern struct task_struct *cpu_switch_to(struct task_struct *prev,
					 struct task_struct *next);

/*
 * Create a new kernel thread
 */
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);

#define task_pt_regs(p) \
	((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)

+4 −1
Original line number Diff line number Diff line
@@ -611,7 +611,10 @@ ENDPROC(ret_to_user)
 */
ENTRY(ret_from_fork)
	bl	schedule_tail
	get_thread_info tsk
	cbz	x19, 1f				// not a kernel thread
	mov	x0, x20
	blr	x19
1:	get_thread_info tsk
	b	ret_to_user
ENDPROC(ret_from_fork)

+24 −53
Original line number Diff line number Diff line
@@ -240,12 +240,14 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
	struct pt_regs *childregs = task_pt_regs(p);
	unsigned long tls = p->thread.tp_value;

	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));

	if (likely(regs)) {
		*childregs = *regs;
		childregs->regs[0] = 0;

	if (is_compat_thread(task_thread_info(p)))
		if (is_compat_thread(task_thread_info(p))) {
			childregs->compat_sp = stack_start;
	else {
		} else {
			/*
			 * Read the current TLS pointer from tpidr_el0 as it may be
			 * out-of-sync with the saved value.
@@ -253,14 +255,20 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
			asm("mrs %0, tpidr_el0" : "=r" (tls));
			childregs->sp = stack_start;
		}

	memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
	p->thread.cpu_context.sp = (unsigned long)childregs;
	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;

	/* If a TLS pointer was passed to clone, use that for the new thread. */
		/*
		 * If a TLS pointer was passed to clone (4th argument), use it
		 * for the new thread.
		 */
		if (clone_flags & CLONE_SETTLS)
			tls = regs->regs[3];
	} else {
		memset(childregs, 0, sizeof(struct pt_regs));
		childregs->pstate = PSR_MODE_EL1h;
		p->thread.cpu_context.x19 = stack_start;
		p->thread.cpu_context.x20 = stk_sz;
	}
	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
	p->thread.cpu_context.sp = (unsigned long)childregs;
	p->thread.tp_value = tls;

	ptrace_hw_copy_thread(p);
@@ -327,43 +335,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
}
EXPORT_SYMBOL(dump_fpu);

/*
 * Shuffle the argument into the correct register before calling the
 * thread function.  x1 is the thread argument, x2 is the pointer to
 * the thread function, and x3 points to the exit function.
 */
extern void kernel_thread_helper(void);
asm(	".section .text\n"
"	.align\n"
"	.type	kernel_thread_helper, #function\n"
"kernel_thread_helper:\n"
"	mov	x0, x1\n"
"	mov	x30, x3\n"
"	br	x2\n"
"	.size	kernel_thread_helper, . - kernel_thread_helper\n"
"	.previous");

#define kernel_thread_exit	do_exit

/*
 * Create a kernel thread.
 */
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
	struct pt_regs regs;

	memset(&regs, 0, sizeof(regs));

	regs.regs[1] = (unsigned long)arg;
	regs.regs[2] = (unsigned long)fn;
	regs.regs[3] = (unsigned long)kernel_thread_exit;
	regs.pc = (unsigned long)kernel_thread_helper;
	regs.pstate = PSR_MODE_EL1h;

	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);

unsigned long get_wchan(struct task_struct *p)
{
	struct stackframe frame;