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 */ 194c4c73e3SLaurent Vivier #include "qemu/osdep.h" 204c4c73e3SLaurent Vivier #include "qemu.h" 214c4c73e3SLaurent Vivier #include "signal-common.h" 224c4c73e3SLaurent Vivier #include "linux-user/trace.h" 234c4c73e3SLaurent Vivier 244c4c73e3SLaurent Vivier #define __NUM_GPRS 16 254c4c73e3SLaurent Vivier #define __NUM_FPRS 16 264c4c73e3SLaurent Vivier #define __NUM_ACRS 16 274c4c73e3SLaurent Vivier 284c4c73e3SLaurent Vivier #define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ 294c4c73e3SLaurent Vivier 304c4c73e3SLaurent Vivier #define _SIGCONTEXT_NSIG 64 314c4c73e3SLaurent Vivier #define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ 324c4c73e3SLaurent Vivier #define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) 334c4c73e3SLaurent Vivier #define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) 344c4c73e3SLaurent Vivier #define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) 354c4c73e3SLaurent Vivier 364c4c73e3SLaurent Vivier typedef struct { 374c4c73e3SLaurent Vivier target_psw_t psw; 385d79bd11SRichard Henderson abi_ulong gprs[__NUM_GPRS]; 395d79bd11SRichard Henderson abi_uint acrs[__NUM_ACRS]; 404c4c73e3SLaurent Vivier } target_s390_regs_common; 414c4c73e3SLaurent Vivier 424c4c73e3SLaurent Vivier typedef struct { 435d79bd11SRichard Henderson uint32_t fpc; 445d79bd11SRichard Henderson uint32_t pad; 455d79bd11SRichard Henderson uint64_t fprs[__NUM_FPRS]; 464c4c73e3SLaurent Vivier } target_s390_fp_regs; 474c4c73e3SLaurent Vivier 484c4c73e3SLaurent Vivier typedef struct { 494c4c73e3SLaurent Vivier target_s390_regs_common regs; 504c4c73e3SLaurent Vivier target_s390_fp_regs fpregs; 514c4c73e3SLaurent Vivier } target_sigregs; 524c4c73e3SLaurent Vivier 535d79bd11SRichard Henderson typedef struct { 545d79bd11SRichard Henderson abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; 555d79bd11SRichard Henderson abi_ulong sregs; 565d79bd11SRichard Henderson } target_sigcontext; 574c4c73e3SLaurent Vivier 584c4c73e3SLaurent Vivier typedef struct { 594c4c73e3SLaurent Vivier uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 605d79bd11SRichard Henderson target_sigcontext sc; 614c4c73e3SLaurent Vivier target_sigregs sregs; 624c4c73e3SLaurent Vivier int signo; 63cb1f1982SRichard Henderson uint16_t retcode; 644c4c73e3SLaurent Vivier } sigframe; 654c4c73e3SLaurent Vivier 664c4c73e3SLaurent Vivier struct target_ucontext { 675d79bd11SRichard Henderson abi_ulong tuc_flags; 685d79bd11SRichard Henderson abi_ulong tuc_link; 694c4c73e3SLaurent Vivier target_stack_t tuc_stack; 704c4c73e3SLaurent Vivier target_sigregs tuc_mcontext; 714c4c73e3SLaurent Vivier target_sigset_t tuc_sigmask; /* mask last for extensibility */ 724c4c73e3SLaurent Vivier }; 734c4c73e3SLaurent Vivier 744c4c73e3SLaurent Vivier typedef struct { 754c4c73e3SLaurent Vivier uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; 76cb1f1982SRichard Henderson uint16_t retcode; 774c4c73e3SLaurent Vivier struct target_siginfo info; 784c4c73e3SLaurent Vivier struct target_ucontext uc; 794c4c73e3SLaurent Vivier } rt_sigframe; 804c4c73e3SLaurent Vivier 814c4c73e3SLaurent Vivier static inline abi_ulong 824c4c73e3SLaurent Vivier get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) 834c4c73e3SLaurent Vivier { 844c4c73e3SLaurent Vivier abi_ulong sp; 854c4c73e3SLaurent Vivier 864c4c73e3SLaurent Vivier /* Default to using normal stack */ 87465e237bSLaurent Vivier sp = get_sp_from_cpustate(env); 884c4c73e3SLaurent Vivier 894c4c73e3SLaurent Vivier /* This is the X/Open sanctioned signal stack switching. */ 904c4c73e3SLaurent Vivier if (ka->sa_flags & TARGET_SA_ONSTACK) { 91465e237bSLaurent Vivier sp = target_sigsp(sp, ka); 924c4c73e3SLaurent Vivier } 934c4c73e3SLaurent Vivier 944c4c73e3SLaurent Vivier /* This is the legacy signal stack switching. */ 954c4c73e3SLaurent Vivier else if (/* FIXME !user_mode(regs) */ 0 && 964c4c73e3SLaurent Vivier !(ka->sa_flags & TARGET_SA_RESTORER) && 974c4c73e3SLaurent Vivier ka->sa_restorer) { 984c4c73e3SLaurent Vivier sp = (abi_ulong) ka->sa_restorer; 994c4c73e3SLaurent Vivier } 1004c4c73e3SLaurent Vivier 1014c4c73e3SLaurent Vivier return (sp - frame_size) & -8ul; 1024c4c73e3SLaurent Vivier } 1034c4c73e3SLaurent Vivier 1044c4c73e3SLaurent Vivier static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) 1054c4c73e3SLaurent Vivier { 1064c4c73e3SLaurent Vivier int i; 1074c4c73e3SLaurent Vivier 10882839490SRichard Henderson /* 10982839490SRichard Henderson * Copy a 'clean' PSW mask to the user to avoid leaking 11082839490SRichard Henderson * information about whether PER is currently on. 11182839490SRichard Henderson */ 1124c4c73e3SLaurent Vivier __put_user(env->psw.mask, &sregs->regs.psw.mask); 1134c4c73e3SLaurent Vivier __put_user(env->psw.addr, &sregs->regs.psw.addr); 11482839490SRichard Henderson 1154c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 1164c4c73e3SLaurent Vivier __put_user(env->regs[i], &sregs->regs.gprs[i]); 1174c4c73e3SLaurent Vivier } 1184c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 1194c4c73e3SLaurent Vivier __put_user(env->aregs[i], &sregs->regs.acrs[i]); 1204c4c73e3SLaurent Vivier } 12182839490SRichard Henderson 1224c4c73e3SLaurent Vivier /* 1234c4c73e3SLaurent Vivier * We have to store the fp registers to current->thread.fp_regs 1244c4c73e3SLaurent Vivier * to merge them with the emulated registers. 1254c4c73e3SLaurent Vivier */ 1264c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 1274f83d7d2SDavid Hildenbrand __put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]); 1284c4c73e3SLaurent Vivier } 1294c4c73e3SLaurent Vivier } 1304c4c73e3SLaurent Vivier 1314c4c73e3SLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka, 1324c4c73e3SLaurent Vivier target_sigset_t *set, CPUS390XState *env) 1334c4c73e3SLaurent Vivier { 1344c4c73e3SLaurent Vivier sigframe *frame; 1354c4c73e3SLaurent Vivier abi_ulong frame_addr; 136*79d6f2baSRichard Henderson abi_ulong restorer; 1374c4c73e3SLaurent Vivier 1384c4c73e3SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof(*frame)); 1394c4c73e3SLaurent Vivier trace_user_setup_frame(env, frame_addr); 1404c4c73e3SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 14120807348SRichard Henderson force_sigsegv(sig); 14220807348SRichard Henderson return; 1434c4c73e3SLaurent Vivier } 1444c4c73e3SLaurent Vivier 145*79d6f2baSRichard Henderson /* Set up backchain. */ 146*79d6f2baSRichard Henderson __put_user(env->regs[15], (abi_ulong *) frame); 147*79d6f2baSRichard Henderson 148*79d6f2baSRichard Henderson /* Create struct sigcontext on the signal stack. */ 1499e0fb648SRichard Henderson /* Make sure that we're initializing all of oldmask. */ 1509e0fb648SRichard Henderson QEMU_BUILD_BUG_ON(ARRAY_SIZE(frame->sc.oldmask) != 1); 1514c4c73e3SLaurent Vivier __put_user(set->sig[0], &frame->sc.oldmask[0]); 1524e4a0820SRichard Henderson __put_user(frame_addr + offsetof(sigframe, sregs), &frame->sc.sregs); 1534c4c73e3SLaurent Vivier 154*79d6f2baSRichard Henderson /* Create _sigregs on the signal stack */ 155*79d6f2baSRichard Henderson save_sigregs(env, &frame->sregs); 156*79d6f2baSRichard Henderson 157*79d6f2baSRichard Henderson /* 158*79d6f2baSRichard Henderson * ??? The kernel uses regs->gprs[2] here, which is not yet the signo. 159*79d6f2baSRichard Henderson * Moreover the comment talks about allowing backtrace, which is really 160*79d6f2baSRichard Henderson * done by the r15 copy above. 161*79d6f2baSRichard Henderson */ 162*79d6f2baSRichard Henderson __put_user(sig, &frame->signo); 163*79d6f2baSRichard Henderson 164*79d6f2baSRichard Henderson /* 165*79d6f2baSRichard Henderson * Set up to return from userspace. 166*79d6f2baSRichard Henderson * If provided, use a stub already in userspace. 167*79d6f2baSRichard Henderson */ 1684c4c73e3SLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 169*79d6f2baSRichard Henderson restorer = ka->sa_restorer; 1704c4c73e3SLaurent Vivier } else { 171*79d6f2baSRichard Henderson restorer = frame_addr + offsetof(sigframe, retcode); 1724c4c73e3SLaurent Vivier __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, 173cb1f1982SRichard Henderson &frame->retcode); 1744c4c73e3SLaurent Vivier } 1754c4c73e3SLaurent Vivier 1764c4c73e3SLaurent Vivier /* Set up registers for signal handler */ 177*79d6f2baSRichard Henderson env->regs[14] = restorer; 1784c4c73e3SLaurent Vivier env->regs[15] = frame_addr; 1797e535557SRichard Henderson /* Force default amode and default user address space control. */ 1807e535557SRichard Henderson env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY 1817e535557SRichard Henderson | (env->psw.mask & ~PSW_MASK_ASC); 182915c69dcSRichard Henderson env->psw.addr = ka->_sa_handler; 1834c4c73e3SLaurent Vivier 1846c18757dSRichard Henderson env->regs[2] = sig; 185ac1a92ecSRichard Henderson env->regs[3] = frame_addr + offsetof(typeof(*frame), sc); 1864c4c73e3SLaurent Vivier 1876c18757dSRichard Henderson /* 1886c18757dSRichard Henderson * We forgot to include these in the sigcontext. 1896c18757dSRichard Henderson * To avoid breaking binary compatibility, they are passed as args. 1906c18757dSRichard Henderson */ 1916c18757dSRichard Henderson env->regs[4] = 0; /* FIXME: regs->int_code & 127 */ 1926c18757dSRichard Henderson env->regs[5] = 0; /* FIXME: regs->int_parm_long */ 1936c18757dSRichard Henderson env->regs[6] = 0; /* FIXME: current->thread.last_break */ 1944c4c73e3SLaurent Vivier 1954c4c73e3SLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 1964c4c73e3SLaurent Vivier } 1974c4c73e3SLaurent Vivier 1984c4c73e3SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 1994c4c73e3SLaurent Vivier target_siginfo_t *info, 2004c4c73e3SLaurent Vivier target_sigset_t *set, CPUS390XState *env) 2014c4c73e3SLaurent Vivier { 2024c4c73e3SLaurent Vivier rt_sigframe *frame; 2034c4c73e3SLaurent Vivier abi_ulong frame_addr; 204*79d6f2baSRichard Henderson abi_ulong restorer; 2054c4c73e3SLaurent Vivier 2064c4c73e3SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof *frame); 2074c4c73e3SLaurent Vivier trace_user_setup_rt_frame(env, frame_addr); 2084c4c73e3SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 20920807348SRichard Henderson force_sigsegv(sig); 21020807348SRichard Henderson return; 2114c4c73e3SLaurent Vivier } 2124c4c73e3SLaurent Vivier 213*79d6f2baSRichard Henderson /* Set up backchain. */ 214*79d6f2baSRichard Henderson __put_user(env->regs[15], (abi_ulong *) frame); 2154c4c73e3SLaurent Vivier 216*79d6f2baSRichard Henderson /* 217*79d6f2baSRichard Henderson * Set up to return from userspace. 218*79d6f2baSRichard Henderson * If provided, use a stub already in userspace. 219*79d6f2baSRichard Henderson */ 2204c4c73e3SLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 221*79d6f2baSRichard Henderson restorer = ka->sa_restorer; 2224c4c73e3SLaurent Vivier } else { 223*79d6f2baSRichard Henderson restorer = frame_addr + offsetof(typeof(*frame), retcode); 2244c4c73e3SLaurent Vivier __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, 225cb1f1982SRichard Henderson &frame->retcode); 2264c4c73e3SLaurent Vivier } 2274c4c73e3SLaurent Vivier 228*79d6f2baSRichard Henderson /* Create siginfo on the signal stack. */ 229*79d6f2baSRichard Henderson tswap_siginfo(&frame->info, info); 230*79d6f2baSRichard Henderson 231*79d6f2baSRichard Henderson /* Create ucontext on the signal stack. */ 232*79d6f2baSRichard Henderson __put_user(0, &frame->uc.tuc_flags); 233*79d6f2baSRichard Henderson __put_user(0, &frame->uc.tuc_link); 234*79d6f2baSRichard Henderson target_save_altstack(&frame->uc.tuc_stack, env); 235*79d6f2baSRichard Henderson save_sigregs(env, &frame->uc.tuc_mcontext); 236*79d6f2baSRichard Henderson tswap_sigset(&frame->uc.tuc_sigmask, set); 2374c4c73e3SLaurent Vivier 2384c4c73e3SLaurent Vivier /* Set up registers for signal handler */ 239*79d6f2baSRichard Henderson env->regs[14] = restorer; 2404c4c73e3SLaurent Vivier env->regs[15] = frame_addr; 2417e535557SRichard Henderson /* Force default amode and default user address space control. */ 2427e535557SRichard Henderson env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY 2437e535557SRichard Henderson | (env->psw.mask & ~PSW_MASK_ASC); 244915c69dcSRichard Henderson env->psw.addr = ka->_sa_handler; 2454c4c73e3SLaurent Vivier 2466c18757dSRichard Henderson env->regs[2] = sig; 2474c4c73e3SLaurent Vivier env->regs[3] = frame_addr + offsetof(typeof(*frame), info); 2484c4c73e3SLaurent Vivier env->regs[4] = frame_addr + offsetof(typeof(*frame), uc); 2496c18757dSRichard Henderson env->regs[5] = 0; /* FIXME: current->thread.last_break */ 2504c4c73e3SLaurent Vivier } 2514c4c73e3SLaurent Vivier 252e6f960fcSRichard Henderson static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) 2534c4c73e3SLaurent Vivier { 254bd45be9fSRichard Henderson target_ulong prev_addr; 2554c4c73e3SLaurent Vivier int i; 2564c4c73e3SLaurent Vivier 2574c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 2584c4c73e3SLaurent Vivier __get_user(env->regs[i], &sc->regs.gprs[i]); 2594c4c73e3SLaurent Vivier } 2604c4c73e3SLaurent Vivier 261bd45be9fSRichard Henderson prev_addr = env->psw.addr; 2624c4c73e3SLaurent Vivier __get_user(env->psw.mask, &sc->regs.psw.mask); 2634c4c73e3SLaurent Vivier __get_user(env->psw.addr, &sc->regs.psw.addr); 264bd45be9fSRichard Henderson trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr); 2654c4c73e3SLaurent Vivier 2664c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 2674c4c73e3SLaurent Vivier __get_user(env->aregs[i], &sc->regs.acrs[i]); 2684c4c73e3SLaurent Vivier } 2694c4c73e3SLaurent Vivier for (i = 0; i < 16; i++) { 2704f83d7d2SDavid Hildenbrand __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]); 2714c4c73e3SLaurent Vivier } 2724c4c73e3SLaurent Vivier } 2734c4c73e3SLaurent Vivier 2744c4c73e3SLaurent Vivier long do_sigreturn(CPUS390XState *env) 2754c4c73e3SLaurent Vivier { 2764c4c73e3SLaurent Vivier sigframe *frame; 2774c4c73e3SLaurent Vivier abi_ulong frame_addr = env->regs[15]; 2784c4c73e3SLaurent Vivier target_sigset_t target_set; 2794c4c73e3SLaurent Vivier sigset_t set; 2804c4c73e3SLaurent Vivier 2814c4c73e3SLaurent Vivier trace_user_do_sigreturn(env, frame_addr); 2824c4c73e3SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 28320807348SRichard Henderson force_sig(TARGET_SIGSEGV); 28420807348SRichard Henderson return -TARGET_QEMU_ESIGRETURN; 2854c4c73e3SLaurent Vivier } 2869e0fb648SRichard Henderson 2879e0fb648SRichard Henderson /* Make sure that we're initializing all of target_set. */ 2889e0fb648SRichard Henderson QEMU_BUILD_BUG_ON(ARRAY_SIZE(target_set.sig) != 1); 2894c4c73e3SLaurent Vivier __get_user(target_set.sig[0], &frame->sc.oldmask[0]); 2904c4c73e3SLaurent Vivier 2914c4c73e3SLaurent Vivier target_to_host_sigset_internal(&set, &target_set); 2924c4c73e3SLaurent Vivier set_sigmask(&set); /* ~_BLOCKABLE? */ 2934c4c73e3SLaurent Vivier 294e6f960fcSRichard Henderson restore_sigregs(env, &frame->sregs); 2954c4c73e3SLaurent Vivier 2964c4c73e3SLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 2974c4c73e3SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 2984c4c73e3SLaurent Vivier } 2994c4c73e3SLaurent Vivier 3004c4c73e3SLaurent Vivier long do_rt_sigreturn(CPUS390XState *env) 3014c4c73e3SLaurent Vivier { 3024c4c73e3SLaurent Vivier rt_sigframe *frame; 3034c4c73e3SLaurent Vivier abi_ulong frame_addr = env->regs[15]; 3044c4c73e3SLaurent Vivier sigset_t set; 3054c4c73e3SLaurent Vivier 3064c4c73e3SLaurent Vivier trace_user_do_rt_sigreturn(env, frame_addr); 3074c4c73e3SLaurent Vivier if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 30820807348SRichard Henderson force_sig(TARGET_SIGSEGV); 30920807348SRichard Henderson return -TARGET_QEMU_ESIGRETURN; 3104c4c73e3SLaurent Vivier } 3114c4c73e3SLaurent Vivier target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 3124c4c73e3SLaurent Vivier 3134c4c73e3SLaurent Vivier set_sigmask(&set); /* ~_BLOCKABLE? */ 3144c4c73e3SLaurent Vivier 315e6f960fcSRichard Henderson restore_sigregs(env, &frame->uc.tuc_mcontext); 3164c4c73e3SLaurent Vivier 317ddc3e74dSRichard Henderson target_restore_altstack(&frame->uc.tuc_stack, env); 31856384cf3SRichard Henderson 3194c4c73e3SLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 3204c4c73e3SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 3214c4c73e3SLaurent Vivier } 322