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