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