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

Commit 9e14f828 authored by Al Viro's avatar Al Viro
Browse files

arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk]



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 38b983b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ config ARM
	select GENERIC_STRNCPY_FROM_USER
	select GENERIC_STRNLEN_USER
	select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
	select GENERIC_KERNEL_THREAD
	help
	  The ARM series is a line of low-power-consumption RISC chip designs
	  licensed by ARM Ltd and targeted at embedded applications and
+0 −5
Original line number Diff line number Diff line
@@ -85,11 +85,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax()			barrier()
#endif

/*
 * 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)

+12 −0
Original line number Diff line number Diff line
@@ -91,6 +91,18 @@ ENTRY(ret_from_fork)
	b	ret_slow_syscall
ENDPROC(ret_from_fork)

ENTRY(ret_from_kernel_thread)
 UNWIND(.fnstart)
 UNWIND(.cantunwind)
	bl	schedule_tail
	mov	r0, r4
	adr	lr, BSYM(1f)	@ kernel threads should not exit
	mov	pc, r5
1:	bl	do_exit
	nop
 UNWIND(.fnend)
ENDPROC(ret_from_kernel_thread)

	.equ NR_syscalls,0
#define CALL(x) .equ NR_syscalls,NR_syscalls+1
#include "calls.S"
+13 −62
Original line number Diff line number Diff line
@@ -373,6 +373,7 @@ void release_thread(struct task_struct *dead_task)
}

asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");

int
copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -381,13 +382,20 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
	struct thread_info *thread = task_thread_info(p);
	struct pt_regs *childregs = task_pt_regs(p);

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

	if (likely(regs)) {
		*childregs = *regs;
		childregs->ARM_r0 = 0;
		childregs->ARM_sp = stack_start;

	memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
	thread->cpu_context.sp = (unsigned long)childregs;
		thread->cpu_context.pc = (unsigned long)ret_from_fork;
	} else {
		thread->cpu_context.r4 = stk_sz;
		thread->cpu_context.r5 = stack_start;
		thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
		childregs->ARM_cpsr = SVC_MODE;
	}
	thread->cpu_context.sp = (unsigned long)childregs;

	clear_ptrace_hw_breakpoint(p);

@@ -423,63 +431,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.  r4 is the thread argument, r5 is the pointer to
 * the thread function, and r6 points to the exit function.
 */
extern void kernel_thread_helper(void);
asm(	".pushsection .text\n"
"	.align\n"
"	.type	kernel_thread_helper, #function\n"
"kernel_thread_helper:\n"
#ifdef CONFIG_TRACE_IRQFLAGS
"	bl	trace_hardirqs_on\n"
#endif
"	msr	cpsr_c, r7\n"
"	mov	r0, r4\n"
"	mov	lr, r6\n"
"	mov	pc, r5\n"
"	.size	kernel_thread_helper, . - kernel_thread_helper\n"
"	.popsection");

#ifdef CONFIG_ARM_UNWIND
extern void kernel_thread_exit(long code);
asm(	".pushsection .text\n"
"	.align\n"
"	.type	kernel_thread_exit, #function\n"
"kernel_thread_exit:\n"
"	.fnstart\n"
"	.cantunwind\n"
"	bl	do_exit\n"
"	nop\n"
"	.fnend\n"
"	.size	kernel_thread_exit, . - kernel_thread_exit\n"
"	.popsection");
#else
#define kernel_thread_exit	do_exit
#endif

/*
 * 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.ARM_r4 = (unsigned long)arg;
	regs.ARM_r5 = (unsigned long)fn;
	regs.ARM_r6 = (unsigned long)kernel_thread_exit;
	regs.ARM_r7 = SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;
	regs.ARM_pc = (unsigned long)kernel_thread_helper;
	regs.ARM_cpsr = regs.ARM_r7 | PSR_I_BIT;

	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;