aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-05-21 21:14:28 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-21 21:14:28 -0400
commita051bc5bb1ac6dc138d529077fa20cbbc6622d95 (patch)
tree103159b2955bfe0fae8f0b63ef3193f20ef4436e /arch
parent3651751fff44ede58f65cbb1e39242139ead251b (diff)
sparc64: Fix kernel thread stack termination.
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/sparc64/kernel/process.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 0a0c05fc3a33..2084f81a76e1 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -657,20 +657,39 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
657 struct task_struct *p, struct pt_regs *regs) 657 struct task_struct *p, struct pt_regs *regs)
658{ 658{
659 struct thread_info *t = task_thread_info(p); 659 struct thread_info *t = task_thread_info(p);
660 struct sparc_stackf *parent_sf;
661 unsigned long child_stack_sz;
660 char *child_trap_frame; 662 char *child_trap_frame;
663 int kernel_thread;
661 664
662 /* Calculate offset to stack_frame & pt_regs */ 665 kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
663 child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ)); 666 parent_sf = ((struct sparc_stackf *) regs) - 1;
664 memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ));
665 667
666 t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) | 668 /* Calculate offset to stack_frame & pt_regs */
669 child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
670 (kernel_thread ? STACKFRAME_SZ : 0));
671 child_trap_frame = (task_stack_page(p) +
672 (THREAD_SIZE - child_stack_sz));
673 memcpy(child_trap_frame, parent_sf, child_stack_sz);
674
675 t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
676 (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
667 (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT); 677 (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
668 t->new_child = 1; 678 t->new_child = 1;
669 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; 679 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
670 t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf)); 680 t->kregs = (struct pt_regs *) (child_trap_frame +
681 sizeof(struct sparc_stackf));
671 t->fpsaved[0] = 0; 682 t->fpsaved[0] = 0;
672 683
673 if (regs->tstate & TSTATE_PRIV) { 684 if (kernel_thread) {
685 struct sparc_stackf *child_sf = (struct sparc_stackf *)
686 (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));
687
688 /* Zero terminate the stack backtrace. */
689 child_sf->fp = NULL;
690 t->kregs->u_regs[UREG_FP] =
691 ((unsigned long) child_sf) - STACK_BIAS;
692
674 /* Special case, if we are spawning a kernel thread from 693 /* Special case, if we are spawning a kernel thread from
675 * a userspace task (via KMOD, NFS, or similar) we must 694 * a userspace task (via KMOD, NFS, or similar) we must
676 * disable performance counters in the child because the 695 * disable performance counters in the child because the
@@ -681,12 +700,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
681 t->pcr_reg = 0; 700 t->pcr_reg = 0;
682 t->flags &= ~_TIF_PERFCTR; 701 t->flags &= ~_TIF_PERFCTR;
683 } 702 }
684 t->kregs->u_regs[UREG_FP] = t->ksp;
685 t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); 703 t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
686 flush_register_windows();
687 memcpy((void *)(t->ksp + STACK_BIAS),
688 (void *)(regs->u_regs[UREG_FP] + STACK_BIAS),
689 sizeof(struct sparc_stackf));
690 t->kregs->u_regs[UREG_G6] = (unsigned long) t; 704 t->kregs->u_regs[UREG_G6] = (unsigned long) t;
691 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; 705 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
692 } else { 706 } else {