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>

+24 -10
+24 -10
arch/sparc64/kernel/process.c
··· 657 struct task_struct *p, struct pt_regs *regs) 658 { 659 struct thread_info *t = task_thread_info(p); 660 char *child_trap_frame; 661 662 /* Calculate offset to stack_frame & pt_regs */ 663 - child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ)); 664 - memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ)); 665 666 - t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) | 667 (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT); 668 t->new_child = 1; 669 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; 670 - t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf)); 671 t->fpsaved[0] = 0; 672 673 - if (regs->tstate & TSTATE_PRIV) { 674 /* Special case, if we are spawning a kernel thread from 675 * a userspace task (via KMOD, NFS, or similar) we must 676 * disable performance counters in the child because the ··· 700 t->pcr_reg = 0; 701 t->flags &= ~_TIF_PERFCTR; 702 } 703 - t->kregs->u_regs[UREG_FP] = t->ksp; 704 t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); 705 - flush_register_windows(); 706 - memcpy((void *)(t->ksp + STACK_BIAS), 707 - (void *)(regs->u_regs[UREG_FP] + STACK_BIAS), 708 - sizeof(struct sparc_stackf)); 709 t->kregs->u_regs[UREG_G6] = (unsigned long) t; 710 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; 711 } else {
··· 657 struct task_struct *p, struct pt_regs *regs) 658 { 659 struct thread_info *t = task_thread_info(p); 660 + struct sparc_stackf *parent_sf; 661 + unsigned long child_stack_sz; 662 char *child_trap_frame; 663 + int kernel_thread; 664 + 665 + kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0; 666 + parent_sf = ((struct sparc_stackf *) regs) - 1; 667 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))) | 677 (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT); 678 t->new_child = 1; 679 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; 680 + t->kregs = (struct pt_regs *) (child_trap_frame + 681 + sizeof(struct sparc_stackf)); 682 t->fpsaved[0] = 0; 683 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 + 693 /* Special case, if we are spawning a kernel thread from 694 * a userspace task (via KMOD, NFS, or similar) we must 695 * disable performance counters in the child because the ··· 681 t->pcr_reg = 0; 682 t->flags &= ~_TIF_PERFCTR; 683 } 684 t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); 685 t->kregs->u_regs[UREG_G6] = (unsigned long) t; 686 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; 687 } else {