lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1409846620-14542-6-git-send-email-daniel.thompson@linaro.org>
Date:	Thu,  4 Sep 2014 17:03:39 +0100
From:	Daniel Thompson <daniel.thompson@...aro.org>
To:	Russell King <linux@....linux.org.uk>
Cc:	Daniel Thompson <daniel.thompson@...aro.org>,
	linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
	patches@...aro.org, linaro-kernel@...ts.linaro.org,
	John Stultz <john.stultz@...aro.org>,
	Thomas Gleixner <tglx@...utronix.de>,
	Sumit Semwal <sumit.semwal@...aro.org>,
	Jason Cooper <jason@...edaemon.net>
Subject: [PATCH v1 5/6] irqchip: gic: Group 0 workaround.

An ARM system based on GICv1 that runs by default in secure mode and
uses both group 0 and group 1 interrupts (in order to exploit FIQ)
will suffer a problem where the IRQ handler occasionally spuriously
acknowledges a group 0 (FIQ) interrupt.

This can be prevented by ensuring the IRQ handler makes non-secure
memory access to the GIC registers but this is complex because
the non-secure bits cannot be apply to 4k pages (the bit is one level
up in the page table and applies to 1MB at a time).

This workaround uses an alternative approach that spots the spurious
acknowledgment and regenerates the FIQ. This keeps the workaround
exclusively within the GIC driver (although there is a runtime
perforamnce penalty resulting from this approach).

Reported-by: Harro Haan <hrhaan@...il.com>
Signed-off-by: Daniel Thompson <daniel.thompson@...aro.org>
Tested-by: Harro Haan <hrhaan@...il.com>
Cc: Thomas Gleixner <tglx@...utronix.de>
Cc: Jason Cooper <jason@...edaemon.net>
---
 drivers/irqchip/irq-gic.c | 52 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ffc64ed..4b25ed9 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -267,14 +267,59 @@ static int gic_set_wake(struct irq_data *d, unsigned int on)
 #define gic_set_wake	NULL
 #endif
 
+#ifdef CONFIG_FIQ
+/* This is a software emulation of the Aliased Interrupt Acknowledge Register
+ * (GIC_AIAR) found in GICv2+.
+ */
+static u32 gic_handle_spurious_group_0(struct gic_chip_data *gic, u32 irqstat)
+{
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	u32 offset, mask;
+
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + 0) || irqnr >= 1021)
+		return irqstat;
+
+	offset = irqnr / 32 * 4;
+	mask = 1 << (irqnr % 32);
+	if (readl_relaxed(dist_base + GIC_DIST_IGROUP + offset) & mask)
+		return irqstat;
+
+	/* this interrupt must be taken as a FIQ so put it back into the
+	 * pending state and end our own servicing of it.
+	 */
+	writel_relaxed(mask, dist_base + GIC_DIST_PENDING_SET + offset);
+	readl_relaxed(dist_base + GIC_DIST_PENDING_SET + offset);
+	writel_relaxed(irqstat, gic_data_cpu_base(gic) + GIC_CPU_EOI);
+
+	return 1023;
+}
+
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	u32 irqstat;
+
+	local_fiq_disable();
+	irqstat = readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+	irqstat = gic_handle_spurious_group_0(gic, irqstat);
+	local_fiq_enable();
+
+	return irqstat;
+}
+#else
+static u32 gic_ack_irq(struct gic_chip_data *gic)
+{
+	return readl_relaxed(gic_data_cpu_base(gic) + GIC_CPU_INTACK);
+}
+#endif
+
 static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 {
 	u32 irqstat, irqnr;
 	struct gic_chip_data *gic = &gic_data[0];
-	void __iomem *cpu_base = gic_data_cpu_base(gic);
 
 	do {
-		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqstat = gic_ack_irq(gic);
 		irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
 		if (likely(irqnr > 15 && irqnr < 1021)) {
@@ -283,7 +328,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 			continue;
 		}
 		if (irqnr < 16) {
-			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+			writel_relaxed(irqstat,
+				       gic_data_cpu_base(gic) + GIC_CPU_EOI);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #endif
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ