aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/arm/cpu.h2
-rw-r--r--target/arm/helper.c6
-rw-r--r--target/arm/op_helper.c22
-rw-r--r--target/arm/translate.c3
-rw-r--r--target/arm/translate.h2
5 files changed, 34 insertions, 1 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 83a809d4ba..cebb3511a5 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3215,6 +3215,8 @@ FIELD(TBFLAG_A32, NS, 6, 1)
FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Partially cached, minus FPEXC. */
FIELD(TBFLAG_A32, CONDEXEC, 8, 8) /* Not cached. */
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
+FIELD(TBFLAG_A32, HSTR_ACTIVE, 17, 1)
+
/* For M profile only, set if FPCCR.LSPACT is set */
FIELD(TBFLAG_A32, LSPACT, 18, 1) /* Not cached. */
/* For M profile only, set if we must create a new FP context */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 93ecab27c0..0ba08d550a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -11283,6 +11283,12 @@ static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el,
if (arm_el_is_aa64(env, 1)) {
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
+
+ if (arm_current_el(env) < 2 && env->cp15.hstr_el2 &&
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
+ flags = FIELD_DP32(flags, TBFLAG_A32, HSTR_ACTIVE, 1);
+ }
+
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
}
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index b529d6c1bf..e5a346cb87 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -603,6 +603,27 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
}
+ /*
+ * Check for an EL2 trap due to HSTR_EL2. We expect EL0 accesses
+ * to sysregs non accessible at EL0 to have UNDEF-ed already.
+ */
+ if (!is_a64(env) && arm_current_el(env) < 2 && ri->cp == 15 &&
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
+ uint32_t mask = 1 << ri->crn;
+
+ if (ri->type & ARM_CP_64BIT) {
+ mask = 1 << ri->crm;
+ }
+
+ /* T4 and T14 are RES0 */
+ mask &= ~((1 << 4) | (1 << 14));
+
+ if (env->cp15.hstr_el2 & mask) {
+ target_el = 2;
+ goto exept;
+ }
+ }
+
if (!ri->accessfn) {
return;
}
@@ -652,6 +673,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
g_assert_not_reached();
}
+exept:
raise_exception(env, EXCP_UDEF, syndrome, target_el);
}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 4d5d4bd888..f162be8434 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -6897,7 +6897,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
return 1;
}
- if (ri->accessfn ||
+ if (s->hstr_active || ri->accessfn ||
(arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
/* Emit code to perform further access permissions checks at
* runtime; this may result in an exception.
@@ -10843,6 +10843,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
!arm_el_is_aa64(env, 3);
dc->thumb = FIELD_EX32(tb_flags, TBFLAG_A32, THUMB);
dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR_B);
+ dc->hstr_active = FIELD_EX32(tb_flags, TBFLAG_A32, HSTR_ACTIVE);
dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
condexec = FIELD_EX32(tb_flags, TBFLAG_A32, CONDEXEC);
dc->condexec_mask = (condexec & 0xf) << 1;
diff --git a/target/arm/translate.h b/target/arm/translate.h
index dd24f91f26..b837b7fcbf 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -77,6 +77,8 @@ typedef struct DisasContext {
bool pauth_active;
/* True with v8.5-BTI and SCTLR_ELx.BT* set. */
bool bt;
+ /* True if any CP15 access is trapped by HSTR_EL2 */
+ bool hstr_active;
/*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction.