ARM: hw_breakpoint: disable preemption during debug exception handling
On ARM, debug exceptions occur in the form of data or prefetch aborts.
One difference is that debug exceptions require access to per-cpu banked
registers and data structures which are not saved in the low-level exception
code. For kernels built with CONFIG_PREEMPT, there is an unlikely scenario
that the debug handler ends up running on a different CPU from the one
that originally signalled the event, resulting in random data being read
from the wrong registers.
This patch adds a debug_entry macro to the low-level exception handling
code which checks whether the taken exception is a debug exception. If
it is, the preempt count for the faulting process is incremented. After
the debug handler has finished, the count is decremented.
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S
index d93f976..ae94649 100644
--- a/arch/arm/kernel/entry-header.S
+++ b/arch/arm/kernel/entry-header.S
@@ -165,6 +165,25 @@
.endm
#endif /* !CONFIG_THUMB2_KERNEL */
+ @
+ @ Debug exceptions are taken as prefetch or data aborts.
+ @ We must disable preemption during the handler so that
+ @ we can access the debug registers safely.
+ @
+ .macro debug_entry, fsr
+#if defined(CONFIG_HAVE_HW_BREAKPOINT) && defined(CONFIG_PREEMPT)
+ ldr r4, =0x40f @ mask out fsr.fs
+ and r5, r4, \fsr
+ cmp r5, #2 @ debug exception
+ bne 1f
+ get_thread_info r10
+ ldr r6, [r10, #TI_PREEMPT] @ get preempt count
+ add r11, r6, #1 @ increment it
+ str r11, [r10, #TI_PREEMPT]
+1:
+#endif
+ .endm
+
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6.