diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 12:22:13 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 12:22:13 -0800 |
commit | 9977d9b379cb77e0f67bd6f4563618106e58e11d (patch) | |
tree | 0191accfddf578edb52c69c933d64521e3dce297 /arch/sparc/kernel/process_32.c | |
parent | cf4af01221579a4e895f43dbfc47598fbfc5a731 (diff) | |
parent | 541880d9a2c7871f6370071d55aa6662d329c51e (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull big execve/kernel_thread/fork unification series from Al Viro:
"All architectures are converted to new model. Quite a bit of that
stuff is actually shared with architecture trees; in such cases it's
literally shared branch pulled by both, not a cherry-pick.
A lot of ugliness and black magic is gone (-3KLoC total in this one):
- kernel_thread()/kernel_execve()/sys_execve() redesign.
We don't do syscalls from kernel anymore for either kernel_thread()
or kernel_execve():
kernel_thread() is essentially clone(2) with callback run before we
return to userland, the callbacks either never return or do
successful do_execve() before returning.
kernel_execve() is a wrapper for do_execve() - it doesn't need to
do transition to user mode anymore.
As a result kernel_thread() and kernel_execve() are
arch-independent now - they live in kernel/fork.c and fs/exec.c
resp. sys_execve() is also in fs/exec.c and it's completely
architecture-independent.
- daemonize() is gone, along with its parts in fs/*.c
- struct pt_regs * is no longer passed to do_fork/copy_process/
copy_thread/do_execve/search_binary_handler/->load_binary/do_coredump.
- sys_fork()/sys_vfork()/sys_clone() unified; some architectures
still need wrappers (ones with callee-saved registers not saved in
pt_regs on syscall entry), but the main part of those suckers is in
kernel/fork.c now."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (113 commits)
do_coredump(): get rid of pt_regs argument
print_fatal_signal(): get rid of pt_regs argument
ptrace_signal(): get rid of unused arguments
get rid of ptrace_signal_deliver() arguments
new helper: signal_pt_regs()
unify default ptrace_signal_deliver
flagday: kill pt_regs argument of do_fork()
death to idle_regs()
don't pass regs to copy_process()
flagday: don't pass regs to copy_thread()
bfin: switch to generic vfork, get rid of pointless wrappers
xtensa: switch to generic clone()
openrisc: switch to use of generic fork and clone
unicore32: switch to generic clone(2)
score: switch to generic fork/vfork/clone
c6x: sanitize copy_thread(), get rid of clone(2) wrapper, switch to generic clone()
take sys_fork/sys_vfork/sys_clone prototypes to linux/syscalls.h
mn10300: switch to generic fork/vfork/clone
h8300: switch to generic fork/vfork/clone
tile: switch to generic clone()
...
Conflicts:
arch/microblaze/include/asm/Kbuild
Diffstat (limited to 'arch/sparc/kernel/process_32.c')
-rw-r--r-- | arch/sparc/kernel/process_32.c | 158 |
1 files changed, 47 insertions, 111 deletions
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 487bffb36f5e..be8e862badaf 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -286,8 +286,7 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, parent_tid_ptr = regs->u_regs[UREG_I2]; child_tid_ptr = regs->u_regs[UREG_I4]; - ret = do_fork(clone_flags, stack_start, - regs, stack_size, + ret = do_fork(clone_flags, stack_start, stack_size, (int __user *) parent_tid_ptr, (int __user *) child_tid_ptr); @@ -316,13 +315,13 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, * XXX See comment above sys_vfork in sparc64. todo. */ extern void ret_from_fork(void); +extern void ret_from_kernel_thread(void); int copy_thread(unsigned long clone_flags, unsigned long sp, - unsigned long unused, - struct task_struct *p, struct pt_regs *regs) + unsigned long arg, struct task_struct *p) { struct thread_info *ti = task_thread_info(p); - struct pt_regs *childregs; + struct pt_regs *childregs, *regs = current_pt_regs(); char *new_stack; #ifndef CONFIG_SMP @@ -336,16 +335,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, } /* - * p->thread_info new_stack childregs - * ! ! ! {if(PSR_PS) } - * V V (stk.fr.) V (pt_regs) { (stk.fr.) } - * +----- - - - - - ------+===========+============={+==========}+ + * p->thread_info new_stack childregs stack bottom + * ! ! ! ! + * V V (stk.fr.) V (pt_regs) V + * +----- - - - - - ------+===========+=============+ */ new_stack = task_stack_page(p) + THREAD_SIZE; - if (regs->psr & PSR_PS) - new_stack -= STACKFRAME_SZ; new_stack -= STACKFRAME_SZ + TRACEREG_SZ; - memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); /* @@ -356,55 +352,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, * Thus, kpsr|=PSR_PIL. */ ti->ksp = (unsigned long) new_stack; + p->thread.kregs = childregs; + + if (unlikely(p->flags & PF_KTHREAD)) { + extern int nwindows; + unsigned long psr; + memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); + p->thread.flags |= SPARC_FLAG_KTHREAD; + p->thread.current_ds = KERNEL_DS; + ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); + childregs->u_regs[UREG_G1] = sp; /* function */ + childregs->u_regs[UREG_G2] = arg; + psr = childregs->psr = get_psr(); + ti->kpsr = psr | PSR_PIL; + ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); + return 0; + } + memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); + childregs->u_regs[UREG_FP] = sp; + p->thread.flags &= ~SPARC_FLAG_KTHREAD; + p->thread.current_ds = USER_DS; ti->kpc = (((unsigned long) ret_from_fork) - 0x8); ti->kpsr = current->thread.fork_kpsr | PSR_PIL; ti->kwim = current->thread.fork_kwim; - if(regs->psr & PSR_PS) { - extern struct pt_regs fake_swapper_regs; + if (sp != regs->u_regs[UREG_FP]) { + struct sparc_stackf __user *childstack; + struct sparc_stackf __user *parentstack; - p->thread.kregs = &fake_swapper_regs; - new_stack += STACKFRAME_SZ + TRACEREG_SZ; - childregs->u_regs[UREG_FP] = (unsigned long) new_stack; - p->thread.flags |= SPARC_FLAG_KTHREAD; - p->thread.current_ds = KERNEL_DS; - memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); - childregs->u_regs[UREG_G6] = (unsigned long) ti; - } else { - p->thread.kregs = childregs; - childregs->u_regs[UREG_FP] = sp; - p->thread.flags &= ~SPARC_FLAG_KTHREAD; - p->thread.current_ds = USER_DS; - - if (sp != regs->u_regs[UREG_FP]) { - struct sparc_stackf __user *childstack; - struct sparc_stackf __user *parentstack; - - /* - * This is a clone() call with supplied user stack. - * Set some valid stack frames to give to the child. - */ - childstack = (struct sparc_stackf __user *) - (sp & ~0xfUL); - parentstack = (struct sparc_stackf __user *) - regs->u_regs[UREG_FP]; + /* + * This is a clone() call with supplied user stack. + * Set some valid stack frames to give to the child. + */ + childstack = (struct sparc_stackf __user *) + (sp & ~0xfUL); + parentstack = (struct sparc_stackf __user *) + regs->u_regs[UREG_FP]; #if 0 - printk("clone: parent stack:\n"); - show_stackframe(parentstack); + printk("clone: parent stack:\n"); + show_stackframe(parentstack); #endif - childstack = clone_stackframe(childstack, parentstack); - if (!childstack) - return -EFAULT; + childstack = clone_stackframe(childstack, parentstack); + if (!childstack) + return -EFAULT; #if 0 - printk("clone: child stack:\n"); - show_stackframe(childstack); + printk("clone: child stack:\n"); + show_stackframe(childstack); #endif - childregs->u_regs[UREG_FP] = (unsigned long)childstack; - } + childregs->u_regs[UREG_FP] = (unsigned long)childstack; } #ifdef CONFIG_SMP @@ -475,69 +474,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) return 1; } -/* - * sparc_execve() executes a new program after the asm stub has set - * things up for us. This should basically do what I want it to. - */ -asmlinkage int sparc_execve(struct pt_regs *regs) -{ - int error, base = 0; - struct filename *filename; - - /* Check for indirect call. */ - if(regs->u_regs[UREG_G1] == 0) - base = 1; - - filename = getname((char __user *)regs->u_regs[base + UREG_I0]); - error = PTR_ERR(filename); - if(IS_ERR(filename)) - goto out; - error = do_execve(filename->name, - (const char __user *const __user *) - regs->u_regs[base + UREG_I1], - (const char __user *const __user *) - regs->u_regs[base + UREG_I2], - regs); - putname(filename); -out: - return error; -} - -/* - * 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; - - __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */ - "mov %5, %%g3\n\t" /* and arg. */ - "mov %1, %%g1\n\t" - "mov %2, %%o0\n\t" /* Clone flags. */ - "mov 0, %%o1\n\t" /* usp arg == 0 */ - "t 0x10\n\t" /* Linux/Sparc clone(). */ - "cmp %%o1, 0\n\t" - "be 1f\n\t" /* The parent, just return. */ - " nop\n\t" /* Delay slot. */ - "jmpl %%g2, %%o7\n\t" /* Call the function. */ - " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ - "mov %3, %%g1\n\t" - "t 0x10\n\t" /* Linux/Sparc exit(). */ - /* Notreached by child. */ - "1: mov %%o0, %0\n\t" : - "=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); - unsigned long get_wchan(struct task_struct *task) { unsigned long pc, fp, bias = 0; |