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 void setup_rt_frame(int sig, struct target_sigaction *ka, 132 target_siginfo_t *info, 133 target_sigset_t *set, CPUXtensaState *env) 134 { 135 abi_ulong frame_addr; 136 struct target_rt_sigframe *frame; 137 uint32_t ra; 138 bool abi_call0; 139 unsigned base; 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 target_save_altstack(&frame->uc.tuc_stack, env); 156 if (!setup_sigcontext(frame, env)) { 157 unlock_user_struct(frame, frame_addr, 0); 158 goto give_sigsegv; 159 } 160 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 161 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 162 } 163 164 if (ka->sa_flags & TARGET_SA_RESTORER) { 165 ra = ka->sa_restorer; 166 } else { 167 ra = frame_addr + offsetof(struct target_rt_sigframe, retcode); 168 #ifdef TARGET_WORDS_BIGENDIAN 169 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 170 __put_user(0x22, &frame->retcode[0]); 171 __put_user(0x0a, &frame->retcode[1]); 172 __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]); 173 /* Generate instruction: SYSCALL */ 174 __put_user(0x00, &frame->retcode[3]); 175 __put_user(0x05, &frame->retcode[4]); 176 __put_user(0x00, &frame->retcode[5]); 177 #else 178 /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 179 __put_user(0x22, &frame->retcode[0]); 180 __put_user(0xa0, &frame->retcode[1]); 181 __put_user(TARGET_NR_rt_sigreturn, &frame->retcode[2]); 182 /* Generate instruction: SYSCALL */ 183 __put_user(0x00, &frame->retcode[3]); 184 __put_user(0x50, &frame->retcode[4]); 185 __put_user(0x00, &frame->retcode[5]); 186 #endif 187 } 188 memset(env->regs, 0, sizeof(env->regs)); 189 env->pc = ka->_sa_handler; 190 env->regs[1] = frame_addr; 191 env->sregs[WINDOW_BASE] = 0; 192 env->sregs[WINDOW_START] = 1; 193 194 abi_call0 = (env->sregs[PS] & PS_WOE) == 0; 195 env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 196 197 if (abi_call0) { 198 base = 0; 199 env->regs[base] = ra; 200 } else { 201 env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); 202 base = 4; 203 env->regs[base] = (ra & 0x3fffffff) | 0x40000000; 204 } 205 env->regs[base + 2] = sig; 206 env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, 207 info); 208 env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc); 209 unlock_user_struct(frame, frame_addr, 1); 210 return; 211 212 give_sigsegv: 213 force_sigsegv(sig); 214 return; 215 } 216 217 static void restore_sigcontext(CPUXtensaState *env, 218 struct target_rt_sigframe *frame) 219 { 220 struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 221 uint32_t ps; 222 int i; 223 224 __get_user(env->pc, &sc->sc_pc); 225 __get_user(ps, &sc->sc_ps); 226 __get_user(env->sregs[LBEG], &sc->sc_lbeg); 227 __get_user(env->sregs[LEND], &sc->sc_lend); 228 __get_user(env->sregs[LCOUNT], &sc->sc_lcount); 229 230 env->sregs[WINDOW_BASE] = 0; 231 env->sregs[WINDOW_START] = 1; 232 env->sregs[PS] = deposit32(env->sregs[PS], 233 PS_CALLINC_SHIFT, 234 PS_CALLINC_LEN, 235 extract32(ps, PS_CALLINC_SHIFT, 236 PS_CALLINC_LEN)); 237 for (i = 0; i < 16; ++i) { 238 __get_user(env->regs[i], sc->sc_a + i); 239 } 240 /* TODO: xtregs */ 241 } 242 243 long do_rt_sigreturn(CPUXtensaState *env) 244 { 245 abi_ulong frame_addr = env->regs[1]; 246 struct target_rt_sigframe *frame; 247 sigset_t set; 248 249 trace_user_do_rt_sigreturn(env, frame_addr); 250 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 251 goto badframe; 252 } 253 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 254 set_sigmask(&set); 255 256 restore_sigcontext(env, frame); 257 target_restore_altstack(&frame->uc.tuc_stack, env); 258 259 unlock_user_struct(frame, frame_addr, 0); 260 return -TARGET_QEMU_ESIGRETURN; 261 262 badframe: 263 unlock_user_struct(frame, frame_addr, 0); 264 force_sig(TARGET_SIGSEGV); 265 return -TARGET_QEMU_ESIGRETURN; 266 } 267