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 "user-internals.h" 22 #include "signal-common.h" 23 #include "linux-user/trace.h" 24 25 # if defined(TARGET_ABI_MIPSO32) 26 struct target_sigcontext { 27 uint32_t sc_regmask; /* Unused */ 28 uint32_t sc_status; 29 uint64_t sc_pc; 30 uint64_t sc_regs[32]; 31 uint64_t sc_fpregs[32]; 32 uint32_t sc_ownedfp; /* Unused */ 33 uint32_t sc_fpc_csr; 34 uint32_t sc_fpc_eir; /* Unused */ 35 uint32_t sc_used_math; 36 uint32_t sc_dsp; /* dsp status, was sc_ssflags */ 37 uint32_t pad0; 38 uint64_t sc_mdhi; 39 uint64_t sc_mdlo; 40 target_ulong sc_hi1; /* Was sc_cause */ 41 target_ulong sc_lo1; /* Was sc_badvaddr */ 42 target_ulong sc_hi2; /* Was sc_sigset[4] */ 43 target_ulong sc_lo2; 44 target_ulong sc_hi3; 45 target_ulong sc_lo3; 46 }; 47 # else /* N32 || N64 */ 48 struct target_sigcontext { 49 uint64_t sc_regs[32]; 50 uint64_t sc_fpregs[32]; 51 uint64_t sc_mdhi; 52 uint64_t sc_hi1; 53 uint64_t sc_hi2; 54 uint64_t sc_hi3; 55 uint64_t sc_mdlo; 56 uint64_t sc_lo1; 57 uint64_t sc_lo2; 58 uint64_t sc_lo3; 59 uint64_t sc_pc; 60 uint32_t sc_fpc_csr; 61 uint32_t sc_used_math; 62 uint32_t sc_dsp; 63 uint32_t sc_reserved; 64 }; 65 # endif /* O32 */ 66 67 struct sigframe { 68 uint32_t sf_ass[4]; /* argument save space for o32 */ 69 uint32_t sf_code[2]; /* signal trampoline */ 70 struct target_sigcontext sf_sc; 71 target_sigset_t sf_mask; 72 }; 73 74 struct target_ucontext { 75 abi_ulong tuc_flags; 76 abi_ulong tuc_link; 77 target_stack_t tuc_stack; 78 struct target_sigcontext tuc_mcontext; 79 target_sigset_t tuc_sigmask; 80 }; 81 82 struct target_rt_sigframe { 83 uint32_t rs_ass[4]; /* argument save space for o32 */ 84 uint32_t rs_code[2]; /* signal trampoline */ 85 struct target_siginfo rs_info; 86 struct target_ucontext rs_uc; 87 }; 88 89 /* Install trampoline to jump back from signal handler */ 90 static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) 91 { 92 int err = 0; 93 94 /* 95 * Set up the return code ... 96 * 97 * li v0, __NR__foo_sigreturn 98 * syscall 99 */ 100 101 __put_user(0x24020000 + syscall, tramp + 0); 102 __put_user(0x0000000c , tramp + 1); 103 return err; 104 } 105 106 static inline void setup_sigcontext(CPUMIPSState *regs, 107 struct target_sigcontext *sc) 108 { 109 int i; 110 111 __put_user(exception_resume_pc(regs), &sc->sc_pc); 112 regs->hflags &= ~MIPS_HFLAG_BMASK; 113 114 __put_user(0, &sc->sc_regs[0]); 115 for (i = 1; i < 32; ++i) { 116 __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); 117 } 118 119 __put_user(regs->active_tc.HI[0], &sc->sc_mdhi); 120 __put_user(regs->active_tc.LO[0], &sc->sc_mdlo); 121 122 /* Rather than checking for dsp existence, always copy. The storage 123 would just be garbage otherwise. */ 124 __put_user(regs->active_tc.HI[1], &sc->sc_hi1); 125 __put_user(regs->active_tc.HI[2], &sc->sc_hi2); 126 __put_user(regs->active_tc.HI[3], &sc->sc_hi3); 127 __put_user(regs->active_tc.LO[1], &sc->sc_lo1); 128 __put_user(regs->active_tc.LO[2], &sc->sc_lo2); 129 __put_user(regs->active_tc.LO[3], &sc->sc_lo3); 130 { 131 uint32_t dsp = cpu_rddsp(0x3ff, regs); 132 __put_user(dsp, &sc->sc_dsp); 133 } 134 135 __put_user(1, &sc->sc_used_math); 136 137 for (i = 0; i < 32; ++i) { 138 __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); 139 } 140 } 141 142 static inline void 143 restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc) 144 { 145 int i; 146 147 __get_user(regs->CP0_EPC, &sc->sc_pc); 148 149 __get_user(regs->active_tc.HI[0], &sc->sc_mdhi); 150 __get_user(regs->active_tc.LO[0], &sc->sc_mdlo); 151 152 for (i = 1; i < 32; ++i) { 153 __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); 154 } 155 156 __get_user(regs->active_tc.HI[1], &sc->sc_hi1); 157 __get_user(regs->active_tc.HI[2], &sc->sc_hi2); 158 __get_user(regs->active_tc.HI[3], &sc->sc_hi3); 159 __get_user(regs->active_tc.LO[1], &sc->sc_lo1); 160 __get_user(regs->active_tc.LO[2], &sc->sc_lo2); 161 __get_user(regs->active_tc.LO[3], &sc->sc_lo3); 162 { 163 uint32_t dsp; 164 __get_user(dsp, &sc->sc_dsp); 165 cpu_wrdsp(dsp, 0x3ff, regs); 166 } 167 168 for (i = 0; i < 32; ++i) { 169 __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]); 170 } 171 } 172 173 /* 174 * Determine which stack to use.. 175 */ 176 static inline abi_ulong 177 get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size) 178 { 179 unsigned long sp; 180 181 /* 182 * FPU emulator may have its own trampoline active just 183 * above the user stack, 16-bytes before the next lowest 184 * 16 byte boundary. Try to avoid trashing it. 185 */ 186 sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); 187 188 return (sp - frame_size) & ~7; 189 } 190 191 static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env) 192 { 193 if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) { 194 env->hflags &= ~MIPS_HFLAG_M16; 195 env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT; 196 env->active_tc.PC &= ~(target_ulong) 1; 197 } 198 } 199 200 # if defined(TARGET_ABI_MIPSO32) 201 /* compare linux/arch/mips/kernel/signal.c:setup_frame() */ 202 void setup_frame(int sig, struct target_sigaction * ka, 203 target_sigset_t *set, CPUMIPSState *regs) 204 { 205 struct sigframe *frame; 206 abi_ulong frame_addr; 207 int i; 208 209 frame_addr = get_sigframe(ka, regs, sizeof(*frame)); 210 trace_user_setup_frame(regs, frame_addr); 211 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 212 goto give_sigsegv; 213 } 214 215 install_sigtramp(frame->sf_code, TARGET_NR_sigreturn); 216 217 setup_sigcontext(regs, &frame->sf_sc); 218 219 for(i = 0; i < TARGET_NSIG_WORDS; i++) { 220 __put_user(set->sig[i], &frame->sf_mask.sig[i]); 221 } 222 223 /* 224 * Arguments to signal handler: 225 * 226 * a0 = signal number 227 * a1 = 0 (should be cause) 228 * a2 = pointer to struct sigcontext 229 * 230 * $25 and PC point to the signal handler, $29 points to the 231 * struct sigframe. 232 */ 233 regs->active_tc.gpr[ 4] = sig; 234 regs->active_tc.gpr[ 5] = 0; 235 regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc); 236 regs->active_tc.gpr[29] = frame_addr; 237 regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code); 238 /* The original kernel code sets CP0_EPC to the handler 239 * since it returns to userland using eret 240 * we cannot do this here, and we must set PC directly */ 241 regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler; 242 mips_set_hflags_isa_mode_from_pc(regs); 243 unlock_user_struct(frame, frame_addr, 1); 244 return; 245 246 give_sigsegv: 247 force_sigsegv(sig); 248 } 249 250 long do_sigreturn(CPUMIPSState *regs) 251 { 252 struct sigframe *frame; 253 abi_ulong frame_addr; 254 sigset_t blocked; 255 target_sigset_t target_set; 256 int i; 257 258 frame_addr = regs->active_tc.gpr[29]; 259 trace_user_do_sigreturn(regs, frame_addr); 260 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) 261 goto badframe; 262 263 for(i = 0; i < TARGET_NSIG_WORDS; i++) { 264 __get_user(target_set.sig[i], &frame->sf_mask.sig[i]); 265 } 266 267 target_to_host_sigset_internal(&blocked, &target_set); 268 set_sigmask(&blocked); 269 270 restore_sigcontext(regs, &frame->sf_sc); 271 272 #if 0 273 /* 274 * Don't let your children do this ... 275 */ 276 __asm__ __volatile__( 277 "move\t$29, %0\n\t" 278 "j\tsyscall_exit" 279 :/* no outputs */ 280 :"r" (®s)); 281 /* Unreached */ 282 #endif 283 284 regs->active_tc.PC = regs->CP0_EPC; 285 mips_set_hflags_isa_mode_from_pc(regs); 286 /* I am not sure this is right, but it seems to work 287 * maybe a problem with nested signals ? */ 288 regs->CP0_EPC = 0; 289 return -TARGET_QEMU_ESIGRETURN; 290 291 badframe: 292 force_sig(TARGET_SIGSEGV); 293 return -TARGET_QEMU_ESIGRETURN; 294 } 295 # endif /* O32 */ 296 297 void setup_rt_frame(int sig, struct target_sigaction *ka, 298 target_siginfo_t *info, 299 target_sigset_t *set, CPUMIPSState *env) 300 { 301 struct target_rt_sigframe *frame; 302 abi_ulong frame_addr; 303 int i; 304 305 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 306 trace_user_setup_rt_frame(env, frame_addr); 307 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 308 goto give_sigsegv; 309 } 310 311 install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn); 312 313 tswap_siginfo(&frame->rs_info, info); 314 315 __put_user(0, &frame->rs_uc.tuc_flags); 316 __put_user(0, &frame->rs_uc.tuc_link); 317 target_save_altstack(&frame->rs_uc.tuc_stack, env); 318 319 setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); 320 321 for(i = 0; i < TARGET_NSIG_WORDS; i++) { 322 __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); 323 } 324 325 /* 326 * Arguments to signal handler: 327 * 328 * a0 = signal number 329 * a1 = pointer to siginfo_t 330 * a2 = pointer to ucontext_t 331 * 332 * $25 and PC point to the signal handler, $29 points to the 333 * struct sigframe. 334 */ 335 env->active_tc.gpr[ 4] = sig; 336 env->active_tc.gpr[ 5] = frame_addr 337 + offsetof(struct target_rt_sigframe, rs_info); 338 env->active_tc.gpr[ 6] = frame_addr 339 + offsetof(struct target_rt_sigframe, rs_uc); 340 env->active_tc.gpr[29] = frame_addr; 341 env->active_tc.gpr[31] = frame_addr 342 + offsetof(struct target_rt_sigframe, rs_code); 343 /* The original kernel code sets CP0_EPC to the handler 344 * since it returns to userland using eret 345 * we cannot do this here, and we must set PC directly */ 346 env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler; 347 mips_set_hflags_isa_mode_from_pc(env); 348 unlock_user_struct(frame, frame_addr, 1); 349 return; 350 351 give_sigsegv: 352 unlock_user_struct(frame, frame_addr, 1); 353 force_sigsegv(sig); 354 } 355 356 long do_rt_sigreturn(CPUMIPSState *env) 357 { 358 struct target_rt_sigframe *frame; 359 abi_ulong frame_addr; 360 sigset_t blocked; 361 362 frame_addr = env->active_tc.gpr[29]; 363 trace_user_do_rt_sigreturn(env, frame_addr); 364 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 365 goto badframe; 366 } 367 368 target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); 369 set_sigmask(&blocked); 370 371 restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); 372 target_restore_altstack(&frame->rs_uc.tuc_stack, env); 373 374 env->active_tc.PC = env->CP0_EPC; 375 mips_set_hflags_isa_mode_from_pc(env); 376 /* I am not sure this is right, but it seems to work 377 * maybe a problem with nested signals ? */ 378 env->CP0_EPC = 0; 379 return -TARGET_QEMU_ESIGRETURN; 380 381 badframe: 382 force_sig(TARGET_SIGSEGV); 383 return -TARGET_QEMU_ESIGRETURN; 384 } 385