static inline int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int wsaved, err, sf_size; void __user *tail; /* 1. Make sure everything is clean */ synchronize_user_stack(); save_and_clear_fpu(); wsaved = get_thread_wsaved(); sf_size = sizeof(struct rt_signal_frame); if (current_thread_info()->fpsaved[0] & FPRS_FEF) sf_size += sizeof(__siginfo_fpu_t); if (wsaved) sf_size += sizeof(__siginfo_rwin_t); sf = (struct rt_signal_frame __user *) get_sigframe(ka, regs, sf_size); if (invalid_frame_pointer (sf)) goto sigill; tail = (sf + 1); /* 2. Save the current process state */ err = copy_to_user(&sf->regs, regs, sizeof (*regs)); if (current_thread_info()->fpsaved[0] & FPRS_FEF) { __siginfo_fpu_t __user *fpu_save = tail; tail += sizeof(__siginfo_fpu_t); err |= save_fpu_state(regs, fpu_save); err |= __put_user((u64)fpu_save, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t __user *rwin_save = tail; tail += sizeof(__siginfo_rwin_t); err |= save_rwin_state(wsaved, rwin_save); err |= __put_user((u64)rwin_save, &sf->rwin_save); set_thread_wsaved(0); } else { err |= __put_user(0, &sf->rwin_save); } /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); if (!wsaved) { err |= copy_in_user((u64 __user *)sf, (u64 __user *)(regs->u_regs[UREG_FP] + STACK_BIAS), sizeof(struct reg_window)); } else { struct reg_window *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= copy_to_user(sf, rp, sizeof(struct reg_window)); } if (info) err |= copy_siginfo_to_user(&sf->info, info); else { err |= __put_user(signo, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); } if (err) goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; /* The sigcontext is passed in this way because of how it * is defined in GLIBC's /usr/include/bits/sigcontext.h * for sparc64. It includes the 128 bytes of siginfo_t. */ regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 5. signal handler */ regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; } /* 4. return to kernel instructions */ regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; return 0; sigill: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset) { struct signal_frame __user *sf; int sigframe_size, err, wsaved; void __user *tail; /* 1. Make sure everything is clean */ synchronize_user_stack(); wsaved = current_thread_info()->w_saved; sigframe_size = sizeof(*sf); if (used_math()) sigframe_size += sizeof(__siginfo_fpu_t); if (wsaved) sigframe_size += sizeof(__siginfo_rwin_t); sf = (struct signal_frame __user *) get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer(sf, sigframe_size)) goto sigill_and_return; tail = sf + 1; /* 2. Save the current process state */ err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); err |= __put_user(0, &sf->extra_size); if (used_math()) { __siginfo_fpu_t __user *fp = tail; tail += sizeof(*fp); err |= save_fpu_state(regs, fp); err |= __put_user(fp, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t __user *rwp = tail; tail += sizeof(*rwp); err |= save_rwin_state(wsaved, rwp); err |= __put_user(rwp, &sf->rwin_save); } else { err |= __put_user(0, &sf->rwin_save); } err |= __put_user(oldset->sig[0], &sf->info.si_mask); err |= __copy_to_user(sf->extramask, &oldset->sig[1], (_NSIG_WORDS - 1) * sizeof(unsigned int)); if (!wsaved) { err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], sizeof(struct reg_window32)); } else { struct reg_window32 *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); } if (err) goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->info; /* 4. signal handler */ regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); /* 5. return to kernel instructions */ if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ err |= __put_user(0x821020d8, &sf->insns[0]); /* t 0x10 */ err |= __put_user(0x91d02010, &sf->insns[1]); if (err) goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } return 0; sigill_and_return: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int sigframe_size, wsaved; void __user *tail; unsigned int psr; int err; synchronize_user_stack(); wsaved = current_thread_info()->w_saved; sigframe_size = sizeof(*sf); if (used_math()) sigframe_size += sizeof(__siginfo_fpu_t); if (wsaved) sigframe_size += sizeof(__siginfo_rwin_t); sf = (struct rt_signal_frame __user *) get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer(sf, sigframe_size)) goto sigill; tail = sf + 1; err = __put_user(regs->pc, &sf->regs.pc); err |= __put_user(regs->npc, &sf->regs.npc); err |= __put_user(regs->y, &sf->regs.y); psr = regs->psr; if (used_math()) psr |= PSR_EF; err |= __put_user(psr, &sf->regs.psr); err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs)); err |= __put_user(0, &sf->extra_size); if (psr & PSR_EF) { __siginfo_fpu_t *fp = tail; tail += sizeof(*fp); err |= save_fpu_state(regs, fp); err |= __put_user(fp, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t *rwp = tail; tail += sizeof(*rwp); err |= save_rwin_state(wsaved, rwp); err |= __put_user(rwp, &sf->rwin_save); } else { err |= __put_user(0, &sf->rwin_save); } err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); if (!wsaved) { err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], sizeof(struct reg_window32)); } else { struct reg_window32 *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= __copy_to_user(sf, rp, sizeof(struct reg_window32)); } err |= copy_siginfo_to_user(&sf->info, info); if (err) goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; regs->pc = (unsigned long) ka->sa.sa_handler; regs->npc = (regs->pc + 4); if (ka->ka_restorer) regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); /* mov __NR_sigreturn, %g1 */ err |= __put_user(0x821020d8, &sf->insns[0]); /* t 0x10 */ err |= __put_user(0x91d02010, &sf->insns[1]); if (err) goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); } return 0; sigill: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }
static inline int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame __user *sf; int wsaved, err, sf_size; void __user *tail; synchronize_user_stack(); save_and_clear_fpu(); wsaved = get_thread_wsaved(); sf_size = sizeof(struct rt_signal_frame); if (current_thread_info()->fpsaved[0] & FPRS_FEF) sf_size += sizeof(__siginfo_fpu_t); if (wsaved) sf_size += sizeof(__siginfo_rwin_t); sf = (struct rt_signal_frame __user *) get_sigframe(ka, regs, sf_size); if (invalid_frame_pointer (sf)) goto sigill; tail = (sf + 1); err = copy_to_user(&sf->regs, regs, sizeof (*regs)); if (current_thread_info()->fpsaved[0] & FPRS_FEF) { __siginfo_fpu_t __user *fpu_save = tail; tail += sizeof(__siginfo_fpu_t); err |= save_fpu_state(regs, fpu_save); err |= __put_user((u64)fpu_save, &sf->fpu_save); } else { err |= __put_user(0, &sf->fpu_save); } if (wsaved) { __siginfo_rwin_t __user *rwin_save = tail; tail += sizeof(__siginfo_rwin_t); err |= save_rwin_state(wsaved, rwin_save); err |= __put_user((u64)rwin_save, &sf->rwin_save); set_thread_wsaved(0); } else { err |= __put_user(0, &sf->rwin_save); } err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); if (!wsaved) { err |= copy_in_user((u64 __user *)sf, (u64 __user *)(regs->u_regs[UREG_FP] + STACK_BIAS), sizeof(struct reg_window)); } else { struct reg_window *rp; rp = ¤t_thread_info()->reg_window[wsaved - 1]; err |= copy_to_user(sf, rp, sizeof(struct reg_window)); } if (info) err |= copy_siginfo_to_user(&sf->info, info); else { err |= __put_user(signo, &sf->info.si_signo); err |= __put_user(SI_NOINFO, &sf->info.si_code); } if (err) goto sigsegv; regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; regs->u_regs[UREG_I0] = signo; regs->u_regs[UREG_I1] = (unsigned long) &sf->info; regs->u_regs[UREG_I2] = (unsigned long) &sf->info; regs->tpc = (unsigned long) ka->sa.sa_handler; regs->tnpc = (regs->tpc + 4); if (test_thread_flag(TIF_32BIT)) { regs->tpc &= 0xffffffff; regs->tnpc &= 0xffffffff; } regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; return 0; sigill: do_exit(SIGILL); return -EINVAL; sigsegv: force_sigsegv(signo, current); return -EFAULT; }