Browse Source

ARM: 8447/1: catch pending imprecise abort on unmask

Install a non-faulting handler just before unmasking imprecise aborts
and switch back to the regular one after unmasking is done.

This catches any pending imprecise abort that the firmware/bootloader
may have left behind that would normally crash the kernel at that point.
As there are apparently a lot of bootlaoders out there that do such a
thing it makes sense to handle it in the common startup code.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Tested-by: Tyler Baker <tyler.baker@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Lucas Stach 10 years ago
parent
commit
9254970cbb
3 changed files with 25 additions and 1 deletions
  1. 22 0
      arch/arm/mm/fault.c
  2. 1 0
      arch/arm/mm/fault.h
  3. 2 1
      arch/arm/mm/mmu.c

+ 22 - 0
arch/arm/mm/fault.c

@@ -593,6 +593,28 @@ do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 	arm_notify_die("", regs, &info, ifsr, 0);
 }
 
+/*
+ * Abort handler to be used only during first unmasking of asynchronous aborts
+ * on the boot CPU. This makes sure that the machine will not die if the
+ * firmware/bootloader left an imprecise abort pending for us to trip over.
+ */
+static int __init early_abort_handler(unsigned long addr, unsigned int fsr,
+				      struct pt_regs *regs)
+{
+	pr_warn("Hit pending asynchronous external abort (FSR=0x%08x) during "
+		"first unmask, this is most likely caused by a "
+		"firmware/bootloader bug.\n", fsr);
+
+	return 0;
+}
+
+void __init early_abt_enable(void)
+{
+	fsr_info[22].fn = early_abort_handler;
+	local_abt_enable();
+	fsr_info[22].fn = do_bad;
+}
+
 #ifndef CONFIG_ARM_LPAE
 static int __init exceptions_init(void)
 {

+ 1 - 0
arch/arm/mm/fault.h

@@ -24,5 +24,6 @@ static inline int fsr_fs(unsigned int fsr)
 
 void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
 unsigned long search_exception_table(unsigned long addr);
+void early_abt_enable(void);
 
 #endif	/* __ARCH_ARM_FAULT_H */

+ 2 - 1
arch/arm/mm/mmu.c

@@ -38,6 +38,7 @@
 #include <asm/mach/pci.h>
 #include <asm/fixmap.h>
 
+#include "fault.h"
 #include "mm.h"
 #include "tcm.h"
 
@@ -1365,7 +1366,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
 	flush_cache_all();
 
 	/* Enable asynchronous aborts */
-	local_abt_enable();
+	early_abt_enable();
 }
 
 static void __init kmap_init(void)