master
c 210 lines 6.8 KB
Raw
1 /*
2 * arm signal functions
3 *
4 * Copyright (c) 2013 Stacey D. Son
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8 #include "qemu/osdep.h"
9 #include "qemu.h"
10
11 /*
12 * Compare to arm/arm/machdep.c sendsig()
13 * Assumes that target stack frame memory is locked.
14 */
15 abi_long set_sigtramp_args(CPUARMState *env, int sig,
16 struct target_sigframe *frame,
17 abi_ulong frame_addr,
18 struct target_sigaction *ka)
19 {
20 /*
21 * Arguments to signal handler:
22 * r0 = signal number
23 * r1 = siginfo pointer
24 * r2 = ucontext pointer
25 * r5 = ucontext pointer
26 * pc = signal handler pointer
27 * sp = sigframe struct pointer
28 * lr = sigtramp at base of user stack
29 */
30
31 env->regs[0] = sig;
32 env->regs[1] = frame_addr +
33 offsetof(struct target_sigframe, sf_si);
34 env->regs[2] = frame_addr +
35 offsetof(struct target_sigframe, sf_uc);
36
37 /* the trampoline uses r5 as the uc address */
38 env->regs[5] = frame_addr +
39 offsetof(struct target_sigframe, sf_uc);
40 env->regs[TARGET_REG_PC] = ka->_sa_handler & ~1;
41 env->regs[TARGET_REG_SP] = frame_addr;
42 env->regs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
43 /*
44 * Low bit indicates whether or not we're entering thumb mode.
45 */
46 cpsr_write(env, (ka->_sa_handler & 1) * CPSR_T, CPSR_T, CPSRWriteByInstr);
47
48 return 0;
49 }
50
51 static abi_long get_vfpcontext(CPUARMState *env, abi_ulong frame_addr,
52 struct target_sigframe *frame)
53 {
54 /* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
55 target_mcontext_vfp_t *vfp = &frame->sf_vfp;
56 target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
57
58 /* Assumes that mcp and vfp are locked */
59 for (int i = 0; i < 32; i++) {
60 vfp->mcv_reg[i] = tswap64(*aa32_vfp_dreg(env, i));
61 }
62 vfp->mcv_fpscr = tswap32(vfp_get_fpscr(env));
63 mcp->mc_vfp_size = tswap32(sizeof(*vfp));
64 mcp->mc_vfp_ptr = tswap32(frame_addr + ((uintptr_t)vfp - (uintptr_t)frame));
65 return 0;
66 }
67
68 /*
69 * Compare to arm/arm/exec_machdep.c get_mcontext()
70 * Assumes that the memory is locked if mcp points to user memory.
71 */
72 abi_long get_mcontext(CPUARMState *env, target_mcontext_t *mcp, int flags)
73 {
74 uint32_t *gr = mcp->__gregs;
75
76 gr[TARGET_REG_CPSR] = tswap32(cpsr_read(env));
77 if (flags & TARGET_MC_GET_CLEAR_RET) {
78 gr[TARGET_REG_R0] = 0;
79 gr[TARGET_REG_CPSR] &= ~CPSR_C;
80 } else {
81 gr[TARGET_REG_R0] = tswap32(env->regs[0]);
82 }
83
84 gr[TARGET_REG_R1] = tswap32(env->regs[1]);
85 gr[TARGET_REG_R2] = tswap32(env->regs[2]);
86 gr[TARGET_REG_R3] = tswap32(env->regs[3]);
87 gr[TARGET_REG_R4] = tswap32(env->regs[4]);
88 gr[TARGET_REG_R5] = tswap32(env->regs[5]);
89 gr[TARGET_REG_R6] = tswap32(env->regs[6]);
90 gr[TARGET_REG_R7] = tswap32(env->regs[7]);
91 gr[TARGET_REG_R8] = tswap32(env->regs[8]);
92 gr[TARGET_REG_R9] = tswap32(env->regs[9]);
93 gr[TARGET_REG_R10] = tswap32(env->regs[10]);
94 gr[TARGET_REG_R11] = tswap32(env->regs[11]);
95 gr[TARGET_REG_R12] = tswap32(env->regs[12]);
96
97 gr[TARGET_REG_SP] = tswap32(env->regs[13]);
98 gr[TARGET_REG_LR] = tswap32(env->regs[14]);
99 gr[TARGET_REG_PC] = tswap32(env->regs[15]);
100
101 /*
102 * FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
103 * size to zero. Applications that need the VFP state use
104 * sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
105 */
106 mcp->mc_vfp_size = 0;
107 mcp->mc_vfp_ptr = 0;
108 memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
109
110 return 0;
111 }
112
113 /*
114 * Compare to arm/arm/exec_machdep.c sendsig()
115 * Assumes that the memory is locked if frame points to user memory.
116 */
117 abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr,
118 struct target_sigframe *frame, int flags)
119 {
120 target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
121
122 get_mcontext(env, mcp, flags);
123 get_vfpcontext(env, frame_addr, frame);
124 return 0;
125 }
126
127 /* Compare to arm/arm/exec_machdep.c set_mcontext() */
128 abi_long set_mcontext(CPUARMState *env, target_mcontext_t *mcp, int srflag)
129 {
130 int err = 0;
131 const uint32_t *gr = mcp->__gregs;
132 uint32_t cpsr, ccpsr = cpsr_read(env);
133 uint32_t fpscr, mask;
134
135 cpsr = tswap32(gr[TARGET_REG_CPSR]);
136 /*
137 * Only allow certain bits to change, reject attempted changes to non-user
138 * bits. In addition, make sure we're headed for user mode and none of the
139 * interrupt bits are set.
140 */
141 if ((ccpsr & ~CPSR_USER) != (cpsr & ~CPSR_USER)) {
142 return -TARGET_EINVAL;
143 }
144 if ((cpsr & CPSR_M) != ARM_CPU_MODE_USR ||
145 (cpsr & (CPSR_I | CPSR_F)) != 0) {
146 return -TARGET_EINVAL;
147 }
148
149 /*
150 * The movs pc,lr instruction that implements the return to userland masks
151 * these bits out.
152 */
153 mask = cpsr & CPSR_T ? 0x1 : 0x3;
154
155 /*
156 * Make sure that we either have no vfp, or it's the correct size.
157 * FreeBSD just ignores it, though, so maybe we'll need to adjust
158 * things below instead.
159 */
160 if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(target_mcontext_vfp_t)) {
161 return -TARGET_EINVAL;
162 }
163
164 env->regs[0] = tswap32(gr[TARGET_REG_R0]);
165 env->regs[1] = tswap32(gr[TARGET_REG_R1]);
166 env->regs[2] = tswap32(gr[TARGET_REG_R2]);
167 env->regs[3] = tswap32(gr[TARGET_REG_R3]);
168 env->regs[4] = tswap32(gr[TARGET_REG_R4]);
169 env->regs[5] = tswap32(gr[TARGET_REG_R5]);
170 env->regs[6] = tswap32(gr[TARGET_REG_R6]);
171 env->regs[7] = tswap32(gr[TARGET_REG_R7]);
172 env->regs[8] = tswap32(gr[TARGET_REG_R8]);
173 env->regs[9] = tswap32(gr[TARGET_REG_R9]);
174 env->regs[10] = tswap32(gr[TARGET_REG_R10]);
175 env->regs[11] = tswap32(gr[TARGET_REG_R11]);
176 env->regs[12] = tswap32(gr[TARGET_REG_R12]);
177
178 env->regs[13] = tswap32(gr[TARGET_REG_SP]);
179 env->regs[14] = tswap32(gr[TARGET_REG_LR]);
180 env->regs[15] = tswap32(gr[TARGET_REG_PC] & ~mask);
181 if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr != 0) {
182 /* see set_vfpcontext in sys/arm/arm/exec_machdep.c */
183 target_mcontext_vfp_t *vfp;
184
185 vfp = lock_user(VERIFY_READ, mcp->mc_vfp_ptr, sizeof(*vfp), 1);
186 for (int i = 0; i < 32; i++) {
187 __get_user(*aa32_vfp_dreg(env, i), &vfp->mcv_reg[i]);
188 }
189 __get_user(fpscr, &vfp->mcv_fpscr);
190 vfp_set_fpscr(env, fpscr);
191 unlock_user(vfp, mcp->mc_vfp_ptr, sizeof(target_ucontext_t));
192
193 /*
194 * linux-user sets fpexc, fpinst and fpinst2, but these aren't in
195 * FreeBSD's mcontext, what to do?
196 */
197 }
198 cpsr_write(env, cpsr, CPSR_USER | CPSR_EXEC, CPSRWriteByInstr);
199
200 return err;
201 }
202
203 /* Compare to arm/arm/machdep.c sys_sigreturn() */
204 abi_long get_ucontext_sigreturn(CPUARMState *env, abi_ulong target_sf,
205 abi_ulong *target_uc)
206 {
207 *target_uc = target_sf;
208
209 return 0;
210 }