Implements v7m exception priority algorithm using FAULTMASK, PRIMASK, BASEPRI, and the highest priority active exception.
The number returned is the current execution priority which may be in the range [-2,0x7f] when an exception is active or 0x100 when no exception is active. --- hw/intc/armv7m_nvic.c | 25 +++++++++++++++++++++++++ target-arm/cpu.h | 1 + 2 files changed, 26 insertions(+) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 6fc167e..0145ca7 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -18,6 +18,8 @@ typedef struct { GICState gic; + uint8_t prigroup; + struct { uint32_t control; uint32_t reload; @@ -116,6 +118,29 @@ static void systick_reset(nvic_state *s) timer_del(s->systick.timer); } +/* @returns the active (running) exception priority. + * only a higher (numerically lower) priority can preempt. + */ +int armv7m_excp_running_prio(ARMCPU *cpu) +{ + CPUARMState *env = &cpu->env; + nvic_state *s = env->nvic; + int running; + + if (env->daif & PSTATE_F) { /* FAULTMASK */ + running = -1; + } else if (env->daif & PSTATE_I) { /* PRIMASK */ + running = 0; + } else if (env->v7m.basepri > 0) { + /* BASEPRI==1 -> masks [1,255] (not same as PRIMASK==1) */ + running = env->v7m.basepri >> (s->prigroup+1); + } else { + running = 0x100; /* lower than any possible priority */ + } + /* consider priority of active handler */ + return MIN(running, env->v7m.exception_prio); +} + /* The external routines use the hardware vector numbering, ie. the first IRQ is #16. The internal GIC routines use #32 as the first IRQ. */ void armv7m_nvic_set_pending(void *opaque, int irq) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c193fbb..e2d9e75 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1034,6 +1034,7 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); /* Interface between CPU and Interrupt controller. */ +int armv7m_excp_running_prio(ARMCPU *cpu); void armv7m_nvic_set_pending(void *opaque, int irq); int armv7m_nvic_acknowledge_irq(void *opaque); void armv7m_nvic_complete_irq(void *opaque, int irq); -- 2.1.4