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 #if TARGET_BIG_ENDIAN 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 int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info); 161 abi_ulong handler = 0; 162 abi_ulong handler_fdpic_GOT = 0; 163 uint32_t ra; 164 bool abi_call0; 165 unsigned base; 166 int i; 167 168 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 169 trace_user_setup_rt_frame(env, frame_addr); 170 171 if (is_fdpic) { 172 abi_ulong funcdesc_ptr = ka->_sa_handler; 173 174 if (get_user_ual(handler, funcdesc_ptr) 175 || get_user_ual(handler_fdpic_GOT, funcdesc_ptr + 4)) { 176 goto give_sigsegv; 177 } 178 } else { 179 handler = ka->_sa_handler; 180 } 181 182 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 183 goto give_sigsegv; 184 } 185 186 if (ka->sa_flags & SA_SIGINFO) { 187 tswap_siginfo(&frame->info, info); 188 } 189 190 __put_user(0, &frame->uc.tuc_flags); 191 __put_user(0, &frame->uc.tuc_link); 192 target_save_altstack(&frame->uc.tuc_stack, env); 193 if (!setup_sigcontext(frame, env)) { 194 unlock_user_struct(frame, frame_addr, 0); 195 goto give_sigsegv; 196 } 197 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 198 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 199 } 200 201 if (ka->sa_flags & TARGET_SA_RESTORER) { 202 if (is_fdpic) { 203 if (get_user_ual(ra, ka->sa_restorer)) { 204 unlock_user_struct(frame, frame_addr, 0); 205 goto give_sigsegv; 206 } 207 } else { 208 ra = ka->sa_restorer; 209 } 210 } else { 211 /* Not used, but retain for ABI compatibility. */ 212 install_sigtramp(frame->retcode); 213 ra = default_rt_sigreturn; 214 } 215 memset(env->regs, 0, sizeof(env->regs)); 216 env->pc = handler; 217 env->regs[1] = frame_addr; 218 env->sregs[WINDOW_BASE] = 0; 219 env->sregs[WINDOW_START] = 1; 220 221 abi_call0 = (env->sregs[PS] & PS_WOE) == 0; 222 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 223 224 if (abi_call0) { 225 base = 0; 226 env->regs[base] = ra; 227 } else { 228 env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); 229 base = 4; 230 env->regs[base] = (ra & 0x3fffffff) | 0x40000000; 231 } 232 env->regs[base + 2] = sig; 233 env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, 234 info); 235 env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc); 236 if (is_fdpic) { 237 env->regs[base + 11] = handler_fdpic_GOT; 238 } 239 unlock_user_struct(frame, frame_addr, 1); 240 return; 241 242 give_sigsegv: 243 force_sigsegv(sig); 244 return; 245 } 246 247 static void restore_sigcontext(CPUXtensaState *env, 248 struct target_rt_sigframe *frame) 249 { 250 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 251 uint32_t ps; 252 int i; 253 254 __get_user(env->pc, &sc->sc_pc); 255 __get_user(ps, &sc->sc_ps); 256 __get_user(env->sregs[LBEG], &sc->sc_lbeg); 257 __get_user(env->sregs[LEND], &sc->sc_lend); 258 __get_user(env->sregs[LCOUNT], &sc->sc_lcount); 259 260 env->sregs[WINDOW_BASE] = 0; 261 env->sregs[WINDOW_START] = 1; 262 env->sregs[PS] = deposit32(env->sregs[PS], 263 PS_CALLINC_SHIFT, 264 PS_CALLINC_LEN, 265 extract32(ps, PS_CALLINC_SHIFT, 266 PS_CALLINC_LEN)); 267 for (i = 0; i < 16; ++i) { 268 __get_user(env->regs[i], sc->sc_a + i); 269 } 270 /* TODO: xtregs */ 271 } 272 273 long do_rt_sigreturn(CPUXtensaState *env) 274 { 275 abi_ulong frame_addr = env->regs[1]; 276 struct target_rt_sigframe *frame; 277 sigset_t set; 278 279 trace_user_do_rt_sigreturn(env, frame_addr); 280 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 281 goto badframe; 282 } 283 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 284 set_sigmask(&set); 285 286 restore_sigcontext(env, frame); 287 target_restore_altstack(&frame->uc.tuc_stack, env); 288 289 unlock_user_struct(frame, frame_addr, 0); 290 return -QEMU_ESIGRETURN; 291 292 badframe: 293 unlock_user_struct(frame, frame_addr, 0); 294 force_sig(TARGET_SIGSEGV); 295 return -QEMU_ESIGRETURN; 296 } 297 298 void setup_sigtramp(abi_ulong sigtramp_page) 299 { 300 uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0); 301 assert(tramp != NULL); 302 303 default_rt_sigreturn = sigtramp_page; 304 install_sigtramp(tramp); 305 unlock_user(tramp, sigtramp_page, 6); 306 } 307