diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-05 22:37:01 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 19:26:52 -0400 |
commit | 1918c7f548dc5abfb37ab74bb3d036d36c92ba5e (patch) | |
tree | c6f1a678fd6dac2ab93579a7246afb27cc7f9f26 /arch/sparc/kernel/process_64.c | |
parent | dff933da765fd4855393846fa55286d1ff2d024a (diff) | |
download | op-kernel-dev-1918c7f548dc5abfb37ab74bb3d036d36c92ba5e.zip op-kernel-dev-1918c7f548dc5abfb37ab74bb3d036d36c92ba5e.tar.gz |
sparc64: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/sparc/kernel/process_64.c')
-rw-r--r-- | arch/sparc/kernel/process_64.c | 107 |
1 files changed, 30 insertions, 77 deletions
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 4c864c7..e375123 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -538,64 +538,56 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, * Child --> %o0 == parents pid, %o1 == 1 */ int copy_thread(unsigned long clone_flags, unsigned long sp, - unsigned long unused, + unsigned long arg, struct task_struct *p, struct pt_regs *regs) { struct thread_info *t = task_thread_info(p); struct sparc_stackf *parent_sf; unsigned long child_stack_sz; char *child_trap_frame; - int kernel_thread; - - kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0; - parent_sf = ((struct sparc_stackf *) regs) - 1; /* Calculate offset to stack_frame & pt_regs */ - child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + - (kernel_thread ? STACKFRAME_SZ : 0)); + child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ); child_trap_frame = (task_stack_page(p) + (THREAD_SIZE - child_stack_sz)); - memcpy(child_trap_frame, parent_sf, child_stack_sz); - __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = - (regs->tstate + 1) & TSTATE_CWP; t->new_child = 1; t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; t->kregs = (struct pt_regs *) (child_trap_frame + sizeof(struct sparc_stackf)); t->fpsaved[0] = 0; - if (kernel_thread) { - struct sparc_stackf *child_sf = (struct sparc_stackf *) - (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); - - /* Zero terminate the stack backtrace. */ - child_sf->fp = NULL; - t->kregs->u_regs[UREG_FP] = - ((unsigned long) child_sf) - STACK_BIAS; - + if (unlikely(p->flags & PF_KTHREAD)) { + memset(child_trap_frame, 0, child_stack_sz); + __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = + (current_pt_regs()->tstate + 1) & TSTATE_CWP; t->current_ds = ASI_P; - t->kregs->u_regs[UREG_G6] = (unsigned long) t; - t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; - } else { - if (t->flags & _TIF_32BIT) { - sp &= 0x00000000ffffffffUL; - regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - } - t->kregs->u_regs[UREG_FP] = sp; - t->current_ds = ASI_AIUS; - if (sp != regs->u_regs[UREG_FP]) { - unsigned long csp; - - csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); - if (!csp) - return -EFAULT; - t->kregs->u_regs[UREG_FP] = csp; - } - if (t->utraps) - t->utraps[0]++; + t->kregs->u_regs[UREG_G1] = sp; /* function */ + t->kregs->u_regs[UREG_G2] = arg; + return 0; } + parent_sf = ((struct sparc_stackf *) regs) - 1; + memcpy(child_trap_frame, parent_sf, child_stack_sz); + if (t->flags & _TIF_32BIT) { + sp &= 0x00000000ffffffffUL; + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + } + t->kregs->u_regs[UREG_FP] = sp; + __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = + (regs->tstate + 1) & TSTATE_CWP; + t->current_ds = ASI_AIUS; + if (sp != regs->u_regs[UREG_FP]) { + unsigned long csp; + + csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); + if (!csp) + return -EFAULT; + t->kregs->u_regs[UREG_FP] = csp; + } + if (t->utraps) + t->utraps[0]++; + /* Set the return value for the child. */ t->kregs->u_regs[UREG_I0] = current->pid; t->kregs->u_regs[UREG_I1] = 1; @@ -609,45 +601,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, return 0; } -/* - * This is the mechanism for creating a new kernel thread. - * - * NOTE! Only a kernel-only process(ie the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be freed until both the parent and the child have exited. - */ -pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - long retval; - - /* If the parent runs before fn(arg) is called by the child, - * the input registers of this function can be clobbered. - * So we stash 'fn' and 'arg' into global registers which - * will not be modified by the parent. - */ - __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */ - "mov %5, %%g3\n\t" /* Save ARG into global */ - "mov %1, %%g1\n\t" /* Clone syscall nr. */ - "mov %2, %%o0\n\t" /* Clone flags. */ - "mov 0, %%o1\n\t" /* usp arg == 0 */ - "t 0x6d\n\t" /* Linux/Sparc clone(). */ - "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ - " mov %%o0, %0\n\t" - "jmpl %%g2, %%o7\n\t" /* Call the function. */ - " mov %%g3, %%o0\n\t" /* Set arg in delay. */ - "mov %3, %%g1\n\t" - "t 0x6d\n\t" /* Linux/Sparc exit(). */ - /* Notreached by child. */ - "1:" : - "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), - "i" (__NR_exit), "r" (fn), "r" (arg) : - "g1", "g2", "g3", "o0", "o1", "memory", "cc"); - return retval; -} -EXPORT_SYMBOL(kernel_thread); - typedef struct { union { unsigned int pr_regs[32]; |