aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2010-11-24 16:51:17 +0000
committerWill Deacon <will.deacon@arm.com>2010-12-06 11:55:56 +0000
commitac88e07122fc0eb5cbad403be97ef02c317a06b7 (patch)
tree0cddfd29474fc4ff5a1be95d2273d3a1e626055f /arch/arm/kernel/hw_breakpoint.c
parente8a7e48bb248a1196484d3f8afa53bded2b24e71 (diff)
ARM: hw_breakpoint: ensure OS lock is clear before writing to debug registers
ARMv7 architects a system for saving and restoring the debug registers across low-power modes. At the heart of this system is a lock register which, when set, forbids writes to the debug registers. While locked, writes to debug registers via the co-processor interface will result in undefined instruction traps. Linux currently doesn't make use of this feature because we update the debug registers on context switch anyway, however the status of the lock is IMPLEMENTATION DEFINED on reset. This patch ensures that the lock is cleared during boot so that we can write to the debug registers safely. Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
-rw-r--r--arch/arm/kernel/hw_breakpoint.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 21e3a4ab3b8..793959ec898 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -768,6 +768,23 @@ static void __init reset_ctrl_regs(void *unused)
{
int i;
+ /*
+ * v7 debug contains save and restore registers so that debug state
+ * can be maintained across low-power modes without leaving
+ * the debug logic powered up. It is IMPLEMENTATION DEFINED whether
+ * we can write to the debug registers out of reset, so we must
+ * unlock the OS Lock Access Register to avoid taking undefined
+ * instruction exceptions later on.
+ */
+ if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
+ /*
+ * Unconditionally clear the lock by writing a value
+ * other than 0xC5ACCE55 to the access register.
+ */
+ asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
+ isb();
+ }
+
if (enable_monitor_mode())
return;
@@ -810,17 +827,17 @@ static int __init arch_hw_breakpoint_init(void)
pr_warning("halting debug mode enabled. Assuming maximum "
"watchpoint size of 4 bytes.");
} else {
- /* Work out the maximum supported watchpoint length. */
- max_watchpoint_len = get_max_wp_len();
- pr_info("maximum watchpoint size is %u bytes.\n",
- max_watchpoint_len);
-
/*
* Reset the breakpoint resources. We assume that a halting
* debugger will leave the world in a nice state for us.
*/
smp_call_function(reset_ctrl_regs, NULL, 1);
reset_ctrl_regs(NULL);
+
+ /* Work out the maximum supported watchpoint length. */
+ max_watchpoint_len = get_max_wp_len();
+ pr_info("maximum watchpoint size is %u bytes.\n",
+ max_watchpoint_len);
}
/* Register debug fault handler. */