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