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
);
63 * Compare to arm/arm/machdep.c get_mcontext()
64 * Assumes that the memory is locked if mcp points to user memory.
66 abi_long
get_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int flags
)
69 uint32_t *gr
= mcp
->__gregs
;
71 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_size
!= sizeof(target_mcontext_vfp_t
)) {
72 return -TARGET_EINVAL
;
75 gr
[TARGET_REG_CPSR
] = tswap32(cpsr_read(env
));
76 if (flags
& TARGET_MC_GET_CLEAR_RET
) {
77 gr
[TARGET_REG_R0
] = 0;
78 gr
[TARGET_REG_CPSR
] &= ~CPSR_C
;
80 gr
[TARGET_REG_R0
] = tswap32(env
->regs
[0]);
83 gr
[TARGET_REG_R1
] = tswap32(env
->regs
[1]);
84 gr
[TARGET_REG_R2
] = tswap32(env
->regs
[2]);
85 gr
[TARGET_REG_R3
] = tswap32(env
->regs
[3]);
86 gr
[TARGET_REG_R4
] = tswap32(env
->regs
[4]);
87 gr
[TARGET_REG_R5
] = tswap32(env
->regs
[5]);
88 gr
[TARGET_REG_R6
] = tswap32(env
->regs
[6]);
89 gr
[TARGET_REG_R7
] = tswap32(env
->regs
[7]);
90 gr
[TARGET_REG_R8
] = tswap32(env
->regs
[8]);
91 gr
[TARGET_REG_R9
] = tswap32(env
->regs
[9]);
92 gr
[TARGET_REG_R10
] = tswap32(env
->regs
[10]);
93 gr
[TARGET_REG_R11
] = tswap32(env
->regs
[11]);
94 gr
[TARGET_REG_R12
] = tswap32(env
->regs
[12]);
96 gr
[TARGET_REG_SP
] = tswap32(env
->regs
[13]);
97 gr
[TARGET_REG_LR
] = tswap32(env
->regs
[14]);
98 gr
[TARGET_REG_PC
] = tswap32(env
->regs
[15]);
100 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_ptr
!= 0) {
101 /* see get_vfpcontext in sys/arm/arm/exec_machdep.c */
102 target_mcontext_vfp_t
*vfp
;
103 vfp
= lock_user(VERIFY_WRITE
, mcp
->mc_vfp_ptr
, sizeof(*vfp
), 0);
104 for (int i
= 0; i
< 32; i
++) {
105 vfp
->mcv_reg
[i
] = tswap64(*aa32_vfp_dreg(env
, i
));
107 vfp
->mcv_fpscr
= tswap32(vfp_get_fpscr(env
));
108 unlock_user(vfp
, mcp
->mc_vfp_ptr
, sizeof(*vfp
));
113 /* Compare to arm/arm/exec_machdep.c set_mcontext() */
114 abi_long
set_mcontext(CPUARMState
*env
, target_mcontext_t
*mcp
, int srflag
)
117 const uint32_t *gr
= mcp
->__gregs
;
118 uint32_t cpsr
, ccpsr
= cpsr_read(env
);
119 uint32_t fpscr
, mask
;
121 cpsr
= tswap32(gr
[TARGET_REG_CPSR
]);
123 * Only allow certain bits to change, reject attempted changes to non-user
124 * bits. In addition, make sure we're headed for user mode and none of the
125 * interrupt bits are set.
127 if ((ccpsr
& ~CPSR_USER
) != (cpsr
& ~CPSR_USER
)) {
128 return -TARGET_EINVAL
;
130 if ((cpsr
& CPSR_M
) != ARM_CPU_MODE_USR
||
131 (cpsr
& (CPSR_I
| CPSR_F
)) != 0) {
132 return -TARGET_EINVAL
;
136 * The movs pc,lr instruction that implements the return to userland masks
139 mask
= cpsr
& CPSR_T
? 0x1 : 0x3;
142 * Make sure that we either have no vfp, or it's the correct size.
143 * FreeBSD just ignores it, though, so maybe we'll need to adjust
144 * things below instead.
146 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_size
!= sizeof(target_mcontext_vfp_t
)) {
147 return -TARGET_EINVAL
;
150 env
->regs
[0] = tswap32(gr
[TARGET_REG_R0
]);
151 env
->regs
[1] = tswap32(gr
[TARGET_REG_R1
]);
152 env
->regs
[2] = tswap32(gr
[TARGET_REG_R2
]);
153 env
->regs
[3] = tswap32(gr
[TARGET_REG_R3
]);
154 env
->regs
[4] = tswap32(gr
[TARGET_REG_R4
]);
155 env
->regs
[5] = tswap32(gr
[TARGET_REG_R5
]);
156 env
->regs
[6] = tswap32(gr
[TARGET_REG_R6
]);
157 env
->regs
[7] = tswap32(gr
[TARGET_REG_R7
]);
158 env
->regs
[8] = tswap32(gr
[TARGET_REG_R8
]);
159 env
->regs
[9] = tswap32(gr
[TARGET_REG_R9
]);
160 env
->regs
[10] = tswap32(gr
[TARGET_REG_R10
]);
161 env
->regs
[11] = tswap32(gr
[TARGET_REG_R11
]);
162 env
->regs
[12] = tswap32(gr
[TARGET_REG_R12
]);
164 env
->regs
[13] = tswap32(gr
[TARGET_REG_SP
]);
165 env
->regs
[14] = tswap32(gr
[TARGET_REG_LR
]);
166 env
->regs
[15] = tswap32(gr
[TARGET_REG_PC
] & ~mask
);
167 if (mcp
->mc_vfp_size
!= 0 && mcp
->mc_vfp_ptr
!= 0) {
168 /* see set_vfpcontext in sys/arm/arm/exec_machdep.c */
169 target_mcontext_vfp_t
*vfp
;
171 vfp
= lock_user(VERIFY_READ
, mcp
->mc_vfp_ptr
, sizeof(*vfp
), 1);
172 for (int i
= 0; i
< 32; i
++) {
173 __get_user(*aa32_vfp_dreg(env
, i
), &vfp
->mcv_reg
[i
]);
175 __get_user(fpscr
, &vfp
->mcv_fpscr
);
176 vfp_set_fpscr(env
, fpscr
);
177 unlock_user(vfp
, mcp
->mc_vfp_ptr
, sizeof(target_ucontext_t
));
180 * linux-user sets fpexc, fpinst and fpinst2, but these aren't in
181 * FreeBSD's mcontext, what to do?
184 cpsr_write(env
, cpsr
, CPSR_USER
| CPSR_EXEC
, CPSRWriteByInstr
);
189 /* Compare to arm/arm/machdep.c sys_sigreturn() */
190 abi_long
get_ucontext_sigreturn(CPUARMState
*env
, abi_ulong target_sf
,
191 abi_ulong
*target_uc
)
193 *target_uc
= target_sf
;