|
@@ -119,46 +119,38 @@ void flush_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 = task_pt_regs(p);
|
|
|
struct thread_info *ti = task_thread_info(p);
|
|
|
|
|
|
+ if (unlikely(p->flags & PF_KTHREAD)) {
|
|
|
+ /* if we're creating a new kernel thread then just zeroing all
|
|
|
+ * the registers. That's OK for a brand new thread.*/
|
|
|
+ memset(childregs, 0, sizeof(struct pt_regs));
|
|
|
+ memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
|
|
|
+ ti->cpu_context.r1 = (unsigned long)childregs;
|
|
|
+ ti->cpu_context.r20 = (unsigned long)usp; /* fn */
|
|
|
+ ti->cpu_context.r19 = (unsigned long)arg;
|
|
|
+ childregs->pt_mode = 1;
|
|
|
+ local_save_flags(childregs->msr);
|
|
|
+#ifdef CONFIG_MMU
|
|
|
+ ti->cpu_context.msr = childregs->msr & ~MSR_IE;
|
|
|
+#endif
|
|
|
+ ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
*childregs = *regs;
|
|
|
- if (user_mode(regs))
|
|
|
- childregs->r1 = usp;
|
|
|
- else
|
|
|
- childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
|
|
|
+ childregs->r1 = usp;
|
|
|
|
|
|
-#ifndef CONFIG_MMU
|
|
|
memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
|
|
|
ti->cpu_context.r1 = (unsigned long)childregs;
|
|
|
+#ifndef CONFIG_MMU
|
|
|
ti->cpu_context.msr = (unsigned long)childregs->msr;
|
|
|
#else
|
|
|
+ childregs->msr |= MSR_UMS;
|
|
|
|
|
|
- /* if creating a kernel thread then update the current reg (we don't
|
|
|
- * want to use the parent's value when restoring by POP_STATE) */
|
|
|
- if (kernel_mode(regs))
|
|
|
- /* save new current on stack to use POP_STATE */
|
|
|
- childregs->CURRENT_TASK = (unsigned long)p;
|
|
|
- /* if returning to user then use the parent's value of this register */
|
|
|
-
|
|
|
- /* if we're creating a new kernel thread then just zeroing all
|
|
|
- * the registers. That's OK for a brand new thread.*/
|
|
|
- /* Pls. note that some of them will be restored in POP_STATE */
|
|
|
- if (kernel_mode(regs))
|
|
|
- memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
|
|
|
- /* if this thread is created for fork/vfork/clone, then we want to
|
|
|
- * restore all the parent's context */
|
|
|
- /* in addition to the registers which will be restored by POP_STATE */
|
|
|
- else {
|
|
|
- ti->cpu_context = *(struct cpu_context *)regs;
|
|
|
- childregs->msr |= MSR_UMS;
|
|
|
- }
|
|
|
-
|
|
|
- /* FIXME STATE_SAVE_PT_OFFSET; */
|
|
|
- ti->cpu_context.r1 = (unsigned long)childregs;
|
|
|
/* we should consider the fact that childregs is a copy of the parent
|
|
|
* regs which were saved immediately after entering the kernel state
|
|
|
* before enabling VM. This MSR will be restored in switch_to and
|
|
@@ -209,29 +201,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static void kernel_thread_helper(int (*fn)(void *), void *arg)
|
|
|
-{
|
|
|
- fn(arg);
|
|
|
- do_exit(-1);
|
|
|
-}
|
|
|
-
|
|
|
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
|
|
-{
|
|
|
- struct pt_regs regs;
|
|
|
-
|
|
|
- memset(®s, 0, sizeof(regs));
|
|
|
- /* store them in non-volatile registers */
|
|
|
- regs.r5 = (unsigned long)fn;
|
|
|
- regs.r6 = (unsigned long)arg;
|
|
|
- local_save_flags(regs.msr);
|
|
|
- regs.pc = (unsigned long)kernel_thread_helper;
|
|
|
- regs.pt_mode = 1;
|
|
|
-
|
|
|
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
|
|
|
- ®s, 0, NULL, NULL);
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(kernel_thread);
|
|
|
-
|
|
|
unsigned long get_wchan(struct task_struct *p)
|
|
|
{
|
|
|
/* TBD (used by procfs) */
|