|
@@ -107,8 +107,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Copy architecture-specific thread state
|
|
|
|
+ */
|
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
- unsigned long arg, struct task_struct *p)
|
|
|
|
|
|
+ unsigned long kthread_arg, struct task_struct *p)
|
|
{
|
|
{
|
|
struct thread_info *ti = task_thread_info(p);
|
|
struct thread_info *ti = task_thread_info(p);
|
|
struct pt_regs *childregs, *regs = current_pt_regs();
|
|
struct pt_regs *childregs, *regs = current_pt_regs();
|
|
@@ -123,11 +126,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
childksp = (unsigned long) childregs;
|
|
childksp = (unsigned long) childregs;
|
|
p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
|
|
p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
|
|
if (unlikely(p->flags & PF_KTHREAD)) {
|
|
if (unlikely(p->flags & PF_KTHREAD)) {
|
|
|
|
+ /* kernel thread */
|
|
unsigned long status = p->thread.cp0_status;
|
|
unsigned long status = p->thread.cp0_status;
|
|
memset(childregs, 0, sizeof(struct pt_regs));
|
|
memset(childregs, 0, sizeof(struct pt_regs));
|
|
ti->addr_limit = KERNEL_DS;
|
|
ti->addr_limit = KERNEL_DS;
|
|
p->thread.reg16 = usp; /* fn */
|
|
p->thread.reg16 = usp; /* fn */
|
|
- p->thread.reg17 = arg;
|
|
|
|
|
|
+ p->thread.reg17 = kthread_arg;
|
|
p->thread.reg29 = childksp;
|
|
p->thread.reg29 = childksp;
|
|
p->thread.reg31 = (unsigned long) ret_from_kernel_thread;
|
|
p->thread.reg31 = (unsigned long) ret_from_kernel_thread;
|
|
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
|
|
#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
|
|
@@ -139,6 +143,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
|
childregs->cp0_status = status;
|
|
childregs->cp0_status = status;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* user thread */
|
|
*childregs = *regs;
|
|
*childregs = *regs;
|
|
childregs->regs[7] = 0; /* Clear error flag */
|
|
childregs->regs[7] = 0; /* Clear error flag */
|
|
childregs->regs[2] = 0; /* Child gets zero as return value */
|
|
childregs->regs[2] = 0; /* Child gets zero as return value */
|