1781be866SWarner Losh /* 2781be866SWarner Losh * arm signal functions 3781be866SWarner Losh * 4781be866SWarner Losh * Copyright (c) 2013 Stacey D. Son 5781be866SWarner Losh * 6781be866SWarner Losh * This program is free software; you can redistribute it and/or modify 7781be866SWarner Losh * it under the terms of the GNU General Public License as published by 8781be866SWarner Losh * the Free Software Foundation; either version 2 of the License, or 9781be866SWarner Losh * (at your option) any later version. 10781be866SWarner Losh * 11781be866SWarner Losh * This program is distributed in the hope that it will be useful, 12781be866SWarner Losh * but WITHOUT ANY WARRANTY; without even the implied warranty of 13781be866SWarner Losh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14781be866SWarner Losh * GNU General Public License for more details. 15781be866SWarner Losh * 16781be866SWarner Losh * You should have received a copy of the GNU General Public License 17781be866SWarner Losh * along with this program; if not, see <http://www.gnu.org/licenses/>. 18781be866SWarner Losh */ 19781be866SWarner Losh 20781be866SWarner Losh #include "qemu.h" 21781be866SWarner Losh 22781be866SWarner Losh /* 23781be866SWarner Losh * Compare to arm/arm/machdep.c sendsig() 24781be866SWarner Losh * Assumes that target stack frame memory is locked. 25781be866SWarner Losh */ 26781be866SWarner Losh abi_long set_sigtramp_args(CPUARMState *env, int sig, 27781be866SWarner Losh struct target_sigframe *frame, 28781be866SWarner Losh abi_ulong frame_addr, 29781be866SWarner Losh struct target_sigaction *ka) 30781be866SWarner Losh { 31781be866SWarner Losh /* 32781be866SWarner Losh * Arguments to signal handler: 33781be866SWarner Losh * r0 = signal number 34781be866SWarner Losh * r1 = siginfo pointer 35781be866SWarner Losh * r2 = ucontext pointer 36781be866SWarner Losh * r5 = ucontext pointer 37781be866SWarner Losh * pc = signal handler pointer 38781be866SWarner Losh * sp = sigframe struct pointer 39781be866SWarner Losh * lr = sigtramp at base of user stack 40781be866SWarner Losh */ 41781be866SWarner Losh 42781be866SWarner Losh env->regs[0] = sig; 43781be866SWarner Losh env->regs[1] = frame_addr + 44781be866SWarner Losh offsetof(struct target_sigframe, sf_si); 45781be866SWarner Losh env->regs[2] = frame_addr + 46781be866SWarner Losh offsetof(struct target_sigframe, sf_uc); 47781be866SWarner Losh 48781be866SWarner Losh /* the trampoline uses r5 as the uc address */ 49781be866SWarner Losh env->regs[5] = frame_addr + 50781be866SWarner Losh offsetof(struct target_sigframe, sf_uc); 51781be866SWarner Losh env->regs[TARGET_REG_PC] = ka->_sa_handler & ~1; 52781be866SWarner Losh env->regs[TARGET_REG_SP] = frame_addr; 53781be866SWarner Losh env->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE; 54781be866SWarner Losh /* 55781be866SWarner Losh * Low bit indicates whether or not we're entering thumb mode. 56781be866SWarner Losh */ 57781be866SWarner Losh cpsr_write(env, (ka->_sa_handler & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr); 58781be866SWarner Losh 59781be866SWarner Losh return 0; 60781be866SWarner Losh } 6138ce1471SWarner Losh 62*22447462SWarner Losh static abi_long get_vfpcontext(CPUARMState *env, abi_ulong frame_addr, 63*22447462SWarner Losh struct target_sigframe *frame) 64*22447462SWarner Losh { 65*22447462SWarner Losh /* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */ 66*22447462SWarner Losh target_mcontext_vfp_t *vfp = &frame->sf_vfp; 67*22447462SWarner Losh target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext; 68*22447462SWarner Losh 69*22447462SWarner Losh /* Assumes that mcp and vfp are locked */ 70*22447462SWarner Losh for (int i = 0; i < 32; i++) { 71*22447462SWarner Losh vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i)); 72*22447462SWarner Losh } 73*22447462SWarner Losh vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env)); 74*22447462SWarner Losh mcp->mc_vfp_size = tswap32(sizeof(*vfp)); 75*22447462SWarner Losh mcp->mc_vfp_ptr = tswap32(frame_addr + ((uintptr_t)vfp - (uintptr_t)frame)); 76*22447462SWarner Losh return 0; 77*22447462SWarner Losh } 78*22447462SWarner Losh 7938ce1471SWarner Losh /* 80*22447462SWarner Losh * Compare to arm/arm/exec_machdep.c get_mcontext() 8138ce1471SWarner Losh * Assumes that the memory is locked if mcp points to user memory. 8238ce1471SWarner Losh */ 8338ce1471SWarner Losh abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags) 8438ce1471SWarner Losh { 8538ce1471SWarner Losh uint32_t *gr = mcp->__gregs; 8638ce1471SWarner Losh 8738ce1471SWarner Losh gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env)); 8838ce1471SWarner Losh if (flags & TARGET_MC_GET_CLEAR_RET) { 8938ce1471SWarner Losh gr[TARGET_REG_R0] = 0; 9038ce1471SWarner Losh gr[TARGET_REG_CPSR] &= ~CPSR_C; 9138ce1471SWarner Losh } else { 9238ce1471SWarner Losh gr[TARGET_REG_R0] = tswap32(env->regs[0]); 9338ce1471SWarner Losh } 9438ce1471SWarner Losh 9538ce1471SWarner Losh gr[TARGET_REG_R1] = tswap32(env->regs[1]); 9638ce1471SWarner Losh gr[TARGET_REG_R2] = tswap32(env->regs[2]); 9738ce1471SWarner Losh gr[TARGET_REG_R3] = tswap32(env->regs[3]); 9838ce1471SWarner Losh gr[TARGET_REG_R4] = tswap32(env->regs[4]); 9938ce1471SWarner Losh gr[TARGET_REG_R5] = tswap32(env->regs[5]); 10038ce1471SWarner Losh gr[TARGET_REG_R6] = tswap32(env->regs[6]); 10138ce1471SWarner Losh gr[TARGET_REG_R7] = tswap32(env->regs[7]); 10238ce1471SWarner Losh gr[TARGET_REG_R8] = tswap32(env->regs[8]); 10338ce1471SWarner Losh gr[TARGET_REG_R9] = tswap32(env->regs[9]); 10438ce1471SWarner Losh gr[TARGET_REG_R10] = tswap32(env->regs[10]); 10538ce1471SWarner Losh gr[TARGET_REG_R11] = tswap32(env->regs[11]); 10638ce1471SWarner Losh gr[TARGET_REG_R12] = tswap32(env->regs[12]); 10738ce1471SWarner Losh 10838ce1471SWarner Losh gr[TARGET_REG_SP] = tswap32(env->regs[13]); 10938ce1471SWarner Losh gr[TARGET_REG_LR] = tswap32(env->regs[14]); 11038ce1471SWarner Losh gr[TARGET_REG_PC] = tswap32(env->regs[15]); 11138ce1471SWarner Losh 112*22447462SWarner Losh return 0; 11338ce1471SWarner Losh } 114*22447462SWarner Losh 115*22447462SWarner Losh /* 116*22447462SWarner Losh * Compare to arm/arm/exec_machdep.c sendsig() 117*22447462SWarner Losh * Assumes that the memory is locked if frame points to user memory. 118*22447462SWarner Losh */ 119*22447462SWarner Losh abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr, 120*22447462SWarner Losh struct target_sigframe *frame, int flags) 121*22447462SWarner Losh { 122*22447462SWarner Losh target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext; 123*22447462SWarner Losh 124*22447462SWarner Losh get_mcontext(env, mcp, flags); 125*22447462SWarner Losh get_vfpcontext(env, frame_addr, frame); 126*22447462SWarner Losh return 0; 12738ce1471SWarner Losh } 128d6d4509aSWarner Losh 129d6d4509aSWarner Losh /* Compare to arm/arm/exec_machdep.c set_mcontext() */ 130d6d4509aSWarner Losh abi_long set_mcontext(CPUARMState *env, target_mcontext_t *mcp, int srflag) 131d6d4509aSWarner Losh { 132d6d4509aSWarner Losh int err = 0; 133d6d4509aSWarner Losh const uint32_t *gr = mcp->__gregs; 134d6d4509aSWarner Losh uint32_t cpsr, ccpsr = cpsr_read(env); 135d6d4509aSWarner Losh uint32_t fpscr, mask; 136d6d4509aSWarner Losh 137d6d4509aSWarner Losh cpsr = tswap32(gr[TARGET_REG_CPSR]); 138d6d4509aSWarner Losh /* 139d6d4509aSWarner Losh * Only allow certain bits to change, reject attempted changes to non-user 140d6d4509aSWarner Losh * bits. In addition, make sure we're headed for user mode and none of the 141d6d4509aSWarner Losh * interrupt bits are set. 142d6d4509aSWarner Losh */ 143d6d4509aSWarner Losh if ((ccpsr & ~CPSR_USER) != (cpsr & ~CPSR_USER)) { 144d6d4509aSWarner Losh return -TARGET_EINVAL; 145d6d4509aSWarner Losh } 146d6d4509aSWarner Losh if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR || 147d6d4509aSWarner Losh (cpsr & (CPSR_I | CPSR_F)) != 0) { 148d6d4509aSWarner Losh return -TARGET_EINVAL; 149d6d4509aSWarner Losh } 150d6d4509aSWarner Losh 151d6d4509aSWarner Losh /* 152d6d4509aSWarner Losh * The movs pc,lr instruction that implements the return to userland masks 153d6d4509aSWarner Losh * these bits out. 154d6d4509aSWarner Losh */ 155d6d4509aSWarner Losh mask = cpsr & CPSR_T ? 0x1 : 0x3; 156d6d4509aSWarner Losh 157d6d4509aSWarner Losh /* 158d6d4509aSWarner Losh * Make sure that we either have no vfp, or it's the correct size. 159d6d4509aSWarner Losh * FreeBSD just ignores it, though, so maybe we'll need to adjust 160d6d4509aSWarner Losh * things below instead. 161d6d4509aSWarner Losh */ 162d6d4509aSWarner Losh if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) { 163d6d4509aSWarner Losh return -TARGET_EINVAL; 164d6d4509aSWarner Losh } 165d6d4509aSWarner Losh 166d6d4509aSWarner Losh env->regs[0] = tswap32(gr[TARGET_REG_R0]); 167d6d4509aSWarner Losh env->regs[1] = tswap32(gr[TARGET_REG_R1]); 168d6d4509aSWarner Losh env->regs[2] = tswap32(gr[TARGET_REG_R2]); 169d6d4509aSWarner Losh env->regs[3] = tswap32(gr[TARGET_REG_R3]); 170d6d4509aSWarner Losh env->regs[4] = tswap32(gr[TARGET_REG_R4]); 171d6d4509aSWarner Losh env->regs[5] = tswap32(gr[TARGET_REG_R5]); 172d6d4509aSWarner Losh env->regs[6] = tswap32(gr[TARGET_REG_R6]); 173d6d4509aSWarner Losh env->regs[7] = tswap32(gr[TARGET_REG_R7]); 174d6d4509aSWarner Losh env->regs[8] = tswap32(gr[TARGET_REG_R8]); 175d6d4509aSWarner Losh env->regs[9] = tswap32(gr[TARGET_REG_R9]); 176d6d4509aSWarner Losh env->regs[10] = tswap32(gr[TARGET_REG_R10]); 177d6d4509aSWarner Losh env->regs[11] = tswap32(gr[TARGET_REG_R11]); 178d6d4509aSWarner Losh env->regs[12] = tswap32(gr[TARGET_REG_R12]); 179d6d4509aSWarner Losh 180d6d4509aSWarner Losh env->regs[13] = tswap32(gr[TARGET_REG_SP]); 181d6d4509aSWarner Losh env->regs[14] = tswap32(gr[TARGET_REG_LR]); 182d6d4509aSWarner Losh env->regs[15] = tswap32(gr[TARGET_REG_PC] & ~mask); 183d6d4509aSWarner Losh if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) { 184d6d4509aSWarner Losh /* see set_vfpcontext in sys/arm/arm/exec_machdep.c */ 185d6d4509aSWarner Losh target_mcontext_vfp_t *vfp; 186d6d4509aSWarner Losh 187d6d4509aSWarner Losh vfp = lock_user(VERIFY_READ, mcp->mc_vfp_ptr, sizeof(*vfp), 1); 188d6d4509aSWarner Losh for (int i = 0; i < 32; i++) { 189d6d4509aSWarner Losh __get_user(*aa32_vfp_dreg(env, i), &vfp->mcv_reg[i]); 190d6d4509aSWarner Losh } 191d6d4509aSWarner Losh __get_user(fpscr, &vfp->mcv_fpscr); 192d6d4509aSWarner Losh vfp_set_fpscr(env, fpscr); 193d6d4509aSWarner Losh unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(target_ucontext_t)); 194d6d4509aSWarner Losh 195d6d4509aSWarner Losh /* 196d6d4509aSWarner Losh * linux-user sets fpexc, fpinst and fpinst2, but these aren't in 197d6d4509aSWarner Losh * FreeBSD's mcontext, what to do? 198d6d4509aSWarner Losh */ 199d6d4509aSWarner Losh } 200d6d4509aSWarner Losh cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr); 201d6d4509aSWarner Losh 202d6d4509aSWarner Losh return err; 203d6d4509aSWarner Losh } 2043ac34cc9SWarner Losh 2053ac34cc9SWarner Losh /* Compare to arm/arm/machdep.c sys_sigreturn() */ 2063ac34cc9SWarner Losh abi_long get_ucontext_sigreturn(CPUARMState *env, abi_ulong target_sf, 2073ac34cc9SWarner Losh abi_ulong *target_uc) 2083ac34cc9SWarner Losh { 2093ac34cc9SWarner Losh *target_uc = target_sf; 2103ac34cc9SWarner Losh 2113ac34cc9SWarner Losh return 0; 2123ac34cc9SWarner Losh } 213