Commit b5c633c5 authored by Peter Maydell's avatar Peter Maydell
Browse files

target-arm: Separate out M profile cpu_exec_interrupt handling



The M profile cpu_exec_interrupt handling is fairly simple
but does include an M profile specific oddity (disabling
interrupts for certain PC values). A/R profile handling
on the other hand is getting rapidly more complicated
with the support for EL2 and EL3. Split the M profile
code out into its own implementation of cpu_exec_interrupt
to keep these two things out of each others' way.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: default avatarEdgar E. Iglesias <edgar.iglesias@xilinx.com>
Message-id: 1414684132-23971-2-git-send-email-peter.maydell@linaro.org
parent f4df2210
Loading
Loading
Loading
Loading
+39 −10
Original line number Diff line number Diff line
@@ -203,15 +203,6 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
        cc->do_interrupt(cs);
        ret = true;
    }
    /* ARMv7-M interrupt return works by loading a magic value
       into the PC.  On real hardware the load causes the
       return to occur.  The qemu implementation performs the
       jump normally, then does the exception return when the
       CPU tries to execute code at the magic address.
       This will cause the magic PC value to be pushed to
       the stack if an interrupt occurred at the wrong time.
       We avoid this by disabling interrupts when
       pc contains a magic address.  */
    if (interrupt_request & CPU_INTERRUPT_HARD
        && arm_excp_unmasked(cs, EXCP_IRQ)) {
        cs->exception_index = EXCP_IRQ;
@@ -234,6 +225,42 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
    return ret;
}

#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
    CPUClass *cc = CPU_GET_CLASS(cs);
    ARMCPU *cpu = ARM_CPU(cs);
    CPUARMState *env = &cpu->env;
    bool ret = false;


    if (interrupt_request & CPU_INTERRUPT_FIQ
        && !(env->daif & PSTATE_F)) {
        cs->exception_index = EXCP_FIQ;
        cc->do_interrupt(cs);
        ret = true;
    }
    /* ARMv7-M interrupt return works by loading a magic value
     * into the PC.  On real hardware the load causes the
     * return to occur.  The qemu implementation performs the
     * jump normally, then does the exception return when the
     * CPU tries to execute code at the magic address.
     * This will cause the magic PC value to be pushed to
     * the stack if an interrupt occurred at the wrong time.
     * We avoid this by disabling interrupts when
     * pc contains a magic address.
     */
    if (interrupt_request & CPU_INTERRUPT_HARD
        && !(env->daif & PSTATE_I)
        && (env->regs[15] < 0xfffffff0)) {
        cs->exception_index = EXCP_IRQ;
        cc->do_interrupt(cs);
        ret = true;
    }
    return ret;
}
#endif

#ifndef CONFIG_USER_ONLY
static void arm_cpu_set_irq(void *opaque, int irq, int level)
{
@@ -670,11 +697,13 @@ static void cortex_m3_initfn(Object *obj)

static void arm_v7m_class_init(ObjectClass *oc, void *data)
{
#ifndef CONFIG_USER_ONLY
    CPUClass *cc = CPU_CLASS(oc);

#ifndef CONFIG_USER_ONLY
    cc->do_interrupt = arm_v7m_cpu_do_interrupt;
#endif

    cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt;
}

static const ARMCPRegInfo cortexa8_cp_reginfo[] = {
+2 −14
Original line number Diff line number Diff line
@@ -1251,18 +1251,6 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
    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;
    /* ARMv7-M interrupt return works by loading a magic value
     * into the PC.  On real hardware the load causes the
     * return to occur.  The qemu implementation performs the
     * jump normally, then does the exception return when the
     * CPU tries to execute code at the magic address.
     * This will cause the magic PC value to be pushed to
     * the stack if an interrupt occurred at the wrong time.
     * We avoid this by disabling interrupts when
     * pc contains a magic address.
     */
    bool irq_unmasked = !(env->daif & PSTATE_I)
                        && (!IS_M(env) || env->regs[15] < 0xfffffff0);

    /* Don't take exceptions if they target a lower EL.  */
    if (cur_el > target_el) {
@@ -1279,7 +1267,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
        if (irq_can_hyp && (env->cp15.hcr_el2 & HCR_IMO)) {
            return true;
        }
        return irq_unmasked;
        return !(env->daif & PSTATE_I);
    case EXCP_VFIQ:
        if (!secure && !(env->cp15.hcr_el2 & HCR_FMO)) {
            /* VFIQs are only taken when hypervized and non-secure.  */
@@ -1291,7 +1279,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
            /* VIRQs are only taken when hypervized and non-secure.  */
            return false;
        }
        return irq_unmasked;
        return !(env->daif & PSTATE_I);
    default:
        g_assert_not_reached();
    }