1 /* 2 * Emulation of Linux signals 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #include "qemu/osdep.h" 20 #include "qemu.h" 21 #include "target_signal.h" 22 #include "signal-common.h" 23 #include "linux-user/trace.h" 24 25 struct target_sigcontext { 26 abi_long sc_onstack; 27 abi_long sc_mask; 28 abi_long sc_pc; 29 abi_long sc_ps; 30 abi_long sc_regs[32]; 31 abi_long sc_ownedfp; 32 abi_long sc_fpregs[32]; 33 abi_ulong sc_fpcr; 34 abi_ulong sc_fp_control; 35 abi_ulong sc_reserved1; 36 abi_ulong sc_reserved2; 37 abi_ulong sc_ssize; 38 abi_ulong sc_sbase; 39 abi_ulong sc_traparg_a0; 40 abi_ulong sc_traparg_a1; 41 abi_ulong sc_traparg_a2; 42 abi_ulong sc_fp_trap_pc; 43 abi_ulong sc_fp_trigger_sum; 44 abi_ulong sc_fp_trigger_inst; 45 }; 46 47 struct target_ucontext { 48 abi_ulong tuc_flags; 49 abi_ulong tuc_link; 50 abi_ulong tuc_osf_sigmask; 51 target_stack_t tuc_stack; 52 struct target_sigcontext tuc_mcontext; 53 target_sigset_t tuc_sigmask; 54 }; 55 56 struct target_sigframe { 57 struct target_sigcontext sc; 58 unsigned int retcode[3]; 59 }; 60 61 struct target_rt_sigframe { 62 target_siginfo_t info; 63 struct target_ucontext uc; 64 unsigned int retcode[3]; 65 }; 66 67 #define INSN_MOV_R30_R16 0x47fe0410 68 #define INSN_LDI_R0 0x201f0000 69 #define INSN_CALLSYS 0x00000083 70 71 static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env, 72 abi_ulong frame_addr, target_sigset_t *set) 73 { 74 int i; 75 76 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); 77 __put_user(set->sig[0], &sc->sc_mask); 78 __put_user(env->pc, &sc->sc_pc); 79 __put_user(8, &sc->sc_ps); 80 81 for (i = 0; i < 31; ++i) { 82 __put_user(env->ir[i], &sc->sc_regs[i]); 83 } 84 __put_user(0, &sc->sc_regs[31]); 85 86 for (i = 0; i < 31; ++i) { 87 __put_user(env->fir[i], &sc->sc_fpregs[i]); 88 } 89 __put_user(0, &sc->sc_fpregs[31]); 90 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); 91 92 __put_user(0, &sc->sc_traparg_a0); /* FIXME */ 93 __put_user(0, &sc->sc_traparg_a1); /* FIXME */ 94 __put_user(0, &sc->sc_traparg_a2); /* FIXME */ 95 } 96 97 static void restore_sigcontext(CPUAlphaState *env, 98 struct target_sigcontext *sc) 99 { 100 uint64_t fpcr; 101 int i; 102 103 __get_user(env->pc, &sc->sc_pc); 104 105 for (i = 0; i < 31; ++i) { 106 __get_user(env->ir[i], &sc->sc_regs[i]); 107 } 108 for (i = 0; i < 31; ++i) { 109 __get_user(env->fir[i], &sc->sc_fpregs[i]); 110 } 111 112 __get_user(fpcr, &sc->sc_fpcr); 113 cpu_alpha_store_fpcr(env, fpcr); 114 } 115 116 static inline abi_ulong get_sigframe(struct target_sigaction *sa, 117 CPUAlphaState *env, 118 unsigned long framesize) 119 { 120 abi_ulong sp; 121 122 sp = target_sigsp(get_sp_from_cpustate(env), sa); 123 124 return (sp - framesize) & -32; 125 } 126 127 void setup_frame(int sig, struct target_sigaction *ka, 128 target_sigset_t *set, CPUAlphaState *env) 129 { 130 abi_ulong frame_addr, r26; 131 struct target_sigframe *frame; 132 int err = 0; 133 134 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 135 trace_user_setup_frame(env, frame_addr); 136 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 137 goto give_sigsegv; 138 } 139 140 setup_sigcontext(&frame->sc, env, frame_addr, set); 141 142 if (ka->sa_restorer) { 143 r26 = ka->sa_restorer; 144 } else { 145 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); 146 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, 147 &frame->retcode[1]); 148 __put_user(INSN_CALLSYS, &frame->retcode[2]); 149 /* imb() */ 150 r26 = frame_addr + offsetof(struct target_sigframe, retcode); 151 } 152 153 unlock_user_struct(frame, frame_addr, 1); 154 155 if (err) { 156 give_sigsegv: 157 force_sigsegv(sig); 158 return; 159 } 160 161 env->ir[IR_RA] = r26; 162 env->ir[IR_PV] = env->pc = ka->_sa_handler; 163 env->ir[IR_A0] = sig; 164 env->ir[IR_A1] = 0; 165 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); 166 env->ir[IR_SP] = frame_addr; 167 } 168 169 void setup_rt_frame(int sig, struct target_sigaction *ka, 170 target_siginfo_t *info, 171 target_sigset_t *set, CPUAlphaState *env) 172 { 173 abi_ulong frame_addr, r26; 174 struct target_rt_sigframe *frame; 175 int i, err = 0; 176 177 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 178 trace_user_setup_rt_frame(env, frame_addr); 179 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 180 goto give_sigsegv; 181 } 182 183 tswap_siginfo(&frame->info, info); 184 185 __put_user(0, &frame->uc.tuc_flags); 186 __put_user(0, &frame->uc.tuc_link); 187 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); 188 189 target_save_altstack(&frame->uc.tuc_stack, env); 190 191 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); 192 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 193 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 194 } 195 196 if (ka->sa_restorer) { 197 r26 = ka->sa_restorer; 198 } else { 199 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); 200 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, 201 &frame->retcode[1]); 202 __put_user(INSN_CALLSYS, &frame->retcode[2]); 203 /* imb(); */ 204 r26 = frame_addr + offsetof(struct target_sigframe, retcode); 205 } 206 207 if (err) { 208 give_sigsegv: 209 force_sigsegv(sig); 210 return; 211 } 212 213 env->ir[IR_RA] = r26; 214 env->ir[IR_PV] = env->pc = ka->_sa_handler; 215 env->ir[IR_A0] = sig; 216 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); 217 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); 218 env->ir[IR_SP] = frame_addr; 219 } 220 221 long do_sigreturn(CPUAlphaState *env) 222 { 223 struct target_sigcontext *sc; 224 abi_ulong sc_addr = env->ir[IR_A0]; 225 target_sigset_t target_set; 226 sigset_t set; 227 228 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { 229 goto badframe; 230 } 231 232 target_sigemptyset(&target_set); 233 __get_user(target_set.sig[0], &sc->sc_mask); 234 235 target_to_host_sigset_internal(&set, &target_set); 236 set_sigmask(&set); 237 238 restore_sigcontext(env, sc); 239 unlock_user_struct(sc, sc_addr, 0); 240 return -TARGET_QEMU_ESIGRETURN; 241 242 badframe: 243 force_sig(TARGET_SIGSEGV); 244 return -TARGET_QEMU_ESIGRETURN; 245 } 246 247 long do_rt_sigreturn(CPUAlphaState *env) 248 { 249 abi_ulong frame_addr = env->ir[IR_A0]; 250 struct target_rt_sigframe *frame; 251 sigset_t set; 252 253 trace_user_do_rt_sigreturn(env, frame_addr); 254 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 255 goto badframe; 256 } 257 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 258 set_sigmask(&set); 259 260 restore_sigcontext(env, &frame->uc.tuc_mcontext); 261 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, 262 uc.tuc_stack), 263 0, env->ir[IR_SP]) == -EFAULT) { 264 goto badframe; 265 } 266 267 unlock_user_struct(frame, frame_addr, 0); 268 return -TARGET_QEMU_ESIGRETURN; 269 270 271 badframe: 272 unlock_user_struct(frame, frame_addr, 0); 273 force_sig(TARGET_SIGSEGV); 274 return -TARGET_QEMU_ESIGRETURN; 275 } 276