mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set
For the A64 instruction set, the only FP/Neon disable trap
is the CPACR FPEN bits, which may indicate "enabled", "disabled"
or "disabled for EL0". Add a bit to the AArch64 tb flags indicating
whether FP/Neon access is currently enabled and make the decoder
emit code to raise exceptions on use of FP/Neon insns if it is not.
We use a new flag in DisasContext rather than borrowing the
existing vfp_enabled flag because the A32/T32 decoder is going
to need both.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Acked-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
I'm aware this is a rather hard to review patch; sorry.
I have done an exhaustive check that we have fp access checks
in all code paths with the aid of the assertions added in the
next patch plus the code-coverage hack patch I posted to the
list earlier.
This patch is correct as of
09e037354 target-arm: A64: Add saturating accumulate ops (USQADD/SUQADD)
which was the last of the Neon insns to be added, so assuming
no refactoring of the code it should be fine.
This commit is contained in:
@@ -100,8 +100,15 @@ static void arm_cpu_reset(CPUState *s)
|
||||
env->pstate = PSTATE_MODE_EL0t;
|
||||
/* Userspace expects access to CTL_EL0 and the cache ops */
|
||||
env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
|
||||
/* and to the FP/Neon instructions */
|
||||
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
|
||||
#else
|
||||
env->pstate = PSTATE_MODE_EL1h;
|
||||
#endif
|
||||
} else {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* Userspace expects access to cp10 and cp11 for FP/Neon */
|
||||
env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 4, 0xf);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1108,6 +1108,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
|
||||
/* Bit usage when in AArch64 state */
|
||||
#define ARM_TBFLAG_AA64_EL_SHIFT 0
|
||||
#define ARM_TBFLAG_AA64_EL_MASK (0x3 << ARM_TBFLAG_AA64_EL_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_FPEN_SHIFT 2
|
||||
#define ARM_TBFLAG_AA64_FPEN_MASK (1 << ARM_TBFLAG_AA64_FPEN_SHIFT)
|
||||
|
||||
/* some convenience accessor macros */
|
||||
#define ARM_TBFLAG_AARCH64_STATE(F) \
|
||||
@@ -1128,14 +1130,21 @@ static inline int cpu_mmu_index (CPUARMState *env)
|
||||
(((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_EL(F) \
|
||||
(((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT)
|
||||
#define ARM_TBFLAG_AA64_FPEN(F) \
|
||||
(((F) & ARM_TBFLAG_AA64_FPEN_MASK) >> ARM_TBFLAG_AA64_FPEN_SHIFT)
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, int *flags)
|
||||
{
|
||||
int fpen = extract32(env->cp15.c1_coproc, 20, 2);
|
||||
|
||||
if (is_a64(env)) {
|
||||
*pc = env->pc;
|
||||
*flags = ARM_TBFLAG_AARCH64_STATE_MASK
|
||||
| (arm_current_pl(env) << ARM_TBFLAG_AA64_EL_SHIFT);
|
||||
if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
|
||||
*flags |= ARM_TBFLAG_AA64_FPEN_MASK;
|
||||
}
|
||||
} else {
|
||||
int privmode;
|
||||
*pc = env->regs[15];
|
||||
|
||||
@@ -188,6 +188,13 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
|
||||
| (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
|
||||
}
|
||||
|
||||
static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_thumb)
|
||||
{
|
||||
return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
|
||||
| (is_thumb ? 0 : ARM_EL_IL)
|
||||
| (cv << 24) | (cond << 20);
|
||||
}
|
||||
|
||||
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
|
||||
{
|
||||
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
|
||||
|
||||
+295
-5
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,8 @@ typedef struct DisasContext {
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int user;
|
||||
#endif
|
||||
int vfp_enabled;
|
||||
bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
|
||||
bool vfp_enabled; /* FP enabled via FPSCR.EN */
|
||||
int vec_len;
|
||||
int vec_stride;
|
||||
/* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
|
||||
|
||||
Reference in New Issue
Block a user