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


Reply via email to