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/>.
23 * Compare to arm/arm/machdep.c sendsig()
24 * Assumes that target stack frame memory is locked.
26 abi_long
set_sigtramp_args(CPUARMState
*env
, int sig
,
27 struct target_sigframe
*frame
,
29 struct target_sigaction
*ka
)
32 * Arguments to signal handler:
34 * r1 = siginfo pointer
35 * r2 = ucontext pointer
36 * r5 = ucontext pointer
37 * pc = signal handler pointer
38 * sp = sigframe struct pointer
39 * lr = sigtramp at base of user stack
43 env
->regs
[1] = frame_addr
+
44 offsetof(struct target_sigframe
, sf_si
);
45 env
->regs
[2] = frame_addr
+
46 offsetof(struct target_sigframe
, sf_uc
);
48 /* the trampoline uses r5 as the uc address */
49 env
->regs
[5] = frame_addr
+
50 offsetof(struct target_sigframe
, sf_uc
);
51 env
->regs
[TARGET_REG_PC
] = ka
->_sa_handler
& ~1;
52 env
->regs
[TARGET_REG_SP
] = frame_addr
;
53 env
->regs
[TARGET_REG_LR
] = TARGET_PS_STRINGS
- TARGET_SZSIGCODE
;
55 * Low bit indicates whether or not we're entering thumb mode.
57 cpsr_write(env
, (ka
->_sa_handler
& 1) * CPSR_T
, CPSR_T
, CPSRWriteByInstr
);
62 static abi_long
get_vfpcontext(CPUARMState
*env
, abi_ulong frame_addr
,
63 struct target_sigframe
*frame
)
65 /* see sendsig and get_vfpcontext in sys/arm/arm/exec_machdep.c */
66 target_mcontext_vfp_t
*vfp
= &frame
->sf_vfp
;
67 target_mcontext_t
*mcp
= &frame
->sf_uc
.uc_mcontext
;
69 /* Assumes that mcp and vfp are locked */
70 for (int i
= 0; i
< 32; i
++) {
71 vfp
->mcv_reg
[i
] = tswap64(*aa32_vfp_dreg(env
, i
));
73 vfp
->mcv_fpscr
= tswap32(vfp_get_fpscr(env
));
74 mcp
->mc_vfp_size
= tswap32(sizeof(*vfp
));
75 mcp
->mc_vfp_ptr
= tswap32(frame_addr
+ ((uintptr_t)vfp
- (uintptr_t)frame
));
80 * Compare to arm/arm/exec_machdep.c get_mcontext()
81 * Assumes that the memory is locked if mcp points to user memory.
83 abi_long
get_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int flags
)
85 uint32_t *gr
= mcp
->__gregs
;
87 gr
[TARGET_REG_CPSR
] = tswap32(cpsr_read(env
));
88 if (flags
& TARGET_MC_GET_CLEAR_RET
) {
89 gr
[TARGET_REG_R0
] = 0;
90 gr
[TARGET_REG_CPSR
] &= ~CPSR_C
;
92 gr
[TARGET_REG_R0
] = tswap32(env
->regs
[0]);
95 gr
[TARGET_REG_R1
] = tswap32(env
->regs
[1]);
96 gr
[TARGET_REG_R2
] = tswap32(env
->regs
[2]);
97 gr
[TARGET_REG_R3
] = tswap32(env
->regs
[3]);
98 gr
[TARGET_REG_R4
] = tswap32(env
->regs
[4]);
99 gr
[TARGET_REG_R5
] = tswap32(env
->regs
[5]);
100 gr
[TARGET_REG_R6
] = tswap32(env
->regs
[6]);
101 gr
[TARGET_REG_R7
] = tswap32(env
->regs
[7]);
102 gr
[TARGET_REG_R8
] = tswap32(env
->regs
[8]);
103 gr
[TARGET_REG_R9
] = tswap32(env
->regs
[9]);
104 gr
[TARGET_REG_R10
] = tswap32(env
->regs
[10]);
105 gr
[TARGET_REG_R11
] = tswap32(env
->regs
[11]);
106 gr
[TARGET_REG_R12
] = tswap32(env
->regs
[12]);
108 gr
[TARGET_REG_SP
] = tswap32(env
->regs
[13]);
109 gr
[TARGET_REG_LR
] = tswap32(env
->regs
[14]);
110 gr
[TARGET_REG_PC
] = tswap32(env
->regs
[15]);
113 * FreeBSD's get_mcontext doesn't save VFP info, but sets the pointer and
114 * size to zero. Applications that need the VFP state use
115 * sysarch(ARM_GET_VFPSTATE) and are expected to adjust mcontext after that.
117 mcp
->mc_vfp_size
= 0;
119 memset(&mcp
->mc_spare
, 0, sizeof(mcp
->mc_spare
));
125 * Compare to arm/arm/exec_machdep.c sendsig()
126 * Assumes that the memory is locked if frame points to user memory.
128 abi_long
setup_sigframe_arch(CPUARMState
*env
, abi_ulong frame_addr
,
129 struct target_sigframe
*frame
, int flags
)
131 target_mcontext_t
*mcp
= &frame
->sf_uc
.uc_mcontext
;
133 get_mcontext(env
, mcp
, flags
);
134 get_vfpcontext(env
, frame_addr
, frame
);
138 /* Compare to arm/arm/exec_machdep.c set_mcontext() */
139 abi_long
set_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int srflag
)
142 const uint32_t *gr
= mcp
->__gregs
;
143 uint32_t cpsr
, ccpsr
= cpsr_read(env
);
144 uint32_t fpscr
, mask
;
146 cpsr
= tswap32(gr
[TARGET_REG_CPSR
]);
148 * Only allow certain bits to change, reject attempted changes to non-user
149 * bits. In addition, make sure we're headed for user mode and none of the
150 * interrupt bits are set.
152 if ((ccpsr
& ~CPSR_USER
) != (cpsr
& ~CPSR_USER
)) {
153 return -TARGET_EINVAL
;
155 if ((cpsr
& CPSR_M
) != ARM_CPU_MODE_USR
||
156 (cpsr
& (CPSR_I
| CPSR_F
)) != 0) {
157 return -TARGET_EINVAL
;
161 * The movs pc,lr instruction that implements the return to userland masks
164 mask
= cpsr
& CPSR_T
? 0x1 : 0x3;
167 * Make sure that we either have no vfp, or it's the correct size.
168 * FreeBSD just ignores it, though, so maybe we'll need to adjust
169 * things below instead.
171 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_size
!= sizeof(target_mcontext_vfp_t
)) {
172 return -TARGET_EINVAL
;
175 env
->regs
[0] = tswap32(gr
[TARGET_REG_R0
]);
176 env
->regs
[1] = tswap32(gr
[TARGET_REG_R1
]);
177 env
->regs
[2] = tswap32(gr
[TARGET_REG_R2
]);
178 env
->regs
[3] = tswap32(gr
[TARGET_REG_R3
]);
179 env
->regs
[4] = tswap32(gr
[TARGET_REG_R4
]);
180 env
->regs
[5] = tswap32(gr
[TARGET_REG_R5
]);
181 env
->regs
[6] = tswap32(gr
[TARGET_REG_R6
]);
182 env
->regs
[7] = tswap32(gr
[TARGET_REG_R7
]);
183 env
->regs
[8] = tswap32(gr
[TARGET_REG_R8
]);
184 env
->regs
[9] = tswap32(gr
[TARGET_REG_R9
]);
185 env
->regs
[10] = tswap32(gr
[TARGET_REG_R10
]);
186 env
->regs
[11] = tswap32(gr
[TARGET_REG_R11
]);
187 env
->regs
[12] = tswap32(gr
[TARGET_REG_R12
]);
189 env
->regs
[13] = tswap32(gr
[TARGET_REG_SP
]);
190 env
->regs
[14] = tswap32(gr
[TARGET_REG_LR
]);
191 env
->regs
[15] = tswap32(gr
[TARGET_REG_PC
] & ~mask
);
192 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_ptr
!= 0) {
193 /* see set_vfpcontext in sys/arm/arm/exec_machdep.c */
194 target_mcontext_vfp_t
*vfp
;
196 vfp
= lock_user(VERIFY_READ
, mcp
->mc_vfp_ptr
, sizeof(*vfp
), 1);
197 for (int i
= 0; i
< 32; i
++) {
198 __get_user(*aa32_vfp_dreg(env
, i
), &vfp
->mcv_reg
[i
]);
200 __get_user(fpscr
, &vfp
->mcv_fpscr
);
201 vfp_set_fpscr(env
, fpscr
);
202 unlock_user(vfp
, mcp
->mc_vfp_ptr
, sizeof(target_ucontext_t
));
205 * linux-user sets fpexc, fpinst and fpinst2, but these aren't in
206 * FreeBSD's mcontext, what to do?
209 cpsr_write(env
, cpsr
, CPSR_USER
| CPSR_EXEC
, CPSRWriteByInstr
);
214 /* Compare to arm/arm/machdep.c sys_sigreturn() */
215 abi_long
get_ucontext_sigreturn(CPUARMState
*env
, abi_ulong target_sf
,
216 abi_ulong
*target_uc
)
218 *target_uc
= target_sf
;