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 abi_long sc_onstack; 26 abi_long sc_mask; 27 abi_long sc_pc; 28 abi_long sc_ps; 29 abi_long sc_regs[32]; 30 abi_long sc_ownedfp; 31 abi_long sc_fpregs[32]; 32 abi_ulong sc_fpcr; 33 abi_ulong sc_fp_control; 34 abi_ulong sc_reserved1; 35 abi_ulong sc_reserved2; 36 abi_ulong sc_ssize; 37 abi_ulong sc_sbase; 38 abi_ulong sc_traparg_a0; 39 abi_ulong sc_traparg_a1; 40 abi_ulong sc_traparg_a2; 41 abi_ulong sc_fp_trap_pc; 42 abi_ulong sc_fp_trigger_sum; 43 abi_ulong sc_fp_trigger_inst; 44 }; 45 46 struct target_ucontext { 47 abi_ulong tuc_flags; 48 abi_ulong tuc_link; 49 abi_ulong tuc_osf_sigmask; 50 target_stack_t tuc_stack; 51 struct target_sigcontext tuc_mcontext; 52 target_sigset_t tuc_sigmask; 53 }; 54 55 struct target_sigframe { 56 struct target_sigcontext sc; 57 unsigned int retcode[3]; 58 }; 59 60 struct target_rt_sigframe { 61 target_siginfo_t info; 62 struct target_ucontext uc; 63 unsigned int retcode[3]; 64 }; 65 66 #define INSN_MOV_R30_R16 0x47fe0410 67 #define INSN_LDI_R0 0x201f0000 68 #define INSN_CALLSYS 0x00000083 69 70 static void setup_sigcontext(struct target_sigcontext *sc, CPUAlphaState *env, 71 abi_ulong frame_addr, target_sigset_t *set) 72 { 73 int i; 74 75 __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); 76 __put_user(set->sig[0], &sc->sc_mask); 77 __put_user(env->pc, &sc->sc_pc); 78 __put_user(8, &sc->sc_ps); 79 80 for (i = 0; i < 31; ++i) { 81 __put_user(env->ir[i], &sc->sc_regs[i]); 82 } 83 __put_user(0, &sc->sc_regs[31]); 84 85 for (i = 0; i < 31; ++i) { 86 __put_user(env->fir[i], &sc->sc_fpregs[i]); 87 } 88 __put_user(0, &sc->sc_fpregs[31]); 89 __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); 90 91 __put_user(0, &sc->sc_traparg_a0); /* FIXME */ 92 __put_user(0, &sc->sc_traparg_a1); /* FIXME */ 93 __put_user(0, &sc->sc_traparg_a2); /* FIXME */ 94 } 95 96 static void restore_sigcontext(CPUAlphaState *env, 97 struct target_sigcontext *sc) 98 { 99 uint64_t fpcr; 100 int i; 101 102 __get_user(env->pc, &sc->sc_pc); 103 104 for (i = 0; i < 31; ++i) { 105 __get_user(env->ir[i], &sc->sc_regs[i]); 106 } 107 for (i = 0; i < 31; ++i) { 108 __get_user(env->fir[i], &sc->sc_fpregs[i]); 109 } 110 111 __get_user(fpcr, &sc->sc_fpcr); 112 cpu_alpha_store_fpcr(env, fpcr); 113 } 114 115 static inline abi_ulong get_sigframe(struct target_sigaction *sa, 116 CPUAlphaState *env, 117 unsigned long framesize) 118 { 119 abi_ulong sp; 120 121 sp = target_sigsp(get_sp_from_cpustate(env), sa); 122 123 return (sp - framesize) & -32; 124 } 125 126 void setup_frame(int sig, struct target_sigaction *ka, 127 target_sigset_t *set, CPUAlphaState *env) 128 { 129 abi_ulong frame_addr, r26; 130 struct target_sigframe *frame; 131 int err = 0; 132 133 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 134 trace_user_setup_frame(env, frame_addr); 135 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 136 goto give_sigsegv; 137 } 138 139 setup_sigcontext(&frame->sc, env, frame_addr, set); 140 141 if (ka->sa_restorer) { 142 r26 = ka->sa_restorer; 143 } else { 144 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); 145 __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, 146 &frame->retcode[1]); 147 __put_user(INSN_CALLSYS, &frame->retcode[2]); 148 /* imb() */ 149 r26 = frame_addr + offsetof(struct target_sigframe, retcode); 150 } 151 152 unlock_user_struct(frame, frame_addr, 1); 153 154 if (err) { 155 give_sigsegv: 156 force_sigsegv(sig); 157 return; 158 } 159 160 env->ir[IR_RA] = r26; 161 env->ir[IR_PV] = env->pc = ka->_sa_handler; 162 env->ir[IR_A0] = sig; 163 env->ir[IR_A1] = 0; 164 env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); 165 env->ir[IR_SP] = frame_addr; 166 } 167 168 void setup_rt_frame(int sig, struct target_sigaction *ka, 169 target_siginfo_t *info, 170 target_sigset_t *set, CPUAlphaState *env) 171 { 172 abi_ulong frame_addr, r26; 173 struct target_rt_sigframe *frame; 174 int i, err = 0; 175 176 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 177 trace_user_setup_rt_frame(env, frame_addr); 178 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 179 goto give_sigsegv; 180 } 181 182 tswap_siginfo(&frame->info, info); 183 184 __put_user(0, &frame->uc.tuc_flags); 185 __put_user(0, &frame->uc.tuc_link); 186 __put_user(set->sig[0], &frame->uc.tuc_osf_sigmask); 187 188 target_save_altstack(&frame->uc.tuc_stack, env); 189 190 setup_sigcontext(&frame->uc.tuc_mcontext, env, frame_addr, set); 191 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 192 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 193 } 194 195 if (ka->sa_restorer) { 196 r26 = ka->sa_restorer; 197 } else { 198 __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); 199 __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, 200 &frame->retcode[1]); 201 __put_user(INSN_CALLSYS, &frame->retcode[2]); 202 /* imb(); */ 203 r26 = frame_addr + offsetof(struct target_sigframe, retcode); 204 } 205 206 if (err) { 207 give_sigsegv: 208 force_sigsegv(sig); 209 return; 210 } 211 212 env->ir[IR_RA] = r26; 213 env->ir[IR_PV] = env->pc = ka->_sa_handler; 214 env->ir[IR_A0] = sig; 215 env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); 216 env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); 217 env->ir[IR_SP] = frame_addr; 218 } 219 220 long do_sigreturn(CPUAlphaState *env) 221 { 222 struct target_sigcontext *sc; 223 abi_ulong sc_addr = env->ir[IR_A0]; 224 target_sigset_t target_set; 225 sigset_t set; 226 227 if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { 228 goto badframe; 229 } 230 231 target_sigemptyset(&target_set); 232 __get_user(target_set.sig[0], &sc->sc_mask); 233 234 target_to_host_sigset_internal(&set, &target_set); 235 set_sigmask(&set); 236 237 restore_sigcontext(env, sc); 238 unlock_user_struct(sc, sc_addr, 0); 239 return -TARGET_QEMU_ESIGRETURN; 240 241 badframe: 242 force_sig(TARGET_SIGSEGV); 243 return -TARGET_QEMU_ESIGRETURN; 244 } 245 246 long do_rt_sigreturn(CPUAlphaState *env) 247 { 248 abi_ulong frame_addr = env->ir[IR_A0]; 249 struct target_rt_sigframe *frame; 250 sigset_t set; 251 252 trace_user_do_rt_sigreturn(env, frame_addr); 253 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 254 goto badframe; 255 } 256 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 257 set_sigmask(&set); 258 259 restore_sigcontext(env, &frame->uc.tuc_mcontext); 260 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, 261 uc.tuc_stack), 262 0, env->ir[IR_SP]) == -EFAULT) { 263 goto badframe; 264 } 265 266 unlock_user_struct(frame, frame_addr, 0); 267 return -TARGET_QEMU_ESIGRETURN; 268 269 270 badframe: 271 unlock_user_struct(frame, frame_addr, 0); 272 force_sig(TARGET_SIGSEGV); 273 return -TARGET_QEMU_ESIGRETURN; 274 } 275