aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/process_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/process_64.c')
-rw-r--r--arch/sparc/kernel/process_64.c143
1 files changed, 30 insertions, 113 deletions
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index c6e0c2910043..dff54f46728d 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -622,64 +622,55 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
622 * Child --> %o0 == parents pid, %o1 == 1 622 * Child --> %o0 == parents pid, %o1 == 1
623 */ 623 */
624int copy_thread(unsigned long clone_flags, unsigned long sp, 624int copy_thread(unsigned long clone_flags, unsigned long sp,
625 unsigned long unused, 625 unsigned long arg,
626 struct task_struct *p, struct pt_regs *regs) 626 struct task_struct *p, struct pt_regs *regs)
627{ 627{
628 struct thread_info *t = task_thread_info(p); 628 struct thread_info *t = task_thread_info(p);
629 struct sparc_stackf *parent_sf; 629 struct sparc_stackf *parent_sf;
630 unsigned long child_stack_sz; 630 unsigned long child_stack_sz;
631 char *child_trap_frame; 631 char *child_trap_frame;
632 int kernel_thread;
633
634 kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
635 parent_sf = ((struct sparc_stackf *) regs) - 1;
636 632
637 /* Calculate offset to stack_frame & pt_regs */ 633 /* Calculate offset to stack_frame & pt_regs */
638 child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + 634 child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
639 (kernel_thread ? STACKFRAME_SZ : 0));
640 child_trap_frame = (task_stack_page(p) + 635 child_trap_frame = (task_stack_page(p) +
641 (THREAD_SIZE - child_stack_sz)); 636 (THREAD_SIZE - child_stack_sz));
642 memcpy(child_trap_frame, parent_sf, child_stack_sz);
643 637
644 t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
645 (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
646 (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
647 t->new_child = 1; 638 t->new_child = 1;
648 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; 639 t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
649 t->kregs = (struct pt_regs *) (child_trap_frame + 640 t->kregs = (struct pt_regs *) (child_trap_frame +
650 sizeof(struct sparc_stackf)); 641 sizeof(struct sparc_stackf));
651 t->fpsaved[0] = 0; 642 t->fpsaved[0] = 0;
652 643
653 if (kernel_thread) { 644 if (unlikely(p->flags & PF_KTHREAD)) {
654 struct sparc_stackf *child_sf = (struct sparc_stackf *) 645 memset(child_trap_frame, 0, child_stack_sz);
655 (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); 646 __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
656 647 (current_pt_regs()->tstate + 1) & TSTATE_CWP;
657 /* Zero terminate the stack backtrace. */ 648 t->current_ds = ASI_P;
658 child_sf->fp = NULL; 649 t->kregs->u_regs[UREG_G1] = sp; /* function */
659 t->kregs->u_regs[UREG_FP] = 650 t->kregs->u_regs[UREG_G2] = arg;
660 ((unsigned long) child_sf) - STACK_BIAS; 651 return 0;
652 }
661 653
662 t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); 654 parent_sf = ((struct sparc_stackf *) regs) - 1;
663 t->kregs->u_regs[UREG_G6] = (unsigned long) t; 655 memcpy(child_trap_frame, parent_sf, child_stack_sz);
664 t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; 656 if (t->flags & _TIF_32BIT) {
665 } else { 657 sp &= 0x00000000ffffffffUL;
666 if (t->flags & _TIF_32BIT) { 658 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
667 sp &= 0x00000000ffffffffUL;
668 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
669 }
670 t->kregs->u_regs[UREG_FP] = sp;
671 t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT);
672 if (sp != regs->u_regs[UREG_FP]) {
673 unsigned long csp;
674
675 csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
676 if (!csp)
677 return -EFAULT;
678 t->kregs->u_regs[UREG_FP] = csp;
679 }
680 if (t->utraps)
681 t->utraps[0]++;
682 } 659 }
660 t->kregs->u_regs[UREG_FP] = sp;
661 __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] =
662 (regs->tstate + 1) & TSTATE_CWP;
663 t->current_ds = ASI_AIUS;
664 if (sp != regs->u_regs[UREG_FP]) {
665 unsigned long csp;
666
667 csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
668 if (!csp)
669 return -EFAULT;
670 t->kregs->u_regs[UREG_FP] = csp;
671 }
672 if (t->utraps)
673 t->utraps[0]++;
683 674
684 /* Set the return value for the child. */ 675 /* Set the return value for the child. */
685 t->kregs->u_regs[UREG_I0] = current->pid; 676 t->kregs->u_regs[UREG_I0] = current->pid;
@@ -694,45 +685,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
694 return 0; 685 return 0;
695} 686}
696 687
697/*
698 * This is the mechanism for creating a new kernel thread.
699 *
700 * NOTE! Only a kernel-only process(ie the swapper or direct descendants
701 * who haven't done an "execve()") should use this: it will work within
702 * a system call from a "real" process, but the process memory space will
703 * not be freed until both the parent and the child have exited.
704 */
705pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
706{
707 long retval;
708
709 /* If the parent runs before fn(arg) is called by the child,
710 * the input registers of this function can be clobbered.
711 * So we stash 'fn' and 'arg' into global registers which
712 * will not be modified by the parent.
713 */
714 __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */
715 "mov %5, %%g3\n\t" /* Save ARG into global */
716 "mov %1, %%g1\n\t" /* Clone syscall nr. */
717 "mov %2, %%o0\n\t" /* Clone flags. */
718 "mov 0, %%o1\n\t" /* usp arg == 0 */
719 "t 0x6d\n\t" /* Linux/Sparc clone(). */
720 "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
721 " mov %%o0, %0\n\t"
722 "jmpl %%g2, %%o7\n\t" /* Call the function. */
723 " mov %%g3, %%o0\n\t" /* Set arg in delay. */
724 "mov %3, %%g1\n\t"
725 "t 0x6d\n\t" /* Linux/Sparc exit(). */
726 /* Notreached by child. */
727 "1:" :
728 "=r" (retval) :
729 "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
730 "i" (__NR_exit), "r" (fn), "r" (arg) :
731 "g1", "g2", "g3", "o0", "o1", "memory", "cc");
732 return retval;
733}
734EXPORT_SYMBOL(kernel_thread);
735
736typedef struct { 688typedef struct {
737 union { 689 union {
738 unsigned int pr_regs[32]; 690 unsigned int pr_regs[32];
@@ -799,41 +751,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
799} 751}
800EXPORT_SYMBOL(dump_fpu); 752EXPORT_SYMBOL(dump_fpu);
801 753
802/*
803 * sparc_execve() executes a new program after the asm stub has set
804 * things up for us. This should basically do what I want it to.
805 */
806asmlinkage int sparc_execve(struct pt_regs *regs)
807{
808 int error, base = 0;
809 struct filename *filename;
810
811 /* User register window flush is done by entry.S */
812
813 /* Check for indirect call. */
814 if (regs->u_regs[UREG_G1] == 0)
815 base = 1;
816
817 filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
818 error = PTR_ERR(filename);
819 if (IS_ERR(filename))
820 goto out;
821 error = do_execve(filename->name,
822 (const char __user *const __user *)
823 regs->u_regs[base + UREG_I1],
824 (const char __user *const __user *)
825 regs->u_regs[base + UREG_I2], regs);
826 putname(filename);
827 if (!error) {
828 fprs_write(0);
829 current_thread_info()->xfsr[0] = 0;
830 current_thread_info()->fpsaved[0] = 0;
831 regs->tstate &= ~TSTATE_PEF;
832 }
833out:
834 return error;
835}
836
837unsigned long get_wchan(struct task_struct *task) 754unsigned long get_wchan(struct task_struct *task)
838{ 755{
839 unsigned long pc, fp, bias = 0; 756 unsigned long pc, fp, bias = 0;