aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/cpu.h66
1 files changed, 52 insertions, 14 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 7f800908f4..810cc0b781 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1247,27 +1247,50 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
CPUARMState *env = cs->env_ptr;
unsigned int cur_el = arm_current_el(env);
unsigned int target_el = arm_excp_target_el(cs, excp_idx);
- /* FIXME: Use actual secure state. */
- bool secure = false;
- /* If in EL1/0, Physical IRQ routing to EL2 only happens from NS state. */
- bool irq_can_hyp = !secure && cur_el < 2 && target_el == 2;
-
- /* Don't take exceptions if they target a lower EL. */
+ bool secure = arm_is_secure(env);
+ uint32_t scr;
+ uint32_t hcr;
+ bool pstate_unmasked;
+ int8_t unmasked = 0;
+
+ /* Don't take exceptions if they target a lower EL.
+ * This check should catch any exceptions that would not be taken but left
+ * pending.
+ */
if (cur_el > target_el) {
return false;
}
switch (excp_idx) {
case EXCP_FIQ:
- if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_FMO)) {
- return true;
- }
- return !(env->daif & PSTATE_F);
+ /* If FIQs are routed to EL3 or EL2 then there are cases where we
+ * override the CPSR.F in determining if the exception is masked or
+ * not. If neither of these are set then we fall back to the CPSR.F
+ * setting otherwise we further assess the state below.
+ */
+ hcr = (env->cp15.hcr_el2 & HCR_FMO);
+ scr = (env->cp15.scr_el3 & SCR_FIQ);
+
+ /* When EL3 is 32-bit, the SCR.FW bit controls whether the CPSR.F bit
+ * masks FIQ interrupts when taken in non-secure state. If SCR.FW is
+ * set then FIQs can be masked by CPSR.F when non-secure but only
+ * when FIQs are only routed to EL3.
+ */
+ scr &= !((env->cp15.scr_el3 & SCR_FW) && !hcr);
+ pstate_unmasked = !(env->daif & PSTATE_F);
+ break;
+
case EXCP_IRQ:
- if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) {
- return true;
- }
- return !(env->daif & PSTATE_I);
+ /* When EL3 execution state is 32-bit, if HCR.IMO is set then we may
+ * override the CPSR.I masking when in non-secure state. The SCR.IRQ
+ * setting has already been taken into consideration when setting the
+ * target EL, so it does not have a further affect here.
+ */
+ hcr = (env->cp15.hcr_el2 & HCR_IMO);
+ scr = false;
+ pstate_unmasked = !(env->daif & PSTATE_I);
+ break;
+
case EXCP_VFIQ:
if (secure || !(env->cp15.hcr_el2 & HCR_FMO)) {
/* VFIQs are only taken when hypervized and non-secure. */
@@ -1283,6 +1306,21 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
default:
g_assert_not_reached();
}
+
+ /* Use the target EL, current execution state and SCR/HCR settings to
+ * determine whether the corresponding CPSR bit is used to mask the
+ * interrupt.
+ */
+ if ((target_el > cur_el) && (target_el != 1)) {
+ if (arm_el_is_aa64(env, 3) || ((scr || hcr) && (!secure))) {
+ unmasked = 1;
+ }
+ }
+
+ /* The PSTATE bits only mask the interrupt if we have not overriden the
+ * ability above.
+ */
+ return unmasked || pstate_unmasked;
}
static inline CPUARMState *cpu_init(const char *cpu_model)