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 struct target_pt_regs regs; /* needs to be first */ 26 uint32_t oldmask; 27 }; 28 29 struct target_stack_t { 30 abi_ulong ss_sp; 31 int ss_flags; 32 unsigned int ss_size; 33 }; 34 35 struct target_ucontext { 36 abi_ulong tuc_flags; 37 abi_ulong tuc_link; 38 target_stack_t tuc_stack; 39 struct target_sigcontext tuc_mcontext; 40 target_sigset_t tuc_sigmask; 41 }; 42 43 /* Signal frames. */ 44 struct target_signal_frame { 45 struct target_ucontext uc; 46 uint32_t extramask[TARGET_NSIG_WORDS - 1]; 47 uint32_t tramp[2]; 48 }; 49 50 struct target_rt_sigframe { 51 target_siginfo_t info; 52 struct target_ucontext uc; 53 uint32_t tramp[2]; 54 }; 55 56 static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 57 { 58 __put_user(env->regs[0], &sc->regs.r0); 59 __put_user(env->regs[1], &sc->regs.r1); 60 __put_user(env->regs[2], &sc->regs.r2); 61 __put_user(env->regs[3], &sc->regs.r3); 62 __put_user(env->regs[4], &sc->regs.r4); 63 __put_user(env->regs[5], &sc->regs.r5); 64 __put_user(env->regs[6], &sc->regs.r6); 65 __put_user(env->regs[7], &sc->regs.r7); 66 __put_user(env->regs[8], &sc->regs.r8); 67 __put_user(env->regs[9], &sc->regs.r9); 68 __put_user(env->regs[10], &sc->regs.r10); 69 __put_user(env->regs[11], &sc->regs.r11); 70 __put_user(env->regs[12], &sc->regs.r12); 71 __put_user(env->regs[13], &sc->regs.r13); 72 __put_user(env->regs[14], &sc->regs.r14); 73 __put_user(env->regs[15], &sc->regs.r15); 74 __put_user(env->regs[16], &sc->regs.r16); 75 __put_user(env->regs[17], &sc->regs.r17); 76 __put_user(env->regs[18], &sc->regs.r18); 77 __put_user(env->regs[19], &sc->regs.r19); 78 __put_user(env->regs[20], &sc->regs.r20); 79 __put_user(env->regs[21], &sc->regs.r21); 80 __put_user(env->regs[22], &sc->regs.r22); 81 __put_user(env->regs[23], &sc->regs.r23); 82 __put_user(env->regs[24], &sc->regs.r24); 83 __put_user(env->regs[25], &sc->regs.r25); 84 __put_user(env->regs[26], &sc->regs.r26); 85 __put_user(env->regs[27], &sc->regs.r27); 86 __put_user(env->regs[28], &sc->regs.r28); 87 __put_user(env->regs[29], &sc->regs.r29); 88 __put_user(env->regs[30], &sc->regs.r30); 89 __put_user(env->regs[31], &sc->regs.r31); 90 __put_user(env->pc, &sc->regs.pc); 91 } 92 93 static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 94 { 95 __get_user(env->regs[0], &sc->regs.r0); 96 __get_user(env->regs[1], &sc->regs.r1); 97 __get_user(env->regs[2], &sc->regs.r2); 98 __get_user(env->regs[3], &sc->regs.r3); 99 __get_user(env->regs[4], &sc->regs.r4); 100 __get_user(env->regs[5], &sc->regs.r5); 101 __get_user(env->regs[6], &sc->regs.r6); 102 __get_user(env->regs[7], &sc->regs.r7); 103 __get_user(env->regs[8], &sc->regs.r8); 104 __get_user(env->regs[9], &sc->regs.r9); 105 __get_user(env->regs[10], &sc->regs.r10); 106 __get_user(env->regs[11], &sc->regs.r11); 107 __get_user(env->regs[12], &sc->regs.r12); 108 __get_user(env->regs[13], &sc->regs.r13); 109 __get_user(env->regs[14], &sc->regs.r14); 110 __get_user(env->regs[15], &sc->regs.r15); 111 __get_user(env->regs[16], &sc->regs.r16); 112 __get_user(env->regs[17], &sc->regs.r17); 113 __get_user(env->regs[18], &sc->regs.r18); 114 __get_user(env->regs[19], &sc->regs.r19); 115 __get_user(env->regs[20], &sc->regs.r20); 116 __get_user(env->regs[21], &sc->regs.r21); 117 __get_user(env->regs[22], &sc->regs.r22); 118 __get_user(env->regs[23], &sc->regs.r23); 119 __get_user(env->regs[24], &sc->regs.r24); 120 __get_user(env->regs[25], &sc->regs.r25); 121 __get_user(env->regs[26], &sc->regs.r26); 122 __get_user(env->regs[27], &sc->regs.r27); 123 __get_user(env->regs[28], &sc->regs.r28); 124 __get_user(env->regs[29], &sc->regs.r29); 125 __get_user(env->regs[30], &sc->regs.r30); 126 __get_user(env->regs[31], &sc->regs.r31); 127 __get_user(env->pc, &sc->regs.pc); 128 } 129 130 static abi_ulong get_sigframe(struct target_sigaction *ka, 131 CPUMBState *env, int frame_size) 132 { 133 abi_ulong sp = env->regs[1]; 134 135 sp = target_sigsp(sp, ka); 136 137 return ((sp - frame_size) & -8UL); 138 } 139 140 void setup_frame(int sig, struct target_sigaction *ka, 141 target_sigset_t *set, CPUMBState *env) 142 { 143 struct target_signal_frame *frame; 144 abi_ulong frame_addr; 145 int i; 146 147 frame_addr = get_sigframe(ka, env, sizeof *frame); 148 trace_user_setup_frame(env, frame_addr); 149 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) 150 goto badframe; 151 152 /* Save the mask. */ 153 __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask); 154 155 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 156 __put_user(set->sig[i], &frame->extramask[i - 1]); 157 } 158 159 setup_sigcontext(&frame->uc.tuc_mcontext, env); 160 161 /* Set up to return from userspace. If provided, use a stub 162 already in userspace. */ 163 /* minus 8 is offset to cater for "rtsd r15,8" offset */ 164 if (ka->sa_flags & TARGET_SA_RESTORER) { 165 env->regs[15] = ((unsigned long)ka->sa_restorer)-8; 166 } else { 167 uint32_t t; 168 /* Note, these encodings are _big endian_! */ 169 /* addi r12, r0, __NR_sigreturn */ 170 t = 0x31800000UL | TARGET_NR_sigreturn; 171 __put_user(t, frame->tramp + 0); 172 /* brki r14, 0x8 */ 173 t = 0xb9cc0008UL; 174 __put_user(t, frame->tramp + 1); 175 176 /* Return from sighandler will jump to the tramp. 177 Negative 8 offset because return is rtsd r15, 8 */ 178 env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp) 179 - 8; 180 } 181 182 /* Set up registers for signal handler */ 183 env->regs[1] = frame_addr; 184 /* Signal handler args: */ 185 env->regs[5] = sig; /* Arg 0: signum */ 186 env->regs[6] = 0; 187 /* arg 1: sigcontext */ 188 env->regs[7] = frame_addr += offsetof(typeof(*frame), uc); 189 190 /* Offset of 4 to handle microblaze rtid r14, 0 */ 191 env->pc = (unsigned long)ka->_sa_handler; 192 193 unlock_user_struct(frame, frame_addr, 1); 194 return; 195 badframe: 196 force_sigsegv(sig); 197 } 198 199 void setup_rt_frame(int sig, struct target_sigaction *ka, 200 target_siginfo_t *info, 201 target_sigset_t *set, CPUMBState *env) 202 { 203 struct target_rt_sigframe *frame; 204 abi_ulong frame_addr; 205 206 frame_addr = get_sigframe(ka, env, sizeof *frame); 207 trace_user_setup_rt_frame(env, frame_addr); 208 209 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 210 force_sigsegv(sig); 211 return; 212 } 213 214 tswap_siginfo(&frame->info, info); 215 216 __put_user(0, &frame->uc.tuc_flags); 217 __put_user(0, &frame->uc.tuc_link); 218 219 target_save_altstack(&frame->uc.tuc_stack, env); 220 setup_sigcontext(&frame->uc.tuc_mcontext, env); 221 222 for (int i = 0; i < TARGET_NSIG_WORDS; i++) { 223 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 224 } 225 226 /* Kernel does not use SA_RESTORER. */ 227 228 /* addi r12, r0, __NR_sigreturn */ 229 __put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0); 230 /* brki r14, 0x8 */ 231 __put_user(0xb9cc0008U, frame->tramp + 1); 232 233 /* 234 * Return from sighandler will jump to the tramp. 235 * Negative 8 offset because return is rtsd r15, 8 236 */ 237 env->regs[15] = 238 frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8; 239 240 /* Set up registers for signal handler */ 241 env->regs[1] = frame_addr; 242 243 /* Signal handler args: */ 244 env->regs[5] = sig; 245 env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info); 246 env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc); 247 248 /* Offset to handle microblaze rtid r14, 0 */ 249 env->pc = (unsigned long)ka->_sa_handler; 250 251 unlock_user_struct(frame, frame_addr, 1); 252 } 253 254 long do_sigreturn(CPUMBState *env) 255 { 256 struct target_signal_frame *frame; 257 abi_ulong frame_addr; 258 target_sigset_t target_set; 259 sigset_t set; 260 int i; 261 262 frame_addr = env->regs[R_SP]; 263 trace_user_do_sigreturn(env, frame_addr); 264 /* Make sure the guest isn't playing games. */ 265 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) 266 goto badframe; 267 268 /* Restore blocked signals */ 269 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask); 270 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 271 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 272 } 273 target_to_host_sigset_internal(&set, &target_set); 274 set_sigmask(&set); 275 276 restore_sigcontext(&frame->uc.tuc_mcontext, env); 277 /* We got here through a sigreturn syscall, our path back is via an 278 rtb insn so setup r14 for that. */ 279 env->regs[14] = env->pc; 280 281 unlock_user_struct(frame, frame_addr, 0); 282 return -TARGET_QEMU_ESIGRETURN; 283 badframe: 284 force_sig(TARGET_SIGSEGV); 285 return -TARGET_QEMU_ESIGRETURN; 286 } 287 288 long do_rt_sigreturn(CPUMBState *env) 289 { 290 struct target_rt_sigframe *frame = NULL; 291 abi_ulong frame_addr = env->regs[1]; 292 sigset_t set; 293 294 trace_user_do_rt_sigreturn(env, frame_addr); 295 296 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 297 goto badframe; 298 } 299 300 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 301 set_sigmask(&set); 302 303 restore_sigcontext(&frame->uc.tuc_mcontext, env); 304 305 if (do_sigaltstack(frame_addr + 306 offsetof(struct target_rt_sigframe, uc.tuc_stack), 307 0, get_sp_from_cpustate(env)) == -EFAULT) { 308 goto badframe; 309 } 310 311 unlock_user_struct(frame, frame_addr, 0); 312 return -TARGET_QEMU_ESIGRETURN; 313 314 badframe: 315 unlock_user_struct(frame, frame_addr, 0); 316 force_sig(TARGET_SIGSEGV); 317 return -TARGET_QEMU_ESIGRETURN; 318 } 319