diff options
-rw-r--r-- | arch/sparc64/kernel/process.c | 36 |
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 { |