Prepare to perform access checks for direct and
indirect uses of FPMR.
Signed-off-by: Richard Henderson <[email protected]>
---
target/arm/cpu.h | 1 +
target/arm/tcg/translate.h | 2 ++
target/arm/tcg/hflags.c | 41 ++++++++++++++++++++++++++++++++++
target/arm/tcg/translate-a64.c | 1 +
4 files changed, 45 insertions(+)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c114510446..9e637c1d80 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2567,6 +2567,7 @@ FIELD(TBFLAG_A64, ZT0EXC_EL, 39, 2)
FIELD(TBFLAG_A64, GCS_EN, 41, 1)
FIELD(TBFLAG_A64, GCS_RVCEN, 42, 1)
FIELD(TBFLAG_A64, GCSSTR_EL, 43, 2)
+FIELD(TBFLAG_A64, FPMR_EL, 45, 2)
/*
* Helpers for using the above. Note that only the A64 accessors use
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index 77fdc5f3a1..1648c2c96f 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -199,6 +199,8 @@ typedef struct DisasContext {
uint8_t gm_blocksize;
/* True if the current insn_start has been updated. */
bool insn_start_updated;
+ /* FMPR exception EL or 0 if enabled. */
+ uint8_t fpmr_el;
/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
uint32_t nv2_redirect_offset;
} DisasContext;
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index 7e6f8d3647..6759b36f28 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -237,6 +237,43 @@ static int zt0_exception_el(CPUARMState *env, int el)
return 0;
}
+/*
+ * Return the exception level to which exceptions should be taken for FPMR.
+ * C.f. the ARM pseudocode function CheckFPMREnabled.
+ */
+static int fpmr_exception_el(CPUARMState *env, int el)
+{
+ switch (el) {
+ case 0:
+ if (el_is_in_host(env, el)) {
+ if (!(env->cp15.sctlr_el[2] & SCTLR_EnFPM)) {
+ return 2;
+ }
+ break;
+ }
+ if (!(env->cp15.sctlr_el[1] & SCTLR_EnFPM)) {
+ return 1;
+ }
+ /* fall through */
+ case 1:
+ if (!(arm_hcrx_el2_eff(env) & HCRX_ENFPM)) {
+ return 2;
+ }
+ break;
+ case 2:
+ break;
+ case 3:
+ return 0;
+ default:
+ g_assert_not_reached();
+ }
+ if (arm_feature(env, ARM_FEATURE_EL3)
+ && !(env->cp15.scr_el3 & SCR_ENFPM)) {
+ return 3;
+ }
+ return 0;
+}
+
static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
ARMMMUIdx mmu_idx)
{
@@ -500,6 +537,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env,
int el, int fp_el,
}
}
+ if (cpu_isar_feature(aa64_fpmr, env_archcpu(env))) {
+ DP_TBFLAG_A64(flags, FPMR_EL, fpmr_exception_el(env, el));
+ }
+
return rebuild_hflags_common(env, fp_el, mmu_idx, flags);
}
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 3c6559964b..b013dd51cb 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10726,6 +10726,7 @@ static void
aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->gcs_en = EX_TBFLAG_A64(tb_flags, GCS_EN);
dc->gcs_rvcen = EX_TBFLAG_A64(tb_flags, GCS_RVCEN);
dc->gcsstr_el = EX_TBFLAG_A64(tb_flags, GCSSTR_EL);
+ dc->fpmr_el = EX_TBFLAG_A64(tb_flags, FPMR_EL);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = arm_cpu->cp_regs;
--
2.43.0