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