OSDN Git Service

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[uclinux-h8/linux.git] / arch / arm64 / mm / fault.c
index dda234b..a30818e 100644 (file)
@@ -811,6 +811,36 @@ void __init hook_debug_fault_code(int nr,
        debug_fault_info[nr].name       = name;
 }
 
+#ifdef CONFIG_ARM64_ERRATUM_1463225
+DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
+
+static int __exception
+cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
+{
+       if (user_mode(regs))
+               return 0;
+
+       if (!__this_cpu_read(__in_cortex_a76_erratum_1463225_wa))
+               return 0;
+
+       /*
+        * We've taken a dummy step exception from the kernel to ensure
+        * that interrupts are re-enabled on the syscall path. Return back
+        * to cortex_a76_erratum_1463225_svc_handler() with debug exceptions
+        * masked so that we can safely restore the mdscr and get on with
+        * handling the syscall.
+        */
+       regs->pstate |= PSR_D_BIT;
+       return 1;
+}
+#else
+static int __exception
+cortex_a76_erratum_1463225_debug_handler(struct pt_regs *regs)
+{
+       return 0;
+}
+#endif /* CONFIG_ARM64_ERRATUM_1463225 */
+
 asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint,
                                               unsigned int esr,
                                               struct pt_regs *regs)
@@ -818,6 +848,9 @@ asmlinkage void __exception do_debug_exception(unsigned long addr_if_watchpoint,
        const struct fault_info *inf = esr_to_debug_fault_info(esr);
        unsigned long pc = instruction_pointer(regs);
 
+       if (cortex_a76_erratum_1463225_debug_handler(regs))
+               return;
+
        /*
         * Tell lockdep we disabled irqs in entry.S. Do nothing if they were
         * already disabled to preserve the last enabled/disabled addresses.