signal.c (7372B)
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 25struct target_sigcontext { 26 struct target_pt_regs regs; /* needs to be first */ 27 uint32_t oldmask; 28}; 29 30struct target_stack_t { 31 abi_ulong ss_sp; 32 int ss_flags; 33 unsigned int ss_size; 34}; 35 36struct 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. */ 45struct target_rt_sigframe { 46 target_siginfo_t info; 47 struct target_ucontext uc; 48 uint32_t tramp[2]; 49}; 50 51static 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 88static 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 125static 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 135void 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 /* 165 * Return from sighandler will jump to the tramp. 166 * Negative 8 offset because return is rtsd r15, 8 167 */ 168 env->regs[15] = default_rt_sigreturn - 8; 169 170 /* Set up registers for signal handler */ 171 env->regs[1] = frame_addr; 172 173 /* Signal handler args: */ 174 env->regs[5] = sig; 175 env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info); 176 env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc); 177 178 /* Offset to handle microblaze rtid r14, 0 */ 179 env->pc = (unsigned long)ka->_sa_handler; 180 181 unlock_user_struct(frame, frame_addr, 1); 182} 183 184 185long do_sigreturn(CPUMBState *env) 186{ 187 return -TARGET_ENOSYS; 188} 189 190long do_rt_sigreturn(CPUMBState *env) 191{ 192 struct target_rt_sigframe *frame = NULL; 193 abi_ulong frame_addr = env->regs[1]; 194 sigset_t set; 195 196 trace_user_do_rt_sigreturn(env, frame_addr); 197 198 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 199 goto badframe; 200 } 201 202 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 203 set_sigmask(&set); 204 205 restore_sigcontext(&frame->uc.tuc_mcontext, env); 206 207 target_restore_altstack(&frame->uc.tuc_stack, env); 208 209 unlock_user_struct(frame, frame_addr, 0); 210 return -TARGET_QEMU_ESIGRETURN; 211 212 badframe: 213 unlock_user_struct(frame, frame_addr, 0); 214 force_sig(TARGET_SIGSEGV); 215 return -TARGET_QEMU_ESIGRETURN; 216} 217 218void setup_sigtramp(abi_ulong sigtramp_page) 219{ 220 uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); 221 assert(tramp != NULL); 222 223 /* 224 * addi r12, r0, __NR_rt_sigreturn 225 * brki r14, 0x8 226 */ 227 __put_user(0x31800000U | TARGET_NR_rt_sigreturn, tramp); 228 __put_user(0xb9cc0008U, tramp + 1); 229 230 default_rt_sigreturn = sigtramp_page; 231 unlock_user(tramp, sigtramp_page, 8); 232}