summaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/frv/kernel/process.c')
-rw-r--r--arch/frv/kernel/process.c44
1 files changed, 23 insertions, 21 deletions
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index ff95f50efea5..0f02dee25e26 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -37,6 +37,7 @@
#include "local.h"
asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
#include <asm/pgalloc.h>
@@ -172,29 +173,21 @@ int copy_thread(unsigned long clone_flags,
unsigned long usp, unsigned long topstk,
struct task_struct *p, struct pt_regs *regs)
{
- struct pt_regs *childregs0, *childregs, *regs0;
+ struct pt_regs *childregs;
- regs0 = __kernel_frame0_ptr;
- childregs0 = (struct pt_regs *)
+ childregs = (struct pt_regs *)
(task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
- childregs = childregs0;
/* set up the userspace frame (the only place that the USP is stored) */
- *childregs0 = *regs0;
-
- childregs0->gr8 = 0;
- childregs0->sp = usp;
- childregs0->next_frame = NULL;
-
- /* set up the return kernel frame if called from kernel_thread() */
- if (regs != regs0) {
- childregs--;
- *childregs = *regs;
- childregs->sp = (unsigned long) childregs0;
- childregs->next_frame = childregs0;
- childregs->gr15 = (unsigned long) task_thread_info(p);
- childregs->gr29 = (unsigned long) p;
- }
+ *childregs = *regs;
+
+ childregs->sp = usp;
+ childregs->next_frame = NULL;
+
+ if (unlikely(!user_mode(regs)))
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ else
+ p->thread.pc = (unsigned long) ret_from_fork;
p->set_child_tid = p->clear_child_tid = NULL;
@@ -203,8 +196,7 @@ int copy_thread(unsigned long clone_flags,
p->thread.sp = (unsigned long) childregs;
p->thread.fp = 0;
p->thread.lr = 0;
- p->thread.pc = (unsigned long) ret_from_fork;
- p->thread.frame0 = childregs0;
+ p->thread.frame0 = childregs;
/* the new TLS pointer is passed in as arg #5 to sys_clone() */
if (clone_flags & CLONE_SETTLS)
@@ -347,3 +339,13 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
sizeof(current->thread.user->f));
return 1;
}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ struct pt_regs regs = {
+ .gr8 = (unsigned long)arg;
+ .gr9 = (unsigned long)fn;
+ .psr = PSR_S;
+ };
+ return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}