diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-03 14:46:55 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 23:12:25 -0400 |
commit | 69b58a67213506f98835b0ee8cf24324f59a1442 (patch) | |
tree | 554e56ac841e958398b0967784db8628dbbf48a3 /arch/cris/arch-v32 | |
parent | ddffeb8c4d0331609ef2581d84de4d763607bd37 (diff) |
cris: switch to generic kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/cris/arch-v32')
-rw-r--r-- | arch/cris/arch-v32/kernel/entry.S | 13 | ||||
-rw-r--r-- | arch/cris/arch-v32/kernel/process.c | 74 |
2 files changed, 35 insertions, 52 deletions
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index c3ea4694fba..a9bcbc41927 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -31,6 +31,7 @@ .globl system_call .globl ret_from_intr .globl ret_from_fork + .globl ret_from_kernel_thread .globl resume .globl multiple_interrupt .globl nmi_interrupt @@ -84,6 +85,18 @@ ret_from_fork: nop .size ret_from_fork, . - ret_from_fork + .type ret_from_kernel_thread,@function +ret_from_kernel_thread: + jsr schedule_tail + nop + move.d $r2, $r10 + jsr $r1 + nop + moveq 0, $r10 + jsr sys_exit + nop + .size ret_from_kernel_thread, . - ret_from_kernel_thread + .type ret_from_intr,@function ret_from_intr: ;; Check for resched if preemptive kernel, or if we're going back to diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 4e999224635..3edbdb88110 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -16,6 +16,7 @@ #include <hwregs/reg_map.h> #include <hwregs/timer_defs.h> #include <hwregs/intr_vect_defs.h> +#include <asm/ptrace.h> extern void stop_watchdog(void); @@ -94,31 +95,6 @@ unsigned long thread_saved_pc(struct task_struct *t) return task_pt_regs(t)->erp; } -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.erp = (unsigned long) kernel_thread_helper; - regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); - - /* 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 call switch_stack() on it. * It will be unnested during _resume and _ret_from_sys_call when the new thread @@ -129,23 +105,33 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ extern asmlinkage void ret_from_fork(void); +extern 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. Note: 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->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); + 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. */ /* Set a new TLS ? @@ -156,7 +142,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, } /* Put the switch stack right below the pt_regs. */ - swstack = ((struct switch_stack *) childregs) - 1; /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ swstack->r9 = 0; @@ -174,35 +159,21 @@ 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) +sys_fork(void) { - return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); + return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); } /* 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, - unsigned long tls, long srp, struct pt_regs *regs) + unsigned long tls) { 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); } /* @@ -210,10 +181,9 @@ sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child * 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) +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); } /* sys_execve() executes a new program. */ |