aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 {