/* * sparc32_execve() executes a new program after the asm stub has set * things up for us. This should basically do what I want it to. */ asmlinkage long sparc32_execve(struct pt_regs *regs) { int error, base = 0; char *filename; /* User register window flush is done by entry.S */ /* Check for indirect call. */ if ((u32)regs->u_regs[UREG_G1] == 0) base = 1; filename = getname(compat_ptr(regs->u_regs[base + UREG_I0])); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = compat_do_execve(filename, compat_ptr(regs->u_regs[base + UREG_I1]), compat_ptr(regs->u_regs[base + UREG_I2]), regs); putname(filename); if (!error) { fprs_write(0); current_thread_info()->xfsr[0] = 0; current_thread_info()->fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; task_lock(current); current->ptrace &= ~PT_DTRACE; task_unlock(current); } out: return error; }
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) { unsigned long *fpregs = current_thread_info()->fpregs; unsigned long fprs; int err; err = __get_user(fprs, &fpu->si_fprs); fprs_write(0); regs->tstate &= ~TSTATE_PEF; if (fprs & FPRS_DL) err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr); err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr); current_thread_info()->fpsaved[0] |= fprs; return err; }
static inline int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; int err; err = __get_user(fprs, &fpu->si_fprs); fprs_write(0); regs->tstate &= ~TSTATE_PEF; if (fprs & FPRS_DL) err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr); err |= __get_user(current->thread.gsr[0], &fpu->si_gsr); current->thread.fpsaved[0] |= fprs; return err; }
/* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) { struct ucontext __user *ucp = (struct ucontext __user *) regs->u_regs[UREG_I0]; mc_gregset_t __user *grp; unsigned long pc, npc, tstate; unsigned long fp, i7; unsigned char fenab; int err; flush_user_windows(); if (get_thread_wsaved() || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok(ucp, sizeof(*ucp)))) goto do_sigsegv; grp = &ucp->uc_mcontext.mc_gregs; err = __get_user(pc, &((*grp)[MC_PC])); err |= __get_user(npc, &((*grp)[MC_NPC])); if (err || ((pc | npc) & 3)) goto do_sigsegv; if (regs->u_regs[UREG_I1]) { sigset_t set; if (_NSIG_WORDS == 1) { if (__get_user(set.sig[0], &ucp->uc_sigmask.sig[0])) goto do_sigsegv; } else { if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t))) goto do_sigsegv; } set_current_blocked(&set); } if (test_thread_flag(TIF_32BIT)) { pc &= 0xffffffff; npc &= 0xffffffff; } regs->tpc = pc; regs->tnpc = npc; err |= __get_user(regs->y, &((*grp)[MC_Y])); err |= __get_user(tstate, &((*grp)[MC_TSTATE])); regs->tstate &= ~(TSTATE_ASI | TSTATE_ICC | TSTATE_XCC); regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC)); err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); /* Skip %g7 as that's the thread register in userspace. */ err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); err |= __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3])); err |= __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4])); err |= __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5])); err |= __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6])); err |= __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7])); err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); err |= __put_user(fp, (&(((struct reg_window __user *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); err |= __put_user(i7, (&(((struct reg_window __user *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); if (fenab) { unsigned long *fpregs = current_thread_info()->fpregs; unsigned long fprs; fprs_write(0); err |= __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); if (fprs & FPRS_DL) err |= copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, ((unsigned long __user *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, (sizeof(unsigned int) * 32)); err |= __get_user(current_thread_info()->xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); err |= __get_user(current_thread_info()->gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); regs->tstate &= ~TSTATE_PEF; } if (err) goto do_sigsegv; return; do_sigsegv: force_sig(SIGSEGV, current); }
/* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) { struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0]; struct thread_struct *tp = ¤t->thread; mc_gregset_t *grp; unsigned long pc, npc, tstate; unsigned long fp, i7; unsigned char fenab; int err; flush_user_windows(); if(tp->w_saved || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok((unsigned long)ucp, sizeof(*ucp)))) goto do_sigsegv; grp = &ucp->uc_mcontext.mc_gregs; err = __get_user(pc, &((*grp)[MC_PC])); err |= __get_user(npc, &((*grp)[MC_NPC])); if(err || ((pc | npc) & 3)) goto do_sigsegv; if(regs->u_regs[UREG_I1]) { sigset_t set; if (_NSIG_WORDS == 1) { if (__get_user(set.sig[0], &ucp->uc_sigmask.sig[0])) goto do_sigsegv; } else { if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t))) goto do_sigsegv; } sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); } if ((tp->flags & SPARC_FLAG_32BIT) != 0) { pc &= 0xffffffff; npc &= 0xffffffff; } regs->tpc = pc; regs->tnpc = npc; err |= __get_user(regs->y, &((*grp)[MC_Y])); err |= __get_user(tstate, &((*grp)[MC_TSTATE])); regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); err |= __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); err |= __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3])); err |= __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4])); err |= __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5])); err |= __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6])); err |= __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7])); err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); err |= __put_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); err |= __put_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); if(fenab) { unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; fprs_write(0); err |= __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); if (fprs & FPRS_DL) err |= copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, (sizeof(unsigned int) * 32)); err |= __get_user(current->thread.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); err |= __get_user(current->thread.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); regs->tstate &= ~TSTATE_PEF; } if (err) goto do_sigsegv; return; do_sigsegv: do_exit(SIGSEGV); }