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 */ 190f22162aSLaurent Vivier #include "qemu/osdep.h" 200f22162aSLaurent Vivier #include "qemu.h" 21*3b249d26SPeter Maydell #include "user-internals.h" 220f22162aSLaurent Vivier #include "signal-common.h" 230f22162aSLaurent Vivier #include "linux-user/trace.h" 240f22162aSLaurent Vivier 250f22162aSLaurent Vivier /* 260f22162aSLaurent Vivier * code and data structures from linux kernel: 270f22162aSLaurent Vivier * include/asm-sh/sigcontext.h 280f22162aSLaurent Vivier * arch/sh/kernel/signal.c 290f22162aSLaurent Vivier */ 300f22162aSLaurent Vivier 310f22162aSLaurent Vivier struct target_sigcontext { 320f22162aSLaurent Vivier target_ulong oldmask; 330f22162aSLaurent Vivier 340f22162aSLaurent Vivier /* CPU registers */ 350f22162aSLaurent Vivier target_ulong sc_gregs[16]; 360f22162aSLaurent Vivier target_ulong sc_pc; 370f22162aSLaurent Vivier target_ulong sc_pr; 380f22162aSLaurent Vivier target_ulong sc_sr; 390f22162aSLaurent Vivier target_ulong sc_gbr; 400f22162aSLaurent Vivier target_ulong sc_mach; 410f22162aSLaurent Vivier target_ulong sc_macl; 420f22162aSLaurent Vivier 430f22162aSLaurent Vivier /* FPU registers */ 440f22162aSLaurent Vivier target_ulong sc_fpregs[16]; 450f22162aSLaurent Vivier target_ulong sc_xfpregs[16]; 460f22162aSLaurent Vivier unsigned int sc_fpscr; 470f22162aSLaurent Vivier unsigned int sc_fpul; 480f22162aSLaurent Vivier unsigned int sc_ownedfp; 490f22162aSLaurent Vivier }; 500f22162aSLaurent Vivier 510f22162aSLaurent Vivier struct target_sigframe 520f22162aSLaurent Vivier { 530f22162aSLaurent Vivier struct target_sigcontext sc; 540f22162aSLaurent Vivier target_ulong extramask[TARGET_NSIG_WORDS-1]; 550f22162aSLaurent Vivier uint16_t retcode[3]; 560f22162aSLaurent Vivier }; 570f22162aSLaurent Vivier 580f22162aSLaurent Vivier 590f22162aSLaurent Vivier struct target_ucontext { 600f22162aSLaurent Vivier target_ulong tuc_flags; 610f22162aSLaurent Vivier struct target_ucontext *tuc_link; 620f22162aSLaurent Vivier target_stack_t tuc_stack; 630f22162aSLaurent Vivier struct target_sigcontext tuc_mcontext; 640f22162aSLaurent Vivier target_sigset_t tuc_sigmask; /* mask last for extensibility */ 650f22162aSLaurent Vivier }; 660f22162aSLaurent Vivier 670f22162aSLaurent Vivier struct target_rt_sigframe 680f22162aSLaurent Vivier { 690f22162aSLaurent Vivier struct target_siginfo info; 700f22162aSLaurent Vivier struct target_ucontext uc; 710f22162aSLaurent Vivier uint16_t retcode[3]; 720f22162aSLaurent Vivier }; 730f22162aSLaurent Vivier 740f22162aSLaurent Vivier 750f22162aSLaurent Vivier #define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ 760f22162aSLaurent Vivier #define TRAP_NOARG 0xc310 /* Syscall w/no args (NR in R3) SH3/4 */ 770f22162aSLaurent Vivier 780f22162aSLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *ka, 790f22162aSLaurent Vivier unsigned long sp, size_t frame_size) 800f22162aSLaurent Vivier { 81465e237bSLaurent Vivier sp = target_sigsp(sp, ka); 820f22162aSLaurent Vivier 830f22162aSLaurent Vivier return (sp - frame_size) & -8ul; 840f22162aSLaurent Vivier } 850f22162aSLaurent Vivier 866cc9d67cSRichard Henderson /* 876cc9d67cSRichard Henderson * Notice when we're in the middle of a gUSA region and reset. 886cc9d67cSRichard Henderson * Note that this will only occur when #CF_PARALLEL is unset, as we 896cc9d67cSRichard Henderson * will translate such sequences differently in a parallel context. 906cc9d67cSRichard Henderson */ 910f22162aSLaurent Vivier static void unwind_gusa(CPUSH4State *regs) 920f22162aSLaurent Vivier { 930f22162aSLaurent Vivier /* If the stack pointer is sufficiently negative, and we haven't 940f22162aSLaurent Vivier completed the sequence, then reset to the entry to the region. */ 950f22162aSLaurent Vivier /* ??? The SH4 kernel checks for and address above 0xC0000000. 960f22162aSLaurent Vivier However, the page mappings in qemu linux-user aren't as restricted 970f22162aSLaurent Vivier and we wind up with the normal stack mapped above 0xF0000000. 980f22162aSLaurent Vivier That said, there is no reason why the kernel should be allowing 990f22162aSLaurent Vivier a gUSA region that spans 1GB. Use a tighter check here, for what 1000f22162aSLaurent Vivier can actually be enabled by the immediate move. */ 1010f22162aSLaurent Vivier if (regs->gregs[15] >= -128u && regs->pc < regs->gregs[0]) { 1020f22162aSLaurent Vivier /* Reset the PC to before the gUSA region, as computed from 1030f22162aSLaurent Vivier R0 = region end, SP = -(region size), plus one more for the 1040f22162aSLaurent Vivier insn that actually initializes SP to the region size. */ 1050f22162aSLaurent Vivier regs->pc = regs->gregs[0] + regs->gregs[15] - 2; 1060f22162aSLaurent Vivier 1070f22162aSLaurent Vivier /* Reset the SP to the saved version in R1. */ 1080f22162aSLaurent Vivier regs->gregs[15] = regs->gregs[1]; 1090f22162aSLaurent Vivier } 1100f22162aSLaurent Vivier } 1110f22162aSLaurent Vivier 1120f22162aSLaurent Vivier static void setup_sigcontext(struct target_sigcontext *sc, 1130f22162aSLaurent Vivier CPUSH4State *regs, unsigned long mask) 1140f22162aSLaurent Vivier { 1150f22162aSLaurent Vivier int i; 1160f22162aSLaurent Vivier 1170f22162aSLaurent Vivier #define COPY(x) __put_user(regs->x, &sc->sc_##x) 1180f22162aSLaurent Vivier COPY(gregs[0]); COPY(gregs[1]); 1190f22162aSLaurent Vivier COPY(gregs[2]); COPY(gregs[3]); 1200f22162aSLaurent Vivier COPY(gregs[4]); COPY(gregs[5]); 1210f22162aSLaurent Vivier COPY(gregs[6]); COPY(gregs[7]); 1220f22162aSLaurent Vivier COPY(gregs[8]); COPY(gregs[9]); 1230f22162aSLaurent Vivier COPY(gregs[10]); COPY(gregs[11]); 1240f22162aSLaurent Vivier COPY(gregs[12]); COPY(gregs[13]); 1250f22162aSLaurent Vivier COPY(gregs[14]); COPY(gregs[15]); 1260f22162aSLaurent Vivier COPY(gbr); COPY(mach); 1270f22162aSLaurent Vivier COPY(macl); COPY(pr); 1280f22162aSLaurent Vivier COPY(sr); COPY(pc); 1290f22162aSLaurent Vivier #undef COPY 1300f22162aSLaurent Vivier 1310f22162aSLaurent Vivier for (i=0; i<16; i++) { 1320f22162aSLaurent Vivier __put_user(regs->fregs[i], &sc->sc_fpregs[i]); 1330f22162aSLaurent Vivier } 1340f22162aSLaurent Vivier __put_user(regs->fpscr, &sc->sc_fpscr); 1350f22162aSLaurent Vivier __put_user(regs->fpul, &sc->sc_fpul); 1360f22162aSLaurent Vivier 1370f22162aSLaurent Vivier /* non-iBCS2 extensions.. */ 1380f22162aSLaurent Vivier __put_user(mask, &sc->oldmask); 1390f22162aSLaurent Vivier } 1400f22162aSLaurent Vivier 1410f22162aSLaurent Vivier static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) 1420f22162aSLaurent Vivier { 1430f22162aSLaurent Vivier int i; 1440f22162aSLaurent Vivier 1450f22162aSLaurent Vivier #define COPY(x) __get_user(regs->x, &sc->sc_##x) 1460f22162aSLaurent Vivier COPY(gregs[0]); COPY(gregs[1]); 1470f22162aSLaurent Vivier COPY(gregs[2]); COPY(gregs[3]); 1480f22162aSLaurent Vivier COPY(gregs[4]); COPY(gregs[5]); 1490f22162aSLaurent Vivier COPY(gregs[6]); COPY(gregs[7]); 1500f22162aSLaurent Vivier COPY(gregs[8]); COPY(gregs[9]); 1510f22162aSLaurent Vivier COPY(gregs[10]); COPY(gregs[11]); 1520f22162aSLaurent Vivier COPY(gregs[12]); COPY(gregs[13]); 1530f22162aSLaurent Vivier COPY(gregs[14]); COPY(gregs[15]); 1540f22162aSLaurent Vivier COPY(gbr); COPY(mach); 1550f22162aSLaurent Vivier COPY(macl); COPY(pr); 1560f22162aSLaurent Vivier COPY(sr); COPY(pc); 1570f22162aSLaurent Vivier #undef COPY 1580f22162aSLaurent Vivier 1590f22162aSLaurent Vivier for (i=0; i<16; i++) { 1600f22162aSLaurent Vivier __get_user(regs->fregs[i], &sc->sc_fpregs[i]); 1610f22162aSLaurent Vivier } 1620f22162aSLaurent Vivier __get_user(regs->fpscr, &sc->sc_fpscr); 1630f22162aSLaurent Vivier __get_user(regs->fpul, &sc->sc_fpul); 1640f22162aSLaurent Vivier 1650f22162aSLaurent Vivier regs->tra = -1; /* disable syscall checks */ 1660f22162aSLaurent Vivier regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 1670f22162aSLaurent Vivier } 1680f22162aSLaurent Vivier 1690f22162aSLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka, 1700f22162aSLaurent Vivier target_sigset_t *set, CPUSH4State *regs) 1710f22162aSLaurent Vivier { 1720f22162aSLaurent Vivier struct target_sigframe *frame; 1730f22162aSLaurent Vivier abi_ulong frame_addr; 1740f22162aSLaurent Vivier int i; 1750f22162aSLaurent Vivier 1760f22162aSLaurent Vivier unwind_gusa(regs); 1770f22162aSLaurent Vivier 1780f22162aSLaurent Vivier frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); 1790f22162aSLaurent Vivier trace_user_setup_frame(regs, frame_addr); 1800f22162aSLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 1810f22162aSLaurent Vivier goto give_sigsegv; 1820f22162aSLaurent Vivier } 1830f22162aSLaurent Vivier 1840f22162aSLaurent Vivier setup_sigcontext(&frame->sc, regs, set->sig[0]); 1850f22162aSLaurent Vivier 1860f22162aSLaurent Vivier for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { 1870f22162aSLaurent Vivier __put_user(set->sig[i + 1], &frame->extramask[i]); 1880f22162aSLaurent Vivier } 1890f22162aSLaurent Vivier 1900f22162aSLaurent Vivier /* Set up to return from userspace. If provided, use a stub 1910f22162aSLaurent Vivier already in userspace. */ 1920f22162aSLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 1930f22162aSLaurent Vivier regs->pr = (unsigned long) ka->sa_restorer; 1940f22162aSLaurent Vivier } else { 1950f22162aSLaurent Vivier /* Generate return code (system call to sigreturn) */ 1960f22162aSLaurent Vivier abi_ulong retcode_addr = frame_addr + 1970f22162aSLaurent Vivier offsetof(struct target_sigframe, retcode); 1980f22162aSLaurent Vivier __put_user(MOVW(2), &frame->retcode[0]); 1990f22162aSLaurent Vivier __put_user(TRAP_NOARG, &frame->retcode[1]); 2000f22162aSLaurent Vivier __put_user((TARGET_NR_sigreturn), &frame->retcode[2]); 2010f22162aSLaurent Vivier regs->pr = (unsigned long) retcode_addr; 2020f22162aSLaurent Vivier } 2030f22162aSLaurent Vivier 2040f22162aSLaurent Vivier /* Set up registers for signal handler */ 2050f22162aSLaurent Vivier regs->gregs[15] = frame_addr; 2060f22162aSLaurent Vivier regs->gregs[4] = sig; /* Arg for signal handler */ 2070f22162aSLaurent Vivier regs->gregs[5] = 0; 2080f22162aSLaurent Vivier regs->gregs[6] = frame_addr += offsetof(typeof(*frame), sc); 2090f22162aSLaurent Vivier regs->pc = (unsigned long) ka->_sa_handler; 2100f22162aSLaurent Vivier regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 2110f22162aSLaurent Vivier 2120f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2130f22162aSLaurent Vivier return; 2140f22162aSLaurent Vivier 2150f22162aSLaurent Vivier give_sigsegv: 2160f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2170f22162aSLaurent Vivier force_sigsegv(sig); 2180f22162aSLaurent Vivier } 2190f22162aSLaurent Vivier 2200f22162aSLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 2210f22162aSLaurent Vivier target_siginfo_t *info, 2220f22162aSLaurent Vivier target_sigset_t *set, CPUSH4State *regs) 2230f22162aSLaurent Vivier { 2240f22162aSLaurent Vivier struct target_rt_sigframe *frame; 2250f22162aSLaurent Vivier abi_ulong frame_addr; 2260f22162aSLaurent Vivier int i; 2270f22162aSLaurent Vivier 2280f22162aSLaurent Vivier unwind_gusa(regs); 2290f22162aSLaurent Vivier 2300f22162aSLaurent Vivier frame_addr = get_sigframe(ka, regs->gregs[15], sizeof(*frame)); 2310f22162aSLaurent Vivier trace_user_setup_rt_frame(regs, frame_addr); 2320f22162aSLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 2330f22162aSLaurent Vivier goto give_sigsegv; 2340f22162aSLaurent Vivier } 2350f22162aSLaurent Vivier 2360f22162aSLaurent Vivier tswap_siginfo(&frame->info, info); 2370f22162aSLaurent Vivier 2380f22162aSLaurent Vivier /* Create the ucontext. */ 2390f22162aSLaurent Vivier __put_user(0, &frame->uc.tuc_flags); 2400f22162aSLaurent Vivier __put_user(0, (unsigned long *)&frame->uc.tuc_link); 241465e237bSLaurent Vivier target_save_altstack(&frame->uc.tuc_stack, regs); 2420f22162aSLaurent Vivier setup_sigcontext(&frame->uc.tuc_mcontext, 2430f22162aSLaurent Vivier regs, set->sig[0]); 2440f22162aSLaurent Vivier for(i = 0; i < TARGET_NSIG_WORDS; i++) { 2450f22162aSLaurent Vivier __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 2460f22162aSLaurent Vivier } 2470f22162aSLaurent Vivier 2480f22162aSLaurent Vivier /* Set up to return from userspace. If provided, use a stub 2490f22162aSLaurent Vivier already in userspace. */ 2500f22162aSLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 2510f22162aSLaurent Vivier regs->pr = (unsigned long) ka->sa_restorer; 2520f22162aSLaurent Vivier } else { 2530f22162aSLaurent Vivier /* Generate return code (system call to sigreturn) */ 2540f22162aSLaurent Vivier abi_ulong retcode_addr = frame_addr + 2550f22162aSLaurent Vivier offsetof(struct target_rt_sigframe, retcode); 2560f22162aSLaurent Vivier __put_user(MOVW(2), &frame->retcode[0]); 2570f22162aSLaurent Vivier __put_user(TRAP_NOARG, &frame->retcode[1]); 2580f22162aSLaurent Vivier __put_user((TARGET_NR_rt_sigreturn), &frame->retcode[2]); 2590f22162aSLaurent Vivier regs->pr = (unsigned long) retcode_addr; 2600f22162aSLaurent Vivier } 2610f22162aSLaurent Vivier 2620f22162aSLaurent Vivier /* Set up registers for signal handler */ 2630f22162aSLaurent Vivier regs->gregs[15] = frame_addr; 2640f22162aSLaurent Vivier regs->gregs[4] = sig; /* Arg for signal handler */ 2650f22162aSLaurent Vivier regs->gregs[5] = frame_addr + offsetof(typeof(*frame), info); 2660f22162aSLaurent Vivier regs->gregs[6] = frame_addr + offsetof(typeof(*frame), uc); 2670f22162aSLaurent Vivier regs->pc = (unsigned long) ka->_sa_handler; 2680f22162aSLaurent Vivier regs->flags &= ~(DELAY_SLOT_MASK | GUSA_MASK); 2690f22162aSLaurent Vivier 2700f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2710f22162aSLaurent Vivier return; 2720f22162aSLaurent Vivier 2730f22162aSLaurent Vivier give_sigsegv: 2740f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 2750f22162aSLaurent Vivier force_sigsegv(sig); 2760f22162aSLaurent Vivier } 2770f22162aSLaurent Vivier 2780f22162aSLaurent Vivier long do_sigreturn(CPUSH4State *regs) 2790f22162aSLaurent Vivier { 2800f22162aSLaurent Vivier struct target_sigframe *frame; 2810f22162aSLaurent Vivier abi_ulong frame_addr; 2820f22162aSLaurent Vivier sigset_t blocked; 2830f22162aSLaurent Vivier target_sigset_t target_set; 2840f22162aSLaurent Vivier int i; 2850f22162aSLaurent Vivier 2860f22162aSLaurent Vivier frame_addr = regs->gregs[15]; 2870f22162aSLaurent Vivier trace_user_do_sigreturn(regs, frame_addr); 2880f22162aSLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 2890f22162aSLaurent Vivier goto badframe; 2900f22162aSLaurent Vivier } 2910f22162aSLaurent Vivier 2920f22162aSLaurent Vivier __get_user(target_set.sig[0], &frame->sc.oldmask); 2930f22162aSLaurent Vivier for(i = 1; i < TARGET_NSIG_WORDS; i++) { 2940f22162aSLaurent Vivier __get_user(target_set.sig[i], &frame->extramask[i - 1]); 2950f22162aSLaurent Vivier } 2960f22162aSLaurent Vivier 2970f22162aSLaurent Vivier target_to_host_sigset_internal(&blocked, &target_set); 2980f22162aSLaurent Vivier set_sigmask(&blocked); 2990f22162aSLaurent Vivier 3000f22162aSLaurent Vivier restore_sigcontext(regs, &frame->sc); 3010f22162aSLaurent Vivier 3020f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 3030f22162aSLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3040f22162aSLaurent Vivier 3050f22162aSLaurent Vivier badframe: 3060f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 3070f22162aSLaurent Vivier force_sig(TARGET_SIGSEGV); 3080f22162aSLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3090f22162aSLaurent Vivier } 3100f22162aSLaurent Vivier 3110f22162aSLaurent Vivier long do_rt_sigreturn(CPUSH4State *regs) 3120f22162aSLaurent Vivier { 3130f22162aSLaurent Vivier struct target_rt_sigframe *frame; 3140f22162aSLaurent Vivier abi_ulong frame_addr; 3150f22162aSLaurent Vivier sigset_t blocked; 3160f22162aSLaurent Vivier 3170f22162aSLaurent Vivier frame_addr = regs->gregs[15]; 3180f22162aSLaurent Vivier trace_user_do_rt_sigreturn(regs, frame_addr); 3190f22162aSLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 3200f22162aSLaurent Vivier goto badframe; 3210f22162aSLaurent Vivier } 3220f22162aSLaurent Vivier 3230f22162aSLaurent Vivier target_to_host_sigset(&blocked, &frame->uc.tuc_sigmask); 3240f22162aSLaurent Vivier set_sigmask(&blocked); 3250f22162aSLaurent Vivier 3260f22162aSLaurent Vivier restore_sigcontext(regs, &frame->uc.tuc_mcontext); 327ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.tuc_stack, regs); 3280f22162aSLaurent Vivier 3290f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 3300f22162aSLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3310f22162aSLaurent Vivier 3320f22162aSLaurent Vivier badframe: 3330f22162aSLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 3340f22162aSLaurent Vivier force_sig(TARGET_SIGSEGV); 3350f22162aSLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3360f22162aSLaurent Vivier } 337