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