1befb7447SLaurent Vivier /* 2befb7447SLaurent Vivier * Emulation of Linux signals 3befb7447SLaurent Vivier * 4befb7447SLaurent Vivier * Copyright (c) 2003 Fabrice Bellard 5befb7447SLaurent Vivier * 6befb7447SLaurent Vivier * This program is free software; you can redistribute it and/or modify 7befb7447SLaurent Vivier * it under the terms of the GNU General Public License as published by 8befb7447SLaurent Vivier * the Free Software Foundation; either version 2 of the License, or 9befb7447SLaurent Vivier * (at your option) any later version. 10befb7447SLaurent Vivier * 11befb7447SLaurent Vivier * This program is distributed in the hope that it will be useful, 12befb7447SLaurent Vivier * but WITHOUT ANY WARRANTY; without even the implied warranty of 13befb7447SLaurent Vivier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14befb7447SLaurent Vivier * GNU General Public License for more details. 15befb7447SLaurent Vivier * 16befb7447SLaurent Vivier * You should have received a copy of the GNU General Public License 17befb7447SLaurent Vivier * along with this program; if not, see <http://www.gnu.org/licenses/>. 18befb7447SLaurent Vivier */ 193612667cSLaurent Vivier #include "qemu/osdep.h" 203612667cSLaurent Vivier #include "qemu.h" 213b249d26SPeter Maydell #include "user-internals.h" 223612667cSLaurent Vivier #include "signal-common.h" 233612667cSLaurent Vivier #include "linux-user/trace.h" 243612667cSLaurent Vivier 253612667cSLaurent Vivier struct target_sigcontext { 263612667cSLaurent Vivier abi_ulong sc_pc; 273612667cSLaurent Vivier abi_ulong sc_ps; 283612667cSLaurent Vivier abi_ulong sc_lbeg; 293612667cSLaurent Vivier abi_ulong sc_lend; 303612667cSLaurent Vivier abi_ulong sc_lcount; 313612667cSLaurent Vivier abi_ulong sc_sar; 323612667cSLaurent Vivier abi_ulong sc_acclo; 333612667cSLaurent Vivier abi_ulong sc_acchi; 343612667cSLaurent Vivier abi_ulong sc_a[16]; 353612667cSLaurent Vivier abi_ulong sc_xtregs; 363612667cSLaurent Vivier }; 373612667cSLaurent Vivier 383612667cSLaurent Vivier struct target_ucontext { 393612667cSLaurent Vivier abi_ulong tuc_flags; 403612667cSLaurent Vivier abi_ulong tuc_link; 413612667cSLaurent Vivier target_stack_t tuc_stack; 423612667cSLaurent Vivier struct target_sigcontext tuc_mcontext; 433612667cSLaurent Vivier target_sigset_t tuc_sigmask; 443612667cSLaurent Vivier }; 453612667cSLaurent Vivier 463612667cSLaurent Vivier struct target_rt_sigframe { 473612667cSLaurent Vivier target_siginfo_t info; 483612667cSLaurent Vivier struct target_ucontext uc; 493612667cSLaurent Vivier /* TODO: xtregs */ 503612667cSLaurent Vivier uint8_t retcode[6]; 513612667cSLaurent Vivier abi_ulong window[4]; 523612667cSLaurent Vivier }; 533612667cSLaurent Vivier 543612667cSLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *sa, 553612667cSLaurent Vivier CPUXtensaState *env, 563612667cSLaurent Vivier unsigned long framesize) 573612667cSLaurent Vivier { 58465e237bSLaurent Vivier abi_ulong sp; 593612667cSLaurent Vivier 60465e237bSLaurent Vivier sp = target_sigsp(get_sp_from_cpustate(env), sa); 61465e237bSLaurent Vivier 623612667cSLaurent Vivier return (sp - framesize) & -16; 633612667cSLaurent Vivier } 643612667cSLaurent Vivier 653612667cSLaurent Vivier static int flush_window_regs(CPUXtensaState *env) 663612667cSLaurent Vivier { 673612667cSLaurent Vivier uint32_t wb = env->sregs[WINDOW_BASE]; 683612667cSLaurent Vivier uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1); 693612667cSLaurent Vivier unsigned d = ctz32(ws) + 1; 703612667cSLaurent Vivier unsigned i; 713612667cSLaurent Vivier int ret = 0; 723612667cSLaurent Vivier 733612667cSLaurent Vivier for (i = d; i < env->config->nareg / 4; i += d) { 743612667cSLaurent Vivier uint32_t ssp, osp; 753612667cSLaurent Vivier unsigned j; 763612667cSLaurent Vivier 773612667cSLaurent Vivier ws >>= d; 783612667cSLaurent Vivier xtensa_rotate_window(env, d); 793612667cSLaurent Vivier 803612667cSLaurent Vivier if (ws & 0x1) { 813612667cSLaurent Vivier ssp = env->regs[5]; 823612667cSLaurent Vivier d = 1; 833612667cSLaurent Vivier } else if (ws & 0x2) { 843612667cSLaurent Vivier ssp = env->regs[9]; 853612667cSLaurent Vivier ret |= get_user_ual(osp, env->regs[1] - 12); 863612667cSLaurent Vivier osp -= 32; 873612667cSLaurent Vivier d = 2; 883612667cSLaurent Vivier } else if (ws & 0x4) { 893612667cSLaurent Vivier ssp = env->regs[13]; 903612667cSLaurent Vivier ret |= get_user_ual(osp, env->regs[1] - 12); 913612667cSLaurent Vivier osp -= 48; 923612667cSLaurent Vivier d = 3; 933612667cSLaurent Vivier } else { 943612667cSLaurent Vivier g_assert_not_reached(); 953612667cSLaurent Vivier } 963612667cSLaurent Vivier 973612667cSLaurent Vivier for (j = 0; j < 4; ++j) { 983612667cSLaurent Vivier ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4); 993612667cSLaurent Vivier } 1003612667cSLaurent Vivier for (j = 4; j < d * 4; ++j) { 1013612667cSLaurent Vivier ret |= put_user_ual(env->regs[j], osp - 16 + j * 4); 1023612667cSLaurent Vivier } 1033612667cSLaurent Vivier } 1043612667cSLaurent Vivier xtensa_rotate_window(env, d); 1053612667cSLaurent Vivier g_assert(env->sregs[WINDOW_BASE] == wb); 1063612667cSLaurent Vivier return ret == 0; 1073612667cSLaurent Vivier } 1083612667cSLaurent Vivier 1093612667cSLaurent Vivier static int setup_sigcontext(struct target_rt_sigframe *frame, 1103612667cSLaurent Vivier CPUXtensaState *env) 1113612667cSLaurent Vivier { 1123612667cSLaurent Vivier struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 1133612667cSLaurent Vivier int i; 1143612667cSLaurent Vivier 1153612667cSLaurent Vivier __put_user(env->pc, &sc->sc_pc); 1163612667cSLaurent Vivier __put_user(env->sregs[PS], &sc->sc_ps); 1173612667cSLaurent Vivier __put_user(env->sregs[LBEG], &sc->sc_lbeg); 1183612667cSLaurent Vivier __put_user(env->sregs[LEND], &sc->sc_lend); 1193612667cSLaurent Vivier __put_user(env->sregs[LCOUNT], &sc->sc_lcount); 1203612667cSLaurent Vivier if (!flush_window_regs(env)) { 1213612667cSLaurent Vivier return 0; 1223612667cSLaurent Vivier } 1233612667cSLaurent Vivier for (i = 0; i < 16; ++i) { 1243612667cSLaurent Vivier __put_user(env->regs[i], sc->sc_a + i); 1253612667cSLaurent Vivier } 1263612667cSLaurent Vivier __put_user(0, &sc->sc_xtregs); 1273612667cSLaurent Vivier /* TODO: xtregs */ 1283612667cSLaurent Vivier return 1; 1293612667cSLaurent Vivier } 1303612667cSLaurent Vivier 13155e83c20SRichard Henderson static void install_sigtramp(uint8_t *tramp) 13255e83c20SRichard Henderson { 133*ee3eb3a7SMarc-André Lureau #if TARGET_BIG_ENDIAN 13455e83c20SRichard Henderson /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 13555e83c20SRichard Henderson __put_user(0x22, &tramp[0]); 13655e83c20SRichard Henderson __put_user(0x0a, &tramp[1]); 13755e83c20SRichard Henderson __put_user(TARGET_NR_rt_sigreturn, &tramp[2]); 13855e83c20SRichard Henderson /* Generate instruction: SYSCALL */ 13955e83c20SRichard Henderson __put_user(0x00, &tramp[3]); 14055e83c20SRichard Henderson __put_user(0x05, &tramp[4]); 14155e83c20SRichard Henderson __put_user(0x00, &tramp[5]); 14255e83c20SRichard Henderson #else 14355e83c20SRichard Henderson /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ 14455e83c20SRichard Henderson __put_user(0x22, &tramp[0]); 14555e83c20SRichard Henderson __put_user(0xa0, &tramp[1]); 14655e83c20SRichard Henderson __put_user(TARGET_NR_rt_sigreturn, &tramp[2]); 14755e83c20SRichard Henderson /* Generate instruction: SYSCALL */ 14855e83c20SRichard Henderson __put_user(0x00, &tramp[3]); 14955e83c20SRichard Henderson __put_user(0x50, &tramp[4]); 15055e83c20SRichard Henderson __put_user(0x00, &tramp[5]); 15155e83c20SRichard Henderson #endif 15255e83c20SRichard Henderson } 15355e83c20SRichard Henderson 1543612667cSLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 1553612667cSLaurent Vivier target_siginfo_t *info, 1563612667cSLaurent Vivier target_sigset_t *set, CPUXtensaState *env) 1573612667cSLaurent Vivier { 1583612667cSLaurent Vivier abi_ulong frame_addr; 1593612667cSLaurent Vivier struct target_rt_sigframe *frame; 1603612667cSLaurent Vivier uint32_t ra; 161130ea832SMax Filippov bool abi_call0; 162130ea832SMax Filippov unsigned base; 1633612667cSLaurent Vivier int i; 1643612667cSLaurent Vivier 1653612667cSLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof(*frame)); 1663612667cSLaurent Vivier trace_user_setup_rt_frame(env, frame_addr); 1673612667cSLaurent Vivier 1683612667cSLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 1693612667cSLaurent Vivier goto give_sigsegv; 1703612667cSLaurent Vivier } 1713612667cSLaurent Vivier 1723612667cSLaurent Vivier if (ka->sa_flags & SA_SIGINFO) { 1733612667cSLaurent Vivier tswap_siginfo(&frame->info, info); 1743612667cSLaurent Vivier } 1753612667cSLaurent Vivier 1763612667cSLaurent Vivier __put_user(0, &frame->uc.tuc_flags); 1773612667cSLaurent Vivier __put_user(0, &frame->uc.tuc_link); 178465e237bSLaurent Vivier target_save_altstack(&frame->uc.tuc_stack, env); 1793612667cSLaurent Vivier if (!setup_sigcontext(frame, env)) { 1803612667cSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 1813612667cSLaurent Vivier goto give_sigsegv; 1823612667cSLaurent Vivier } 1833612667cSLaurent Vivier for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 1843612667cSLaurent Vivier __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 1853612667cSLaurent Vivier } 1863612667cSLaurent Vivier 1873612667cSLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 1883612667cSLaurent Vivier ra = ka->sa_restorer; 1893612667cSLaurent Vivier } else { 19055e83c20SRichard Henderson /* Not used, but retain for ABI compatibility. */ 19155e83c20SRichard Henderson install_sigtramp(frame->retcode); 19255e83c20SRichard Henderson ra = default_rt_sigreturn; 1933612667cSLaurent Vivier } 1943612667cSLaurent Vivier memset(env->regs, 0, sizeof(env->regs)); 1953612667cSLaurent Vivier env->pc = ka->_sa_handler; 1963612667cSLaurent Vivier env->regs[1] = frame_addr; 1973612667cSLaurent Vivier env->sregs[WINDOW_BASE] = 0; 1983612667cSLaurent Vivier env->sregs[WINDOW_START] = 1; 1993612667cSLaurent Vivier 200130ea832SMax Filippov abi_call0 = (env->sregs[PS] & PS_WOE) == 0; 201130ea832SMax Filippov env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); 202130ea832SMax Filippov 203130ea832SMax Filippov if (abi_call0) { 204130ea832SMax Filippov base = 0; 205130ea832SMax Filippov env->regs[base] = ra; 206130ea832SMax Filippov } else { 207130ea832SMax Filippov env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); 208130ea832SMax Filippov base = 4; 209130ea832SMax Filippov env->regs[base] = (ra & 0x3fffffff) | 0x40000000; 210130ea832SMax Filippov } 211130ea832SMax Filippov env->regs[base + 2] = sig; 212130ea832SMax Filippov env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, 213130ea832SMax Filippov info); 214130ea832SMax Filippov env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc); 2153612667cSLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2163612667cSLaurent Vivier return; 2173612667cSLaurent Vivier 2183612667cSLaurent Vivier give_sigsegv: 2193612667cSLaurent Vivier force_sigsegv(sig); 2203612667cSLaurent Vivier return; 2213612667cSLaurent Vivier } 2223612667cSLaurent Vivier 2233612667cSLaurent Vivier static void restore_sigcontext(CPUXtensaState *env, 2243612667cSLaurent Vivier struct target_rt_sigframe *frame) 2253612667cSLaurent Vivier { 2263612667cSLaurent Vivier struct target_sigcontext *sc = &frame->uc.tuc_mcontext; 2273612667cSLaurent Vivier uint32_t ps; 2283612667cSLaurent Vivier int i; 2293612667cSLaurent Vivier 2303612667cSLaurent Vivier __get_user(env->pc, &sc->sc_pc); 2313612667cSLaurent Vivier __get_user(ps, &sc->sc_ps); 2323612667cSLaurent Vivier __get_user(env->sregs[LBEG], &sc->sc_lbeg); 2333612667cSLaurent Vivier __get_user(env->sregs[LEND], &sc->sc_lend); 2343612667cSLaurent Vivier __get_user(env->sregs[LCOUNT], &sc->sc_lcount); 2353612667cSLaurent Vivier 2363612667cSLaurent Vivier env->sregs[WINDOW_BASE] = 0; 2373612667cSLaurent Vivier env->sregs[WINDOW_START] = 1; 2383612667cSLaurent Vivier env->sregs[PS] = deposit32(env->sregs[PS], 2393612667cSLaurent Vivier PS_CALLINC_SHIFT, 2403612667cSLaurent Vivier PS_CALLINC_LEN, 2413612667cSLaurent Vivier extract32(ps, PS_CALLINC_SHIFT, 2423612667cSLaurent Vivier PS_CALLINC_LEN)); 2433612667cSLaurent Vivier for (i = 0; i < 16; ++i) { 2443612667cSLaurent Vivier __get_user(env->regs[i], sc->sc_a + i); 2453612667cSLaurent Vivier } 2463612667cSLaurent Vivier /* TODO: xtregs */ 2473612667cSLaurent Vivier } 2483612667cSLaurent Vivier 2493612667cSLaurent Vivier long do_rt_sigreturn(CPUXtensaState *env) 2503612667cSLaurent Vivier { 2513612667cSLaurent Vivier abi_ulong frame_addr = env->regs[1]; 2523612667cSLaurent Vivier struct target_rt_sigframe *frame; 2533612667cSLaurent Vivier sigset_t set; 2543612667cSLaurent Vivier 2553612667cSLaurent Vivier trace_user_do_rt_sigreturn(env, frame_addr); 2563612667cSLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 2573612667cSLaurent Vivier goto badframe; 2583612667cSLaurent Vivier } 2593612667cSLaurent Vivier target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 2603612667cSLaurent Vivier set_sigmask(&set); 2613612667cSLaurent Vivier 2623612667cSLaurent Vivier restore_sigcontext(env, frame); 263ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.tuc_stack, env); 2643612667cSLaurent Vivier 2653612667cSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 26657a0c938SRichard Henderson return -QEMU_ESIGRETURN; 2673612667cSLaurent Vivier 2683612667cSLaurent Vivier badframe: 2693612667cSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 2703612667cSLaurent Vivier force_sig(TARGET_SIGSEGV); 27157a0c938SRichard Henderson return -QEMU_ESIGRETURN; 2723612667cSLaurent Vivier } 27355e83c20SRichard Henderson 27455e83c20SRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page) 27555e83c20SRichard Henderson { 27655e83c20SRichard Henderson uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0); 27755e83c20SRichard Henderson assert(tramp != NULL); 27855e83c20SRichard Henderson 27955e83c20SRichard Henderson default_rt_sigreturn = sigtramp_page; 28055e83c20SRichard Henderson install_sigtramp(tramp); 28155e83c20SRichard Henderson unlock_user(tramp, sigtramp_page, 6); 28255e83c20SRichard Henderson } 283