1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 3*1da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 4*1da177e4SLinus Torvalds * for more details. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 7*1da177e4SLinus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle 8*1da177e4SLinus Torvalds * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds 11*1da177e4SLinus Torvalds static inline int 12*1da177e4SLinus Torvalds setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) 13*1da177e4SLinus Torvalds { 14*1da177e4SLinus Torvalds int err = 0; 15*1da177e4SLinus Torvalds 16*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_epc, &sc->sc_pc); 17*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_status, &sc->sc_status); 18*1da177e4SLinus Torvalds 19*1da177e4SLinus Torvalds #define save_gp_reg(i) do { \ 20*1da177e4SLinus Torvalds err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ 21*1da177e4SLinus Torvalds } while(0) 22*1da177e4SLinus Torvalds __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); 23*1da177e4SLinus Torvalds save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); 24*1da177e4SLinus Torvalds save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); 25*1da177e4SLinus Torvalds save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); 26*1da177e4SLinus Torvalds save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); 27*1da177e4SLinus Torvalds save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); 28*1da177e4SLinus Torvalds save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); 29*1da177e4SLinus Torvalds save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); 30*1da177e4SLinus Torvalds save_gp_reg(31); 31*1da177e4SLinus Torvalds #undef save_gp_reg 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds err |= __put_user(regs->hi, &sc->sc_mdhi); 34*1da177e4SLinus Torvalds err |= __put_user(regs->lo, &sc->sc_mdlo); 35*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_cause, &sc->sc_cause); 36*1da177e4SLinus Torvalds err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds err |= __put_user(!!used_math(), &sc->sc_used_math); 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds if (!used_math()) 41*1da177e4SLinus Torvalds goto out; 42*1da177e4SLinus Torvalds 43*1da177e4SLinus Torvalds /* 44*1da177e4SLinus Torvalds * Save FPU state to signal context. Signal handler will "inherit" 45*1da177e4SLinus Torvalds * current FPU state. 46*1da177e4SLinus Torvalds */ 47*1da177e4SLinus Torvalds preempt_disable(); 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds if (!is_fpu_owner()) { 50*1da177e4SLinus Torvalds own_fpu(); 51*1da177e4SLinus Torvalds restore_fp(current); 52*1da177e4SLinus Torvalds } 53*1da177e4SLinus Torvalds err |= save_fp_context(sc); 54*1da177e4SLinus Torvalds 55*1da177e4SLinus Torvalds preempt_enable(); 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds out: 58*1da177e4SLinus Torvalds return err; 59*1da177e4SLinus Torvalds } 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds static inline int 62*1da177e4SLinus Torvalds restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) 63*1da177e4SLinus Torvalds { 64*1da177e4SLinus Torvalds int err = 0; 65*1da177e4SLinus Torvalds unsigned int used_math; 66*1da177e4SLinus Torvalds 67*1da177e4SLinus Torvalds /* Always make any pending restarted system calls return -EINTR */ 68*1da177e4SLinus Torvalds current_thread_info()->restart_block.fn = do_no_restart_syscall; 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds err |= __get_user(regs->cp0_epc, &sc->sc_pc); 71*1da177e4SLinus Torvalds err |= __get_user(regs->hi, &sc->sc_mdhi); 72*1da177e4SLinus Torvalds err |= __get_user(regs->lo, &sc->sc_mdlo); 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds #define restore_gp_reg(i) do { \ 75*1da177e4SLinus Torvalds err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ 76*1da177e4SLinus Torvalds } while(0) 77*1da177e4SLinus Torvalds restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); 78*1da177e4SLinus Torvalds restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); 79*1da177e4SLinus Torvalds restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); 80*1da177e4SLinus Torvalds restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); 81*1da177e4SLinus Torvalds restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); 82*1da177e4SLinus Torvalds restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); 83*1da177e4SLinus Torvalds restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); 84*1da177e4SLinus Torvalds restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); 85*1da177e4SLinus Torvalds restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); 86*1da177e4SLinus Torvalds restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); 87*1da177e4SLinus Torvalds restore_gp_reg(31); 88*1da177e4SLinus Torvalds #undef restore_gp_reg 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds err |= __get_user(used_math, &sc->sc_used_math); 91*1da177e4SLinus Torvalds conditional_used_math(used_math); 92*1da177e4SLinus Torvalds 93*1da177e4SLinus Torvalds preempt_disable(); 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds if (used_math()) { 96*1da177e4SLinus Torvalds /* restore fpu context if we have used it before */ 97*1da177e4SLinus Torvalds own_fpu(); 98*1da177e4SLinus Torvalds err |= restore_fp_context(sc); 99*1da177e4SLinus Torvalds } else { 100*1da177e4SLinus Torvalds /* signal handler may have used FPU. Give it up. */ 101*1da177e4SLinus Torvalds lose_fpu(); 102*1da177e4SLinus Torvalds } 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds preempt_enable(); 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds return err; 107*1da177e4SLinus Torvalds } 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds /* 110*1da177e4SLinus Torvalds * Determine which stack to use.. 111*1da177e4SLinus Torvalds */ 112*1da177e4SLinus Torvalds static inline void * 113*1da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) 114*1da177e4SLinus Torvalds { 115*1da177e4SLinus Torvalds unsigned long sp, almask; 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds /* Default to using normal stack */ 118*1da177e4SLinus Torvalds sp = regs->regs[29]; 119*1da177e4SLinus Torvalds 120*1da177e4SLinus Torvalds /* 121*1da177e4SLinus Torvalds * FPU emulator may have it's own trampoline active just 122*1da177e4SLinus Torvalds * above the user stack, 16-bytes before the next lowest 123*1da177e4SLinus Torvalds * 16 byte boundary. Try to avoid trashing it. 124*1da177e4SLinus Torvalds */ 125*1da177e4SLinus Torvalds sp -= 32; 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds /* This is the X/Open sanctioned signal stack switching. */ 128*1da177e4SLinus Torvalds if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) 129*1da177e4SLinus Torvalds sp = current->sas_ss_sp + current->sas_ss_size; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds if (PLAT_TRAMPOLINE_STUFF_LINE) 132*1da177e4SLinus Torvalds almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1); 133*1da177e4SLinus Torvalds else 134*1da177e4SLinus Torvalds almask = ALMASK; 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds return (void *)((sp - frame_size) & almask); 137*1da177e4SLinus Torvalds } 138