Hi Paul,
When I run a preemptive kernel-2.6.20 for SH7780, a created kthread(pdflush) can not exit by do_exit() in kernel_thread_helper. I think that the created kthread should have a room for 'struct pt_regs' space on the stack top, because __switch_to() will refer to the space as follows using 'regs = task_pt_regs(prev)' and next condition may be true.
struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
{
#if defined(CONFIG_SH_FPU)
unlazy_fpu(prev, task_pt_regs(prev));
#endif
#ifdef CONFIG_PREEMPT
{
unsigned long flags;
struct pt_regs *regs;
local_irq_save(flags);
regs = task_pt_regs(prev);
if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
int offset = (int)regs->regs[15];
/* Reset stack pointer: clear critical region mark */
regs->regs[15] = regs->regs[1];
if (regs->pc < regs->regs[0])
/* Go to rewind point */
regs->pc = regs->regs[0] + offset;
}
I think that the following patch can avoid this problem.
--- arch/sh/kernel/process.c2 Mon Feb 5 18:52:29 2007
+++ arch/sh/kernel/process.c Mon Feb 26 12:35:17 2007
@@ -270,20 +270,20 @@ int copy_thread(int nr, unsigned long cl
childregs = task_pt_regs(p);
*childregs = *regs;
if (user_mode(regs)) {
childregs->regs[15] = usp;
ti->addr_limit = USER_DS;
} else {
- childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+ childregs->regs[15] = (unsigned long)childregs;
ti->addr_limit = KERNEL_DS;
}
- if (clone_flags & CLONE_SETTLS) {
+ if (clone_flags & CLONE_SETTLS) {
childregs->gbr = childregs->regs[0];
}
childregs->regs[0] = 0; /* Set return value for child */
p->thread.sp = (unsigned long) childregs;
p->thread.pc = (unsigned long) ret_from_fork;
p->thread.ubc_pc = 0;
|