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