diff options
Diffstat (limited to 'target-arm')
-rw-r--r-- | target-arm/cpu.h | 66 |
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) |