powerpc: split ret_from_fork

... and get rid of in-kernel syscalls in kernel_thread()

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro
2012-09-12 18:32:42 -04:00
parent f322220d61
commit 58254e1002
8 changed files with 43 additions and 84 deletions

View File

@@ -734,30 +734,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
int copy_thread(unsigned long clone_flags, unsigned long usp,
unsigned long unused, struct task_struct *p,
unsigned long arg, struct task_struct *p,
struct pt_regs *regs)
{
struct pt_regs *childregs, *kregs;
extern void ret_from_fork(void);
extern void ret_from_kernel_thread(void);
void (*f)(void);
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
CHECK_FULL_REGS(regs);
/* Copy registers */
sp -= sizeof(struct pt_regs);
childregs = (struct pt_regs *) sp;
*childregs = *regs;
if ((childregs->msr & MSR_PR) == 0) {
if (!regs) {
/* for kernel thread, set `current' and stackptr in new task */
memset(childregs, 0, sizeof(struct pt_regs));
childregs->gpr[1] = sp + sizeof(struct pt_regs);
#ifdef CONFIG_PPC32
childregs->gpr[2] = (unsigned long) p;
#else
#ifdef CONFIG_PPC64
childregs->gpr[14] = *(unsigned long *)usp;
childregs->gpr[2] = ((unsigned long *)usp)[1],
clear_tsk_thread_flag(p, TIF_32BIT);
#else
childregs->gpr[14] = usp; /* function */
childregs->gpr[2] = (unsigned long) p;
#endif
childregs->gpr[15] = arg;
p->thread.regs = NULL; /* no user register state */
f = ret_from_kernel_thread;
} else {
CHECK_FULL_REGS(regs);
*childregs = *regs;
childregs->gpr[1] = usp;
p->thread.regs = childregs;
childregs->gpr[3] = 0; /* Result from fork() */
if (clone_flags & CLONE_SETTLS) {
#ifdef CONFIG_PPC64
if (!is_32bit_task())
@@ -766,8 +775,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
#endif
childregs->gpr[2] = childregs->gpr[6];
}
f = ret_from_fork;
}
childregs->gpr[3] = 0; /* Result from fork() */
sp -= STACK_FRAME_OVERHEAD;
/*
@@ -806,19 +816,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.dscr = current->thread.dscr;
}
#endif
/*
* The PPC64 ABI makes use of a TOC to contain function
* pointers. The function (ret_from_except) is actually a pointer
* to the TOC entry. The first entry is a pointer to the actual
* function.
*/
*/
#ifdef CONFIG_PPC64
kregs->nip = *((unsigned long *)ret_from_fork);
kregs->nip = *((unsigned long *)f);
#else
kregs->nip = (unsigned long)ret_from_fork;
kregs->nip = (unsigned long)f;
#endif
return 0;
}