ia64: switch to generic kernel_thread()/kernel_execve()
Acked-by: Tony Luck <tony.luck@intel.com> Tested-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
@@ -401,55 +401,15 @@ copy_thread(unsigned long clone_flags,
|
||||
struct pt_regs *child_ptregs;
|
||||
int retval = 0;
|
||||
|
||||
stack = ((struct switch_stack *) regs) - 1;
|
||||
|
||||
child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1;
|
||||
child_stack = (struct switch_stack *) child_ptregs - 1;
|
||||
|
||||
/* copy parent's switch_stack & pt_regs to child: */
|
||||
memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
|
||||
|
||||
rbs = (unsigned long) current + IA64_RBS_OFFSET;
|
||||
child_rbs = (unsigned long) p + IA64_RBS_OFFSET;
|
||||
|
||||
if (likely(user_mode(child_ptregs))) {
|
||||
/* copy the parent's register backing store to the child: */
|
||||
rbs_size = stack->ar_bspstore - rbs;
|
||||
memcpy((void *) child_rbs, (void *) rbs, rbs_size);
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */
|
||||
if (user_stack_base) {
|
||||
child_ptregs->r12 = user_stack_base + user_stack_size - 16;
|
||||
child_ptregs->ar_bspstore = user_stack_base;
|
||||
child_ptregs->ar_rnat = 0;
|
||||
child_ptregs->loadrs = 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Note: we simply preserve the relative position of
|
||||
* the stack pointer here. There is no need to
|
||||
* allocate a scratch area here, since that will have
|
||||
* been taken care of by the caller of sys_clone()
|
||||
* already.
|
||||
*/
|
||||
rbs_size = 0;
|
||||
child_ptregs->r12 = (unsigned long) child_ptregs - 16; /* kernel sp */
|
||||
child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */
|
||||
}
|
||||
child_stack->ar_bspstore = child_rbs + rbs_size;
|
||||
child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
|
||||
|
||||
/* copy parts of thread_struct: */
|
||||
p->thread.ksp = (unsigned long) child_stack - 16;
|
||||
|
||||
/* stop some PSR bits from being inherited.
|
||||
* the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
|
||||
* therefore we must specify them explicitly here and not include them in
|
||||
* IA64_PSR_BITS_TO_CLEAR.
|
||||
*/
|
||||
child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
|
||||
& ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
|
||||
|
||||
/*
|
||||
* NOTE: The calling convention considers all floating point
|
||||
* registers in the high partition (fph) to be scratch. Since
|
||||
@@ -471,8 +431,66 @@ copy_thread(unsigned long clone_flags,
|
||||
# define THREAD_FLAGS_TO_SET 0
|
||||
p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
|
||||
| THREAD_FLAGS_TO_SET);
|
||||
|
||||
ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */
|
||||
|
||||
if (unlikely(p->flags & PF_KTHREAD)) {
|
||||
if (unlikely(!user_stack_base)) {
|
||||
/* fork_idle() called us */
|
||||
return 0;
|
||||
}
|
||||
memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack));
|
||||
child_stack->r4 = user_stack_base; /* payload */
|
||||
child_stack->r5 = user_stack_size; /* argument */
|
||||
/*
|
||||
* Preserve PSR bits, except for bits 32-34 and 37-45,
|
||||
* which we can't read.
|
||||
*/
|
||||
child_ptregs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
|
||||
/* mark as valid, empty frame */
|
||||
child_ptregs->cr_ifs = 1UL << 63;
|
||||
child_stack->ar_fpsr = child_ptregs->ar_fpsr
|
||||
= ia64_getreg(_IA64_REG_AR_FPSR);
|
||||
child_stack->pr = (1 << PRED_KERNEL_STACK);
|
||||
child_stack->ar_bspstore = child_rbs;
|
||||
child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
|
||||
|
||||
/* stop some PSR bits from being inherited.
|
||||
* the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
|
||||
* therefore we must specify them explicitly here and not include them in
|
||||
* IA64_PSR_BITS_TO_CLEAR.
|
||||
*/
|
||||
child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
|
||||
& ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
|
||||
|
||||
return 0;
|
||||
}
|
||||
stack = ((struct switch_stack *) regs) - 1;
|
||||
/* copy parent's switch_stack & pt_regs to child: */
|
||||
memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
|
||||
|
||||
/* copy the parent's register backing store to the child: */
|
||||
rbs_size = stack->ar_bspstore - rbs;
|
||||
memcpy((void *) child_rbs, (void *) rbs, rbs_size);
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */
|
||||
if (user_stack_base) {
|
||||
child_ptregs->r12 = user_stack_base + user_stack_size - 16;
|
||||
child_ptregs->ar_bspstore = user_stack_base;
|
||||
child_ptregs->ar_rnat = 0;
|
||||
child_ptregs->loadrs = 0;
|
||||
}
|
||||
child_stack->ar_bspstore = child_rbs + rbs_size;
|
||||
child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
|
||||
|
||||
/* stop some PSR bits from being inherited.
|
||||
* the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
|
||||
* therefore we must specify them explicitly here and not include them in
|
||||
* IA64_PSR_BITS_TO_CLEAR.
|
||||
*/
|
||||
child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
|
||||
& ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
|
||||
|
||||
#ifdef CONFIG_PERFMON
|
||||
if (current->thread.pfm_context)
|
||||
pfm_inherit(p, child_ptregs);
|
||||
@@ -618,37 +636,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
pid_t
|
||||
kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
|
||||
{
|
||||
extern void start_kernel_thread (void);
|
||||
unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread;
|
||||
struct {
|
||||
struct switch_stack sw;
|
||||
struct pt_regs pt;
|
||||
} regs;
|
||||
|
||||
memset(®s, 0, sizeof(regs));
|
||||
regs.pt.cr_iip = helper_fptr[0]; /* set entry point (IP) */
|
||||
regs.pt.r1 = helper_fptr[1]; /* set GP */
|
||||
regs.pt.r9 = (unsigned long) fn; /* 1st argument */
|
||||
regs.pt.r11 = (unsigned long) arg; /* 2nd argument */
|
||||
/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */
|
||||
regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
|
||||
regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */
|
||||
regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
|
||||
regs.sw.pr = (1 << PRED_KERNEL_STACK);
|
||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
/* This gets called from kernel_thread() via ia64_invoke_thread_helper(). */
|
||||
int
|
||||
kernel_thread_helper (int (*fn)(void *), void *arg)
|
||||
{
|
||||
return (*fn)(arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush thread state. This is called when a thread does an execve().
|
||||
*/
|
||||
|
Reference in New Issue
Block a user