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 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; 59 60 sp = target_sigsp(get_sp_from_cpustate(env), sa); 61 62 return (sp - framesize) & -16; 63 } 64 65 static int flush_window_regs(CPUXtensaState *env) 66 { 67 uint32_t wb = env->sregs[WINDOW_BASE]; 68 uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1); 69 unsigned d = ctz32(ws) + 1; 70 unsigned i; 71 int ret = 0; 72 73 for (i = d; i < env->config->nareg / 4; i += d) { 74 uint32_t ssp, osp; 75 unsigned j; 76 77 ws >>= d; 78 xtensa_rotate_window(env, d); 79 80 if (ws & 0x1) { 81 ssp = env->regs[5]; 82 d = 1; 83 } else if (ws & 0x2) { 84 ssp = env->regs[9]; 85 ret |= get_user_ual(osp, env->regs[1] - 12); 86 osp -= 32; 87 d = 2; 88 } else if (ws & 0x4) { 89 ssp = env->regs[13]; 90 ret |= get_user_ual(osp, env->regs[1] - 12); 91 osp -= 48; 92 d = 3; 93 } else { 94 g_assert_not_reached(); 95 } 96 97 for (j = 0; j < 4; ++j) { 98 ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4); 99 } 100 for (j = 4; j < d * 4; ++j) { 101 ret |= put_user_ual(env->regs[j], osp - 16 + j * 4); 102 } 103 } 104 xtensa_rotate_window(env, d); 105 g_assert(env->sregs[WINDOW_BASE] == wb); 106 return ret == 0; 107 } 108 109 static int setup_sigcontext(struct target_rt_sigframe *frame, 110 CPUXtensaState *env) 111 { 112 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 113 int i; 114 115 __put_user(env->pc, &sc->sc_pc); 116 __put_user(env->sregs[PS], &sc->sc_ps); 117 __put_user(env->sregs[LBEG], &sc->sc_lbeg); 118 __put_user(env->sregs[LEND], &sc->sc_lend); 119 __put_user(env->sregs[LCOUNT], &sc->sc_lcount); 120 if (!flush_window_regs(env)) { 121 return 0; 122 } 123 for (i = 0; i < 16; ++i) { 124 __put_user(env->regs[i], sc->sc_a + i); 125 } 126 __put_user(0, &sc->sc_xtregs); 127 /* TODO: xtregs */ 128 return 1; 129 } 130 131 static void install_sigtramp(uint8_t *tramp) 132 { 133 #ifdef TARGET_WORDS_BIGENDIAN 134 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 135 __put_user(0x22, &tramp[0]); 136 __put_user(0x0a, &tramp[1]); 137 __put_user(TARGET_NR_rt_sigreturn, &tramp[2]); 138 /* Generate instruction: SYSCALL */ 139 __put_user(0x00, &tramp[3]); 140 __put_user(0x05, &tramp[4]); 141 __put_user(0x00, &tramp[5]); 142 #else 143 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 144 __put_user(0x22, &tramp[0]); 145 __put_user(0xa0, &tramp[1]); 146 __put_user(TARGET_NR_rt_sigreturn, &tramp[2]); 147 /* Generate instruction: SYSCALL */ 148 __put_user(0x00, &tramp[3]); 149 __put_user(0x50, &tramp[4]); 150 __put_user(0x00, &tramp[5]); 151 #endif 152 } 153 154 void setup_rt_frame(int sig, struct target_sigaction *ka, 155 target_siginfo_t *info, 156 target_sigset_t *set, CPUXtensaState *env) 157 { 158 abi_ulong frame_addr; 159 struct target_rt_sigframe *frame; 160 uint32_t ra; 161 bool abi_call0; 162 unsigned base; 163 int i; 164 165 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 166 trace_user_setup_rt_frame(env, frame_addr); 167 168 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 169 goto give_sigsegv; 170 } 171 172 if (ka->sa_flags & SA_SIGINFO) { 173 tswap_siginfo(&frame->info, info); 174 } 175 176 __put_user(0, &frame->uc.tuc_flags); 177 __put_user(0, &frame->uc.tuc_link); 178 target_save_altstack(&frame->uc.tuc_stack, env); 179 if (!setup_sigcontext(frame, env)) { 180 unlock_user_struct(frame, frame_addr, 0); 181 goto give_sigsegv; 182 } 183 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 184 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 185 } 186 187 if (ka->sa_flags & TARGET_SA_RESTORER) { 188 ra = ka->sa_restorer; 189 } else { 190 /* Not used, but retain for ABI compatibility. */ 191 install_sigtramp(frame->retcode); 192 ra = default_rt_sigreturn; 193 } 194 memset(env->regs, 0, sizeof(env->regs)); 195 env->pc = ka->_sa_handler; 196 env->regs[1] = frame_addr; 197 env->sregs[WINDOW_BASE] = 0; 198 env->sregs[WINDOW_START] = 1; 199 200 abi_call0 = (env->sregs[PS] & PS_WOE) == 0; 201 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 202 203 if (abi_call0) { 204 base = 0; 205 env->regs[base] = ra; 206 } else { 207 env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); 208 base = 4; 209 env->regs[base] = (ra & 0x3fffffff) | 0x40000000; 210 } 211 env->regs[base + 2] = sig; 212 env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, 213 info); 214 env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc); 215 unlock_user_struct(frame, frame_addr, 1); 216 return; 217 218 give_sigsegv: 219 force_sigsegv(sig); 220 return; 221 } 222 223 static void restore_sigcontext(CPUXtensaState *env, 224 struct target_rt_sigframe *frame) 225 { 226 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 227 uint32_t ps; 228 int i; 229 230 __get_user(env->pc, &sc->sc_pc); 231 __get_user(ps, &sc->sc_ps); 232 __get_user(env->sregs[LBEG], &sc->sc_lbeg); 233 __get_user(env->sregs[LEND], &sc->sc_lend); 234 __get_user(env->sregs[LCOUNT], &sc->sc_lcount); 235 236 env->sregs[WINDOW_BASE] = 0; 237 env->sregs[WINDOW_START] = 1; 238 env->sregs[PS] = deposit32(env->sregs[PS], 239 PS_CALLINC_SHIFT, 240 PS_CALLINC_LEN, 241 extract32(ps, PS_CALLINC_SHIFT, 242 PS_CALLINC_LEN)); 243 for (i = 0; i < 16; ++i) { 244 __get_user(env->regs[i], sc->sc_a + i); 245 } 246 /* TODO: xtregs */ 247 } 248 249 long do_rt_sigreturn(CPUXtensaState *env) 250 { 251 abi_ulong frame_addr = env->regs[1]; 252 struct target_rt_sigframe *frame; 253 sigset_t set; 254 255 trace_user_do_rt_sigreturn(env, frame_addr); 256 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 257 goto badframe; 258 } 259 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 260 set_sigmask(&set); 261 262 restore_sigcontext(env, frame); 263 target_restore_altstack(&frame->uc.tuc_stack, env); 264 265 unlock_user_struct(frame, frame_addr, 0); 266 return -TARGET_QEMU_ESIGRETURN; 267 268 badframe: 269 unlock_user_struct(frame, frame_addr, 0); 270 force_sig(TARGET_SIGSEGV); 271 return -TARGET_QEMU_ESIGRETURN; 272 } 273 274 void setup_sigtramp(abi_ulong sigtramp_page) 275 { 276 uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0); 277 assert(tramp != NULL); 278 279 default_rt_sigreturn = sigtramp_page; 280 install_sigtramp(tramp); 281 unlock_user(tramp, sigtramp_page, 6); 282 } 283