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 struct target_stack_t tuc_stack; 39 struct target_sigcontext tuc_mcontext; 40 uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1]; 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 rt_signal_frame { 51 siginfo_t info; 52 ucontext_t 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->sregs[SR_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->sregs[SR_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->sregs[SR_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 qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n"); 204 } 205 206 long do_sigreturn(CPUMBState *env) 207 { 208 struct target_signal_frame *frame; 209 abi_ulong frame_addr; 210 target_sigset_t target_set; 211 sigset_t set; 212 int i; 213 214 frame_addr = env->regs[R_SP]; 215 trace_user_do_sigreturn(env, frame_addr); 216 /* Make sure the guest isn't playing games. */ 217 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) 218 goto badframe; 219 220 /* Restore blocked signals */ 221 __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask); 222 for(i = 1; i < TARGET_NSIG_WORDS; i++) { 223 __get_user(target_set.sig[i], &frame->extramask[i - 1]); 224 } 225 target_to_host_sigset_internal(&set, &target_set); 226 set_sigmask(&set); 227 228 restore_sigcontext(&frame->uc.tuc_mcontext, env); 229 /* We got here through a sigreturn syscall, our path back is via an 230 rtb insn so setup r14 for that. */ 231 env->regs[14] = env->sregs[SR_PC]; 232 233 unlock_user_struct(frame, frame_addr, 0); 234 return -TARGET_QEMU_ESIGRETURN; 235 badframe: 236 force_sig(TARGET_SIGSEGV); 237 return -TARGET_QEMU_ESIGRETURN; 238 } 239 240 long do_rt_sigreturn(CPUMBState *env) 241 { 242 trace_user_do_rt_sigreturn(env, 0); 243 qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n"); 244 return -TARGET_ENOSYS; 245 } 246