summary refs log tree commit diff stats
path: root/hw/intc/arm_gic.c
diff options
context:
space:
mode:
authorFabian Aggeler <aggelerf@ethz.ch>2015-05-12 11:57:17 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-05-12 11:57:17 +0100
commit679aa175e84f5f80b32b307fce5a6b92729e0e61 (patch)
tree55aefc4eb7ed961e5dcfedc990521b2d5a08e756 /hw/intc/arm_gic.c
parenteb8b9530b0c618d4f2e728eae10d89239d35b0c0 (diff)
downloadfocaccia-qemu-679aa175e84f5f80b32b307fce5a6b92729e0e61.tar.gz
focaccia-qemu-679aa175e84f5f80b32b307fce5a6b92729e0e61.zip
hw/intc/arm_gic: Make ICDDCR/GICD_CTLR banked
ICDDCR/GICD_CTLR is banked if the GIC has the security extensions,
and the S (or only) copy has separate enable bits for Group0 and
Group1 enable if the GIC implements interrupt groups.

EnableGroup0 (Bit [1]) in GICv1 is architecturally IMPDEF. Since this
bit (Enable Non-secure) is present in the integrated GIC of the Cortex-A9
MPCore, we support this bit in our GICv1 implementation too.

Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1430502643-25909-7-git-send-email-peter.maydell@linaro.org
Message-id: 1429113742-8371-8-git-send-email-greg.bellows@linaro.org
[PMM: rewritten to store the state in a single s->ctlr uint32,
 with the NS register handled as an alias of bit 1 in that value;
 added vmstate version bump]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc/arm_gic.c')
-rw-r--r--hw/intc/arm_gic.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 1aa45209ce..4f13ff2c90 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -67,7 +67,8 @@ void gic_update(GICState *s)
     for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
         cm = 1 << cpu;
         s->current_pending[cpu] = 1023;
-        if (!s->enabled || !s->cpu_enabled[cpu]) {
+        if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1))
+            || !s->cpu_enabled[cpu]) {
             qemu_irq_lower(s->parent_irq[cpu]);
             return;
         }
@@ -303,8 +304,16 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
     cpu = gic_get_current_cpu(s);
     cm = 1 << cpu;
     if (offset < 0x100) {
-        if (offset == 0)
-            return s->enabled;
+        if (offset == 0) {      /* GICD_CTLR */
+            if (s->security_extn && !attrs.secure) {
+                /* The NS bank of this register is just an alias of the
+                 * EnableGrp1 bit in the S bank version.
+                 */
+                return extract32(s->ctlr, 1, 1);
+            } else {
+                return s->ctlr;
+            }
+        }
         if (offset == 4)
             /* Interrupt Controller Type Register */
             return ((s->num_irq / 32) - 1)
@@ -475,8 +484,17 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
     cpu = gic_get_current_cpu(s);
     if (offset < 0x100) {
         if (offset == 0) {
-            s->enabled = (value & 1);
-            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
+            if (s->security_extn && !attrs.secure) {
+                /* NS version is just an alias of the S version's bit 1 */
+                s->ctlr = deposit32(s->ctlr, 1, 1, value);
+            } else if (gic_has_groups(s)) {
+                s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1);
+            } else {
+                s->ctlr = value & GICD_CTLR_EN_GRP0;
+            }
+            DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n",
+                    s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis",
+                    s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis");
         } else if (offset < 4) {
             /* ignored.  */
         } else if (offset >= 0x80) {