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