|
@@ -542,3 +542,73 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|
{
|
|
{
|
|
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
|
|
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
|
|
struct siginfo info;
|
|
struct siginfo info;
|
|
|
|
+
|
|
|
|
+ if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
|
|
|
|
+ inf->name, fsr, addr);
|
|
|
|
+
|
|
|
|
+ info.si_signo = inf->sig;
|
|
|
|
+ info.si_errno = 0;
|
|
|
|
+ info.si_code = inf->code;
|
|
|
|
+ info.si_addr = (void __user *)addr;
|
|
|
|
+ arm_notify_die("", regs, &info, fsr, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void __init
|
|
|
|
+hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
|
|
|
|
+ int sig, int code, const char *name)
|
|
|
|
+{
|
|
|
|
+ if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
|
|
|
|
+ BUG();
|
|
|
|
+
|
|
|
|
+ ifsr_info[nr].fn = fn;
|
|
|
|
+ ifsr_info[nr].sig = sig;
|
|
|
|
+ ifsr_info[nr].code = code;
|
|
|
|
+ ifsr_info[nr].name = name;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+asmlinkage void __exception
|
|
|
|
+do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
|
|
|
|
+{
|
|
|
|
+ const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
|
|
|
|
+ struct siginfo info;
|
|
|
|
+
|
|
|
|
+ if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
|
|
|
|
+ inf->name, ifsr, addr);
|
|
|
|
+
|
|
|
|
+ info.si_signo = inf->sig;
|
|
|
|
+ info.si_errno = 0;
|
|
|
|
+ info.si_code = inf->code;
|
|
|
|
+ info.si_addr = (void __user *)addr;
|
|
|
|
+ arm_notify_die("", regs, &info, ifsr, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#ifndef CONFIG_ARM_LPAE
|
|
|
|
+static int __init exceptions_init(void)
|
|
|
|
+{
|
|
|
|
+ if (cpu_architecture() >= CPU_ARCH_ARMv6) {
|
|
|
|
+ hook_fault_code(4, do_translation_fault, SIGSEGV, SEGV_MAPERR,
|
|
|
|
+ "I-cache maintenance fault");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (cpu_architecture() >= CPU_ARCH_ARMv7) {
|
|
|
|
+ /*
|
|
|
|
+ * TODO: Access flag faults introduced in ARMv6K.
|
|
|
|
+ * Runtime check for 'K' extension is needed
|
|
|
|
+ */
|
|
|
|
+ hook_fault_code(3, do_bad, SIGSEGV, SEGV_MAPERR,
|
|
|
|
+ "section access flag fault");
|
|
|
|
+ hook_fault_code(6, do_bad, SIGSEGV, SEGV_MAPERR,
|
|
|
|
+ "section access flag fault");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+arch_initcall(exceptions_init);
|
|
|
|
+#endif
|