summaryrefslogtreecommitdiff
path: root/arch/parisc/kernel/process.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 12:22:13 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 12:22:13 -0800
commit9977d9b379cb77e0f67bd6f4563618106e58e11d (patch)
tree0191accfddf578edb52c69c933d64521e3dce297 /arch/parisc/kernel/process.c
parentcf4af01221579a4e895f43dbfc47598fbfc5a731 (diff)
parent541880d9a2c7871f6370071d55aa6662d329c51e (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/parisc/kernel/process.c')
-rw-r--r--arch/parisc/kernel/process.c142
1 files changed, 23 insertions, 119 deletions
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index cbc37216bf90..d13507246c5d 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -52,6 +52,7 @@
#include <asm/io.h>
#include <asm/asm-offsets.h>
+#include <asm/assembly.h>
#include <asm/pdc.h>
#include <asm/pdc_chassis.h>
#include <asm/pgalloc.h>
@@ -165,23 +166,6 @@ void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);
/*
- * Create a kernel thread
- */
-
-extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-
- /*
- * FIXME: Once we are sure we don't need any debug here,
- * kernel_thread can become a #define.
- */
-
- return __kernel_thread(fn, arg, flags);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
* Free current thread data structures etc..
*/
void exit_thread(void)
@@ -218,48 +202,11 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r)
return 1;
}
-/* Note that "fork()" is implemented in terms of clone, with
- parameters (SIGCHLD, regs->gr[30], regs). */
-int
-sys_clone(unsigned long clone_flags, unsigned long usp,
- struct pt_regs *regs)
-{
- /* Arugments from userspace are:
- r26 = Clone flags.
- r25 = Child stack.
- r24 = parent_tidptr.
- r23 = Is the TLS storage descriptor
- r22 = child_tidptr
-
- However, these last 3 args are only examined
- if the proper flags are set. */
- int __user *parent_tidptr = (int __user *)regs->gr[24];
- int __user *child_tidptr = (int __user *)regs->gr[22];
-
- /* usp must be word aligned. This also prevents users from
- * passing in the value 1 (which is the signal for a special
- * return for a kernel thread) */
- usp = ALIGN(usp, 4);
-
- /* A zero value for usp means use the current stack */
- if (usp == 0)
- usp = regs->gr[30];
-
- return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-int
-sys_vfork(struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL);
-}
-
int
copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, /* in ia64 this is "user_stack_size" */
- struct task_struct * p, struct pt_regs * pregs)
+ unsigned long arg, struct task_struct *p)
{
- struct pt_regs * cregs = &(p->thread.regs);
+ struct pt_regs *cregs = &(p->thread.regs);
void *stack = task_stack_page(p);
/* We have to use void * instead of a function pointer, because
@@ -270,48 +217,39 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
#ifdef CONFIG_HPUX
extern void * const hpux_child_return;
#endif
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(cregs, 0, sizeof(struct pt_regs));
+ if (!usp) /* idle thread */
+ return 0;
- *cregs = *pregs;
-
- /* Set the return value for the child. Note that this is not
- actually restored by the syscall exit path, but we put it
- here for consistency in case of signals. */
- cregs->gr[28] = 0; /* child */
-
- /*
- * We need to differentiate between a user fork and a
- * kernel fork. We can't use user_mode, because the
- * the syscall path doesn't save iaoq. Right now
- * We rely on the fact that kernel_thread passes
- * in zero for usp.
- */
- if (usp == 1) {
/* kernel thread */
- cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
/* Must exit via ret_from_kernel_thread in order
* to call schedule_tail()
*/
+ cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
cregs->kpc = (unsigned long) &ret_from_kernel_thread;
/*
* Copy function and argument to be called from
* ret_from_kernel_thread.
*/
#ifdef CONFIG_64BIT
- cregs->gr[27] = pregs->gr[27];
+ cregs->gr[27] = ((unsigned long *)usp)[3];
+ cregs->gr[26] = ((unsigned long *)usp)[2];
+#else
+ cregs->gr[26] = usp;
#endif
- cregs->gr[26] = pregs->gr[26];
- cregs->gr[25] = pregs->gr[25];
+ cregs->gr[25] = arg;
} else {
/* user thread */
- /*
- * Note that the fork wrappers are responsible
- * for setting gr[21].
- */
-
- /* Use same stack depth as parent */
- cregs->ksp = (unsigned long)stack
- + (pregs->gr[21] & (THREAD_SIZE - 1));
- cregs->gr[30] = usp;
+ /* usp must be word aligned. This also prevents users from
+ * passing in the value 1 (which is the signal for a special
+ * return for a kernel thread) */
+ if (usp) {
+ usp = ALIGN(usp, 4);
+ if (likely(usp))
+ cregs->gr[30] = usp;
+ }
+ cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
if (personality(p->personality) == PER_HPUX) {
#ifdef CONFIG_HPUX
cregs->kpc = (unsigned long) &hpux_child_return;
@@ -323,8 +261,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
}
/* Setup thread TLS area from the 4th parameter in clone */
if (clone_flags & CLONE_SETTLS)
- cregs->cr27 = pregs->gr[23];
-
+ cregs->cr27 = cregs->gr[23];
}
return 0;
@@ -335,39 +272,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
return t->thread.regs.kpc;
}
-/*
- * sys_execve() executes a new program.
- */
-
-asmlinkage int sys_execve(struct pt_regs *regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname((const char __user *) regs->gr[26]);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name,
- (const char __user *const __user *) regs->gr[25],
- (const char __user *const __user *) regs->gr[24],
- regs);
- putname(filename);
-out:
-
- return error;
-}
-
-extern int __execve(const char *filename,
- const char *const argv[],
- const char *const envp[], struct task_struct *task);
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- return __execve(filename, argv, envp, current);
-}
-
unsigned long
get_wchan(struct task_struct *p)
{