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 */ 19f9fb3ba3SLaurent Vivier #include "qemu/osdep.h" 20f9fb3ba3SLaurent Vivier #include "qemu.h" 213b249d26SPeter Maydell #include "user-internals.h" 22f9fb3ba3SLaurent Vivier #include "signal-common.h" 23f9fb3ba3SLaurent Vivier #include "linux-user/trace.h" 24f9fb3ba3SLaurent Vivier 25f9fb3ba3SLaurent Vivier struct target_sigcontext { 26f9fb3ba3SLaurent Vivier struct target_pt_regs regs; /* needs to be first */ 27f9fb3ba3SLaurent Vivier uint32_t oldmask; 28f9fb3ba3SLaurent Vivier }; 29f9fb3ba3SLaurent Vivier 30f9fb3ba3SLaurent Vivier struct target_stack_t { 31f9fb3ba3SLaurent Vivier abi_ulong ss_sp; 32f9fb3ba3SLaurent Vivier int ss_flags; 33f9fb3ba3SLaurent Vivier unsigned int ss_size; 34f9fb3ba3SLaurent Vivier }; 35f9fb3ba3SLaurent Vivier 36f9fb3ba3SLaurent Vivier struct target_ucontext { 37f9fb3ba3SLaurent Vivier abi_ulong tuc_flags; 38f9fb3ba3SLaurent Vivier abi_ulong tuc_link; 394fa3876eSRichard Henderson target_stack_t tuc_stack; 40f9fb3ba3SLaurent Vivier struct target_sigcontext tuc_mcontext; 414fa3876eSRichard Henderson target_sigset_t tuc_sigmask; 42f9fb3ba3SLaurent Vivier }; 43f9fb3ba3SLaurent Vivier 44f9fb3ba3SLaurent Vivier /* Signal frames. */ 454fa3876eSRichard Henderson struct target_rt_sigframe { 464fa3876eSRichard Henderson target_siginfo_t info; 474fa3876eSRichard Henderson struct target_ucontext uc; 48f9fb3ba3SLaurent Vivier uint32_t tramp[2]; 49f9fb3ba3SLaurent Vivier }; 50f9fb3ba3SLaurent Vivier 51f9fb3ba3SLaurent Vivier static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 52f9fb3ba3SLaurent Vivier { 53f9fb3ba3SLaurent Vivier __put_user(env->regs[0], &sc->regs.r0); 54f9fb3ba3SLaurent Vivier __put_user(env->regs[1], &sc->regs.r1); 55f9fb3ba3SLaurent Vivier __put_user(env->regs[2], &sc->regs.r2); 56f9fb3ba3SLaurent Vivier __put_user(env->regs[3], &sc->regs.r3); 57f9fb3ba3SLaurent Vivier __put_user(env->regs[4], &sc->regs.r4); 58f9fb3ba3SLaurent Vivier __put_user(env->regs[5], &sc->regs.r5); 59f9fb3ba3SLaurent Vivier __put_user(env->regs[6], &sc->regs.r6); 60f9fb3ba3SLaurent Vivier __put_user(env->regs[7], &sc->regs.r7); 61f9fb3ba3SLaurent Vivier __put_user(env->regs[8], &sc->regs.r8); 62f9fb3ba3SLaurent Vivier __put_user(env->regs[9], &sc->regs.r9); 63f9fb3ba3SLaurent Vivier __put_user(env->regs[10], &sc->regs.r10); 64f9fb3ba3SLaurent Vivier __put_user(env->regs[11], &sc->regs.r11); 65f9fb3ba3SLaurent Vivier __put_user(env->regs[12], &sc->regs.r12); 66f9fb3ba3SLaurent Vivier __put_user(env->regs[13], &sc->regs.r13); 67f9fb3ba3SLaurent Vivier __put_user(env->regs[14], &sc->regs.r14); 68f9fb3ba3SLaurent Vivier __put_user(env->regs[15], &sc->regs.r15); 69f9fb3ba3SLaurent Vivier __put_user(env->regs[16], &sc->regs.r16); 70f9fb3ba3SLaurent Vivier __put_user(env->regs[17], &sc->regs.r17); 71f9fb3ba3SLaurent Vivier __put_user(env->regs[18], &sc->regs.r18); 72f9fb3ba3SLaurent Vivier __put_user(env->regs[19], &sc->regs.r19); 73f9fb3ba3SLaurent Vivier __put_user(env->regs[20], &sc->regs.r20); 74f9fb3ba3SLaurent Vivier __put_user(env->regs[21], &sc->regs.r21); 75f9fb3ba3SLaurent Vivier __put_user(env->regs[22], &sc->regs.r22); 76f9fb3ba3SLaurent Vivier __put_user(env->regs[23], &sc->regs.r23); 77f9fb3ba3SLaurent Vivier __put_user(env->regs[24], &sc->regs.r24); 78f9fb3ba3SLaurent Vivier __put_user(env->regs[25], &sc->regs.r25); 79f9fb3ba3SLaurent Vivier __put_user(env->regs[26], &sc->regs.r26); 80f9fb3ba3SLaurent Vivier __put_user(env->regs[27], &sc->regs.r27); 81f9fb3ba3SLaurent Vivier __put_user(env->regs[28], &sc->regs.r28); 82f9fb3ba3SLaurent Vivier __put_user(env->regs[29], &sc->regs.r29); 83f9fb3ba3SLaurent Vivier __put_user(env->regs[30], &sc->regs.r30); 84f9fb3ba3SLaurent Vivier __put_user(env->regs[31], &sc->regs.r31); 8576e8187dSRichard Henderson __put_user(env->pc, &sc->regs.pc); 86f9fb3ba3SLaurent Vivier } 87f9fb3ba3SLaurent Vivier 88f9fb3ba3SLaurent Vivier static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 89f9fb3ba3SLaurent Vivier { 90f9fb3ba3SLaurent Vivier __get_user(env->regs[0], &sc->regs.r0); 91f9fb3ba3SLaurent Vivier __get_user(env->regs[1], &sc->regs.r1); 92f9fb3ba3SLaurent Vivier __get_user(env->regs[2], &sc->regs.r2); 93f9fb3ba3SLaurent Vivier __get_user(env->regs[3], &sc->regs.r3); 94f9fb3ba3SLaurent Vivier __get_user(env->regs[4], &sc->regs.r4); 95f9fb3ba3SLaurent Vivier __get_user(env->regs[5], &sc->regs.r5); 96f9fb3ba3SLaurent Vivier __get_user(env->regs[6], &sc->regs.r6); 97f9fb3ba3SLaurent Vivier __get_user(env->regs[7], &sc->regs.r7); 98f9fb3ba3SLaurent Vivier __get_user(env->regs[8], &sc->regs.r8); 99f9fb3ba3SLaurent Vivier __get_user(env->regs[9], &sc->regs.r9); 100f9fb3ba3SLaurent Vivier __get_user(env->regs[10], &sc->regs.r10); 101f9fb3ba3SLaurent Vivier __get_user(env->regs[11], &sc->regs.r11); 102f9fb3ba3SLaurent Vivier __get_user(env->regs[12], &sc->regs.r12); 103f9fb3ba3SLaurent Vivier __get_user(env->regs[13], &sc->regs.r13); 104f9fb3ba3SLaurent Vivier __get_user(env->regs[14], &sc->regs.r14); 105f9fb3ba3SLaurent Vivier __get_user(env->regs[15], &sc->regs.r15); 106f9fb3ba3SLaurent Vivier __get_user(env->regs[16], &sc->regs.r16); 107f9fb3ba3SLaurent Vivier __get_user(env->regs[17], &sc->regs.r17); 108f9fb3ba3SLaurent Vivier __get_user(env->regs[18], &sc->regs.r18); 109f9fb3ba3SLaurent Vivier __get_user(env->regs[19], &sc->regs.r19); 110f9fb3ba3SLaurent Vivier __get_user(env->regs[20], &sc->regs.r20); 111f9fb3ba3SLaurent Vivier __get_user(env->regs[21], &sc->regs.r21); 112f9fb3ba3SLaurent Vivier __get_user(env->regs[22], &sc->regs.r22); 113f9fb3ba3SLaurent Vivier __get_user(env->regs[23], &sc->regs.r23); 114f9fb3ba3SLaurent Vivier __get_user(env->regs[24], &sc->regs.r24); 115f9fb3ba3SLaurent Vivier __get_user(env->regs[25], &sc->regs.r25); 116f9fb3ba3SLaurent Vivier __get_user(env->regs[26], &sc->regs.r26); 117f9fb3ba3SLaurent Vivier __get_user(env->regs[27], &sc->regs.r27); 118f9fb3ba3SLaurent Vivier __get_user(env->regs[28], &sc->regs.r28); 119f9fb3ba3SLaurent Vivier __get_user(env->regs[29], &sc->regs.r29); 120f9fb3ba3SLaurent Vivier __get_user(env->regs[30], &sc->regs.r30); 121f9fb3ba3SLaurent Vivier __get_user(env->regs[31], &sc->regs.r31); 12276e8187dSRichard Henderson __get_user(env->pc, &sc->regs.pc); 123f9fb3ba3SLaurent Vivier } 124f9fb3ba3SLaurent Vivier 125f9fb3ba3SLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *ka, 126f9fb3ba3SLaurent Vivier CPUMBState *env, int frame_size) 127f9fb3ba3SLaurent Vivier { 128f9fb3ba3SLaurent Vivier abi_ulong sp = env->regs[1]; 129f9fb3ba3SLaurent Vivier 130465e237bSLaurent Vivier sp = target_sigsp(sp, ka); 131f9fb3ba3SLaurent Vivier 132f9fb3ba3SLaurent Vivier return ((sp - frame_size) & -8UL); 133f9fb3ba3SLaurent Vivier } 134f9fb3ba3SLaurent Vivier 135f9fb3ba3SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 136f9fb3ba3SLaurent Vivier target_siginfo_t *info, 137f9fb3ba3SLaurent Vivier target_sigset_t *set, CPUMBState *env) 138f9fb3ba3SLaurent Vivier { 1394fa3876eSRichard Henderson struct target_rt_sigframe *frame; 1404fa3876eSRichard Henderson abi_ulong frame_addr; 1414fa3876eSRichard Henderson 1424fa3876eSRichard Henderson frame_addr = get_sigframe(ka, env, sizeof *frame); 1434fa3876eSRichard Henderson trace_user_setup_rt_frame(env, frame_addr); 1444fa3876eSRichard Henderson 1454fa3876eSRichard Henderson if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 1464fa3876eSRichard Henderson force_sigsegv(sig); 1474fa3876eSRichard Henderson return; 1484fa3876eSRichard Henderson } 1494fa3876eSRichard Henderson 1504fa3876eSRichard Henderson tswap_siginfo(&frame->info, info); 1514fa3876eSRichard Henderson 1524fa3876eSRichard Henderson __put_user(0, &frame->uc.tuc_flags); 1534fa3876eSRichard Henderson __put_user(0, &frame->uc.tuc_link); 1544fa3876eSRichard Henderson 1554fa3876eSRichard Henderson target_save_altstack(&frame->uc.tuc_stack, env); 1564fa3876eSRichard Henderson setup_sigcontext(&frame->uc.tuc_mcontext, env); 1574fa3876eSRichard Henderson 1584fa3876eSRichard Henderson for (int i = 0; i < TARGET_NSIG_WORDS; i++) { 1594fa3876eSRichard Henderson __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 1604fa3876eSRichard Henderson } 1614fa3876eSRichard Henderson 1624fa3876eSRichard Henderson /* Kernel does not use SA_RESTORER. */ 1634fa3876eSRichard Henderson 1644fa3876eSRichard Henderson /* 1654fa3876eSRichard Henderson * Return from sighandler will jump to the tramp. 1664fa3876eSRichard Henderson * Negative 8 offset because return is rtsd r15, 8 1674fa3876eSRichard Henderson */ 1688004316dSRichard Henderson env->regs[15] = default_rt_sigreturn - 8; 1694fa3876eSRichard Henderson 1704fa3876eSRichard Henderson /* Set up registers for signal handler */ 1714fa3876eSRichard Henderson env->regs[1] = frame_addr; 1724fa3876eSRichard Henderson 1734fa3876eSRichard Henderson /* Signal handler args: */ 1744fa3876eSRichard Henderson env->regs[5] = sig; 1754fa3876eSRichard Henderson env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info); 1764fa3876eSRichard Henderson env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc); 1774fa3876eSRichard Henderson 1784fa3876eSRichard Henderson /* Offset to handle microblaze rtid r14, 0 */ 1794fa3876eSRichard Henderson env->pc = (unsigned long)ka->_sa_handler; 1804fa3876eSRichard Henderson 1814fa3876eSRichard Henderson unlock_user_struct(frame, frame_addr, 1); 182f9fb3ba3SLaurent Vivier } 183f9fb3ba3SLaurent Vivier 18449e258dfSRichard Henderson 185f9fb3ba3SLaurent Vivier long do_sigreturn(CPUMBState *env) 186f9fb3ba3SLaurent Vivier { 18749e258dfSRichard Henderson return -TARGET_ENOSYS; 188f9fb3ba3SLaurent Vivier } 189f9fb3ba3SLaurent Vivier 190f9fb3ba3SLaurent Vivier long do_rt_sigreturn(CPUMBState *env) 191f9fb3ba3SLaurent Vivier { 1924fa3876eSRichard Henderson struct target_rt_sigframe *frame = NULL; 1934fa3876eSRichard Henderson abi_ulong frame_addr = env->regs[1]; 1944fa3876eSRichard Henderson sigset_t set; 1954fa3876eSRichard Henderson 1964fa3876eSRichard Henderson trace_user_do_rt_sigreturn(env, frame_addr); 1974fa3876eSRichard Henderson 1984fa3876eSRichard Henderson if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 1994fa3876eSRichard Henderson goto badframe; 2004fa3876eSRichard Henderson } 2014fa3876eSRichard Henderson 2024fa3876eSRichard Henderson target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 2034fa3876eSRichard Henderson set_sigmask(&set); 2044fa3876eSRichard Henderson 2054fa3876eSRichard Henderson restore_sigcontext(&frame->uc.tuc_mcontext, env); 2064fa3876eSRichard Henderson 207ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.tuc_stack, env); 2084fa3876eSRichard Henderson 2094fa3876eSRichard Henderson unlock_user_struct(frame, frame_addr, 0); 210*57a0c938SRichard Henderson return -QEMU_ESIGRETURN; 2114fa3876eSRichard Henderson 2124fa3876eSRichard Henderson badframe: 2134fa3876eSRichard Henderson unlock_user_struct(frame, frame_addr, 0); 2144fa3876eSRichard Henderson force_sig(TARGET_SIGSEGV); 215*57a0c938SRichard Henderson return -QEMU_ESIGRETURN; 216f9fb3ba3SLaurent Vivier } 2178004316dSRichard Henderson 2188004316dSRichard Henderson void setup_sigtramp(abi_ulong sigtramp_page) 2198004316dSRichard Henderson { 2208004316dSRichard Henderson uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0); 2218004316dSRichard Henderson assert(tramp != NULL); 2228004316dSRichard Henderson 2238004316dSRichard Henderson /* 2248004316dSRichard Henderson * addi r12, r0, __NR_rt_sigreturn 2258004316dSRichard Henderson * brki r14, 0x8 2268004316dSRichard Henderson */ 2278004316dSRichard Henderson __put_user(0x31800000U | TARGET_NR_rt_sigreturn, tramp); 2288004316dSRichard Henderson __put_user(0xb9cc0008U, tramp + 1); 2298004316dSRichard Henderson 2308004316dSRichard Henderson default_rt_sigreturn = sigtramp_page; 2318004316dSRichard Henderson unlock_user(tramp, sigtramp_page, 8); 2328004316dSRichard Henderson } 233