On armv7m mcus, the BASEPRI register can be set to mask interrupts above a certain priority.
This changeset implements that functionality by way of the NVIC which ultimately sets the interrupt mask in the GIC. Signed-off-by: François Baldassari <franc...@pebble.com> --- hw/intc/arm_gic.c | 2 +- hw/intc/armv7m_nvic.c | 11 +++++++++++ hw/intc/gic_internal.h | 4 ++++ target-arm/cpu.h | 1 + target-arm/helper.c | 2 ++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index d71aeb8..27b4906 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -399,7 +399,7 @@ static uint32_t gic_get_priority(GICState *s, int cpu, int irq, return prio; } -static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, +void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, MemTxAttrs attrs) { if (s->security_extn && !attrs.secure) { diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 6fc167e..d1aa556 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -148,6 +148,17 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) gic_complete_irq(&s->gic, 0, irq, MEMTXATTRS_UNSPECIFIED); } + +void armv7m_nvic_set_priority_mask(void *opaque, uint16_t mask) +{ + nvic_state *s = (nvic_state *)opaque; + if (mask == 0) { + /* 0 is used to disable the priority mask */ + mask = 0x100; + } + gic_set_priority_mask(&s->gic, 0, mask, MEMTXATTRS_UNSPECIFIED); +} + static uint32_t nvic_readl(nvic_state *s, uint32_t offset) { ARMCPU *cpu; diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 20c1e8a..995f337 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -84,6 +84,10 @@ void gic_update(GICState *s); void gic_init_irqs_and_distributor(GICState *s); void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, MemTxAttrs attrs); +void gic_set_priority_mask(GICState *s, + int cpu, + uint8_t pmask, + MemTxAttrs attrs); static inline bool gic_test_pending(GICState *s, int irq, int cm) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 815fef8..fb7dc61 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, 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); +void armv7m_nvic_set_priority_mask(void *opaque, uint16_t mask); /* Interface for defining coprocessor registers. * Registers are defined in tables of arm_cp_reginfo structs diff --git a/target-arm/helper.c b/target-arm/helper.c index 4ecae61..27807e9 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -7449,11 +7449,13 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val) break; case 17: /* BASEPRI */ env->v7m.basepri = val & 0xff; + armv7m_nvic_set_priority_mask(env->nvic, env->v7m.basepri); break; case 18: /* BASEPRI_MAX */ val &= 0xff; if (val != 0 && (val < env->v7m.basepri || env->v7m.basepri == 0)) env->v7m.basepri = val; + armv7m_nvic_set_priority_mask(env->nvic, env->v7m.basepri); break; case 19: /* FAULTMASK */ if (val & 1) { -- 2.4.0