aboutsummaryrefslogtreecommitdiff
path: root/hw/intc/arm_gic.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-03-04 11:46:32 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-03-04 11:46:32 +0000
commit3c0f12df65da872d5fbccae469f2cb21ed1c03b7 (patch)
treeda8e1ea0ee497fea96ed2bf52ef5ca93285bc9f4 /hw/intc/arm_gic.c
parent2d3b7c0164e1b9287304bc70dd6ed071ba3e8dfc (diff)
parentba63cf47a93041137a94e86b7d0cd87fc896949b (diff)
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160304' into staging
target-arm queue: * Correct handling of writes to CPSR from gdbstub in user mode * virt: lift maximum RAM limit to 255GB * sdhci: implement reset * virt: if booting in Secure mode, provide secure-only RAM, make first flash device secure-only, and assume the EL3 boot rom will handle PSCI * bcm2835: use explicit endianness accessors rather than ldl/stl_phys * support big-endian in system mode for ARM * implement SETEND instruction * arm_gic: implement the GICv2 GICC_DIR register * fix SRS bug: only trap from S-EL1 to EL3 if specified mode is Mon # gpg: Signature made Fri 04 Mar 2016 11:38:53 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160304: (30 commits) target-arm: Only trap SRS from S-EL1 if specified mode is MON hw/intc/arm_gic.c: Implement GICv2 GICC_DIR arm: boot: Support big-endian elfs loader: Add data swap option to load-elf loader: load_elf(): Add doc comment loader: add API to load elf header target-arm: implement BE32 mode in system emulation target-arm: implement setend target-arm: introduce tbflag for endianness target-arm: a64: Add endianness support target-arm: introduce disas flag for endianness target-arm: pass DisasContext to gen_aa32_ld*/st* target-arm: implement SCTLR.EE linux-user: arm: handle CPSR.E correctly in strex emulation linux-user: arm: set CPSR.E/SCTLR.E0E correctly for BE mode arm: cpu: handle BE32 user-mode as BE target-arm: cpu: Move cpu_is_big_endian to header target-arm: implement SCTLR.B, drop bswap_code linux-user: arm: pass env to get_user_code_* linux-user: arm: fix coding style for some linux-user signal functions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc/arm_gic.c')
-rw-r--r--hw/intc/arm_gic.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 60ab9b858b..0834c2f1a7 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -500,6 +500,41 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
}
}
+/* Return true if we should split priority drop and interrupt deactivation,
+ * ie whether the relevant EOIMode bit is set.
+ */
+static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs)
+{
+ if (s->revision != 2) {
+ /* Before GICv2 prio-drop and deactivate are not separable */
+ return false;
+ }
+ if (s->security_extn && !attrs.secure) {
+ return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS;
+ }
+ return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE;
+}
+
+static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
+{
+ int cm = 1 << cpu;
+ int group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
+
+ if (!gic_eoi_split(s, cpu, attrs)) {
+ /* This is UNPREDICTABLE; we choose to ignore it */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "gic_deactivate_irq: GICC_DIR write when EOIMode clear");
+ return;
+ }
+
+ if (s->security_extn && !attrs.secure && !group) {
+ DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq);
+ return;
+ }
+
+ GIC_CLEAR_ACTIVE(irq, cm);
+}
+
void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
{
int cm = 1 << cpu;
@@ -544,7 +579,11 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
*/
gic_drop_prio(s, cpu, group);
- GIC_CLEAR_ACTIVE(irq, cm);
+
+ /* In GICv2 the guest can choose to split priority-drop and deactivate */
+ if (!gic_eoi_split(s, cpu, attrs)) {
+ GIC_CLEAR_ACTIVE(irq, cm);
+ }
gic_update(s);
}
@@ -1210,6 +1249,10 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
s->nsapr[regno][cpu] = value;
break;
}
+ case 0x1000:
+ /* GICC_DIR */
+ gic_deactivate_irq(s, cpu, value & 0x3ff, attrs);
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"gic_cpu_write: Bad offset %x\n", (int)offset);