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