From patchwork Tue Dec 17 11:52:26 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stacey Son X-Patchwork-Id: 302493 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 94D5E2C00B8 for ; Wed, 18 Dec 2013 08:08:19 +1100 (EST) Received: from localhost ([::1]:35463 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1sG-00049C-KG for incoming@patchwork.ozlabs.org; Tue, 17 Dec 2013 16:08:16 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58303) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1g9-0007tH-Go for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:55:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Vt1fu-0002C8-H1 for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:55:45 -0500 Received: from cdptpa-omtalb.mail.rr.com ([75.180.132.120]:59887) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Vt1ft-00029Q-IG for qemu-devel@nongnu.org; Tue, 17 Dec 2013 15:55:30 -0500 X-Authority-Analysis: v=2.0 cv=dq5Z+ic4 c=1 sm=0 a=Hbpc8ax9VmIgqBixU/K2CA==:17 a=t8buS8aMOPwA:10 a=dBRESv0yCI8A:10 a=ozSPa0bqj5AA:10 a=6I5d2MoRAAAA:8 a=KGjhK52YXX0A:10 a=hnPrfKq_EtYA:10 a=mDV3o1hIAAAA:8 a=GyPf67-kd_892WQb7RkA:9 a=Lu4Kfm9P2UW-SkPi:21 a=mBs5cCpMqzDtAzt2:21 a=6-qVcZ9Iiv6Eg7EH:21 a=Hbpc8ax9VmIgqBixU/K2CA==:117 X-Cloudmark-Score: 0 X-Authenticated-User: X-Originating-IP: 76.187.139.93 Received: from [76.187.139.93] ([76.187.139.93:62490] helo=son.org) by cdptpa-oedge03.mail.rr.com (envelope-from ) (ecelerity 2.2.3.46 r()) with ESMTP id 06/9A-21884-04AB0B25; Tue, 17 Dec 2013 20:55:28 +0000 Received: from son.org (localhost [127.0.0.1]) by son.org (8.14.7/8.14.7) with ESMTP id rBHBqwWx065888; Tue, 17 Dec 2013 05:52:58 -0600 (CST) (envelope-from sson@son.org) Received: (from sson@localhost) by son.org (8.14.7/8.14.7/Submit) id rBHBqwjZ065887; Tue, 17 Dec 2013 05:52:58 -0600 (CST) (envelope-from sson) From: Stacey Son To: qemu-devel@nongnu.org Date: Tue, 17 Dec 2013 05:52:26 -0600 Message-Id: <1387281158-65744-8-git-send-email-sson@FreeBSD.org> X-Mailer: git-send-email 1.7.8 In-Reply-To: <1387281158-65744-1-git-send-email-sson@FreeBSD.org> References: <1387281158-65744-1-git-send-email-sson@FreeBSD.org> In-Reply-To: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> References: <1383928417-38009-1-git-send-email-sson@FreeBSD.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 75.180.132.120 Cc: Stacey Son Subject: [Qemu-devel] [PATCH v3 07/19] bsd-user: add support for freebsd signal related system calls X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This change adds support or stubs for signal related system calls including sigtimedwait(2), sigaction(2), sigprocmask(2), sigpending(2), sigsuspend(2), sigreturn(2), sigwait(2), sigwaitinfo(2), sigqueue(2), sigaltstack(2), kill(2), killpg(2), and pdkill(2). --- bsd-user/arm/target_arch_signal.h | 257 ++++++++++ bsd-user/bsd-signal.h | 232 +++++++++ bsd-user/errno_defs.h | 13 +- bsd-user/freebsd/os-signal.h | 43 ++ bsd-user/freebsd/target_os_siginfo.h | 110 ++++ bsd-user/freebsd/target_os_signal.h | 79 +++ bsd-user/i386/target_arch_signal.h | 94 ++++ bsd-user/mips/target_arch_signal.h | 237 +++++++++ bsd-user/mips64/target_arch_signal.h | 214 ++++++++ bsd-user/netbsd/target_os_siginfo.h | 82 +++ bsd-user/netbsd/target_os_signal.h | 70 +++ bsd-user/openbsd/target_os_siginfo.h | 82 +++ bsd-user/openbsd/target_os_signal.h | 70 +++ bsd-user/qemu.h | 33 +- bsd-user/signal.c | 907 ++++++++++++++++++++++++++++++++- bsd-user/sparc/target_arch_signal.h | 77 +++ bsd-user/sparc64/target_arch_signal.h | 94 ++++ bsd-user/syscall.c | 59 +++ bsd-user/x86_64/target_arch_signal.h | 94 ++++ 19 files changed, 2830 insertions(+), 17 deletions(-) create mode 100644 bsd-user/arm/target_arch_signal.h create mode 100644 bsd-user/bsd-signal.h create mode 100644 bsd-user/freebsd/os-signal.h create mode 100644 bsd-user/freebsd/target_os_siginfo.h create mode 100644 bsd-user/freebsd/target_os_signal.h create mode 100644 bsd-user/i386/target_arch_signal.h create mode 100644 bsd-user/mips/target_arch_signal.h create mode 100644 bsd-user/mips64/target_arch_signal.h create mode 100644 bsd-user/netbsd/target_os_siginfo.h create mode 100644 bsd-user/netbsd/target_os_signal.h create mode 100644 bsd-user/openbsd/target_os_siginfo.h create mode 100644 bsd-user/openbsd/target_os_signal.h create mode 100644 bsd-user/sparc/target_arch_signal.h create mode 100644 bsd-user/sparc64/target_arch_signal.h create mode 100644 bsd-user/x86_64/target_arch_signal.h diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h new file mode 100644 index 0000000..048bd4f --- /dev/null +++ b/bsd-user/arm/target_arch_signal.h @@ -0,0 +1,257 @@ +/* + * arm signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_ARCH_SIGNAL_H_ +#define _TARGET_ARCH_SIGNAL_H_ + +#include "cpu.h" + +#define TARGET_REG_R0 0 +#define TARGET_REG_R1 1 +#define TARGET_REG_R2 2 +#define TARGET_REG_R3 3 +#define TARGET_REG_R4 4 +#define TARGET_REG_R5 5 +#define TARGET_REG_R6 6 +#define TARGET_REG_R7 7 +#define TARGET_REG_R8 8 +#define TARGET_REG_R9 9 +#define TARGET_REG_R10 10 +#define TARGET_REG_R11 11 +#define TARGET_REG_R12 12 +#define TARGET_REG_R13 13 +#define TARGET_REG_R14 14 +#define TARGET_REG_R15 15 +#define TARGET_REG_CPSR 16 +#define TARGET__NGREG 17 +/* Convenience synonyms */ +#define TARGET_REG_FP TARGET_REG_R11 +#define TARGET_REG_SP TARGET_REG_R13 +#define TARGET_REG_LR TARGET_REG_R14 +#define TARGET_REG_PC TARGET_REG_R15 + +#define TARGET_INSN_SIZE 4 /* arm instruction size */ + +/* Size of the signal trampolin code. See _sigtramp(). */ +#define TARGET_SZSIGCODE ((abi_ulong)(8 * TARGET_INSN_SIZE)) + +/* compare to arm/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */ + +/* arm/arm/machdep.c */ +#define TARGET_MC_GET_CLEAR_RET 0x0001 +#define TARGET_MC_ADD_MAGIC 0x0002 +#define TARGET_MC_SET_ONSTACK 0x0004 + +struct target_sigcontext { + target_sigset_t sc_mask; /* signal mask to retstore */ + int32_t sc_onstack; /* sigstack state to restore */ + abi_long sc_pc; /* pc at time of signal */ + abi_long sc_reg[32]; /* processor regs 0 to 31 */ + abi_long mullo, mulhi; /* mullo and mulhi registers */ + int32_t sc_fpused; /* fp has been used */ + abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ + abi_long sc_fpc_eir; /* fp exception instr reg */ + /* int32_t reserved[8]; */ +}; + +typedef struct { + uint32_t __fp_fpsr; + struct { + uint32_t __fp_exponent; + uint32_t __fp_mantissa_hi; + uint32_t __fp_mantissa_lo; + } __fp_fr[8]; +} target__fpregset_t; + +typedef struct { + uint32_t __vfp_fpscr; + uint32_t __vfp_fstmx[33]; + uint32_t __vfp_fpsid; +} target__vfpregset_t; + +typedef struct target_mcontext { + uint32_t __gregs[TARGET__NGREG]; + union { + target__fpregset_t __fpregs; + target__vfpregset_t __vfpregs; + } __fpu; +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + target_siginfo_t sf_si; /* saved siginfo */ + target_ucontext_t sf_uc; /* saved ucontext */ +}; + + +/* compare to sys/arm/include/frame.h */ +struct target_trapframe { + abi_ulong tf_spsr; /* Zero on arm26 */ + abi_ulong tf_r0; + abi_ulong tf_r1; + abi_ulong tf_r2; + abi_ulong tf_r3; + abi_ulong tf_r4; + abi_ulong tf_r5; + abi_ulong tf_r6; + abi_ulong tf_r7; + abi_ulong tf_r8; + abi_ulong tf_r9; + abi_ulong tf_r10; + abi_ulong tf_r11; + abi_ulong tf_r12; + abi_ulong tf_usr_sp; + abi_ulong tf_usr_lr; + abi_ulong tf_svc_sp; /* Not used on arm26 */ + abi_ulong tf_svc_lr; /* Not used on arm26 */ + abi_ulong tf_pc; +}; + +/* + * Compare to arm/arm/machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long +set_sigtramp_args(CPUARMState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) +{ + /* + * Arguments to signal handler: + * r0 = signal number + * r1 = siginfo pointer + * r2 = ucontext pointer + * r5 = ucontext pointer + * pc = signal handler pointer + * sp = sigframe struct pointer + * lr = sigtramp at base of user stack + */ + + regs->regs[0] = sig; + regs->regs[1] = frame_addr + + offsetof(struct target_sigframe, sf_si); + regs->regs[2] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + + /* the trampoline uses r5 as the uc address */ + regs->regs[5] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + regs->regs[TARGET_REG_PC] = ka->_sa_handler; + regs->regs[TARGET_REG_SP] = frame_addr; + regs->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + + return 0; +} + +/* + * Compare to arm/arm/machdep.c get_mcontext() + * Assumes that the memory is locked if mcp points to user memory. + */ +static inline abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp, + int flags) +{ + int err = 0; + uint32_t *gr = mcp->__gregs; + + + if (flags & TARGET_MC_GET_CLEAR_RET) { + gr[TARGET_REG_R0] = 0; + } else { + gr[TARGET_REG_R0] = tswap32(regs->regs[0]); + } + + gr[TARGET_REG_R1] = tswap32(regs->regs[1]); + gr[TARGET_REG_R2] = tswap32(regs->regs[2]); + gr[TARGET_REG_R3] = tswap32(regs->regs[3]); + gr[TARGET_REG_R4] = tswap32(regs->regs[4]); + gr[TARGET_REG_R5] = tswap32(regs->regs[5]); + gr[TARGET_REG_R6] = tswap32(regs->regs[6]); + gr[TARGET_REG_R7] = tswap32(regs->regs[7]); + gr[TARGET_REG_R8] = tswap32(regs->regs[8]); + gr[TARGET_REG_R9] = tswap32(regs->regs[9]); + gr[TARGET_REG_R10] = tswap32(regs->regs[10]); + gr[TARGET_REG_R11] = tswap32(regs->regs[11]); + gr[TARGET_REG_R12] = tswap32(regs->regs[12]); + + gr[TARGET_REG_SP] = tswap32(regs->regs[13]); + gr[TARGET_REG_LR] = tswap32(regs->regs[14]); + gr[TARGET_REG_PC] = tswap32(regs->regs[15]); + gr[TARGET_REG_CPSR] = tswap32(cpsr_read(regs)); + + return err; +} + +/* Compare to arm/arm/machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp, + int srflag) +{ + int err = 0; + const uint32_t *gr = mcp->__gregs; + uint32_t cpsr; + + regs->regs[0] = tswap32(gr[TARGET_REG_R0]); + regs->regs[1] = tswap32(gr[TARGET_REG_R1]); + regs->regs[2] = tswap32(gr[TARGET_REG_R2]); + regs->regs[3] = tswap32(gr[TARGET_REG_R3]); + regs->regs[4] = tswap32(gr[TARGET_REG_R4]); + regs->regs[5] = tswap32(gr[TARGET_REG_R5]); + regs->regs[6] = tswap32(gr[TARGET_REG_R6]); + regs->regs[7] = tswap32(gr[TARGET_REG_R7]); + regs->regs[8] = tswap32(gr[TARGET_REG_R8]); + regs->regs[9] = tswap32(gr[TARGET_REG_R9]); + regs->regs[10] = tswap32(gr[TARGET_REG_R10]); + regs->regs[11] = tswap32(gr[TARGET_REG_R11]); + regs->regs[12] = tswap32(gr[TARGET_REG_R12]); + + regs->regs[13] = tswap32(gr[TARGET_REG_SP]); + regs->regs[14] = tswap32(gr[TARGET_REG_LR]); + regs->regs[15] = tswap32(gr[TARGET_REG_PC]); + cpsr = tswap32(gr[TARGET_REG_CPSR]); + cpsr_write(regs, cpsr, CPSR_USER | CPSR_EXEC); + + return err; +} + +/* Compare to arm/arm/machdep.c sys_sigreturn() */ +static inline abi_long get_ucontext_sigreturn(CPUARMState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + uint32_t cpsr = cpsr_read(regs); + + *target_uc = 0; + + if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR || + (cpsr & (CPSR_I | CPSR_F)) != 0) { + return -TARGET_EINVAL; + } + + *target_uc = target_sf + offsetof(struct target_sigframe, sf_uc); + + return 0; +} + + +#endif /* !_TARGET_ARCH_SIGNAL_H_ */ diff --git a/bsd-user/bsd-signal.h b/bsd-user/bsd-signal.h new file mode 100644 index 0000000..48a8b56 --- /dev/null +++ b/bsd-user/bsd-signal.h @@ -0,0 +1,232 @@ +/* + * signal related system call shims + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __BSD_SIGNAL_H_ +#define __BSD_SIGNAL_H_ + +/* sigaction(2) */ +static inline abi_long do_bsd_sigaction(abi_long arg1, abi_long arg2, + abi_long arg3) +{ + abi_long ret; + struct target_sigaction *old_act, act, oact, *pact; + + if (arg2) { + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) { + return -TARGET_EFAULT; + } + act._sa_handler = old_act->_sa_handler; + act.sa_flags = old_act->sa_flags; + memcpy(&act.sa_mask, &old_act->sa_mask, sizeof(target_sigset_t)); + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) { + return -TARGET_EFAULT; + } + old_act->_sa_handler = oact._sa_handler; + old_act->sa_flags = oact.sa_flags; + memcpy(&old_act->sa_mask, &oact.sa_mask, sizeof(target_sigset_t)); + unlock_user_struct(old_act, arg3, 1); + } + return ret; +} + + +/* sigprocmask(2) */ +static inline abi_long do_bsd_sigprocmask(abi_long arg1, abi_ulong arg2, + abi_ulong arg3) +{ + abi_long ret; + void *p; + sigset_t set, oldset, *set_ptr; + int how; + + if (arg2) { + switch (arg1) { + case TARGET_SIG_BLOCK: + how = SIG_BLOCK; + break; + + case TARGET_SIG_UNBLOCK: + how = SIG_UNBLOCK; + break; + + case TARGET_SIG_SETMASK: + how = SIG_SETMASK; + break; + + default: + return -TARGET_EFAULT; + } + p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, arg2, 0); + set_ptr = &set; + } else { + how = 0; + set_ptr = NULL; + } + ret = get_errno(sigprocmask(how, set_ptr, &oldset)); + if (!is_error(ret) && arg3) { + p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + host_to_target_sigset(p, &oldset); + unlock_user(p, arg3, sizeof(target_sigset_t)); + } + return ret; +} + +/* sigpending(2) */ +static inline abi_long do_bsd_sigpending(abi_long arg1) +{ + abi_long ret; + void *p; + sigset_t set; + + ret = get_errno(sigpending(&set)); + if (!is_error(ret)) { + p = lock_user(VERIFY_WRITE, arg1, sizeof(target_sigset_t), 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + host_to_target_sigset(p, &set); + unlock_user(p, arg1, sizeof(target_sigset_t)); + } + return ret; +} + +/* sigsuspend(2) */ +static inline abi_long do_bsd_sigsuspend(abi_long arg1, abi_long arg2) +{ + void *p; + sigset_t set; + + p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + + return get_errno(sigsuspend(&set)); +} + +/* sigreturn(2) */ +static inline abi_long do_bsd_sigreturn(void *cpu_env, abi_long arg1) +{ + + return do_sigreturn(cpu_env, arg1); +} + +/* sigvec(2) - not defined */ +/* sigblock(2) - not defined */ +/* sigsetmask(2) - not defined */ +/* sigstack(2) - not defined */ + +/* sigwait(2) */ +static inline abi_long do_bsd_sigwait(abi_ulong arg1, abi_ulong arg2, + abi_long arg3) +{ + abi_long ret; + void *p; + sigset_t set; + int sig; + + p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + ret = get_errno(sigwait(&set, &sig)); + if (!is_error(ret) && arg2) { + ret = put_user_s32(sig, arg2); + } + return ret; +} + +/* sigwaitinfo(2) */ +static inline abi_long do_bsd_sigwaitinfo(abi_ulong arg1, abi_ulong arg2) +{ + abi_long ret; + void *p; + sigset_t set; + siginfo_t uinfo; + + p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1); + if (p == NULL) { + return -TARGET_EFAULT; + } + target_to_host_sigset(&set, p); + unlock_user(p, arg1, 0); + ret = get_errno(sigwaitinfo(&set, &uinfo)); + if (!is_error(ret) && arg2) { + p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0); + if (p == NULL) { + return -TARGET_EFAULT; + } + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_siginfo_t)); + } + return ret; +} + +/* sigqueue(2) */ +static inline abi_long do_bsd_sigqueue(abi_long arg1, abi_long arg2, + abi_ulong arg3) +{ + union sigval value; + + value.sival_ptr = (void *)(uintptr_t)arg3; + return get_errno(sigqueue(arg1, target_to_host_signal(arg2), value)); +} + +/* sigaltstck(2) */ +static inline abi_long do_bsd_sigaltstack(void *cpu_env, abi_ulong arg1, + abi_ulong arg2) +{ + + return do_sigaltstack(arg1, arg2, get_sp_from_cpustate(cpu_env)); +} + +/* kill(2) */ +static inline abi_long do_bsd_kill(abi_long pid, abi_long sig) +{ + + return get_errno(kill(pid, target_to_host_signal(sig))); +} + +/* killpg(2) */ +static inline abi_long do_bsd_killpg(abi_long pg, abi_long sig) +{ + + return get_errno(killpg(pg, target_to_host_signal(sig))); +} + +#endif /* ! __BSD_SIGNAL_H_ */ diff --git a/bsd-user/errno_defs.h b/bsd-user/errno_defs.h index 1efa502..f01181d 100644 --- a/bsd-user/errno_defs.h +++ b/bsd-user/errno_defs.h @@ -1,6 +1,3 @@ -/* $OpenBSD: errno.h,v 1.20 2007/09/03 14:37:52 millert Exp $ */ -/* $NetBSD: errno.h,v 1.10 1996/01/20 01:33:53 jtc Exp $ */ - /* * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -37,6 +34,9 @@ * @(#)errno.h 8.5 (Berkeley) 1/21/94 */ +#ifndef _ERRNO_DEFS_H_ +#define _ERRNO_DEFS_H_ + #define TARGET_EPERM 1 /* Operation not permitted */ #define TARGET_ENOENT 2 /* No such file or directory */ #define TARGET_ESRCH 3 /* No such process */ @@ -147,3 +147,10 @@ #define TARGET_EIDRM 89 /* Identifier removed */ #define TARGET_ENOMSG 90 /* No message of desired type */ #define TARGET_ELAST 90 /* Must be equal largest errno */ + +/* Internal errors: */ +#define TARGET_EJUSTRETURN 254 /* Just return without + modifing regs */ +#define TARGET_ERESTART 255 /* Restart syscall */ + +#endif /* ! _ERRNO_DEFS_H_ */ diff --git a/bsd-user/freebsd/os-signal.h b/bsd-user/freebsd/os-signal.h new file mode 100644 index 0000000..d4a26da --- /dev/null +++ b/bsd-user/freebsd/os-signal.h @@ -0,0 +1,43 @@ +/* + * FreeBSD signal system call shims + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __FREEBSD_OS_SIGNAL_H_ +#define __FREEBSD_OS_SIGNAL_H_ + +#include + +#if defined(__FreeBSD_version) && __FreeBSD_version > 900000 +/* pdkill(2) */ +static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2) +{ + + return get_errno(pdkill(arg1, arg2)); +} + +#else + +static inline abi_long do_freebsd_pdkill(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall pdkill()\n"); + return -TARGET_ENOSYS; +} +#endif /* ! __FreeBSD_version > 900000 */ + +#endif /* ! __FREEBSD_OS_SIGNAL_H_ */ diff --git a/bsd-user/freebsd/target_os_siginfo.h b/bsd-user/freebsd/target_os_siginfo.h new file mode 100644 index 0000000..39180ec --- /dev/null +++ b/bsd-user/freebsd/target_os_siginfo.h @@ -0,0 +1,110 @@ +/* + * FreeBSD siginfo related definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_OS_SIGINFO_H_ +#define _TARGET_OS_SIGINFO_H_ + +#define TARGET_NSIG 128 +#define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + +typedef struct { + uint32_t __bits[TARGET_NSIG_WORDS]; +} target_sigset_t; + +struct target_sigaction { + abi_ulong _sa_handler; + int32_t sa_flags; + target_sigset_t sa_mask; +}; + +union target_sigval { + int32_t sival_int; + abi_ulong sival_ptr; + int32_t sigval_int; + abi_ulong sigval_ptr; +}; + +typedef struct target_siginfo { + int32_t si_signo; /* signal number */ + int32_t si_errno; /* errno association */ + int32_t si_code; /* signal code */ + int32_t si_pid; /* sending process */ + int32_t si_uid; /* sender's ruid */ + int32_t si_status; /* exit value */ + abi_ulong si_addr; /* faulting instruction */ + union target_sigval si_value; /* signal value */ + union { + struct { + int32_t _trapno; /* machine specific trap code */ + } _fault; + + /* POSIX.1b timers */ + struct { + int32_t _timerid; + int32_t _overrun; + } _timer; + + struct { + int32_t _mqd; + } _mesgp; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + } _poll; + + struct { + abi_long __spare1__; + int32_t __spare2_[7]; + } __spare__; + } _reason; +} target_siginfo_t; + +#define target_si_signo si_signo +#define target_si_code si_code +#define target_si_errno si_errno +#define target_si_addr si_addr + +/* SIGILL si_codes */ +#define TARGET_ILL_ILLOPC (1) /* Illegal opcode. */ +#define TARGET_ILL_ILLOPN (2) /* Illegal operand. */ +#define TARGET_ILL_ILLADR (3) /* Illegal addressing mode. */ +#define TARGET_ILL_ILLTRP (4) /* Illegal trap. */ +#define TARGET_ILL_PRVOPC (5) /* Privileged opcode. */ +#define TARGET_ILL_PRVREG (6) /* Privileged register. */ +#define TARGET_ILL_COPROC (7) /* Coprocessor error. */ +#define TARGET_ILL_BADSTK (8) /* Internal stack error. */ + +/* SIGSEGV si_codes */ +#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */ +#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped + object */ + +/* SIGTRAP si_codes */ +#define TARGET_TRAP_BRKPT (1) /* process beakpoint */ +#define TARGET_TRAP_TRACE (2) /* process trace trap */ + +#endif /* !_TARGET_OS_SIGINFO_H_ */ diff --git a/bsd-user/freebsd/target_os_signal.h b/bsd-user/freebsd/target_os_signal.h new file mode 100644 index 0000000..d7004c8 --- /dev/null +++ b/bsd-user/freebsd/target_os_signal.h @@ -0,0 +1,79 @@ +#ifndef _TARGET_OS_SIGNAL_H_ +#define _TARGET_OS_SIGNAL_H_ + +#include "target_os_siginfo.h" +#include "target_arch_signal.h" + +/* Compare to sys/signal.h */ +#define TARGET_SIGHUP 1 /* hangup */ +#define TARGET_SIGINT 2 /* interrupt */ +#define TARGET_SIGQUIT 3 /* quit */ +#define TARGET_SIGILL 4 /* illegal instruction (not reset when caught) */ +#define TARGET_SIGTRAP 5 /* trace trap (not reset when caught) */ +#define TARGET_SIGABRT 6 /* abort() */ +#define TARGET_SIGIOT SIGABRT /* compatibility */ +#define TARGET_SIGEMT 7 /* EMT instruction */ +#define TARGET_SIGFPE 8 /* floating point exception */ +#define TARGET_SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define TARGET_SIGBUS 10 /* bus error */ +#define TARGET_SIGSEGV 11 /* segmentation violation */ +#define TARGET_SIGSYS 12 /* bad argument to system call */ +#define TARGET_SIGPIPE 13 /* write on a pipe with no one to read it */ +#define TARGET_SIGALRM 14 /* alarm clock */ +#define TARGET_SIGTERM 15 /* software termination signal from kill */ +#define TARGET_SIGURG 16 /* urgent condition on IO channel */ +#define TARGET_SIGSTOP 17 /* sendable stop signal not from tty */ +#define TARGET_SIGTSTP 18 /* stop signal from tty */ +#define TARGET_SIGCONT 19 /* continue a stopped process */ +#define TARGET_SIGCHLD 20 /* to parent on child stop or exit */ +#define TARGET_SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define TARGET_SIGTTOU 22 /* like TTIN for output if(tp->t_local<OSTOP)*/ +#define TARGET_SIGIO 23 /* input/output possible signal */ +#define TARGET_SIGXCPU 24 /* exceeded CPU time limit */ +#define TARGET_SIGXFSZ 25 /* exceeded file size limit */ +#define TARGET_SIGVTALRM 26 /* virtual time alarm */ +#define TARGET_SIGPROF 27 /* profiling time alarm */ +#define TARGET_SIGWINCH 28 /* window size changes */ +#define TARGET_SIGINFO 29 /* information request */ +#define TARGET_SIGUSR1 30 /* user defined signal 1 */ +#define TARGET_SIGUSR2 31 /* user defined signal 2 */ +#define TARGET_SIGTHR 32 /* reserved by thread library */ +#define TARGET_SIGLWP SIGTHR /* compatibility */ +#define TARGET_SIGLIBRT 33 /* reserved by the real-time library */ +#define TARGET_SIGRTMIN 65 +#define TARGET_SIGRTMAX 126 +#define TARGET_QEMU_ESIGRETURN 255 /* fake errno value for use by sigreturn */ + +/* + * Language spec says we must list exactly one parameter, even though we + * actually supply three. Ugh! + */ +#define TARGET_SIG_DFL ((abi_long)0) /* default signal handling */ +#define TARGET_SIG_IGN ((abi_long)1) /* ignore signal */ +#define TARGET_SIG_ERR ((abi_long)-1) /* error return from signal */ + +#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */ +#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */ +#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ +#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1) */ +#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */ +#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ +#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */ + +/* + * Flags for sigprocmask: + */ +#define TARGET_SIG_BLOCK 1 /* block specified signal set */ +#define TARGET_SIG_UNBLOCK 2 /* unblock specified signal set */ +#define TARGET_SIG_SETMASK 3 /* set specified signal set */ + +#define TARGET_BADSIG SIG_ERR + +/* + * sigaltstack control + */ +#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ +#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack*/ + +#endif /* !_TARGET_OS_SIGNAL_H_ */ diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h new file mode 100644 index 0000000..e2387b2 --- /dev/null +++ b/bsd-user/i386/target_arch_signal.h @@ -0,0 +1,94 @@ +/* + * i386 dependent signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H + +#include "cpu.h" + +/* Size of the signal trampolin code placed on the stack. */ +/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */ + +/* compare to x86/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */ + +#define TARGET_MC_GET_CLEAR_RET 0x0001 + +struct target_sigcontext { + /* to be added */ +}; + +typedef struct target_mcontext { +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to i386/i386/machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long set_sigtramp_args(CPUX86State *regs, + int sig, struct target_sigframe *frame, abi_ulong frame_addr, + struct target_sigaction *ka) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to i386/i386/machdep.c get_mcontext() */ +static inline abi_long get_mcontext(CPUX86State *regs, + target_mcontext_t *mcp, int flags) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to i386/i386/machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUX86State *regs, + target_mcontext_t *mcp, int srflag) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +static inline abi_long get_ucontext_sigreturn(CPUX86State *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + /* XXX */ + *target_uc = 0; + return -TARGET_EOPNOTSUPP; +} + +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h new file mode 100644 index 0000000..79d6f65 --- /dev/null +++ b/bsd-user/mips/target_arch_signal.h @@ -0,0 +1,237 @@ +/* + * mips signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_ARCH_SIGNAL_H_ +#define _TARGET_ARCH_SIGNAL_H_ + +#include "cpu.h" + +#define TARGET_INSN_SIZE 4 /* mips instruction size */ + +/* Size of the signal trampolin code. See insall_sigtramp(). */ +#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE)) + +/* compare to mips/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */ + +/* compare to sys/mips/include/asm.h */ +#define TARGET_SZREG 8 +#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4) + +/* mips/mips/pm_machdep.c */ +#define TARGET_UCONTEXT_MAGIC 0xACEDBADE +#define TARGET_MC_GET_CLEAR_RET 0x0001 +#define TARGET_MC_ADD_MAGIC 0x0002 +#define TARGET_MC_SET_ONSTACK 0x0004 + +struct target_sigcontext { + target_sigset_t sc_mask; /* signal mask to retstore */ + int32_t sc_onstack; /* sigstack state to restore */ + abi_long sc_pc; /* pc at time of signal */ + abi_long sc_reg[32]; /* processor regs 0 to 31 */ + abi_long mullo, mulhi; /* mullo and mulhi registers */ + int32_t sc_fpused; /* fp has been used */ + abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ + abi_long sc_fpc_eir; /* fp exception instr reg */ + /* int32_t reserved[8]; */ +}; + +typedef struct target_mcontext { + int32_t mc_onstack; /* sigstack state to restore */ + abi_long mc_pc; /* pc at time of signal */ + abi_long mc_regs[32]; /* process regs 0 to 31 */ + abi_long sr; /* status register */ + abi_long mullo, mulhi; + int32_t mc_fpused; /* fp has been used */ + abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ + abi_long mc_fpc_eir; /* fp exception instr reg */ + abi_ulong mc_tls; /* pointer to TLS area */ +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to mips/mips/pm_machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long +set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) +{ + + /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */ + + /* MIPS only struct target_sigframe members: */ + frame->sf_signum = sig; + frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si); + frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc); + + /* + * Arguments to signal handler: + * a0 ($4) = signal number + * a1 ($5) = siginfo pointer + * a2 ($6) = ucontext pointer + * PC = signal handler pointer + * t9 ($25) = signal handler pointer + * $29 = point to sigframe struct + * ra ($31) = sigtramp at base of user stack + */ + regs->active_tc.gpr[4] = sig; + regs->active_tc.gpr[5] = frame_addr + + offsetof(struct target_sigframe, sf_si); + regs->active_tc.gpr[6] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; + regs->active_tc.gpr[29] = frame_addr; + regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + + return 0; +} + +/* + * Compare to mips/mips/pm_machdep.c get_mcontext() + * Assumes that the memory is locked if mcp points to user memory. + */ +static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, + int flags) +{ + int i, err = 0; + + if (flags & TARGET_MC_ADD_MAGIC) { + mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC); + } else { + mcp->mc_regs[0] = 0; + } + + if (flags & TARGET_MC_SET_ONSTACK) { + mcp->mc_onstack = tswapal(1); + } else { + mcp->mc_onstack = 0; + } + + for (i = 1; i < 32; i++) { + mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]); + } + +#if 0 /* XXX FP is not used right now */ + abi_ulong used_fp = used_math() ? TARGET_MDTD_FPUSED : 0; + + mcp->mc_fpused = used_fp; + if (used_fp) { + preempt_disable(); + if (!is_fpu_owner()) { + own_fpu(); + for (i = 0; i < 33; i++) { + mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i]); + } + } + preempt_enable(); + } +#else + mcp->mc_fpused = 0; +#endif + + if (flags & TARGET_MC_GET_CLEAR_RET) { + mcp->mc_regs[2] = 0; /* v0 = 0 */ + mcp->mc_regs[3] = 0; /* v1 = 0 */ + mcp->mc_regs[7] = 0; /* a3 = 0 */ + } + + mcp->mc_pc = tswapal(regs->active_tc.PC); + mcp->mullo = tswapal(regs->active_tc.LO[0]); + mcp->mulhi = tswapal(regs->active_tc.HI[0]); + mcp->mc_tls = tswapal(regs->tls_value); + + /* Don't do any of the status and cause registers. */ + + return err; +} + +/* Compare to mips/mips/pm_machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, + int srflag) +{ + int i, err = 0; + + for (i = 1; i < 32; i++) { + regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]); + } + +#if 0 /* XXX FP is not used right now */ + abi_ulong used_fp = 0; + + used_fp = tswapal(mcp->mc_fpused) + conditional_used_math(used_fp); + + preempt_disabled(); + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + for (i = 0; i < 32; i++) { + regs->active_fpu.fpr[i] = tswapal(mcp->mc_fpregs[i]); + } + } else { + /* Signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + preempt_enable(); +#endif + + regs->CP0_EPC = tswapal(mcp->mc_pc); + regs->active_tc.LO[0] = tswapal(mcp->mullo); + regs->active_tc.HI[0] = tswapal(mcp->mulhi); + regs->tls_value = tswapal(mcp->mc_tls); + + if (srflag) { + /* doing sigreturn() */ + regs->active_tc.PC = regs->CP0_EPC; + regs->CP0_EPC = 0; /* XXX for nested signals ? */ + } + + /* Don't do any of the status and cause registers. */ + + return err; +} + +static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + + *target_uc = target_sf; + return 0; +} + + +#endif /* !_TARGET_ARCH_SIGNAL_H_ */ diff --git a/bsd-user/mips64/target_arch_signal.h b/bsd-user/mips64/target_arch_signal.h new file mode 100644 index 0000000..2f79a24 --- /dev/null +++ b/bsd-user/mips64/target_arch_signal.h @@ -0,0 +1,214 @@ +/* + * mips64 signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_ARCH_SIGNAL_H_ +#define _TARGET_ARCH_SIGNAL_H_ + +#include "cpu.h" + +#define TARGET_INSN_SIZE 4 /* mips64 instruction size */ + +/* Size of the signal trampolin code placed on the stack. */ +#define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE)) + +#define TARGET_MINSIGSTKSZ (512 * 4) +#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) + +/* compare to sys/mips/include/asm.h */ +#define TARGET_SZREG 8 +#define TARGET_CALLFRAME_SIZ (TARGET_SZREG * 4) + +/* mips/mips/pm_machdep.c */ +#define TARGET_UCONTEXT_MAGIC 0xACEDBADE +#define TARGET_MC_GET_CLEAR_RET 0x0001 +#define TARGET_MC_ADD_MAGIC 0x0002 +#define TARGET_MC_SET_ONSTACK 0x0004 + +struct target_sigcontext { + target_sigset_t sc_mask; /* signal mask to retstore */ + int32_t sc_onstack; /* sigstack state to restore */ + abi_long sc_pc; /* pc at time of signal */ + abi_long sc_reg[32]; /* processor regs 0 to 31 */ + abi_long mullo, mulhi; /* mullo and mulhi registers */ + int32_t sc_fpused; /* fp has been used */ + abi_long sc_fpregs[33]; /* fp regs 0 to 31 & csr */ + abi_long sc_fpc_eir; /* fp exception instr reg */ + /* int32_t reserved[8]; */ +}; + +typedef struct target_mcontext { + int32_t mc_onstack; /* sigstack state to restore */ + abi_long mc_pc; /* pc at time of signal */ + abi_long mc_regs[32]; /* process regs 0 to 31 */ + abi_long sr; /* status register */ + abi_long mullo, mulhi; + int32_t mc_fpused; /* fp has been used */ + abi_long mc_fpregs[33]; /* fp regs 0 to 32 & csr */ + abi_long mc_fpc_eir; /* fp exception instr reg */ + abi_ulong mc_tls; /* pointer to TLS area */ +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to mips/mips/pm_machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long +set_sigtramp_args(CPUMIPSState *regs, int sig, struct target_sigframe *frame, + abi_ulong frame_addr, struct target_sigaction *ka) +{ + + /* frame->sf_si.si_addr = regs->CP0_BadVAddr; */ + + /* MIPS only struct target_sigframe members: */ + frame->sf_signum = sig; + frame->sf_siginfo = frame_addr + offsetof(struct target_sigframe, sf_si); + frame->sf_ucontext = frame_addr + offsetof(struct target_sigframe, sf_uc); + + /* + * Arguments to signal handler: + * a0 ($4) = signal number + * a1 ($5) = siginfo pointer + * a2 ($6) = ucontext pointer + * PC = signal handler pointer + * t9 ($25) = signal handler pointer + * $29 = point to sigframe struct + * ra ($31) = sigtramp at base of user stack + */ + regs->active_tc.gpr[4] = sig; + regs->active_tc.gpr[5] = frame_addr + + offsetof(struct target_sigframe, sf_si); + regs->active_tc.gpr[6] = frame_addr + + offsetof(struct target_sigframe, sf_uc); + regs->active_tc.gpr[25] = regs->active_tc.PC = ka->_sa_handler; + regs->active_tc.gpr[29] = frame_addr; + regs->active_tc.gpr[31] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; + + return 0; +} + +/* + * Compare to mips/mips/pm_machdep.c get_mcontext() + * Assumes that the memory is locked if mcp points to user memory. + */ +static inline abi_long get_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, + int flags) +{ + int i, err = 0; + + if (flags & TARGET_MC_ADD_MAGIC) { + mcp->mc_regs[0] = tswapal(TARGET_UCONTEXT_MAGIC); + } else { + mcp->mc_regs[0] = 0; + } + + if (flags & TARGET_MC_SET_ONSTACK) { + mcp->mc_onstack = tswapal(1); + } else { + mcp->mc_onstack = 0; + } + + for (i = 1; i < 32; i++) { + mcp->mc_regs[i] = tswapal(regs->active_tc.gpr[i]); + } + + mcp->mc_fpused = 1; + for (i = 0; i < 32; i++) { + mcp->mc_fpregs[i] = tswapal(regs->active_fpu.fpr[i].d); + } + mcp->mc_fpregs[32] = tswapal(regs->active_fpu.fcr0); + mcp->mc_fpc_eir = tswapal(regs->active_fpu.fcr31); + + if (flags & TARGET_MC_GET_CLEAR_RET) { + mcp->mc_regs[2] = 0; /* v0 = 0 */ + mcp->mc_regs[3] = 0; /* v1 = 0 */ + mcp->mc_regs[7] = 0; /* a3 = 0 */ + } + + mcp->mc_pc = tswapal(regs->active_tc.PC); + mcp->mullo = tswapal(regs->active_tc.LO[0]); + mcp->mulhi = tswapal(regs->active_tc.HI[0]); + mcp->mc_tls = tswapal(regs->tls_value); + + /* Don't do any of the status and cause registers. */ + + return err; +} + +/* Compare to mips/mips/pm_machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUMIPSState *regs, target_mcontext_t *mcp, + int srflag) +{ + int i, err = 0; + + for (i = 1; i < 32; i++) { + regs->active_tc.gpr[i] = tswapal(mcp->mc_regs[i]); + } + + if (mcp->mc_fpused) { + /* restore fpu context if we have used it before */ + for (i = 0; i < 32; i++) { + regs->active_fpu.fpr[i].d = tswapal(mcp->mc_fpregs[i]); + } + regs->active_fpu.fcr0 = tswapal(mcp->mc_fpregs[32]); + regs->active_fpu.fcr31 = tswapal(mcp->mc_fpc_eir); + } + + regs->CP0_EPC = tswapal(mcp->mc_pc); + regs->active_tc.LO[0] = tswapal(mcp->mullo); + regs->active_tc.HI[0] = tswapal(mcp->mulhi); + regs->tls_value = tswapal(mcp->mc_tls); + + if (srflag) { + /* doing sigreturn() */ + regs->active_tc.PC = regs->CP0_EPC; + regs->CP0_EPC = 0; /* XXX for nested signals ? */ + } + + /* Don't do any of the status and cause registers. */ + + return err; +} + +static inline abi_long get_ucontext_sigreturn(CPUMIPSState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + + /* mips passes ucontext struct as the stack frame */ + *target_uc = target_sf; + return 0; +} + +#endif /* !_TARGET_ARCH_SIGNAL_H_ */ diff --git a/bsd-user/netbsd/target_os_siginfo.h b/bsd-user/netbsd/target_os_siginfo.h new file mode 100644 index 0000000..667c19c --- /dev/null +++ b/bsd-user/netbsd/target_os_siginfo.h @@ -0,0 +1,82 @@ +#ifndef _TARGET_OS_SIGINFO_H_ +#define _TARGET_OS_SIGINFO_H_ + +#define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ +#define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + +typedef struct { + uint32_t __bits[TARGET_NSIG_WORDS]; +} target_sigset_t + +struct target_sigaction { + abi_ulong _sa_handler; + int32_t sa_flags; + target_sigset_t sa_mask; +}; + +/* Compare to sys/siginfo.h */ +typedef union target_sigval { + int sival_int; + abi_ulong sival_ptr; +} target_sigval_t; + +struct target_ksiginfo { + int32_t _signo; + int32_t _code; + int32_t _errno; +#if TARGET_ABI_BITS == 64 + int32_t _pad; +#endif + union { + struct { + int32_t _pid; + int32_t _uid; + target_sigval_t _value; + } _rt; + + struct { + int32_t _pid; + int32_t _uid; + int32_t _struct; + /* clock_t _utime; */ + /* clock_t _stime; */ + } _child; + + struct { + abi_ulong _addr; + int32_t _trap; + } _fault; + + struct { + long _band; + int _fd; + } _poll; + } _reason; +}; + +typedef union target_siginfo { + int8_t si_pad[128]; + struct target_ksiginfo _info; +} target_siginfo_t; + +#define target_si_signo _info._signo +#define target_si_code _info._code +#define target_si_errno _info._errno +#define target_si_addr _info._reason._fault._addr + +#define TARGET_SEGV_MAPERR 1 +#define TARGET_SEGV_ACCERR 2 + +#define TARGET_TRAP_BRKPT 1 +#define TARGET_TRAP_TRACE 2 + + +#endif /* ! _TARGET_OS_SIGINFO_H_ */ diff --git a/bsd-user/netbsd/target_os_signal.h b/bsd-user/netbsd/target_os_signal.h new file mode 100644 index 0000000..d39a26f --- /dev/null +++ b/bsd-user/netbsd/target_os_signal.h @@ -0,0 +1,70 @@ +#ifndef _TARGET_OS_SIGNAL_H_ +#define _TARGET_OS_SIGNAL_H_ + +#include "target_os_siginfo.h" +#include "target_arch_signal.h" + +#define TARGET_SIGHUP 1 /* hangup */ +#define TARGET_SIGINT 2 /* interrupt */ +#define TARGET_SIGQUIT 3 /* quit */ +#define TARGET_SIGILL 4 /* illegal instruction (not reset when caught) */ +#define TARGET_SIGTRAP 5 /* trace trap (not reset when caught) */ +#define TARGET_SIGABRT 6 /* abort() */ +#define TARGET_SIGIOT SIGABRT /* compatibility */ +#define TARGET_SIGEMT 7 /* EMT instruction */ +#define TARGET_SIGFPE 8 /* floating point exception */ +#define TARGET_SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define TARGET_SIGBUS 10 /* bus error */ +#define TARGET_SIGSEGV 11 /* segmentation violation */ +#define TARGET_SIGSYS 12 /* bad argument to system call */ +#define TARGET_SIGPIPE 13 /* write on a pipe with no one to read it */ +#define TARGET_SIGALRM 14 /* alarm clock */ +#define TARGET_SIGTERM 15 /* software termination signal from kill */ +#define TARGET_SIGURG 16 /* urgent condition on IO channel */ +#define TARGET_SIGSTOP 17 /* sendable stop signal not from tty */ +#define TARGET_SIGTSTP 18 /* stop signal from tty */ +#define TARGET_SIGCONT 19 /* continue a stopped process */ +#define TARGET_SIGCHLD 20 /* to parent on child stop or exit */ +#define TARGET_SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define TARGET_SIGTTOU 22 /* like TTIN for output if + (tp->t_local<OSTOP) */ +#define TARGET_SIGIO 23 /* input/output possible signal */ +#define TARGET_SIGXCPU 24 /* exceeded CPU time limit */ +#define TARGET_SIGXFSZ 25 /* exceeded file size limit */ +#define TARGET_SIGVTALRM 26 /* virtual time alarm */ +#define TARGET_SIGPROF 27 /* profiling time alarm */ +#define TARGET_SIGWINCH 28 /* window size changes */ +#define TARGET_SIGINFO 29 /* information request */ +#define TARGET_SIGUSR1 30 /* user defined signal 1 */ +#define TARGET_SIGUSR2 31 /* user defined signal 2 */ + +/* + * Language spec says we must list exactly one parameter, even though we + * actually supply three. Ugh! + */ +#define TARGET_SIG_DFL ((void (*)(int))0) +#define TARGET_SIG_IGN ((void (*)(int))1) +#define TARGET_SIG_ERR ((void (*)(int))-1) + +#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */ +#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */ +#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ +#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1) */ +#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */ +#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ +#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */ + +/* + * Flags for sigprocmask: + */ +#define TARGET_SIG_BLOCK 1 /* block specified signal set */ +#define TARGET_SIG_UNBLOCK 2 /* unblock specified signal set */ +#define TARGET_SIG_SETMASK 3 /* set specified signal set */ + +#define TARGET_BADSIG SIG_ERR + +#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ +#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ + +#endif /* !_TARGET_OS_SIGNAL_H_ */ diff --git a/bsd-user/openbsd/target_os_siginfo.h b/bsd-user/openbsd/target_os_siginfo.h new file mode 100644 index 0000000..baf646a --- /dev/null +++ b/bsd-user/openbsd/target_os_siginfo.h @@ -0,0 +1,82 @@ +#ifndef _TARGET_OS_SIGINFO_H_ +#define _TARGET_OS_SIGINFO_H_ + +#define TARGET_NSIG 32 /* counting 0; could be 33 (mask is 1-32) */ +#define TARGET_NSIG_BPW (sizeof(uint32_t) * 8) +#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW) + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_long ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + +typedef struct { + uint32_t __bits[TARGET_NSIG_WORDS]; +} target_sigset_t + +struct target_sigaction { + abi_ulong _sa_handler; + int32_t sa_flags; + target_sigset_t sa_mask; +}; + +/* Compare to sys/siginfo.h */ +typedef union target_sigval { + int sival_int; + abi_ulong sival_ptr; +} target_sigval_t; + +struct target_ksiginfo { + int32_t _signo; + int32_t _code; + int32_t _errno; +#if TARGET_ABI_BITS == 64 + int32_t _pad; +#endif + union { + struct { + int32_t _pid; + int32_t _uid; + target_sigval_t _value; + } _rt; + + struct { + int32_t _pid; + int32_t _uid; + int32_t _struct; + /* clock_t _utime; */ + /* clock_t _stime; */ + } _child; + + struct { + abi_ulong _addr; + int32_t _trap; + } _fault; + + struct { + long _band; + int _fd; + } _poll; + } _reason; +}; + +typedef union target_siginfo { + int8_t si_pad[128]; + struct target_ksiginfo _info; +} target_siginfo_t; + +#define target_si_signo _info._signo +#define target_si_code _info._code +#define target_si_errno _info._errno +#define target_si_addr _info._reason._fault._addr + +#define TARGET_SEGV_MAPERR 1 +#define TARGET_SEGV_ACCERR 2 + +#define TARGET_TRAP_BRKPT 1 +#define TARGET_TRAP_TRACE 2 + + +#endif /* ! _TARGET_OS_SIGINFO_H_ */ diff --git a/bsd-user/openbsd/target_os_signal.h b/bsd-user/openbsd/target_os_signal.h new file mode 100644 index 0000000..d39a26f --- /dev/null +++ b/bsd-user/openbsd/target_os_signal.h @@ -0,0 +1,70 @@ +#ifndef _TARGET_OS_SIGNAL_H_ +#define _TARGET_OS_SIGNAL_H_ + +#include "target_os_siginfo.h" +#include "target_arch_signal.h" + +#define TARGET_SIGHUP 1 /* hangup */ +#define TARGET_SIGINT 2 /* interrupt */ +#define TARGET_SIGQUIT 3 /* quit */ +#define TARGET_SIGILL 4 /* illegal instruction (not reset when caught) */ +#define TARGET_SIGTRAP 5 /* trace trap (not reset when caught) */ +#define TARGET_SIGABRT 6 /* abort() */ +#define TARGET_SIGIOT SIGABRT /* compatibility */ +#define TARGET_SIGEMT 7 /* EMT instruction */ +#define TARGET_SIGFPE 8 /* floating point exception */ +#define TARGET_SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define TARGET_SIGBUS 10 /* bus error */ +#define TARGET_SIGSEGV 11 /* segmentation violation */ +#define TARGET_SIGSYS 12 /* bad argument to system call */ +#define TARGET_SIGPIPE 13 /* write on a pipe with no one to read it */ +#define TARGET_SIGALRM 14 /* alarm clock */ +#define TARGET_SIGTERM 15 /* software termination signal from kill */ +#define TARGET_SIGURG 16 /* urgent condition on IO channel */ +#define TARGET_SIGSTOP 17 /* sendable stop signal not from tty */ +#define TARGET_SIGTSTP 18 /* stop signal from tty */ +#define TARGET_SIGCONT 19 /* continue a stopped process */ +#define TARGET_SIGCHLD 20 /* to parent on child stop or exit */ +#define TARGET_SIGTTIN 21 /* to readers pgrp upon background tty read */ +#define TARGET_SIGTTOU 22 /* like TTIN for output if + (tp->t_local<OSTOP) */ +#define TARGET_SIGIO 23 /* input/output possible signal */ +#define TARGET_SIGXCPU 24 /* exceeded CPU time limit */ +#define TARGET_SIGXFSZ 25 /* exceeded file size limit */ +#define TARGET_SIGVTALRM 26 /* virtual time alarm */ +#define TARGET_SIGPROF 27 /* profiling time alarm */ +#define TARGET_SIGWINCH 28 /* window size changes */ +#define TARGET_SIGINFO 29 /* information request */ +#define TARGET_SIGUSR1 30 /* user defined signal 1 */ +#define TARGET_SIGUSR2 31 /* user defined signal 2 */ + +/* + * Language spec says we must list exactly one parameter, even though we + * actually supply three. Ugh! + */ +#define TARGET_SIG_DFL ((void (*)(int))0) +#define TARGET_SIG_IGN ((void (*)(int))1) +#define TARGET_SIG_ERR ((void (*)(int))-1) + +#define TARGET_SA_ONSTACK 0x0001 /* take signal on signal stack */ +#define TARGET_SA_RESTART 0x0002 /* restart system on signal return */ +#define TARGET_SA_RESETHAND 0x0004 /* reset to SIG_DFL when taking signal */ +#define TARGET_SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ +#define TARGET_SA_NOCLDWAIT 0x0020 /* don't create zombies (assign to pid 1) */ +#define TARGET_SA_USERTRAMP 0x0100 /* do not bounce off kernel's sigtramp */ +#define TARGET_SA_NOCLDSTOP 0x0008 /* do not generate SIGCHLD on child stop */ +#define TARGET_SA_SIGINFO 0x0040 /* generate siginfo_t */ + +/* + * Flags for sigprocmask: + */ +#define TARGET_SIG_BLOCK 1 /* block specified signal set */ +#define TARGET_SIG_UNBLOCK 2 /* unblock specified signal set */ +#define TARGET_SIG_SETMASK 3 /* set specified signal set */ + +#define TARGET_BADSIG SIG_ERR + +#define TARGET_SS_ONSTACK 0x0001 /* take signals on alternate stack */ +#define TARGET_SS_DISABLE 0x0004 /* disable taking signals on alternate stack */ + +#endif /* !_TARGET_OS_SIGNAL_H_ */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 594de5c..0e332af 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -39,7 +39,7 @@ extern enum BSDType bsd_type; #include "syscall_defs.h" #include "syscall.h" #include "target_os_vmparam.h" -#include "target_signal.h" +#include "target_os_signal.h" #include "exec/gdbstub.h" #if defined(CONFIG_USE_NPTL) @@ -72,16 +72,16 @@ struct image_info { #define MAX_SIGQUEUE_SIZE 1024 -struct sigqueue { - struct sigqueue *next; - //target_siginfo_t info; +struct qemu_sigqueue { + struct qemu_sigqueue *next; + target_siginfo_t info; }; struct emulated_sigtable { int pending; /* true if signal is pending */ - struct sigqueue *first; - struct sigqueue info; /* in order to always have memory for the - first signal, we put it here */ + struct qemu_sigqueue *first; + struct qemu_sigqueue info; /* in order to always have memory for the + first signal, we put it here */ }; /* NOTE: we force a big alignment so that the stack stored after is @@ -93,8 +93,8 @@ typedef struct TaskState { struct bsd_binprm *bprm; struct emulated_sigtable sigtab[TARGET_NSIG]; - struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ - struct sigqueue *first_free; /* first free siginfo queue entry */ + struct qemu_sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */ + struct qemu_sigqueue *first_free; /* first free siginfo queue entry */ int signal_pending; /* non zero if a signal may be pending */ uint8_t stack[0]; @@ -202,12 +202,19 @@ extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); void signal_init(void); -//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); -//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); -//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); -long do_sigreturn(CPUArchState *env); +int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); +void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); +int target_to_host_signal(int sig); +int host_to_target_signal(int sig); +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s); +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s); +long do_sigreturn(CPUArchState *env, abi_ulong addr); long do_rt_sigreturn(CPUArchState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact); +void QEMU_NORETURN force_sig(int target_sig); /* mmap.c */ int target_mprotect(abi_ulong start, abi_ulong len, int prot); diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 445f69e..3619b00 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -2,6 +2,7 @@ * Emulation of BSD signals * * Copyright (c) 2003 - 2008 Fabrice Bellard + * Copyright (c) 2013 Stacey Son * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,16 +24,920 @@ #include #include #include +#include +#include +#include #include "qemu.h" -#include "target_signal.h" //#define DEBUG_SIGNAL +static target_stack_t target_sigaltstack_used = { + .ss_sp = 0, + .ss_size = 0, + .ss_flags = TARGET_SS_DISABLE, +}; + +static uint8_t host_to_target_signal_table[TARGET_NSIG] = { + [SIGHUP] = TARGET_SIGHUP, + [SIGINT] = TARGET_SIGINT, + [SIGQUIT] = TARGET_SIGQUIT, + [SIGILL] = TARGET_SIGILL, + [SIGTRAP] = TARGET_SIGTRAP, + [SIGABRT] = TARGET_SIGABRT, + [SIGEMT] = TARGET_SIGEMT, + [SIGFPE] = TARGET_SIGFPE, + [SIGKILL] = TARGET_SIGKILL, + [SIGBUS] = TARGET_SIGBUS, + [SIGSEGV] = TARGET_SIGSEGV, + [SIGSYS] = TARGET_SIGSYS, + [SIGPIPE] = TARGET_SIGPIPE, + [SIGALRM] = TARGET_SIGALRM, + [SIGTERM] = TARGET_SIGTERM, + [SIGURG] = TARGET_SIGURG, + [SIGSTOP] = TARGET_SIGSTOP, + [SIGTSTP] = TARGET_SIGTSTP, + [SIGCONT] = TARGET_SIGCONT, + [SIGCHLD] = TARGET_SIGCHLD, + [SIGTTIN] = TARGET_SIGTTIN, + [SIGTTOU] = TARGET_SIGTTOU, + [SIGIO] = TARGET_SIGIO, + [SIGXCPU] = TARGET_SIGXCPU, + [SIGXFSZ] = TARGET_SIGXFSZ, + [SIGVTALRM] = TARGET_SIGVTALRM, + [SIGPROF] = TARGET_SIGPROF, + [SIGWINCH] = TARGET_SIGWINCH, + [SIGINFO] = TARGET_SIGINFO, + [SIGUSR1] = TARGET_SIGUSR1, + [SIGUSR2] = TARGET_SIGUSR2, +#ifdef SIGTHR + [SIGTHR + 3] = TARGET_SIGTHR, +#endif + /* [SIGLWP] = TARGET_SIGLWP, */ +#ifdef SIGLIBRT + [SIGLIBRT] = TARGET_SIGLIBRT, +#endif + + /* + * The following signals stay the same. + * Nasty hack: Reverse SIGRTMIN and SIGRTMAX to avoid overlap with + * host libpthread signals. This assumes no one actually uses + * SIGRTMAX. To fix this properly we need to manual signal delivery + * multiplexed over a single host signal. + */ + [SIGRTMIN] = SIGRTMAX, + [SIGRTMAX] = SIGRTMIN, +}; + +static uint8_t target_to_host_signal_table[TARGET_NSIG]; +static struct target_sigaction sigact_table[TARGET_NSIG]; +static void host_signal_handler(int host_signum, siginfo_t *info, void *puc); +static void target_to_host_sigset_internal(sigset_t *d, + const target_sigset_t *s); + +static inline int on_sig_stack(unsigned long sp) +{ + return sp - target_sigaltstack_used.ss_sp < target_sigaltstack_used.ss_size; +} + +static inline int sas_ss_flags(unsigned long sp) +{ + return target_sigaltstack_used.ss_size == 0 ? SS_DISABLE : on_sig_stack(sp) + ? SS_ONSTACK : 0; +} + +int host_to_target_signal(int sig) +{ + + if (sig < 0 || sig >= TARGET_NSIG) { + return sig; + } + + return host_to_target_signal_table[sig]; +} + +int target_to_host_signal(int sig) +{ + + if (sig >= TARGET_NSIG) { + return sig; + } + + return target_to_host_signal_table[sig]; +} + +static inline void target_sigemptyset(target_sigset_t *set) +{ + + memset(set, 0, sizeof(*set)); +} + +static inline void target_sigaddset(target_sigset_t *set, int signum) +{ + + signum--; + uint32_t mask = (uint32_t)1 << (signum % TARGET_NSIG_BPW); + set->__bits[signum / TARGET_NSIG_BPW] |= mask; +} + +static inline int target_sigismember(const target_sigset_t *set, int signum) +{ + + signum--; + abi_ulong mask = (abi_ulong)1 << (signum % TARGET_NSIG_BPW); + return (set->__bits[signum / TARGET_NSIG_BPW] & mask) != 0; +} + +static void host_to_target_sigset_internal(target_sigset_t *d, + const sigset_t *s) +{ + int i; + + target_sigemptyset(d); + for (i = 1; i <= TARGET_NSIG; i++) { + if (sigismember(s, i)) { + target_sigaddset(d, host_to_target_signal(i)); + } + } +} + +void host_to_target_sigset(target_sigset_t *d, const sigset_t *s) +{ + target_sigset_t d1; + int i; + + host_to_target_sigset_internal(&d1, s); + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + d->__bits[i] = tswap32(d1.__bits[i]); + } +} + +static void target_to_host_sigset_internal(sigset_t *d, + const target_sigset_t *s) +{ + int i; + + sigemptyset(d); + for (i = 1; i <= TARGET_NSIG; i++) { + if (target_sigismember(s, i)) { + sigaddset(d, target_to_host_signal(i)); + } + } +} + +void target_to_host_sigset(sigset_t *d, const target_sigset_t *s) +{ + target_sigset_t s1; + int i; + + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + s1.__bits[i] = tswap32(s->__bits[i]); + } + target_to_host_sigset_internal(d, &s1); +} + +/* Siginfo conversion. */ +static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, + const siginfo_t *info) +{ + int sig, code; + + sig = host_to_target_signal(info->si_signo); + /* XXX should have host_to_target_si_code() */ + code = tswap32(info->si_code); + tinfo->si_signo = sig; + tinfo->si_errno = info->si_errno; + tinfo->si_code = info->si_code; + tinfo->si_pid = info->si_pid; + tinfo->si_uid = info->si_uid; + tinfo->si_addr = (abi_ulong)(unsigned long)info->si_addr; + /* si_value is opaque to kernel */ + tinfo->si_value.sival_ptr = + (abi_ulong)(unsigned long)info->si_value.sival_ptr; + if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig || + SIGTRAP == sig) { + tinfo->_reason._fault._trapno = info->_reason._fault._trapno; + } +#ifdef SIGPOLL + if (SIGPOLL == sig) { + tinfo->_reason._poll._band = info->_reason._poll._band; + } +#endif + if (SI_TIMER == code) { + tinfo->_reason._timer._timerid = info->_reason._timer._timerid; + tinfo->_reason._timer._overrun = info->_reason._timer._overrun; + } +} + +static void tswap_siginfo(target_siginfo_t *tinfo, const target_siginfo_t *info) +{ + int sig, code; + + sig = info->si_signo; + code = info->si_code; + tinfo->si_signo = tswap32(sig); + tinfo->si_errno = tswap32(info->si_errno); + tinfo->si_code = tswap32(info->si_code); + tinfo->si_pid = tswap32(info->si_pid); + tinfo->si_uid = tswap32(info->si_uid); + tinfo->si_addr = tswapal(info->si_addr); + if (SIGILL == sig || SIGFPE == sig || SIGSEGV == sig || SIGBUS == sig || + SIGTRAP == sig) { + tinfo->_reason._fault._trapno = tswap32(info->_reason._fault._trapno); + } +#ifdef SIGPOLL + if (SIGPOLL == sig) { + tinfo->_reason._poll._band = tswap32(info->_reason._poll._band); + } +#endif + if (SI_TIMER == code) { + tinfo->_reason._timer._timerid = tswap32(info->_reason._timer._timerid); + tinfo->_reason._timer._overrun = tswap32(info->_reason._timer._overrun); + } +} + +void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info) +{ + + host_to_target_siginfo_noswap(tinfo, info); + tswap_siginfo(tinfo, tinfo); +} + +/* Returns 1 if given signal should dump core if not handled. */ +static int core_dump_signal(int sig) +{ + switch (sig) { + case TARGET_SIGABRT: + case TARGET_SIGFPE: + case TARGET_SIGILL: + case TARGET_SIGQUIT: + case TARGET_SIGSEGV: + case TARGET_SIGTRAP: + case TARGET_SIGBUS: + return 1; + default: + return 0; + } +} + +/* Signal queue handling. */ +static inline struct qemu_sigqueue *alloc_sigqueue(CPUArchState *env) +{ + TaskState *ts = env->opaque; + struct qemu_sigqueue *q = ts->first_free; + + if (!q) { + return NULL; + } + ts->first_free = q->next; + return q; +} + +static inline void free_sigqueue(CPUArchState *env, struct qemu_sigqueue *q) +{ + + TaskState *ts = env->opaque; + q->next = ts->first_free; + ts->first_free = q; +} + +/* Abort execution with signal. */ +void QEMU_NORETURN force_sig(int target_sig) +{ + CPUArchState *env = thread_cpu->env_ptr; + TaskState *ts = (TaskState *)env->opaque; + int core_dumped = 0; + int host_sig; + struct sigaction act; + + host_sig = target_to_host_signal(target_sig); + gdb_signalled(env, target_sig); + + /* Dump core if supported by target binary format */ + if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) { + stop_all_tasks(); + core_dumped = + ((*ts->bprm->core_dump)(target_sig, env) == 0); + } + if (core_dumped) { + struct rlimit nodump; + + /* + * We already dumped the core of target process, we don't want + * a coredump of qemu itself. + */ + getrlimit(RLIMIT_CORE, &nodump); + nodump.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &nodump); + (void) fprintf(stderr, "qemu: uncaught target signal %d (%s) " + "- %s\n", target_sig, strsignal(host_sig), "core dumped"); + } + + /* + * The proper exit code for dying from an uncaught signal is + * -. The kernel doesn't allow exit() or _exit() to pass + * a negative value. To get the proper exit code we need to + * actually die from an uncaught signal. Here the default signal + * handler is installed, we send ourself a signal and we wait for + * it to arrive. + */ + memset(&act, 0, sizeof(act)); + sigfillset(&act.sa_mask); + act.sa_handler = SIG_DFL; + sigaction(host_sig, &act, NULL); + + kill(getpid(), host_sig); + + /* + * Make sure the signal isn't masked (just reuse the mask inside + * of act). + */ + sigdelset(&act.sa_mask, host_sig); + sigsuspend(&act.sa_mask); + + /* unreachable */ + abort(); +} + +/* + * Queue a signal so that it will be send to the virtual CPU as soon as + * possible. + */ +int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info) +{ + TaskState *ts = env->opaque; + struct emulated_sigtable *k; + struct qemu_sigqueue *q, **pq; + abi_ulong handler; + int queue; + + k = &ts->sigtab[sig - 1]; + queue = gdb_queuesig(); + handler = sigact_table[sig - 1]._sa_handler; +#ifdef DEBUG_SIGNAL + fprintf(stderr, "queue_signal: sig=%d handler=0x%lx flags=0x%x\n", sig, + handler, (uint32_t)sigact_table[sig - 1].sa_flags); +#endif + if (!queue && (TARGET_SIG_DFL == handler)) { + if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || + sig == TARGET_SIGTTOU) { + kill(getpid(), SIGSTOP); + return 0; + } else { + if (sig != TARGET_SIGCHLD && + sig != TARGET_SIGURG && + sig != TARGET_SIGWINCH && + sig != TARGET_SIGCONT) { + force_sig(sig); + } else { + return 0; /* The signal was ignored. */ + } + } + } else if (!queue && (TARGET_SIG_IGN == handler)) { + return 0; /* Ignored signal. */ + } else if (!queue && (TARGET_SIG_ERR == handler)) { + force_sig(sig); + } else { + pq = &k->first; + + /* + * FreeBSD signals are always queued. + * Linux only queues real time signals. + * XXX this code is not thread safe. + */ + if (!k->pending) { + /* first signal */ + q = &k->info; + } else { + q = alloc_sigqueue(env); + if (!q) { + return -EAGAIN; + } + while (*pq != NULL) { + pq = &(*pq)->next; + } + } + *pq = q; + q->info = *info; + q->next = NULL; + k->pending = 1; + /* Signal that a new signal is pending. */ + ts->signal_pending = 1; + return 1; /* Indicates that the signal was queued. */ + } +} + +static void host_signal_handler(int host_signum, siginfo_t *info, void *puc) +{ + CPUArchState *env = thread_cpu->env_ptr; + int sig; + target_siginfo_t tinfo; + + /* + * The CPU emulator uses some host signal to detect exceptions so + * we forward to it some signals. + */ + if ((host_signum == SIGSEGV || host_signum == SIGBUS) && + info->si_code < 0x10000) { + if (cpu_signal_handler(host_signum, info, puc)) { + return; + } + } + + /* Get the target signal number. */ + sig = host_to_target_signal(host_signum); + if (sig < 1 || sig > TARGET_NSIG) { + return; + } +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: got signal %d\n", sig); +#endif + host_to_target_siginfo_noswap(&tinfo, info); + if (queue_signal(env, sig, &tinfo) == 1) { + /* Interrupt the virtual CPU as soon as possible. */ + cpu_exit(thread_cpu); + } +} + +/* do_sigaltstack() returns target values and errnos. */ +/* compare to kern/kern_sig.c sys_sigaltstack() and kern_sigaltstack() */ +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) +{ + int ret = 0; + target_stack_t ss, oss, *uss; + + if (uoss_addr) { + /* Save current signal stack params */ + oss.ss_sp = tswapl(target_sigaltstack_used.ss_sp); + oss.ss_size = tswapl(target_sigaltstack_used.ss_size); + oss.ss_flags = tswapl(sas_ss_flags(sp)); + } + + if (uss_addr) { + + if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1) || + __get_user(ss.ss_sp, &uss->ss_sp) || + __get_user(ss.ss_size, &uss->ss_size) || + __get_user(ss.ss_flags, &uss->ss_flags)) { + ret = -TARGET_EFAULT; + goto out; + } + unlock_user_struct(uss, uss_addr, 0); + + if (on_sig_stack(sp)) { + ret = -TARGET_EPERM; + goto out; + } + + if ((ss.ss_flags & ~TARGET_SS_DISABLE) != 0) { + ret = -TARGET_EINVAL; + goto out; + } + + if (!(ss.ss_flags & ~TARGET_SS_DISABLE)) { + if (ss.ss_size < TARGET_MINSIGSTKSZ) { + ret = -TARGET_ENOMEM; + goto out; + } + } else { + ss.ss_size = 0; + ss.ss_sp = 0; + } + + target_sigaltstack_used.ss_sp = ss.ss_sp; + target_sigaltstack_used.ss_size = ss.ss_size; + } + + if (uoss_addr) { + /* Copy out to user saved signal stack params */ + if (copy_to_user(uoss_addr, &oss, sizeof(oss))) { + ret = -TARGET_EFAULT; + goto out; + } + } + +out: + return ret; +} + +static int fatal_signal(int sig) +{ + + switch (sig) { + case TARGET_SIGCHLD: + case TARGET_SIGURG: + case TARGET_SIGWINCH: + /* Ignored by default. */ + return 0; + case TARGET_SIGCONT: + case TARGET_SIGSTOP: + case TARGET_SIGTSTP: + case TARGET_SIGTTIN: + case TARGET_SIGTTOU: + /* Job control signals. */ + return 0; + default: + return 1; + } +} + +/* do_sigaction() return host values and errnos */ +int do_sigaction(int sig, const struct target_sigaction *act, + struct target_sigaction *oact) +{ + struct target_sigaction *k; + struct sigaction act1; + int host_sig; + int ret = 0; + + if (sig < 1 || sig > TARGET_NSIG || TARGET_SIGKILL == sig || + TARGET_SIGSTOP == sig) { + return -EINVAL; + } + k = &sigact_table[sig - 1]; +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "do_sigaction sig=%d act=%p, oact=%p\n", + sig, act, oact); +#endif + if (oact) { + oact->_sa_handler = tswapal(k->_sa_handler); + oact->sa_flags = tswap32(k->sa_flags); + oact->sa_mask = k->sa_mask; + } + if (act) { + /* XXX: this is most likely not threadsafe. */ + k->_sa_handler = tswapal(act->_sa_handler); + k->sa_flags = tswap32(act->sa_flags); + k->sa_mask = act->sa_mask; + + /* Update the host signal state. */ + host_sig = target_to_host_signal(sig); + if (host_sig != SIGSEGV && host_sig != SIGBUS) { + memset(&act1, 0, sizeof(struct sigaction)); + sigfillset(&act1.sa_mask); + if (k->sa_flags & TARGET_SA_RESTART) { + act1.sa_flags |= SA_RESTART; + } + /* + * Note: It is important to update the host kernel signal mask to + * avoid getting unexpected interrupted system calls. + */ + if (k->_sa_handler == TARGET_SIG_IGN) { + act1.sa_sigaction = (void *)SIG_IGN; + } else if (k->_sa_handler == TARGET_SIG_DFL) { + if (fatal_signal(sig)) { + act1.sa_flags = SA_SIGINFO; + act1.sa_sigaction = host_signal_handler; + } else { + act1.sa_sigaction = (void *)SIG_DFL; + } + } else { + act1.sa_flags = SA_SIGINFO; + act1.sa_sigaction = host_signal_handler; + } + ret = sigaction(host_sig, &act1, NULL); +#if defined(DEBUG_SIGNAL) + fprintf(stderr, "sigaction (action = %p " + "(host_signal_handler = %p)) returned: %d\n", + act1.sa_sigaction, host_signal_handler, ret); +#endif + } + } + return ret; +} + +static inline abi_ulong get_sigframe(struct target_sigaction *ka, + CPUArchState *regs, size_t frame_size) +{ + abi_ulong sp; + + /* Use default user stack */ + sp = get_sp_from_cpustate(regs); + + if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags(sp) == 0)) { + sp = target_sigaltstack_used.ss_sp + + target_sigaltstack_used.ss_size; + } + +#if defined(TARGET_MIPS) || defined(TARGET_ARM) + return (sp - frame_size) & ~7; +#else + return sp - frame_size; +#endif +} + +/* compare to mips/mips/pm_machdep.c and sparc64/sparc64/machdep.c sendsig() */ +static void setup_frame(int sig, int code, struct target_sigaction *ka, + target_sigset_t *set, target_siginfo_t *tinfo, CPUArchState *regs) +{ + struct target_sigframe *frame; + abi_ulong frame_addr; + int i; + +#ifdef DEBUG_SIGNAL + fprintf(stderr, "setup_frame()\n"); +#endif + frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + memset(frame, 0, sizeof(*frame)); +#if defined(TARGET_MIPS) + int mflags = on_sig_stack(frame_addr) ? TARGET_MC_ADD_MAGIC : + TARGET_MC_SET_ONSTACK | TARGET_MC_ADD_MAGIC; +#else + int mflags = 0; +#endif + if (get_mcontext(regs, &frame->sf_uc.uc_mcontext, mflags)) { + goto give_sigsegv; + } + + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->__bits[i], &frame->sf_uc.uc_sigmask.__bits[i])) { + goto give_sigsegv; + } + } + + if (tinfo) { + frame->sf_si.si_signo = tinfo->si_signo; + frame->sf_si.si_errno = tinfo->si_errno; + frame->sf_si.si_code = tinfo->si_code; + frame->sf_si.si_pid = tinfo->si_pid; + frame->sf_si.si_uid = tinfo->si_uid; + frame->sf_si.si_status = tinfo->si_status; + frame->sf_si.si_addr = tinfo->si_addr; + + if (TARGET_SIGILL == sig || TARGET_SIGFPE == sig || + TARGET_SIGSEGV == sig || TARGET_SIGBUS == sig || + TARGET_SIGTRAP == sig) { + frame->sf_si._reason._fault._trapno = tinfo->_reason._fault._trapno; + } + + /* + * If si_code is one of SI_QUEUE, SI_TIMER, SI_ASYNCIO, or + * SI_MESGQ, then si_value contains the application-specified + * signal value. Otherwise, the contents of si_value are + * undefined. + */ + if (SI_QUEUE == code || SI_TIMER == code || SI_ASYNCIO == code || + SI_MESGQ == code) { + frame->sf_si.si_value.sival_int = tinfo->si_value.sival_int; + } + + if (SI_TIMER == code) { + frame->sf_si._reason._timer._timerid = + tinfo->_reason._timer._timerid; + frame->sf_si._reason._timer._overrun = + tinfo->_reason._timer._overrun; + } + +#ifdef SIGPOLL + if (SIGPOLL == sig) { + frame->sf_si._reason._band = tinfo->_reason._band; + } +#endif + + } + + if (set_sigtramp_args(regs, sig, frame, frame_addr, ka)) { + goto give_sigsegv; + } + + unlock_user_struct(frame, frame_addr, 1); + return; + +give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); + force_sig(TARGET_SIGSEGV); +} + +static int reset_signal_mask(target_ucontext_t *ucontext) +{ + int i; + sigset_t blocked; + target_sigset_t target_set; + + for (i = 0; i < TARGET_NSIG_WORDS; i++) + if (__get_user(target_set.__bits[i], + &ucontext->uc_sigmask.__bits[i])) { + return -TARGET_EFAULT; + } + target_to_host_sigset_internal(&blocked, &target_set); + sigprocmask(SIG_SETMASK, &blocked, NULL); + + return 0; +} + +long do_sigreturn(CPUArchState *regs, abi_ulong addr) +{ + long ret; + abi_ulong target_ucontext; + target_ucontext_t *ucontext = NULL; + + /* Get the target ucontext address from the stack frame */ + ret = get_ucontext_sigreturn(regs, addr, &target_ucontext); + if (is_error(ret)) { + return ret; + } + if (!lock_user_struct(VERIFY_READ, ucontext, target_ucontext, 0)) { + goto badframe; + } + + /* Set the register state back to before the signal. */ + if (set_mcontext(regs, &ucontext->uc_mcontext, 1)) { + goto badframe; + } + + /* And reset the signal mask. */ + if (reset_signal_mask(ucontext)) { + goto badframe; + } + + unlock_user_struct(ucontext, target_ucontext, 0); + return -TARGET_EJUSTRETURN; + +badframe: + if (ucontext != NULL) { + unlock_user_struct(ucontext, target_ucontext, 0); + } + force_sig(TARGET_SIGSEGV); + return -TARGET_EFAULT; +} + void signal_init(void) { + struct sigaction act; + struct sigaction oact; + int i, j; + int host_sig; + + /* Generate the signal conversion tables. */ + for (i = 1; i < TARGET_NSIG; i++) { + if (host_to_target_signal_table[i] == 0) { + host_to_target_signal_table[i] = i; + } + } + for (i = 1; i < TARGET_NSIG; i++) { + j = host_to_target_signal_table[i]; + target_to_host_signal_table[j] = i; + } + + /* + * Set all host signal handlers. ALL signals are blocked during the + * handlers to serialize them. + */ + memset(sigact_table, 0, sizeof(sigact_table)); + + sigfillset(&act.sa_mask); + act.sa_sigaction = host_signal_handler; + act.sa_flags = SA_SIGINFO; + + for (i = 1; i <= TARGET_NSIG; i++) { + host_sig = target_to_host_signal(i); + sigaction(host_sig, NULL, &oact); + if (oact.sa_sigaction == (void *)SIG_IGN) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_IGN; + } else if (oact.sa_sigaction == (void *)SIG_DFL) { + sigact_table[i - 1]._sa_handler = TARGET_SIG_DFL; + } + /* + * If there's already a handler installed then something has + * gone horribly wrong, so don't even try to handle that case. + * Install some handlers for our own use. We need at least + * SIGSEGV and SIGBUS, to detect exceptions. We can not just + * trap all signals because it affects syscall interrupt + * behavior. But do trap all default-fatal signals. + */ + if (fatal_signal(i)) { + sigaction(host_sig, &act, NULL); + } + } } void process_pending_signals(CPUArchState *cpu_env) { + CPUState *cpu = ENV_GET_CPU(cpu_env); + int sig, code; + abi_ulong handler; + sigset_t set, old_set; + target_sigset_t target_old_set; + target_siginfo_t tinfo; + struct emulated_sigtable *k; + struct target_sigaction *sa; + struct qemu_sigqueue *q; + TaskState *ts = cpu_env->opaque; + + if (!ts->signal_pending) { + return; + } + + /* FIXME: This is not threadsafe. */ + k = ts->sigtab; + for (sig = 1; sig <= TARGET_NSIG; sig++) { + if (k->pending) { + goto handle_signal; + } + k++; + } +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: process_pending_signals has no signals\n"); +#endif + /* If no signal is pending then just return. */ + ts->signal_pending = 0; + return; + +handle_signal: +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: process signal %d\n", sig); +#endif + + /* Dequeue signal. */ + q = k->first; + k->first = q->next; + if (!k->first) { + k->pending = 0; + } + + sig = gdb_handlesig(cpu, sig); + if (!sig) { + sa = NULL; + handler = TARGET_SIG_IGN; + } else { + sa = &sigact_table[sig - 1]; + handler = sa->_sa_handler; + } + + if (handler == TARGET_SIG_DFL) { +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: TARGET_SIG_DFL\n"); +#endif + /* + * default handler : ignore some signal. The other are job + * control or fatal. + */ + if (TARGET_SIGTSTP == sig || TARGET_SIGTTIN == sig || + TARGET_SIGTTOU == sig) { + kill(getpid(), SIGSTOP); + } else if (TARGET_SIGCHLD != sig && TARGET_SIGURG != sig && + TARGET_SIGWINCH != sig && TARGET_SIGCONT != sig) { + force_sig(sig); + } + } else if (TARGET_SIG_IGN == handler) { + /* ignore sig */ +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: TARGET_SIG_IGN\n"); +#endif + } else if (TARGET_SIG_ERR == handler) { +#ifdef DEBUG_SIGNAL + fprintf(stderr, "qemu: TARGET_SIG_ERR\n"); +#endif + force_sig(sig); + } else { + /* compute the blocked signals during the handler execution */ + target_to_host_sigset(&set, &sa->sa_mask); + /* + * SA_NODEFER indicates that the current signal should not be + * blocked during the handler. + */ + if (!(sa->sa_flags & TARGET_SA_NODEFER)) { + sigaddset(&set, target_to_host_signal(sig)); + } + + /* block signals in the handler */ + sigprocmask(SIG_BLOCK, &set, &old_set); + + /* + * Save the previous blocked signal state to restore it at the + * end of the signal execution (see do_sigreturn). + */ + host_to_target_sigset_internal(&target_old_set, &old_set); + +#if 0 /* not yet */ +#if defined(TARGET_I386) && !defined(TARGET_X86_64) + /* if the CPU is in VM86 mode, we restore the 32 bit values */ + { + CPUX86State *env = cpu_env; + if (env->eflags & VM_MASK) { + save_v86_state(env); + } + } +#endif +#endif /* not yet */ + + code = q->info.si_code; + /* prepare the stack frame of the virtual CPU */ + if (sa->sa_flags & TARGET_SA_SIGINFO) { + tswap_siginfo(&tinfo, &q->info); + setup_frame(sig, code, sa, &target_old_set, &tinfo, cpu_env); + } else { + setup_frame(sig, code, sa, &target_old_set, NULL, cpu_env); + } + if (sa->sa_flags & TARGET_SA_RESETHAND) { + sa->_sa_handler = TARGET_SIG_DFL; + } + } + if (q != &k->info) { + free_sigqueue(cpu_env, q); + } } diff --git a/bsd-user/sparc/target_arch_signal.h b/bsd-user/sparc/target_arch_signal.h new file mode 100644 index 0000000..f934f8c --- /dev/null +++ b/bsd-user/sparc/target_arch_signal.h @@ -0,0 +1,77 @@ +#ifndef TARGET_ARCH_SIGNAL_H +#define TARGET_ARCH_SIGNAL_H + +#include "cpu.h" + +/* Size of the signal trampolin code placed on the stack. */ +/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */ + +/* compare to sparc64/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */ + +#define TARGET_MC_GET_CLEAR_RET 0x0001 + +struct target_sigcontext { + /* to be added */ +}; + +typedef struct target_mcontext { +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to sparc64/sparc64/machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long set_sigtramp_args(CPUSPARCState *regs, + int sig, struct target_sigframe *frame, abi_ulong frame_addr, + struct target_sigaction *ka) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to sparc64/sparc64/machdep.c get_mcontext() */ +static inline abi_long get_mcontext(CPUSPARCState *regs, + target_mcontext_t *mcp, int flags) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to sparc64/space64/machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUSPARCState *regs, + target_mcontext_t *mcp, int srflag) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + /* XXX */ + *target_uc = 0; + return -TARGET_EOPNOTSUPP; +} + +#endif /* TARGET_ARCH_SIGNAL_H */ diff --git a/bsd-user/sparc64/target_arch_signal.h b/bsd-user/sparc64/target_arch_signal.h new file mode 100644 index 0000000..1529b0f --- /dev/null +++ b/bsd-user/sparc64/target_arch_signal.h @@ -0,0 +1,94 @@ +/* + * sparc64 dependent signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_ARCH_SIGNAL_H_ +#define _TARGET_ARCH_SIGNAL_H_ + +#include "cpu.h" + +/* Size of the signal trampolin code placed on the stack. */ +/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added. */ + +/* compare to sparc64/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */ + +#define TARGET_MC_GET_CLEAR_RET 0x0001 + +struct target_sigcontext { + /* to be added */ +}; + +typedef struct target_mcontext { +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to sparc64/sparc64/machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long set_sigtramp_args(CPUSPARCState *regs, + int sig, struct target_sigframe *frame, abi_ulong frame_addr, + struct target_sigaction *ka) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to sparc64/sparc64/machdep.c get_mcontext() */ +static inline abi_long get_mcontext(CPUSPARCState *regs, + target_mcontext_t *mcp, int flags) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to sparc64/space64/machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUSPARCState *regs, + target_mcontext_t *mcp, int srflag) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +static inline abi_long get_ucontext_sigreturn(CPUSPARCState *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + /* XXX */ + *target_uc = 0; + return -TARGET_EOPNOTSUPP; +} + +#endif /* !_TARGET_ARCH_SIGNAL_H_ */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 0996787..bc4a7e4 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -39,8 +39,12 @@ #define target_to_host_bitmask(x, tbl) (x) +/* BSD independent syscall shims */ +#include "bsd-signal.h" + /* *BSD dependent syscall shims */ #include "os-time.h" +#include "os-signal.h" /* #define DEBUG */ @@ -326,6 +330,61 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, break; /* + * signal system calls + */ + case TARGET_FREEBSD_NR_sigtimedwait: /* sigtimedwait(2) */ + ret = do_freebsd_sigtimedwait(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sigaction: /* sigaction(2) */ + ret = do_bsd_sigaction(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sigprocmask: /* sigprocmask(2) */ + ret = do_bsd_sigprocmask(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sigpending: /* sigpending(2) */ + ret = do_bsd_sigpending(arg1); + break; + + case TARGET_FREEBSD_NR_sigsuspend: /* sigsuspend(2) */ + ret = do_bsd_sigsuspend(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_sigreturn: /* sigreturn(2) */ + ret = do_bsd_sigreturn(cpu_env, arg1); + break; + + case TARGET_FREEBSD_NR_sigwait: /* sigwait(2) */ + ret = do_bsd_sigwait(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sigwaitinfo: /* sigwaitinfo(2) */ + ret = do_bsd_sigwaitinfo(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_sigqueue: /* sigqueue(2) */ + ret = do_bsd_sigqueue(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_sigaltstack: /* sigaltstack(2) */ + ret = do_bsd_sigaltstack(cpu_env, arg1, arg2); + break; + + case TARGET_FREEBSD_NR_kill: /* kill(2) */ + ret = do_bsd_kill(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_killpg: /* killpg(2) */ + ret = do_bsd_killpg(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_pdkill: /* pdkill(2) */ + ret = do_freebsd_pdkill(arg1, arg2); + break; + + /* * sys{ctl, arch, call} */ case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */ diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h new file mode 100644 index 0000000..1998570 --- /dev/null +++ b/bsd-user/x86_64/target_arch_signal.h @@ -0,0 +1,94 @@ +/* + * x86_64 signal definitions + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _TARGET_ARCH_SIGNAL_H_ +#define _TARGET_ARCH_SIGNAL_H_ + +#include "cpu.h" + +/* Size of the signal trampolin code placed on the stack. */ +/* #define TARGET_SZSIGCODE (0) */ /* XXX to be added */ + +/* compare to x86/include/_limits.h */ +#define TARGET_MINSIGSTKSZ (512 * 4) /* min sig stack size */ +#define TARGET_SIGSTKSZ (MINSIGSTKSZ + 32768) /* recommended size */ + +#define TARGET_MC_GET_CLEAR_RET 0x0001 + +struct target_sigcontext { + /* to be added */ +}; + +typedef struct target_mcontext { +} target_mcontext_t; + +typedef struct target_ucontext { + target_sigset_t uc_sigmask; + target_mcontext_t uc_mcontext; + abi_ulong uc_link; + target_stack_t uc_stack; + int32_t uc_flags; + int32_t __spare__[4]; +} target_ucontext_t; + +struct target_sigframe { + abi_ulong sf_signum; + abi_ulong sf_siginfo; /* code or pointer to sf_si */ + abi_ulong sf_ucontext; /* points to sf_uc */ + abi_ulong sf_addr; /* undocumented 4th arg */ + target_ucontext_t sf_uc; /* = *sf_uncontext */ + target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/ + uint32_t __spare__[2]; +}; + +/* + * Compare to amd64/amd64/machdep.c sendsig() + * Assumes that target stack frame memory is locked. + */ +static inline abi_long set_sigtramp_args(CPUX86State *regs, + int sig, struct target_sigframe *frame, abi_ulong frame_addr, + struct target_sigaction *ka) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to amd64/amd64/machdep.c get_mcontext() */ +static inline abi_long get_mcontext(CPUX86State *regs, + target_mcontext_t *mcp, int flags) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +/* Compare to amd64/amd64/machdep.c set_mcontext() */ +static inline abi_long set_mcontext(CPUX86State *regs, + target_mcontext_t *mcp, int srflag) +{ + /* XXX */ + return -TARGET_EOPNOTSUPP; +} + +static inline abi_long get_ucontext_sigreturn(CPUX86State *regs, + abi_ulong target_sf, abi_ulong *target_uc) +{ + /* XXX */ + *target_uc = 0; + return -TARGET_EOPNOTSUPP; +} + +#endif /* !TARGET_ARCH_SIGNAL_H_ */