From c5619bf9e8935aeb972c0bd935549e9ee0a739f2 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:18 +0100 Subject: hw/intc/arm_gic: Change behavior of IAR writes Grouping (GICv2) and Security Extensions change the behavior of IAR reads. Acknowledging Group0 interrupts is only allowed from Secure state and acknowledging Group1 interrupts from Secure state is only allowed if AckCtl bit is set. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-14-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-14-git-send-email-greg.bellows@linaro.org [PMM: simplify significantly by reusing the existing gic_get_current_pending_irq() rather than reimplementing the same logic here] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 22 ++++++++++++++++------ hw/intc/armv7m_nvic.c | 2 +- hw/intc/gic_internal.h | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 4ad80e77bb..6abdb14379 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -213,14 +213,24 @@ static void gic_set_running_irq(GICState *s, int cpu, int irq) gic_update(s); } -uint32_t gic_acknowledge_irq(GICState *s, int cpu) +uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) { int ret, irq, src; int cm = 1 << cpu; - irq = s->current_pending[cpu]; - if (irq == 1023 - || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { - DPRINTF("ACK no pending IRQ\n"); + + /* gic_get_current_pending_irq() will return 1022 or 1023 appropriately + * for the case where this GIC supports grouping and the pending interrupt + * is in the wrong group. + */ + irq = gic_get_current_pending_irq(s, cpu, attrs);; + + if (irq >= GIC_MAXIRQ) { + DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); + return irq; + } + + if (GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { + DPRINTF("ACK, pending interrupt (%d) has insufficient priority\n", irq); return 1023; } s->last_active[irq][cpu] = s->running_irq[cpu]; @@ -920,7 +930,7 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, } break; case 0x0c: /* Acknowledge */ - *data = gic_acknowledge_irq(s, cpu); + *data = gic_acknowledge_irq(s, cpu, attrs); break; case 0x14: /* Running Priority */ *data = gic_get_running_priority(s, cpu, attrs); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 1bfff7530a..e13b729e1d 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -131,7 +131,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque) nvic_state *s = (nvic_state *)opaque; uint32_t irq; - irq = gic_acknowledge_irq(&s->gic, 0); + irq = gic_acknowledge_irq(&s->gic, 0, MEMTXATTRS_UNSPECIFIED); if (irq == 1023) hw_error("Interrupt but no vector\n"); if (irq >= 32) diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index d3cebeff3b..20c1e8a242 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -78,7 +78,7 @@ #define REV_NVIC 0xffffffff void gic_set_pending_private(GICState *s, int cpu, int irq); -uint32_t gic_acknowledge_irq(GICState *s, int cpu); +uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs); void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs); void gic_update(GICState *s); void gic_init_irqs_and_distributor(GICState *s); -- cgit v1.2.3