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 abi_ulong sc_pc; 27 abi_ulong sc_ps; 28 abi_ulong sc_lbeg; 29 abi_ulong sc_lend; 30 abi_ulong sc_lcount; 31 abi_ulong sc_sar; 32 abi_ulong sc_acclo; 33 abi_ulong sc_acchi; 34 abi_ulong sc_a[16]; 35 abi_ulong sc_xtregs; 36 }; 37 38 struct target_ucontext { 39 abi_ulong tuc_flags; 40 abi_ulong tuc_link; 41 target_stack_t tuc_stack; 42 struct target_sigcontext tuc_mcontext; 43 target_sigset_t tuc_sigmask; 44 }; 45 46 struct target_rt_sigframe { 47 target_siginfo_t info; 48 struct target_ucontext uc; 49 /* TODO: xtregs */ 50 uint8_t retcode[6]; 51 abi_ulong window[4]; 52 }; 53 54 static abi_ulong get_sigframe(struct target_sigaction *sa, 55 CPUXtensaState *env, 56 unsigned long framesize) 57 { 58 abi_ulong sp = env->regs[1]; 59 60 /* This is the X/Open sanctioned signal stack switching. */ 61 if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { 62 sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; 63 } 64 return (sp - framesize) & -16; 65 } 66 67 static int flush_window_regs(CPUXtensaState *env) 68 { 69 uint32_t wb = env->sregs[WINDOW_BASE]; 70 uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1); 71 unsigned d = ctz32(ws) + 1; 72 unsigned i; 73 int ret = 0; 74 75 for (i = d; i < env->config->nareg / 4; i += d) { 76 uint32_t ssp, osp; 77 unsigned j; 78 79 ws >>= d; 80 xtensa_rotate_window(env, d); 81 82 if (ws & 0x1) { 83 ssp = env->regs[5]; 84 d = 1; 85 } else if (ws & 0x2) { 86 ssp = env->regs[9]; 87 ret |= get_user_ual(osp, env->regs[1] - 12); 88 osp -= 32; 89 d = 2; 90 } else if (ws & 0x4) { 91 ssp = env->regs[13]; 92 ret |= get_user_ual(osp, env->regs[1] - 12); 93 osp -= 48; 94 d = 3; 95 } else { 96 g_assert_not_reached(); 97 } 98 99 for (j = 0; j < 4; ++j) { 100 ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4); 101 } 102 for (j = 4; j < d * 4; ++j) { 103 ret |= put_user_ual(env->regs[j], osp - 16 + j * 4); 104 } 105 } 106 xtensa_rotate_window(env, d); 107 g_assert(env->sregs[WINDOW_BASE] == wb); 108 return ret == 0; 109 } 110 111 static int setup_sigcontext(struct target_rt_sigframe *frame, 112 CPUXtensaState *env) 113 { 114 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 115 int i; 116 117 __put_user(env->pc, &sc->sc_pc); 118 __put_user(env->sregs[PS], &sc->sc_ps); 119 __put_user(env->sregs[LBEG], &sc->sc_lbeg); 120 __put_user(env->sregs[LEND], &sc->sc_lend); 121 __put_user(env->sregs[LCOUNT], &sc->sc_lcount); 122 if (!flush_window_regs(env)) { 123 return 0; 124 } 125 for (i = 0; i < 16; ++i) { 126 __put_user(env->regs[i], sc->sc_a + i); 127 } 128 __put_user(0, &sc->sc_xtregs); 129 /* TODO: xtregs */ 130 return 1; 131 } 132 133 void setup_rt_frame(int sig, struct target_sigaction *ka, 134 target_siginfo_t *info, 135 target_sigset_t *set, CPUXtensaState *env) 136 { 137 abi_ulong frame_addr; 138 struct target_rt_sigframe *frame; 139 uint32_t ra; 140 int i; 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 goto give_sigsegv; 147 } 148 149 if (ka->sa_flags & SA_SIGINFO) { 150 tswap_siginfo(&frame->info, info); 151 } 152 153 __put_user(0, &frame->uc.tuc_flags); 154 __put_user(0, &frame->uc.tuc_link); 155 __put_user(target_sigaltstack_used.ss_sp, 156 &frame->uc.tuc_stack.ss_sp); 157 __put_user(sas_ss_flags(env->regs[1]), 158 &frame->uc.tuc_stack.ss_flags); 159 __put_user(target_sigaltstack_used.ss_size, 160 &frame->uc.tuc_stack.ss_size); 161 if (!setup_sigcontext(frame, env)) { 162 unlock_user_struct(frame, frame_addr, 0); 163 goto give_sigsegv; 164 } 165 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 166 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 167 } 168 169 if (ka->sa_flags & TARGET_SA_RESTORER) { 170 ra = ka->sa_restorer; 171 } else { 172 ra = frame_addr + offsetof(struct target_rt_sigframe, retcode); 173 #ifdef TARGET_WORDS_BIGENDIAN 174 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 175 __put_user(0x22, &frame->retcode[0]); 176 __put_user(0x0a, &frame->retcode[1]); 177 __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]); 178 /* Generate instruction: SYSCALL */ 179 __put_user(0x00, &frame->retcode[3]); 180 __put_user(0x05, &frame->retcode[4]); 181 __put_user(0x00, &frame->retcode[5]); 182 #else 183 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 184 __put_user(0x22, &frame->retcode[0]); 185 __put_user(0xa0, &frame->retcode[1]); 186 __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]); 187 /* Generate instruction: SYSCALL */ 188 __put_user(0x00, &frame->retcode[3]); 189 __put_user(0x50, &frame->retcode[4]); 190 __put_user(0x00, &frame->retcode[5]); 191 #endif 192 } 193 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 194 if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER)) { 195 env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); 196 } 197 memset(env->regs, 0, sizeof(env->regs)); 198 env->pc = ka->_sa_handler; 199 env->regs[1] = frame_addr; 200 env->sregs[WINDOW_BASE] = 0; 201 env->sregs[WINDOW_START] = 1; 202 203 env->regs[4] = (ra & 0x3fffffff) | 0x40000000; 204 env->regs[6] = sig; 205 env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info); 206 env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc); 207 unlock_user_struct(frame, frame_addr, 1); 208 return; 209 210 give_sigsegv: 211 force_sigsegv(sig); 212 return; 213 } 214 215 static void restore_sigcontext(CPUXtensaState *env, 216 struct target_rt_sigframe *frame) 217 { 218 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 219 uint32_t ps; 220 int i; 221 222 __get_user(env->pc, &sc->sc_pc); 223 __get_user(ps, &sc->sc_ps); 224 __get_user(env->sregs[LBEG], &sc->sc_lbeg); 225 __get_user(env->sregs[LEND], &sc->sc_lend); 226 __get_user(env->sregs[LCOUNT], &sc->sc_lcount); 227 228 env->sregs[WINDOW_BASE] = 0; 229 env->sregs[WINDOW_START] = 1; 230 env->sregs[PS] = deposit32(env->sregs[PS], 231 PS_CALLINC_SHIFT, 232 PS_CALLINC_LEN, 233 extract32(ps, PS_CALLINC_SHIFT, 234 PS_CALLINC_LEN)); 235 for (i = 0; i < 16; ++i) { 236 __get_user(env->regs[i], sc->sc_a + i); 237 } 238 /* TODO: xtregs */ 239 } 240 241 long do_rt_sigreturn(CPUXtensaState *env) 242 { 243 abi_ulong frame_addr = env->regs[1]; 244 struct target_rt_sigframe *frame; 245 sigset_t set; 246 247 trace_user_do_rt_sigreturn(env, frame_addr); 248 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 249 goto badframe; 250 } 251 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 252 set_sigmask(&set); 253 254 restore_sigcontext(env, frame); 255 256 if (do_sigaltstack(frame_addr + 257 offsetof(struct target_rt_sigframe, uc.tuc_stack), 258 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) { 259 goto badframe; 260 } 261 unlock_user_struct(frame, frame_addr, 0); 262 return -TARGET_QEMU_ESIGRETURN; 263 264 badframe: 265 unlock_user_struct(frame, frame_addr, 0); 266 force_sig(TARGET_SIGSEGV); 267 return -TARGET_QEMU_ESIGRETURN; 268 } 269