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 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 target_stack_t tuc_stack; 40 struct target_sigcontext tuc_mcontext; 41 target_sigset_t tuc_sigmask; 42 }; 43 44 /* Signal frames. */ 45 struct target_rt_sigframe { 46 target_siginfo_t info; 47 struct target_ucontext uc; 48 uint32_t tramp[2]; 49 }; 50 51 static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 52 { 53 __put_user(env->regs[0], &sc->regs.r0); 54 __put_user(env->regs[1], &sc->regs.r1); 55 __put_user(env->regs[2], &sc->regs.r2); 56 __put_user(env->regs[3], &sc->regs.r3); 57 __put_user(env->regs[4], &sc->regs.r4); 58 __put_user(env->regs[5], &sc->regs.r5); 59 __put_user(env->regs[6], &sc->regs.r6); 60 __put_user(env->regs[7], &sc->regs.r7); 61 __put_user(env->regs[8], &sc->regs.r8); 62 __put_user(env->regs[9], &sc->regs.r9); 63 __put_user(env->regs[10], &sc->regs.r10); 64 __put_user(env->regs[11], &sc->regs.r11); 65 __put_user(env->regs[12], &sc->regs.r12); 66 __put_user(env->regs[13], &sc->regs.r13); 67 __put_user(env->regs[14], &sc->regs.r14); 68 __put_user(env->regs[15], &sc->regs.r15); 69 __put_user(env->regs[16], &sc->regs.r16); 70 __put_user(env->regs[17], &sc->regs.r17); 71 __put_user(env->regs[18], &sc->regs.r18); 72 __put_user(env->regs[19], &sc->regs.r19); 73 __put_user(env->regs[20], &sc->regs.r20); 74 __put_user(env->regs[21], &sc->regs.r21); 75 __put_user(env->regs[22], &sc->regs.r22); 76 __put_user(env->regs[23], &sc->regs.r23); 77 __put_user(env->regs[24], &sc->regs.r24); 78 __put_user(env->regs[25], &sc->regs.r25); 79 __put_user(env->regs[26], &sc->regs.r26); 80 __put_user(env->regs[27], &sc->regs.r27); 81 __put_user(env->regs[28], &sc->regs.r28); 82 __put_user(env->regs[29], &sc->regs.r29); 83 __put_user(env->regs[30], &sc->regs.r30); 84 __put_user(env->regs[31], &sc->regs.r31); 85 __put_user(env->pc, &sc->regs.pc); 86 } 87 88 static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 89 { 90 __get_user(env->regs[0], &sc->regs.r0); 91 __get_user(env->regs[1], &sc->regs.r1); 92 __get_user(env->regs[2], &sc->regs.r2); 93 __get_user(env->regs[3], &sc->regs.r3); 94 __get_user(env->regs[4], &sc->regs.r4); 95 __get_user(env->regs[5], &sc->regs.r5); 96 __get_user(env->regs[6], &sc->regs.r6); 97 __get_user(env->regs[7], &sc->regs.r7); 98 __get_user(env->regs[8], &sc->regs.r8); 99 __get_user(env->regs[9], &sc->regs.r9); 100 __get_user(env->regs[10], &sc->regs.r10); 101 __get_user(env->regs[11], &sc->regs.r11); 102 __get_user(env->regs[12], &sc->regs.r12); 103 __get_user(env->regs[13], &sc->regs.r13); 104 __get_user(env->regs[14], &sc->regs.r14); 105 __get_user(env->regs[15], &sc->regs.r15); 106 __get_user(env->regs[16], &sc->regs.r16); 107 __get_user(env->regs[17], &sc->regs.r17); 108 __get_user(env->regs[18], &sc->regs.r18); 109 __get_user(env->regs[19], &sc->regs.r19); 110 __get_user(env->regs[20], &sc->regs.r20); 111 __get_user(env->regs[21], &sc->regs.r21); 112 __get_user(env->regs[22], &sc->regs.r22); 113 __get_user(env->regs[23], &sc->regs.r23); 114 __get_user(env->regs[24], &sc->regs.r24); 115 __get_user(env->regs[25], &sc->regs.r25); 116 __get_user(env->regs[26], &sc->regs.r26); 117 __get_user(env->regs[27], &sc->regs.r27); 118 __get_user(env->regs[28], &sc->regs.r28); 119 __get_user(env->regs[29], &sc->regs.r29); 120 __get_user(env->regs[30], &sc->regs.r30); 121 __get_user(env->regs[31], &sc->regs.r31); 122 __get_user(env->pc, &sc->regs.pc); 123 } 124 125 static abi_ulong get_sigframe(struct target_sigaction *ka, 126 CPUMBState *env, int frame_size) 127 { 128 abi_ulong sp = env->regs[1]; 129 130 sp = target_sigsp(sp, ka); 131 132 return ((sp - frame_size) & -8UL); 133 } 134 135 void setup_rt_frame(int sig, struct target_sigaction *ka, 136 target_siginfo_t *info, 137 target_sigset_t *set, CPUMBState *env) 138 { 139 struct target_rt_sigframe *frame; 140 abi_ulong frame_addr; 141 142 frame_addr = get_sigframe(ka, env, sizeof *frame); 143 trace_user_setup_rt_frame(env, frame_addr); 144 145 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 146 force_sigsegv(sig); 147 return; 148 } 149 150 tswap_siginfo(&frame->info, info); 151 152 __put_user(0, &frame->uc.tuc_flags); 153 __put_user(0, &frame->uc.tuc_link); 154 155 target_save_altstack(&frame->uc.tuc_stack, env); 156 setup_sigcontext(&frame->uc.tuc_mcontext, env); 157 158 for (int i = 0; i < TARGET_NSIG_WORDS; i++) { 159 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 160 } 161 162 /* Kernel does not use SA_RESTORER. */ 163 164 /* addi r12, r0, __NR_sigreturn */ 165 __put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0); 166 /* brki r14, 0x8 */ 167 __put_user(0xb9cc0008U, frame->tramp + 1); 168 169 /* 170 * Return from sighandler will jump to the tramp. 171 * Negative 8 offset because return is rtsd r15, 8 172 */ 173 env->regs[15] = 174 frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8; 175 176 /* Set up registers for signal handler */ 177 env->regs[1] = frame_addr; 178 179 /* Signal handler args: */ 180 env->regs[5] = sig; 181 env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info); 182 env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc); 183 184 /* Offset to handle microblaze rtid r14, 0 */ 185 env->pc = (unsigned long)ka->_sa_handler; 186 187 unlock_user_struct(frame, frame_addr, 1); 188 } 189 190 191 long do_sigreturn(CPUMBState *env) 192 { 193 return -TARGET_ENOSYS; 194 } 195 196 long do_rt_sigreturn(CPUMBState *env) 197 { 198 struct target_rt_sigframe *frame = NULL; 199 abi_ulong frame_addr = env->regs[1]; 200 sigset_t set; 201 202 trace_user_do_rt_sigreturn(env, frame_addr); 203 204 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 205 goto badframe; 206 } 207 208 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 209 set_sigmask(&set); 210 211 restore_sigcontext(&frame->uc.tuc_mcontext, env); 212 213 target_restore_altstack(&frame->uc.tuc_stack, env); 214 215 unlock_user_struct(frame, frame_addr, 0); 216 return -TARGET_QEMU_ESIGRETURN; 217 218 badframe: 219 unlock_user_struct(frame, frame_addr, 0); 220 force_sig(TARGET_SIGSEGV); 221 return -TARGET_QEMU_ESIGRETURN; 222 } 223