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 struct target_sigcontext { 25 abi_ulong sc_mask; 26 abi_ulong sc_usp; 27 abi_ulong sc_d0; 28 abi_ulong sc_d1; 29 abi_ulong sc_a0; 30 abi_ulong sc_a1; 31 unsigned short sc_sr; 32 abi_ulong sc_pc; 33 }; 34 35 struct target_sigframe 36 { 37 abi_ulong pretcode; 38 int sig; 39 int code; 40 abi_ulong psc; 41 char retcode[8]; 42 abi_ulong extramask[TARGET_NSIG_WORDS-1]; 43 struct target_sigcontext sc; 44 }; 45 46 typedef int target_greg_t; 47 #define TARGET_NGREG 18 48 typedef target_greg_t target_gregset_t[TARGET_NGREG]; 49 50 typedef struct target_fpregset { 51 int f_fpcntl[3]; 52 int f_fpregs[8*3]; 53 } target_fpregset_t; 54 55 struct target_mcontext { 56 int version; 57 target_gregset_t gregs; 58 target_fpregset_t fpregs; 59 }; 60 61 #define TARGET_MCONTEXT_VERSION 2 62 63 struct target_ucontext { 64 abi_ulong tuc_flags; 65 abi_ulong tuc_link; 66 target_stack_t tuc_stack; 67 struct target_mcontext tuc_mcontext; 68 abi_long tuc_filler[80]; 69 target_sigset_t tuc_sigmask; 70 }; 71 72 struct target_rt_sigframe 73 { 74 abi_ulong pretcode; 75 int sig; 76 abi_ulong pinfo; 77 abi_ulong puc; 78 char retcode[8]; 79 struct target_siginfo info; 80 struct target_ucontext uc; 81 }; 82 83 static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env, 84 abi_ulong mask) 85 { 86 uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env); 87 __put_user(mask, &sc->sc_mask); 88 __put_user(env->aregs[7], &sc->sc_usp); 89 __put_user(env->dregs[0], &sc->sc_d0); 90 __put_user(env->dregs[1], &sc->sc_d1); 91 __put_user(env->aregs[0], &sc->sc_a0); 92 __put_user(env->aregs[1], &sc->sc_a1); 93 __put_user(sr, &sc->sc_sr); 94 __put_user(env->pc, &sc->sc_pc); 95 } 96 97 static void 98 restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc) 99 { 100 int temp; 101 102 __get_user(env->aregs[7], &sc->sc_usp); 103 __get_user(env->dregs[0], &sc->sc_d0); 104 __get_user(env->dregs[1], &sc->sc_d1); 105 __get_user(env->aregs[0], &sc->sc_a0); 106 __get_user(env->aregs[1], &sc->sc_a1); 107 __get_user(env->pc, &sc->sc_pc); 108 __get_user(temp, &sc->sc_sr); 109 cpu_m68k_set_ccr(env, temp); 110 } 111 112 /* 113 * Determine which stack to use.. 114 */ 115 static inline abi_ulong 116 get_sigframe(struct target_sigaction *ka, CPUM68KState *regs, 117 size_t frame_size) 118 { 119 abi_ulong sp; 120 121 sp = target_sigsp(get_sp_from_cpustate(regs), ka); 122 123 124 return ((sp - frame_size) & -8UL); 125 } 126 127 void setup_frame(int sig, struct target_sigaction *ka, 128 target_sigset_t *set, CPUM68KState *env) 129 { 130 struct target_sigframe *frame; 131 abi_ulong frame_addr; 132 abi_ulong retcode_addr; 133 abi_ulong sc_addr; 134 int i; 135 136 frame_addr = get_sigframe(ka, env, sizeof *frame); 137 trace_user_setup_frame(env, frame_addr); 138 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 139 goto give_sigsegv; 140 } 141 142 __put_user(sig, &frame->sig); 143 144 sc_addr = frame_addr + offsetof(struct target_sigframe, sc); 145 __put_user(sc_addr, &frame->psc); 146 147 setup_sigcontext(&frame->sc, env, set->sig[0]); 148 149 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 150 __put_user(set->sig[i], &frame->extramask[i - 1]); 151 } 152 153 /* Set up to return from userspace. */ 154 155 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode); 156 __put_user(retcode_addr, &frame->pretcode); 157 158 /* moveq #,d0; trap #0 */ 159 160 __put_user(0x70004e40 + (TARGET_NR_sigreturn << 16), 161 (uint32_t *)(frame->retcode)); 162 163 /* Set up to return from userspace */ 164 165 env->aregs[7] = frame_addr; 166 env->pc = ka->_sa_handler; 167 168 unlock_user_struct(frame, frame_addr, 1); 169 return; 170 171 give_sigsegv: 172 force_sigsegv(sig); 173 } 174 175 static inline void target_rt_save_fpu_state(struct target_ucontext *uc, 176 CPUM68KState *env) 177 { 178 int i; 179 target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs; 180 181 __put_user(env->fpcr, &fpregs->f_fpcntl[0]); 182 __put_user(env->fpsr, &fpregs->f_fpcntl[1]); 183 /* fpiar is not emulated */ 184 185 for (i = 0; i < 8; i++) { 186 uint32_t high = env->fregs[i].d.high << 16; 187 __put_user(high, &fpregs->f_fpregs[i * 3]); 188 __put_user(env->fregs[i].d.low, 189 (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]); 190 } 191 } 192 193 static inline int target_rt_setup_ucontext(struct target_ucontext *uc, 194 CPUM68KState *env) 195 { 196 target_greg_t *gregs = uc->tuc_mcontext.gregs; 197 uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env); 198 199 __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version); 200 __put_user(env->dregs[0], &gregs[0]); 201 __put_user(env->dregs[1], &gregs[1]); 202 __put_user(env->dregs[2], &gregs[2]); 203 __put_user(env->dregs[3], &gregs[3]); 204 __put_user(env->dregs[4], &gregs[4]); 205 __put_user(env->dregs[5], &gregs[5]); 206 __put_user(env->dregs[6], &gregs[6]); 207 __put_user(env->dregs[7], &gregs[7]); 208 __put_user(env->aregs[0], &gregs[8]); 209 __put_user(env->aregs[1], &gregs[9]); 210 __put_user(env->aregs[2], &gregs[10]); 211 __put_user(env->aregs[3], &gregs[11]); 212 __put_user(env->aregs[4], &gregs[12]); 213 __put_user(env->aregs[5], &gregs[13]); 214 __put_user(env->aregs[6], &gregs[14]); 215 __put_user(env->aregs[7], &gregs[15]); 216 __put_user(env->pc, &gregs[16]); 217 __put_user(sr, &gregs[17]); 218 219 target_rt_save_fpu_state(uc, env); 220 221 return 0; 222 } 223 224 static inline void target_rt_restore_fpu_state(CPUM68KState *env, 225 struct target_ucontext *uc) 226 { 227 int i; 228 target_fpregset_t *fpregs = &uc->tuc_mcontext.fpregs; 229 uint32_t fpcr; 230 231 __get_user(fpcr, &fpregs->f_fpcntl[0]); 232 cpu_m68k_set_fpcr(env, fpcr); 233 __get_user(env->fpsr, &fpregs->f_fpcntl[1]); 234 /* fpiar is not emulated */ 235 236 for (i = 0; i < 8; i++) { 237 uint32_t high; 238 __get_user(high, &fpregs->f_fpregs[i * 3]); 239 env->fregs[i].d.high = high >> 16; 240 __get_user(env->fregs[i].d.low, 241 (uint64_t *)&fpregs->f_fpregs[i * 3 + 1]); 242 } 243 } 244 245 static inline int target_rt_restore_ucontext(CPUM68KState *env, 246 struct target_ucontext *uc) 247 { 248 int temp; 249 target_greg_t *gregs = uc->tuc_mcontext.gregs; 250 251 __get_user(temp, &uc->tuc_mcontext.version); 252 if (temp != TARGET_MCONTEXT_VERSION) 253 goto badframe; 254 255 /* restore passed registers */ 256 __get_user(env->dregs[0], &gregs[0]); 257 __get_user(env->dregs[1], &gregs[1]); 258 __get_user(env->dregs[2], &gregs[2]); 259 __get_user(env->dregs[3], &gregs[3]); 260 __get_user(env->dregs[4], &gregs[4]); 261 __get_user(env->dregs[5], &gregs[5]); 262 __get_user(env->dregs[6], &gregs[6]); 263 __get_user(env->dregs[7], &gregs[7]); 264 __get_user(env->aregs[0], &gregs[8]); 265 __get_user(env->aregs[1], &gregs[9]); 266 __get_user(env->aregs[2], &gregs[10]); 267 __get_user(env->aregs[3], &gregs[11]); 268 __get_user(env->aregs[4], &gregs[12]); 269 __get_user(env->aregs[5], &gregs[13]); 270 __get_user(env->aregs[6], &gregs[14]); 271 __get_user(env->aregs[7], &gregs[15]); 272 __get_user(env->pc, &gregs[16]); 273 __get_user(temp, &gregs[17]); 274 cpu_m68k_set_ccr(env, temp); 275 276 target_rt_restore_fpu_state(env, uc); 277 278 return 0; 279 280 badframe: 281 return 1; 282 } 283 284 void setup_rt_frame(int sig, struct target_sigaction *ka, 285 target_siginfo_t *info, 286 target_sigset_t *set, CPUM68KState *env) 287 { 288 struct target_rt_sigframe *frame; 289 abi_ulong frame_addr; 290 abi_ulong retcode_addr; 291 abi_ulong info_addr; 292 abi_ulong uc_addr; 293 int err = 0; 294 int i; 295 296 frame_addr = get_sigframe(ka, env, sizeof *frame); 297 trace_user_setup_rt_frame(env, frame_addr); 298 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 299 goto give_sigsegv; 300 } 301 302 __put_user(sig, &frame->sig); 303 304 info_addr = frame_addr + offsetof(struct target_rt_sigframe, info); 305 __put_user(info_addr, &frame->pinfo); 306 307 uc_addr = frame_addr + offsetof(struct target_rt_sigframe, uc); 308 __put_user(uc_addr, &frame->puc); 309 310 tswap_siginfo(&frame->info, info); 311 312 /* Create the ucontext */ 313 314 __put_user(0, &frame->uc.tuc_flags); 315 __put_user(0, &frame->uc.tuc_link); 316 target_save_altstack(&frame->uc.tuc_stack, env); 317 err |= target_rt_setup_ucontext(&frame->uc, env); 318 319 if (err) 320 goto give_sigsegv; 321 322 for(i = 0; i < TARGET_NSIG_WORDS; i++) { 323 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 324 } 325 326 /* Set up to return from userspace. */ 327 328 retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode); 329 __put_user(retcode_addr, &frame->pretcode); 330 331 /* moveq #,d0; notb d0; trap #0 */ 332 333 __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16), 334 (uint32_t *)(frame->retcode + 0)); 335 __put_user(0x4e40, (uint16_t *)(frame->retcode + 4)); 336 337 /* Set up to return from userspace */ 338 339 env->aregs[7] = frame_addr; 340 env->pc = ka->_sa_handler; 341 342 unlock_user_struct(frame, frame_addr, 1); 343 return; 344 345 give_sigsegv: 346 unlock_user_struct(frame, frame_addr, 1); 347 force_sigsegv(sig); 348 } 349 350 long do_sigreturn(CPUM68KState *env) 351 { 352 struct target_sigframe *frame; 353 abi_ulong frame_addr = env->aregs[7] - 4; 354 target_sigset_t target_set; 355 sigset_t set; 356 int i; 357 358 trace_user_do_sigreturn(env, frame_addr); 359 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) 360 goto badframe; 361 362 /* set blocked signals */ 363 364 __get_user(target_set.sig[0], &frame->sc.sc_mask); 365 366 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 367 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 368 } 369 370 target_to_host_sigset_internal(&set, &target_set); 371 set_sigmask(&set); 372 373 /* restore registers */ 374 375 restore_sigcontext(env, &frame->sc); 376 377 unlock_user_struct(frame, frame_addr, 0); 378 return -TARGET_QEMU_ESIGRETURN; 379 380 badframe: 381 force_sig(TARGET_SIGSEGV); 382 return -TARGET_QEMU_ESIGRETURN; 383 } 384 385 long do_rt_sigreturn(CPUM68KState *env) 386 { 387 struct target_rt_sigframe *frame; 388 abi_ulong frame_addr = env->aregs[7] - 4; 389 sigset_t set; 390 391 trace_user_do_rt_sigreturn(env, frame_addr); 392 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) 393 goto badframe; 394 395 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 396 set_sigmask(&set); 397 398 /* restore registers */ 399 400 if (target_rt_restore_ucontext(env, &frame->uc)) 401 goto badframe; 402 403 target_restore_altstack(&frame->uc.tuc_stack, env); 404 405 unlock_user_struct(frame, frame_addr, 0); 406 return -TARGET_QEMU_ESIGRETURN; 407 408 badframe: 409 unlock_user_struct(frame, frame_addr, 0); 410 force_sig(TARGET_SIGSEGV); 411 return -TARGET_QEMU_ESIGRETURN; 412 } 413