From 5f7645975d23b90a28067f258b79887aa30ada8e Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 24 Apr 2018 21:26:18 +0200 Subject: linux-user: move arm signal.c parts to arm directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No code change, only move code from signal.c to arm/signal.c, except adding includes and exporting setup_frame() and setup_rt_frame(). Signed-off-by: Laurent Vivier Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20180424192635.6027-4-laurent@vivier.eu> --- linux-user/arm/signal.c | 754 +++++++++++++++++++++++++++++++++++++++++ linux-user/arm/target_signal.h | 6 +- 2 files changed, 759 insertions(+), 1 deletion(-) (limited to 'linux-user/arm') diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index 02ca338..0c1ec53 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -16,3 +16,757 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ +#include "qemu/osdep.h" +#include "qemu.h" +#include "target_signal.h" +#include "signal-common.h" +#include "linux-user/trace.h" + +struct target_sigcontext { + abi_ulong trap_no; + abi_ulong error_code; + abi_ulong oldmask; + abi_ulong arm_r0; + abi_ulong arm_r1; + abi_ulong arm_r2; + abi_ulong arm_r3; + abi_ulong arm_r4; + abi_ulong arm_r5; + abi_ulong arm_r6; + abi_ulong arm_r7; + abi_ulong arm_r8; + abi_ulong arm_r9; + abi_ulong arm_r10; + abi_ulong arm_fp; + abi_ulong arm_ip; + abi_ulong arm_sp; + abi_ulong arm_lr; + abi_ulong arm_pc; + abi_ulong arm_cpsr; + abi_ulong fault_address; +}; + +struct target_ucontext_v1 { + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ +}; + +struct target_ucontext_v2 { + abi_ulong tuc_flags; + abi_ulong tuc_link; + target_stack_t tuc_stack; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; /* mask last for extensibility */ + char __unused[128 - sizeof(target_sigset_t)]; + abi_ulong tuc_regspace[128] __attribute__((__aligned__(8))); +}; + +struct target_user_vfp { + uint64_t fpregs[32]; + abi_ulong fpscr; +}; + +struct target_user_vfp_exc { + abi_ulong fpexc; + abi_ulong fpinst; + abi_ulong fpinst2; +}; + +struct target_vfp_sigframe { + abi_ulong magic; + abi_ulong size; + struct target_user_vfp ufp; + struct target_user_vfp_exc ufp_exc; +} __attribute__((__aligned__(8))); + +struct target_iwmmxt_sigframe { + abi_ulong magic; + abi_ulong size; + uint64_t regs[16]; + /* Note that not all the coprocessor control registers are stored here */ + uint32_t wcssf; + uint32_t wcasf; + uint32_t wcgr0; + uint32_t wcgr1; + uint32_t wcgr2; + uint32_t wcgr3; +} __attribute__((__aligned__(8))); + +#define TARGET_VFP_MAGIC 0x56465001 +#define TARGET_IWMMXT_MAGIC 0x12ef842a + +struct sigframe_v1 +{ + struct target_sigcontext sc; + abi_ulong extramask[TARGET_NSIG_WORDS-1]; + abi_ulong retcode; +}; + +struct sigframe_v2 +{ + struct target_ucontext_v2 uc; + abi_ulong retcode; +}; + +struct rt_sigframe_v1 +{ + abi_ulong pinfo; + abi_ulong puc; + struct target_siginfo info; + struct target_ucontext_v1 uc; + abi_ulong retcode; +}; + +struct rt_sigframe_v2 +{ + struct target_siginfo info; + struct target_ucontext_v2 uc; + abi_ulong retcode; +}; + +#define TARGET_CONFIG_CPU_32 1 + +/* + * For ARM syscalls, we encode the syscall number into the instruction. + */ +#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE)) +#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE)) + +/* + * For Thumb syscalls, we pass the syscall number via r7. We therefore + * need two 16-bit instructions. + */ +#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn)) +#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn)) + +static const abi_ulong retcodes[4] = { + SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, + SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN +}; + + +static inline int valid_user_regs(CPUARMState *regs) +{ + return 1; +} + +static void +setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ + CPUARMState *env, abi_ulong mask) +{ + __put_user(env->regs[0], &sc->arm_r0); + __put_user(env->regs[1], &sc->arm_r1); + __put_user(env->regs[2], &sc->arm_r2); + __put_user(env->regs[3], &sc->arm_r3); + __put_user(env->regs[4], &sc->arm_r4); + __put_user(env->regs[5], &sc->arm_r5); + __put_user(env->regs[6], &sc->arm_r6); + __put_user(env->regs[7], &sc->arm_r7); + __put_user(env->regs[8], &sc->arm_r8); + __put_user(env->regs[9], &sc->arm_r9); + __put_user(env->regs[10], &sc->arm_r10); + __put_user(env->regs[11], &sc->arm_fp); + __put_user(env->regs[12], &sc->arm_ip); + __put_user(env->regs[13], &sc->arm_sp); + __put_user(env->regs[14], &sc->arm_lr); + __put_user(env->regs[15], &sc->arm_pc); +#ifdef TARGET_CONFIG_CPU_32 + __put_user(cpsr_read(env), &sc->arm_cpsr); +#endif + + __put_user(/* current->thread.trap_no */ 0, &sc->trap_no); + __put_user(/* current->thread.error_code */ 0, &sc->error_code); + __put_user(/* current->thread.address */ 0, &sc->fault_address); + __put_user(mask, &sc->oldmask); +} + +static inline abi_ulong +get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize) +{ + unsigned long sp = regs->regs[13]; + + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + /* + * ATPCS B01 mandates 8-byte alignment + */ + return (sp - framesize) & ~7; +} + +static void +setup_return(CPUARMState *env, struct target_sigaction *ka, + abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr) +{ + abi_ulong handler = ka->_sa_handler; + abi_ulong retcode; + int thumb = handler & 1; + uint32_t cpsr = cpsr_read(env); + + cpsr &= ~CPSR_IT; + if (thumb) { + cpsr |= CPSR_T; + } else { + cpsr &= ~CPSR_T; + } + + if (ka->sa_flags & TARGET_SA_RESTORER) { + retcode = ka->sa_restorer; + } else { + unsigned int idx = thumb; + + if (ka->sa_flags & TARGET_SA_SIGINFO) { + idx += 2; + } + + __put_user(retcodes[idx], rc); + + retcode = rc_addr + thumb; + } + + env->regs[0] = usig; + env->regs[13] = frame_addr; + env->regs[14] = retcode; + env->regs[15] = handler & (thumb ? ~1 : ~3); + cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr); +} + +static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env) +{ + int i; + struct target_vfp_sigframe *vfpframe; + vfpframe = (struct target_vfp_sigframe *)regspace; + __put_user(TARGET_VFP_MAGIC, &vfpframe->magic); + __put_user(sizeof(*vfpframe), &vfpframe->size); + for (i = 0; i < 32; i++) { + __put_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]); + } + __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr); + __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc); + __put_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst); + __put_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2); + return (abi_ulong*)(vfpframe+1); +} + +static abi_ulong *setup_sigframe_v2_iwmmxt(abi_ulong *regspace, + CPUARMState *env) +{ + int i; + struct target_iwmmxt_sigframe *iwmmxtframe; + iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace; + __put_user(TARGET_IWMMXT_MAGIC, &iwmmxtframe->magic); + __put_user(sizeof(*iwmmxtframe), &iwmmxtframe->size); + for (i = 0; i < 16; i++) { + __put_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]); + } + __put_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf); + __put_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf); + __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0); + __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1); + __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2); + __put_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3); + return (abi_ulong*)(iwmmxtframe+1); +} + +static void setup_sigframe_v2(struct target_ucontext_v2 *uc, + target_sigset_t *set, CPUARMState *env) +{ + struct target_sigaltstack stack; + int i; + abi_ulong *regspace; + + /* Clear all the bits of the ucontext we don't use. */ + memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); + + memset(&stack, 0, sizeof(stack)); + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + memcpy(&uc->tuc_stack, &stack, sizeof(stack)); + + setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]); + /* Save coprocessor signal frame. */ + regspace = uc->tuc_regspace; + if (arm_feature(env, ARM_FEATURE_VFP)) { + regspace = setup_sigframe_v2_vfp(regspace, env); + } + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + regspace = setup_sigframe_v2_iwmmxt(regspace, env); + } + + /* Write terminating magic word */ + __put_user(0, regspace); + + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]); + } +} + +/* compare linux/arch/arm/kernel/signal.c:setup_frame() */ +static void setup_frame_v1(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUARMState *regs) +{ + struct sigframe_v1 *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + int i; + + trace_user_setup_frame(regs, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto sigsegv; + } + + setup_sigcontext(&frame->sc, regs, set->sig[0]); + + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->extramask[i - 1]); + } + + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v1, retcode)); + + unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); +} + +static void setup_frame_v2(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUARMState *regs) +{ + struct sigframe_v2 *frame; + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); + + trace_user_setup_frame(regs, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto sigsegv; + } + + setup_sigframe_v2(&frame->uc, set, regs); + + setup_return(regs, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct sigframe_v2, retcode)); + + unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); +} + +void setup_frame(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUARMState *regs) +{ + if (get_osversion() >= 0x020612) { + setup_frame_v2(usig, ka, set, regs); + } else { + setup_frame_v1(usig, ka, set, regs); + } +} + +/* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ +static void setup_rt_frame_v1(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUARMState *env) +{ + struct rt_sigframe_v1 *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); + struct target_sigaltstack stack; + int i; + abi_ulong info_addr, uc_addr; + + trace_user_setup_rt_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto sigsegv; + } + + info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); + __put_user(info_addr, &frame->pinfo); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); + __put_user(uc_addr, &frame->puc); + tswap_siginfo(&frame->info, info); + + /* Clear all the bits of the ucontext we don't use. */ + memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); + + memset(&stack, 0, sizeof(stack)); + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); + memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); + + setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); + for(i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); + } + + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); + + env->regs[1] = info_addr; + env->regs[2] = uc_addr; + + unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); +} + +static void setup_rt_frame_v2(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUARMState *env) +{ + struct rt_sigframe_v2 *frame; + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); + abi_ulong info_addr, uc_addr; + + trace_user_setup_rt_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto sigsegv; + } + + info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); + uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); + tswap_siginfo(&frame->info, info); + + setup_sigframe_v2(&frame->uc, set, env); + + setup_return(env, ka, &frame->retcode, frame_addr, usig, + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); + + env->regs[1] = info_addr; + env->regs[2] = uc_addr; + + unlock_user_struct(frame, frame_addr, 1); + return; +sigsegv: + force_sigsegv(usig); +} + +void setup_rt_frame(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUARMState *env) +{ + if (get_osversion() >= 0x020612) { + setup_rt_frame_v2(usig, ka, info, set, env); + } else { + setup_rt_frame_v1(usig, ka, info, set, env); + } +} + +static int +restore_sigcontext(CPUARMState *env, struct target_sigcontext *sc) +{ + int err = 0; + uint32_t cpsr; + + __get_user(env->regs[0], &sc->arm_r0); + __get_user(env->regs[1], &sc->arm_r1); + __get_user(env->regs[2], &sc->arm_r2); + __get_user(env->regs[3], &sc->arm_r3); + __get_user(env->regs[4], &sc->arm_r4); + __get_user(env->regs[5], &sc->arm_r5); + __get_user(env->regs[6], &sc->arm_r6); + __get_user(env->regs[7], &sc->arm_r7); + __get_user(env->regs[8], &sc->arm_r8); + __get_user(env->regs[9], &sc->arm_r9); + __get_user(env->regs[10], &sc->arm_r10); + __get_user(env->regs[11], &sc->arm_fp); + __get_user(env->regs[12], &sc->arm_ip); + __get_user(env->regs[13], &sc->arm_sp); + __get_user(env->regs[14], &sc->arm_lr); + __get_user(env->regs[15], &sc->arm_pc); +#ifdef TARGET_CONFIG_CPU_32 + __get_user(cpsr, &sc->arm_cpsr); + cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr); +#endif + + err |= !valid_user_regs(env); + + return err; +} + +static long do_sigreturn_v1(CPUARMState *env) +{ + abi_ulong frame_addr; + struct sigframe_v1 *frame = NULL; + target_sigset_t set; + sigset_t host_set; + int i; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + + __get_user(set.sig[0], &frame->sc.oldmask); + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + __get_user(set.sig[i], &frame->extramask[i - 1]); + } + + target_to_host_sigset_internal(&host_set, &set); + set_sigmask(&host_set); + + if (restore_sigcontext(env, &frame->sc)) { + goto badframe; + } + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + +badframe: + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} + +static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace) +{ + int i; + abi_ulong magic, sz; + uint32_t fpscr, fpexc; + struct target_vfp_sigframe *vfpframe; + vfpframe = (struct target_vfp_sigframe *)regspace; + + __get_user(magic, &vfpframe->magic); + __get_user(sz, &vfpframe->size); + if (magic != TARGET_VFP_MAGIC || sz != sizeof(*vfpframe)) { + return 0; + } + for (i = 0; i < 32; i++) { + __get_user(*aa32_vfp_dreg(env, i), &vfpframe->ufp.fpregs[i]); + } + __get_user(fpscr, &vfpframe->ufp.fpscr); + vfp_set_fpscr(env, fpscr); + __get_user(fpexc, &vfpframe->ufp_exc.fpexc); + /* Sanitise FPEXC: ensure VFP is enabled, FPINST2 is invalid + * and the exception flag is cleared + */ + fpexc |= (1 << 30); + fpexc &= ~((1 << 31) | (1 << 28)); + env->vfp.xregs[ARM_VFP_FPEXC] = fpexc; + __get_user(env->vfp.xregs[ARM_VFP_FPINST], &vfpframe->ufp_exc.fpinst); + __get_user(env->vfp.xregs[ARM_VFP_FPINST2], &vfpframe->ufp_exc.fpinst2); + return (abi_ulong*)(vfpframe + 1); +} + +static abi_ulong *restore_sigframe_v2_iwmmxt(CPUARMState *env, + abi_ulong *regspace) +{ + int i; + abi_ulong magic, sz; + struct target_iwmmxt_sigframe *iwmmxtframe; + iwmmxtframe = (struct target_iwmmxt_sigframe *)regspace; + + __get_user(magic, &iwmmxtframe->magic); + __get_user(sz, &iwmmxtframe->size); + if (magic != TARGET_IWMMXT_MAGIC || sz != sizeof(*iwmmxtframe)) { + return 0; + } + for (i = 0; i < 16; i++) { + __get_user(env->iwmmxt.regs[i], &iwmmxtframe->regs[i]); + } + __get_user(env->vfp.xregs[ARM_IWMMXT_wCSSF], &iwmmxtframe->wcssf); + __get_user(env->vfp.xregs[ARM_IWMMXT_wCASF], &iwmmxtframe->wcssf); + __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR0], &iwmmxtframe->wcgr0); + __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR1], &iwmmxtframe->wcgr1); + __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR2], &iwmmxtframe->wcgr2); + __get_user(env->vfp.xregs[ARM_IWMMXT_wCGR3], &iwmmxtframe->wcgr3); + return (abi_ulong*)(iwmmxtframe + 1); +} + +static int do_sigframe_return_v2(CPUARMState *env, + target_ulong context_addr, + struct target_ucontext_v2 *uc) +{ + sigset_t host_set; + abi_ulong *regspace; + + target_to_host_sigset(&host_set, &uc->tuc_sigmask); + set_sigmask(&host_set); + + if (restore_sigcontext(env, &uc->tuc_mcontext)) + return 1; + + /* Restore coprocessor signal frame */ + regspace = uc->tuc_regspace; + if (arm_feature(env, ARM_FEATURE_VFP)) { + regspace = restore_sigframe_v2_vfp(env, regspace); + if (!regspace) { + return 1; + } + } + if (arm_feature(env, ARM_FEATURE_IWMMXT)) { + regspace = restore_sigframe_v2_iwmmxt(env, regspace); + if (!regspace) { + return 1; + } + } + + if (do_sigaltstack(context_addr + + offsetof(struct target_ucontext_v2, tuc_stack), + 0, get_sp_from_cpustate(env)) == -EFAULT) { + return 1; + } + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + + return 0; +} + +static long do_sigreturn_v2(CPUARMState *env) +{ + abi_ulong frame_addr; + struct sigframe_v2 *frame = NULL; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct sigframe_v2, uc), + &frame->uc)) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} + +long do_sigreturn(CPUARMState *env) +{ + if (get_osversion() >= 0x020612) { + return do_sigreturn_v2(env); + } else { + return do_sigreturn_v1(env); + } +} + +static long do_rt_sigreturn_v1(CPUARMState *env) +{ + abi_ulong frame_addr; + struct rt_sigframe_v1 *frame = NULL; + sigset_t host_set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_rt_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); + set_sigmask(&host_set); + + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) { + goto badframe; + } + + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) + goto badframe; + +#if 0 + /* Send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt(current)) + send_sig(SIGTRAP, current, 1); +#endif + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} + +static long do_rt_sigreturn_v2(CPUARMState *env) +{ + abi_ulong frame_addr; + struct rt_sigframe_v2 *frame = NULL; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + frame_addr = env->regs[13]; + trace_user_do_rt_sigreturn(env, frame_addr); + if (frame_addr & 7) { + goto badframe; + } + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + + if (do_sigframe_return_v2(env, + frame_addr + + offsetof(struct rt_sigframe_v2, uc), + &frame->uc)) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + +badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} + +long do_rt_sigreturn(CPUARMState *env) +{ + if (get_osversion() >= 0x020612) { + return do_rt_sigreturn_v2(env); + } else { + return do_rt_sigreturn_v1(env); + } +} diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h index cbbeb09..4b542c3 100644 --- a/linux-user/arm/target_signal.h +++ b/linux-user/arm/target_signal.h @@ -26,5 +26,9 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state) return state->regs[13]; } - +void setup_frame(int usig, struct target_sigaction *ka, + target_sigset_t *set, CPUARMState *regs); +void setup_rt_frame(int usig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUARMState *env); #endif /* ARM_TARGET_SIGNAL_H */ -- cgit v1.1