From: Fabian Aggeler <aggel...@ethz.ch> Grouping (GICv2) and Security Extensions change the behaviour of reads of the highest priority pending interrupt register (ICCHPIR/GICC_HPPIR).
Signed-off-by: Fabian Aggeler <aggel...@ethz.ch> --- hw/intc/arm_gic.c | 29 ++++++++++++++++++++++++++++- hw/intc/gic_internal.h | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 9b021d7..15fd660 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -329,6 +329,33 @@ uint8_t gic_get_running_priority(GICState *s, int cpu) } } +uint16_t gic_get_current_pending_irq(GICState *s, int cpu) +{ + bool isGrp0; + uint16_t pendingId = s->current_pending[cpu]; + + if (pendingId < GIC_MAXIRQ && (s->revision >= 2 || s->security_extn)) { + isGrp0 = GIC_TEST_GROUP0(pendingId, (1 << cpu)); + if ((isGrp0 && !s->enabled_grp[0]) + || (!isGrp0 && !s->enabled_grp[1])) { + return 1023; + } + if (s->security_extn) { + if (isGrp0 && ns_access()) { + /* Group0 interrupts hidden from Non-secure access */ + return 1023; + } + if (!isGrp0 && !ns_access() + && !(s->cpu_control[cpu][0] & GICC_CTLR_S_ACK_CTL)) { + /* Group1 interrupts only seen by Secure access if + * AckCtl bit set. */ + return 1022; + } + } + } + return pendingId; +} + void gic_complete_irq(GICState *s, int cpu, int irq) { int update = 0; @@ -866,7 +893,7 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) case 0x14: /* Running Priority */ return gic_get_running_priority(s, cpu); case 0x18: /* Highest Pending Interrupt */ - return s->current_pending[cpu]; + return gic_get_current_pending_irq(s, cpu); case 0x1c: /* Aliased Binary Point */ if (!s->security_extn || (s->security_extn && ns_access())) { /* If Security Extensions are present ABPR is a secure register, diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 821ce16..fbb1f66 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -79,6 +79,7 @@ void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val); uint32_t gic_get_cpu_control(GICState *s, int cpu); void gic_set_cpu_control(GICState *s, int cpu, uint32_t value); uint8_t gic_get_running_priority(GICState *s, int cpu); +uint16_t gic_get_current_pending_irq(GICState *s, int cpu); static inline bool gic_test_pending(GICState *s, int irq, int cm) -- 1.8.3.2