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