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 /* 25 * code and data structures from linux kernel: 26 * include/asm-sh/sigcontext.h 27 * arch/sh/kernel/signal.c 28 */ 29 30 struct target_sigcontext { 31 target_ulong oldmask; 32 33 /* CPU registers */ 34 target_ulong sc_gregs[16]; 35 target_ulong sc_pc; 36 target_ulong sc_pr; 37 target_ulong sc_sr; 38 target_ulong sc_gbr; 39 target_ulong sc_mach; 40 target_ulong sc_macl; 41 42 /* FPU registers */ 43 target_ulong sc_fpregs[16]; 44 target_ulong sc_xfpregs[16]; 45 unsigned int sc_fpscr; 46 unsigned int sc_fpul; 47 unsigned int sc_ownedfp; 48 }; 49 50 struct target_sigframe 51 { 52 struct target_sigcontext sc; 53 target_ulong extramask[TARGET_NSIG_WORDS-1]; 54 uint16_t retcode[3]; 55 }; 56 57 58 struct target_ucontext { 59 target_ulong tuc_flags; 60 struct target_ucontext *tuc_link; 61 target_stack_t tuc_stack; 62 struct target_sigcontext tuc_mcontext; 63 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 64 }; 65 66 struct target_rt_sigframe 67 { 68 struct target_siginfo info; 69 struct target_ucontext uc; 70 uint16_t retcode[3]; 71 }; 72 73 74 #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ 75 #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ 76 77 static abi_ulong get_sigframe(struct target_sigaction *ka, 78 unsigned long sp, size_t frame_size) 79 { 80 sp = target_sigsp(sp, ka); 81 82 return (sp - frame_size) & -8ul; 83 } 84 85 /* 86 * Notice when we're in the middle of a gUSA region and reset. 87 * Note that this will only occur when #CF_PARALLEL is unset, as we 88 * will translate such sequences differently in a parallel context. 89 */ 90 static void unwind_gusa(CPUSH4State *regs) 91 { 92 /* If the stack pointer is sufficiently negative, and we haven't 93 completed the sequence, then reset to the entry to the region. */ 94 /* ??? The SH4 kernel checks for and address above 0xC0000000. 95 However, the page mappings in qemu linux-user aren't as restricted 96 and we wind up with the normal stack mapped above 0xF0000000. 97 That said, there is no reason why the kernel should be allowing 98 a gUSA region that spans 1GB. Use a tighter check here, for what 99 can actually be enabled by the immediate move. */ 100 if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) { 101 /* Reset the PC to before the gUSA region, as computed from 102 R0 = region end, SP = -(region size), plus one more for the 103 insn that actually initializes SP to the region size. */ 104 regs->pc = regs->gregs[0] + regs->gregs[15] - 2; 105 106 /* Reset the SP to the saved version in R1. */ 107 regs->gregs[15] = regs->gregs[1]; 108 } 109 } 110 111 static void setup_sigcontext(struct target_sigcontext *sc, 112 CPUSH4State *regs, unsigned long mask) 113 { 114 int i; 115 116 #define COPY(x) __put_user(regs->x, &sc->sc_##x) 117 COPY(gregs[0]); COPY(gregs[1]); 118 COPY(gregs[2]); COPY(gregs[3]); 119 COPY(gregs[4]); COPY(gregs[5]); 120 COPY(gregs[6]); COPY(gregs[7]); 121 COPY(gregs[8]); COPY(gregs[9]); 122 COPY(gregs[10]); COPY(gregs[11]); 123 COPY(gregs[12]); COPY(gregs[13]); 124 COPY(gregs[14]); COPY(gregs[15]); 125 COPY(gbr); COPY(mach); 126 COPY(macl); COPY(pr); 127 COPY(sr); COPY(pc); 128 #undef COPY 129 130 for (i=0; i<16; i++) { 131 __put_user(regs->fregs[i], &sc->sc_fpregs[i]); 132 } 133 __put_user(regs->fpscr, &sc->sc_fpscr); 134 __put_user(regs->fpul, &sc->sc_fpul); 135 136 /* non-iBCS2 extensions.. */ 137 __put_user(mask, &sc->oldmask); 138 } 139 140 static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) 141 { 142 int i; 143 144 #define COPY(x) __get_user(regs->x, &sc->sc_##x) 145 COPY(gregs[0]); COPY(gregs[1]); 146 COPY(gregs[2]); COPY(gregs[3]); 147 COPY(gregs[4]); COPY(gregs[5]); 148 COPY(gregs[6]); COPY(gregs[7]); 149 COPY(gregs[8]); COPY(gregs[9]); 150 COPY(gregs[10]); COPY(gregs[11]); 151 COPY(gregs[12]); COPY(gregs[13]); 152 COPY(gregs[14]); COPY(gregs[15]); 153 COPY(gbr); COPY(mach); 154 COPY(macl); COPY(pr); 155 COPY(sr); COPY(pc); 156 #undef COPY 157 158 for (i=0; i<16; i++) { 159 __get_user(regs->fregs[i], &sc->sc_fpregs[i]); 160 } 161 __get_user(regs->fpscr, &sc->sc_fpscr); 162 __get_user(regs->fpul, &sc->sc_fpul); 163 164 regs->tra = -1; /* disable syscall checks */ 165 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 166 } 167 168 void setup_frame(int sig, struct target_sigaction *ka, 169 target_sigset_t *set, CPUSH4State *regs) 170 { 171 struct target_sigframe *frame; 172 abi_ulong frame_addr; 173 int i; 174 175 unwind_gusa(regs); 176 177 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); 178 trace_user_setup_frame(regs, frame_addr); 179 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 180 goto give_sigsegv; 181 } 182 183 setup_sigcontext(&frame->sc, regs, set->sig[0]); 184 185 for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { 186 __put_user(set->sig[i + 1], &frame->extramask[i]); 187 } 188 189 /* Set up to return from userspace. If provided, use a stub 190 already in userspace. */ 191 if (ka->sa_flags & TARGET_SA_RESTORER) { 192 regs->pr = (unsigned long) ka->sa_restorer; 193 } else { 194 /* Generate return code (system call to sigreturn) */ 195 abi_ulong retcode_addr = frame_addr + 196 offsetof(struct target_sigframe, retcode); 197 __put_user(MOVW(2), &frame->retcode[0]); 198 __put_user(TRAP_NOARG, &frame->retcode[1]); 199 __put_user((TARGET_NR_sigreturn), &frame->retcode[2]); 200 regs->pr = (unsigned long) retcode_addr; 201 } 202 203 /* Set up registers for signal handler */ 204 regs->gregs[15] = frame_addr; 205 regs->gregs[4] = sig; /* Arg for signal handler */ 206 regs->gregs[5] = 0; 207 regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc); 208 regs->pc = (unsigned long) ka->_sa_handler; 209 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 210 211 unlock_user_struct(frame, frame_addr, 1); 212 return; 213 214 give_sigsegv: 215 unlock_user_struct(frame, frame_addr, 1); 216 force_sigsegv(sig); 217 } 218 219 void setup_rt_frame(int sig, struct target_sigaction *ka, 220 target_siginfo_t *info, 221 target_sigset_t *set, CPUSH4State *regs) 222 { 223 struct target_rt_sigframe *frame; 224 abi_ulong frame_addr; 225 int i; 226 227 unwind_gusa(regs); 228 229 frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); 230 trace_user_setup_rt_frame(regs, frame_addr); 231 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 232 goto give_sigsegv; 233 } 234 235 tswap_siginfo(&frame->info, info); 236 237 /* Create the ucontext. */ 238 __put_user(0, &frame->uc.tuc_flags); 239 __put_user(0, (unsigned long *)&frame->uc.tuc_link); 240 target_save_altstack(&frame->uc.tuc_stack, regs); 241 setup_sigcontext(&frame->uc.tuc_mcontext, 242 regs, set->sig[0]); 243 for(i = 0; i < TARGET_NSIG_WORDS; i++) { 244 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 245 } 246 247 /* Set up to return from userspace. If provided, use a stub 248 already in userspace. */ 249 if (ka->sa_flags & TARGET_SA_RESTORER) { 250 regs->pr = (unsigned long) ka->sa_restorer; 251 } else { 252 /* Generate return code (system call to sigreturn) */ 253 abi_ulong retcode_addr = frame_addr + 254 offsetof(struct target_rt_sigframe, retcode); 255 __put_user(MOVW(2), &frame->retcode[0]); 256 __put_user(TRAP_NOARG, &frame->retcode[1]); 257 __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]); 258 regs->pr = (unsigned long) retcode_addr; 259 } 260 261 /* Set up registers for signal handler */ 262 regs->gregs[15] = frame_addr; 263 regs->gregs[4] = sig; /* Arg for signal handler */ 264 regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info); 265 regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc); 266 regs->pc = (unsigned long) ka->_sa_handler; 267 regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 268 269 unlock_user_struct(frame, frame_addr, 1); 270 return; 271 272 give_sigsegv: 273 unlock_user_struct(frame, frame_addr, 1); 274 force_sigsegv(sig); 275 } 276 277 long do_sigreturn(CPUSH4State *regs) 278 { 279 struct target_sigframe *frame; 280 abi_ulong frame_addr; 281 sigset_t blocked; 282 target_sigset_t target_set; 283 int i; 284 285 frame_addr = regs->gregs[15]; 286 trace_user_do_sigreturn(regs, frame_addr); 287 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 288 goto badframe; 289 } 290 291 __get_user(target_set.sig[0], &frame->sc.oldmask); 292 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 293 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 294 } 295 296 target_to_host_sigset_internal(&blocked, &target_set); 297 set_sigmask(&blocked); 298 299 restore_sigcontext(regs, &frame->sc); 300 301 unlock_user_struct(frame, frame_addr, 0); 302 return -TARGET_QEMU_ESIGRETURN; 303 304 badframe: 305 unlock_user_struct(frame, frame_addr, 0); 306 force_sig(TARGET_SIGSEGV); 307 return -TARGET_QEMU_ESIGRETURN; 308 } 309 310 long do_rt_sigreturn(CPUSH4State *regs) 311 { 312 struct target_rt_sigframe *frame; 313 abi_ulong frame_addr; 314 sigset_t blocked; 315 316 frame_addr = regs->gregs[15]; 317 trace_user_do_rt_sigreturn(regs, frame_addr); 318 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 319 goto badframe; 320 } 321 322 target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask); 323 set_sigmask(&blocked); 324 325 restore_sigcontext(regs, &frame->uc.tuc_mcontext); 326 target_restore_altstack(&frame->uc.tuc_stack, regs); 327 328 unlock_user_struct(frame, frame_addr, 0); 329 return -TARGET_QEMU_ESIGRETURN; 330 331 badframe: 332 unlock_user_struct(frame, frame_addr, 0); 333 force_sig(TARGET_SIGSEGV); 334 return -TARGET_QEMU_ESIGRETURN; 335 } 336