Skip to content

Commit

Permalink
sparc64: Fix kernel thread stack termination.
Browse files Browse the repository at this point in the history
Because of the silly way I set up the initial stack for
new kernel threads, there is a loop at the top of the
stack.

To fix this, properly add another stack frame that is copied
from the parent and terminate it in the child by setting
the frame pointer in that frame to zero.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 22, 2008
1 parent 3651751 commit a051bc5
Showing 1 changed file with 25 additions and 11 deletions.
36 changes: 25 additions & 11 deletions arch/sparc64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,20 +657,39 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *t = task_thread_info(p);
struct sparc_stackf *parent_sf;
unsigned long child_stack_sz;
char *child_trap_frame;
int kernel_thread;

/* Calculate offset to stack_frame & pt_regs */
child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ));
memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
parent_sf = ((struct sparc_stackf *) regs) - 1;

t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
/* Calculate offset to stack_frame & pt_regs */
child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
(kernel_thread ? STACKFRAME_SZ : 0));
child_trap_frame = (task_stack_page(p) +
(THREAD_SIZE - child_stack_sz));
memcpy(child_trap_frame, parent_sf, child_stack_sz);

t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
(0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
(((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
t->new_child = 1;
t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf));
t->kregs = (struct pt_regs *) (child_trap_frame +
sizeof(struct sparc_stackf));
t->fpsaved[0] = 0;

if (regs->tstate & TSTATE_PRIV) {
if (kernel_thread) {
struct sparc_stackf *child_sf = (struct sparc_stackf *)
(child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));

/* Zero terminate the stack backtrace. */
child_sf->fp = NULL;
t->kregs->u_regs[UREG_FP] =
((unsigned long) child_sf) - STACK_BIAS;

/* Special case, if we are spawning a kernel thread from
* a userspace task (via KMOD, NFS, or similar) we must
* disable performance counters in the child because the
Expand All @@ -681,12 +700,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
t->pcr_reg = 0;
t->flags &= ~_TIF_PERFCTR;
}
t->kregs->u_regs[UREG_FP] = t->ksp;
t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
flush_register_windows();
memcpy((void *)(t->ksp + STACK_BIAS),
(void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
sizeof(struct sparc_stackf));
t->kregs->u_regs[UREG_G6] = (unsigned long) t;
t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
} else {
Expand Down

0 comments on commit a051bc5

Please sign in to comment.