diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-03 22:46:55 +0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-15 07:12:25 +0400 |
commit | 69b58a67213506f98835b0ee8cf24324f59a1442 (patch) | |
tree | 554e56ac841e958398b0967784db8628dbbf48a3 /arch/cris/arch-v10 | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) | |
download | linux-69b58a67213506f98835b0ee8cf24324f59a1442.tar.xz |
cris: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/cris/arch-v10')
-rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 10 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/process.c | 83 |
2 files changed, 33 insertions, 60 deletions
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 592fbe9dfb62..b8e39e00acb2 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -35,6 +35,7 @@ .globl system_call .globl ret_from_intr .globl ret_from_fork + .globl ret_from_kernel_thread .globl resume .globl multiple_interrupt .globl hwbreakpoint @@ -81,7 +82,14 @@ ret_from_fork: jsr schedule_tail ba ret_from_sys_call nop - + +ret_from_kernel_thread: + jsr schedule_tail + move.d $r2, $r10 ; argument is here + jsr $r1 ; call the payload + moveq 0, $r10 + jsr sys_exit ; never returns + ret_from_intr: ;; check for resched if preemptive kernel or if we're going back to user-mode ;; this test matches the user_regs(regs) macro diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 15ac7150371f..8a673aa81cdd 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -17,6 +17,7 @@ #include <arch/svinto.h> #include <linux/init.h> #include <arch/system.h> +#include <asm/ptrace.h> #ifdef CONFIG_ETRAX_GPIO void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ @@ -81,31 +82,6 @@ unsigned long thread_saved_pc(struct task_struct *t) return task_pt_regs(t)->irp; } -static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) -{ - fn(arg); - do_exit(-1); /* Should never be called, return bad exit value */ -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - - /* Don't use r10 since that is set to 0 in copy_thread */ - regs.r11 = (unsigned long)fn; - regs.r12 = (unsigned long)arg; - regs.irp = (unsigned long)kernel_thread_helper; - regs.dccr = 1 << I_DCCR_BITNR; - - /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); -} - /* setup the child's kernel stack with a pt_regs and switch_stack on it. * it will be un-nested during _resume and _ret_from_sys_call when the * new thread is scheduled. @@ -115,29 +91,35 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) * */ asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, + unsigned long arg, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs * childregs; - struct switch_stack *swstack; + struct pt_regs *childregs = task_pt_regs(p); + struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1; /* put the pt_regs structure at the end of the new kernel stack page and fix it up * remember that the task_struct doubles as the kernel stack for the task */ - childregs = task_pt_regs(p); - + if (unlikely(p->flags & PF_KTHREAD)) { + memset(swstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + swstack->r1 = usp; + swstack->r2 = arg; + childregs->dccr = 1 << I_DCCR_BITNR; + swstack->return_ip = (unsigned long) ret_from_kernel_thread; + p->thread.ksp = (unsigned long) swstack; + p->thread.usp = 0; + return 0; + } *childregs = *regs; /* struct copy of pt_regs */ - - p->set_child_tid = p->clear_child_tid = NULL; childregs->r10 = 0; /* child returns 0 after a fork/clone */ - - /* put the switch stack right below the pt_regs */ - swstack = ((struct switch_stack *)childregs) - 1; + /* put the switch stack right below the pt_regs */ swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ @@ -147,7 +129,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, /* fix the user-mode stackpointer */ - p->thread.usp = usp; + p->thread.usp = usp; /* and the kernel-mode one */ @@ -161,45 +143,28 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } -/* - * Be aware of the "magic" 7th argument in the four system-calls below. - * They need the latest stackframe, which is put as the 7th argument by - * entry.S. The previous arguments are dummies or actually used, but need - * to be defined to reach the 7th argument. - * - * N.B.: Another method to get the stackframe is to use current_regs(). But - * it returns the latest stack-frame stacked when going from _user mode_ and - * some of these (at least sys_clone) are called from kernel-mode sometimes - * (for example during kernel_thread, above) and thus cannot use it. Thus, - * to be sure not to get any surprises, we use the method for the other calls - * as well. - */ - -asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) +asmlinkage int sys_fork(void) { - return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); + return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); } /* if newusp is 0, we just grab the old usp */ /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, - int* parent_tid, int* child_tid, long mof, long srp, - struct pt_regs *regs) + int* parent_tid, int* child_tid) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); + return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); } /* vfork is a system call in i386 because of register-pressure - maybe * we can remove it and handle it in libc but we put it here until then. */ -asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) +asmlinkage int sys_vfork(void) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); } /* |