4 * Copyright (c) 2013 Stacey D. Son
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
24 * Compare to arm/arm/machdep.c sendsig()
25 * Assumes that target stack frame memory is locked.
27 abi_long
set_sigtramp_args(CPUARMState
*env
, int sig
,
28 struct target_sigframe
*frame
,
30 struct target_sigaction
*ka
)
33 * Arguments to signal handler:
35 * r1 = siginfo pointer
36 * r2 = ucontext pointer
37 * r5 = ucontext pointer
38 * pc = signal handler pointer
39 * sp = sigframe struct pointer
40 * lr = sigtramp at base of user stack
44 env
->regs
[1] = frame_addr
+
45 offsetof(struct target_sigframe
, sf_si
);
46 env
->regs
[2] = frame_addr
+
47 offsetof(struct target_sigframe
, sf_uc
);
49 /* the trampoline uses r5 as the uc address */
50 env
->regs
[5] = frame_addr
+
51 offsetof(struct target_sigframe
, sf_uc
);
52 env
->regs
[TARGET_REG_PC
] = ka
->_sa_handler
& ~1;
53 env
->regs
[TARGET_REG_SP
] = frame_addr
;
54 env
->regs
[TARGET_REG_LR
] = TARGET_PS_STRINGS
- TARGET_SZSIGCODE
;
56 * Low bit indicates whether or not we're entering thumb mode.
58 cpsr_write(env
, (ka
->_sa_handler
& 1) * CPSR_T
, CPSR_T
, CPSRWriteByInstr
);
63 static abi_long
get_vfpcontext(CPUARMState
*env
, abi_ulong frame_addr
,
64 struct target_sigframe
*frame
)
66 /* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
67 target_mcontext_vfp_t
*vfp
= &frame
->sf_vfp
;
68 target_mcontext_t
*mcp
= &frame
->sf_uc
.uc_mcontext
;
70 /* Assumes that mcp and vfp are locked */
71 for (int i
= 0; i
< 32; i
++) {
72 vfp
->mcv_reg
[i
] = tswap64(*aa32_vfp_dreg(env
, i
));
74 vfp
->mcv_fpscr
= tswap32(vfp_get_fpscr(env
));
75 mcp
->mc_vfp_size
= tswap32(sizeof(*vfp
));
76 mcp
->mc_vfp_ptr
= tswap32(frame_addr
+ ((uintptr_t)vfp
- (uintptr_t)frame
));
81 * Compare to arm/arm/exec_machdep.c get_mcontext()
82 * Assumes that the memory is locked if mcp points to user memory.
84 abi_long
get_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int flags
)
86 uint32_t *gr
= mcp
->__gregs
;
88 gr
[TARGET_REG_CPSR
] = tswap32(cpsr_read(env
));
89 if (flags
& TARGET_MC_GET_CLEAR_RET
) {
90 gr
[TARGET_REG_R0
] = 0;
91 gr
[TARGET_REG_CPSR
] &= ~CPSR_C
;
93 gr
[TARGET_REG_R0
] = tswap32(env
->regs
[0]);
96 gr
[TARGET_REG_R1
] = tswap32(env
->regs
[1]);
97 gr
[TARGET_REG_R2
] = tswap32(env
->regs
[2]);
98 gr
[TARGET_REG_R3
] = tswap32(env
->regs
[3]);
99 gr
[TARGET_REG_R4
] = tswap32(env
->regs
[4]);
100 gr
[TARGET_REG_R5
] = tswap32(env
->regs
[5]);
101 gr
[TARGET_REG_R6
] = tswap32(env
->regs
[6]);
102 gr
[TARGET_REG_R7
] = tswap32(env
->regs
[7]);
103 gr
[TARGET_REG_R8
] = tswap32(env
->regs
[8]);
104 gr
[TARGET_REG_R9
] = tswap32(env
->regs
[9]);
105 gr
[TARGET_REG_R10
] = tswap32(env
->regs
[10]);
106 gr
[TARGET_REG_R11
] = tswap32(env
->regs
[11]);
107 gr
[TARGET_REG_R12
] = tswap32(env
->regs
[12]);
109 gr
[TARGET_REG_SP
] = tswap32(env
->regs
[13]);
110 gr
[TARGET_REG_LR
] = tswap32(env
->regs
[14]);
111 gr
[TARGET_REG_PC
] = tswap32(env
->regs
[15]);
114 * FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
115 * size to zero. Applications that need the VFP state use
116 * sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
118 mcp
->mc_vfp_size
= 0;
120 memset(&mcp
->mc_spare
, 0, sizeof(mcp
->mc_spare
));
126 * Compare to arm/arm/exec_machdep.c sendsig()
127 * Assumes that the memory is locked if frame points to user memory.
129 abi_long
setup_sigframe_arch(CPUARMState
*env
, abi_ulong frame_addr
,
130 struct target_sigframe
*frame
, int flags
)
132 target_mcontext_t
*mcp
= &frame
->sf_uc
.uc_mcontext
;
134 get_mcontext(env
, mcp
, flags
);
135 get_vfpcontext(env
, frame_addr
, frame
);
139 /* Compare to arm/arm/exec_machdep.c set_mcontext() */
140 abi_long
set_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int srflag
)
143 const uint32_t *gr
= mcp
->__gregs
;
144 uint32_t cpsr
, ccpsr
= cpsr_read(env
);
145 uint32_t fpscr
, mask
;
147 cpsr
= tswap32(gr
[TARGET_REG_CPSR
]);
149 * Only allow certain bits to change, reject attempted changes to non-user
150 * bits. In addition, make sure we're headed for user mode and none of the
151 * interrupt bits are set.
153 if ((ccpsr
& ~CPSR_USER
) != (cpsr
& ~CPSR_USER
)) {
154 return -TARGET_EINVAL
;
156 if ((cpsr
& CPSR_M
) != ARM_CPU_MODE_USR
||
157 (cpsr
& (CPSR_I
| CPSR_F
)) != 0) {
158 return -TARGET_EINVAL
;
162 * The movs pc,lr instruction that implements the return to userland masks
165 mask
= cpsr
& CPSR_T
? 0x1 : 0x3;
168 * Make sure that we either have no vfp, or it's the correct size.
169 * FreeBSD just ignores it, though, so maybe we'll need to adjust
170 * things below instead.
172 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_size
!= sizeof(target_mcontext_vfp_t
)) {
173 return -TARGET_EINVAL
;
176 env
->regs
[0] = tswap32(gr
[TARGET_REG_R0
]);
177 env
->regs
[1] = tswap32(gr
[TARGET_REG_R1
]);
178 env
->regs
[2] = tswap32(gr
[TARGET_REG_R2
]);
179 env
->regs
[3] = tswap32(gr
[TARGET_REG_R3
]);
180 env
->regs
[4] = tswap32(gr
[TARGET_REG_R4
]);
181 env
->regs
[5] = tswap32(gr
[TARGET_REG_R5
]);
182 env
->regs
[6] = tswap32(gr
[TARGET_REG_R6
]);
183 env
->regs
[7] = tswap32(gr
[TARGET_REG_R7
]);
184 env
->regs
[8] = tswap32(gr
[TARGET_REG_R8
]);
185 env
->regs
[9] = tswap32(gr
[TARGET_REG_R9
]);
186 env
->regs
[10] = tswap32(gr
[TARGET_REG_R10
]);
187 env
->regs
[11] = tswap32(gr
[TARGET_REG_R11
]);
188 env
->regs
[12] = tswap32(gr
[TARGET_REG_R12
]);
190 env
->regs
[13] = tswap32(gr
[TARGET_REG_SP
]);
191 env
->regs
[14] = tswap32(gr
[TARGET_REG_LR
]);
192 env
->regs
[15] = tswap32(gr
[TARGET_REG_PC
] & ~mask
);
193 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_ptr
!= 0) {
194 /* see set_vfpcontext in sys/arm/arm/exec_machdep.c */
195 target_mcontext_vfp_t
*vfp
;
197 vfp
= lock_user(VERIFY_READ
, mcp
->mc_vfp_ptr
, sizeof(*vfp
), 1);
198 for (int i
= 0; i
< 32; i
++) {
199 __get_user(*aa32_vfp_dreg(env
, i
), &vfp
->mcv_reg
[i
]);
201 __get_user(fpscr
, &vfp
->mcv_fpscr
);
202 vfp_set_fpscr(env
, fpscr
);
203 unlock_user(vfp
, mcp
->mc_vfp_ptr
, sizeof(target_ucontext_t
));
206 * linux-user sets fpexc, fpinst and fpinst2, but these aren't in
207 * FreeBSD's mcontext, what to do?
210 cpsr_write(env
, cpsr
, CPSR_USER
| CPSR_EXEC
, CPSRWriteByInstr
);
215 /* Compare to arm/arm/machdep.c sys_sigreturn() */
216 abi_long
get_ucontext_sigreturn(CPUARMState
*env
, abi_ulong target_sf
,
217 abi_ulong
*target_uc
)
219 *target_uc
= target_sf
;