Commit 5adc807f authored by Al Viro's avatar Al Viro
Browse files

avr32: switch to generic kernel_thread()/kernel_execve()



Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ddffeb8c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ config AVR32
	select GENERIC_CLOCKEVENTS
	select HAVE_MOD_ARCH_SPECIFIC
	select MODULES_USE_ELF_RELA
	select GENERIC_KERNEL_THREAD
	select GENERIC_KERNEL_EXECVE
	help
	  AVR32 is a high-performance 32-bit RISC microprocessor core,
	  designed for cost-sensitive embedded applications, with particular
+0 −3
Original line number Diff line number Diff line
@@ -142,9 +142,6 @@ struct task_struct;
/* Free all resources held by a thread */
extern void release_thread(struct task_struct *);

/* Create a kernel thread without removing it from tasklists */
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);

/* Return saved PC of a blocked thread */
#define thread_saved_pc(tsk)    ((tsk)->thread.cpu_context.pc)

+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds
obj-$(CONFIG_SUBARCH_AVR32B)	+= entry-avr32b.o
obj-y				+= syscall_table.o syscall-stubs.o irq.o
obj-y				+= setup.o traps.o ocd.o ptrace.o
obj-y				+= signal.o sys_avr32.o process.o time.o
obj-y				+= signal.o process.o time.o
obj-y				+= switch_to.o cpu.o
obj-$(CONFIG_MODULES)		+= module.o avr32_ksyms.o
obj-$(CONFIG_KPROBES)		+= kprobes.o
+8 −6
Original line number Diff line number Diff line
@@ -251,13 +251,15 @@ syscall_badsys:
	.global ret_from_fork
ret_from_fork:
	call   schedule_tail
	mov	r12, 0
	rjmp	syscall_return

	/* check for syscall tracing */
	get_thread_info r0
	ld.w	r1, r0[TI_flags]
	andl	r1, _TIF_ALLWORK_MASK, COH
	brne	syscall_exit_work
	rjmp    syscall_exit_cont
	.global ret_from_kernel_thread
ret_from_kernel_thread:
	call   schedule_tail
	mov	r12, r0
	mov	lr, r2	/* syscall_return */
	mov	pc, r1

syscall_trace_enter:
	pushm	r8-r12
+17 −50
Original line number Diff line number Diff line
@@ -68,44 +68,6 @@ void machine_restart(char *cmd)
	while (1) ;
}

/*
 * PC is actually discarded when returning from a system call -- the
 * return address must be stored in LR. This function will make sure
 * LR points to do_exit before starting the thread.
 *
 * Also, when returning from fork(), r12 is 0, so we must copy the
 * argument as well.
 *
 *  r0 : The argument to the main thread function
 *  r1 : The address of do_exit
 *  r2 : The address of the main thread function
 */
asmlinkage extern void kernel_thread_helper(void);
__asm__("	.type	kernel_thread_helper, @function\n"
	"kernel_thread_helper:\n"
	"	mov	r12, r0\n"
	"	mov	lr, r2\n"
	"	mov	pc, r1\n"
	"	.size	kernel_thread_helper, . - kernel_thread_helper");

int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
	struct pt_regs regs;

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

	regs.r0 = (unsigned long)arg;
	regs.r1 = (unsigned long)fn;
	regs.r2 = (unsigned long)do_exit;
	regs.lr = (unsigned long)kernel_thread_helper;
	regs.pc = (unsigned long)kernel_thread_helper;
	regs.sr = MODE_SUPERVISOR;

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

/*
 * Free current thread data structures etc
 */
@@ -332,26 +294,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
}

asmlinkage void ret_from_fork(void);
asmlinkage void ret_from_kernel_thread(void);
asmlinkage void syscall_return(void);

int copy_thread(unsigned long clone_flags, unsigned long usp,
		unsigned long unused,
		unsigned long arg,
		struct task_struct *p, struct pt_regs *regs)
{
	struct pt_regs *childregs;

	childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
	struct pt_regs *childregs = task_pt_regs(p);

	if (unlikely(!regs)) {
		memset(childregs, 0, sizeof(struct pt_regs));
		p->thread.cpu_context.r0 = arg;
		p->thread.cpu_context.r1 = usp; /* fn */
		p->thread.cpu_context.r2 = syscall_return;
		p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
		childregs->sr = MODE_SUPERVISOR;
	} else {
		*childregs = *regs;

	if (user_mode(regs))
		childregs->sp = usp;
	else
		childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;

		childregs->r12 = 0; /* Set return value for child */
		p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
	}

	p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
	p->thread.cpu_context.ksp = (unsigned long)childregs;
	p->thread.cpu_context.pc = (unsigned long)ret_from_fork;

	clear_tsk_thread_flag(p, TIF_DEBUG);
	if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
Loading