summaryrefslogtreecommitdiff
path: root/arch/xtensa/kernel/entry.S
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2016-01-24 10:32:10 +0300
committerChris Zankel <chris@zankel.net>2016-03-11 08:53:32 +0000
commitc91e02bd9702f2c00c6a6dc82dec1b2d5bb9f039 (patch)
tree7ffa9530078b594c2ad0ea97259abe15e9dd9619 /arch/xtensa/kernel/entry.S
parent6ec7026ac01f3db039e0428db1f37590685ad3e7 (diff)
xtensa: support hardware breakpoints/watchpoints
Use perf framework to manage hardware instruction and data breakpoints. Add two new ptrace calls: PTRACE_GETHBPREGS and PTRACE_SETHBPREGS to query and set instruction and data breakpoints. Address bit 0 choose instruction (0) or data (1) break register, bits 31..1 are the register number. Both calls transfer two 32-bit words: address (0) and control (1). Instruction breakpoint contorl word is 0 to clear breakpoint, 1 to set. Data breakpoint control word bit 31 is 'trigger on store', bit 30 is 'trigger on load, bits 29..0 are length. Length 0 is used to clear a breakpoint. To set a breakpoint length must be a power of 2 in the range 1..64 and the address must be length-aligned. Introduce new thread_info flag: TIF_DB_DISABLED. Set it if debug exception is raised by the kernel code accessing watched userspace address and disable corresponding data breakpoint. On exit to userspace check that flag and, if set, restore all data breakpoints. Handle debug exceptions raised with PS.EXCM set. This may happen when window overflow/underflow handler or fast exception handler hits data breakpoint, in which case save and disable all data breakpoints, single-step faulting instruction and restore data breakpoints. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/kernel/entry.S')
-rw-r--r--arch/xtensa/kernel/entry.S72
1 files changed, 71 insertions, 1 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index ab7904fd027f..fe8f7e7efb9d 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -543,6 +543,12 @@ common_exception_return:
#endif
5:
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ _bbci.l a4, TIF_DB_DISABLED, 7f
+ movi a4, restore_dbreak
+ callx4 a4
+7:
+#endif
#ifdef CONFIG_DEBUG_TLB_SANITY
l32i a4, a1, PT_DEPC
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
@@ -808,6 +814,18 @@ ENTRY(debug_exception)
s32i a0, a2, PT_AREG2
mov a1, a2
+ /* Debug exception is handled as an exception, so interrupts will
+ * likely be enabled in the common exception handler. Disable
+ * preemption if we have HW breakpoints to preserve DEBUGCAUSE.DBNUM
+ * meaning.
+ */
+#if defined(CONFIG_PREEMPT_COUNT) && defined(CONFIG_HAVE_HW_BREAKPOINT)
+ GET_THREAD_INFO(a2, a1)
+ l32i a3, a2, TI_PRE_COUNT
+ addi a3, a3, 1
+ s32i a3, a2, TI_PRE_COUNT
+#endif
+
rsr a2, ps
bbsi.l a2, PS_UM_BIT, _user_exception
j _kernel_exception
@@ -816,8 +834,60 @@ ENTRY(debug_exception)
l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer
j 3b
- /* Debug exception while in exception mode. */
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ /* Debug exception while in exception mode. This may happen when
+ * window overflow/underflow handler or fast exception handler hits
+ * data breakpoint, in which case save and disable all data
+ * breakpoints, single-step faulting instruction and restore data
+ * breakpoints.
+ */
+1:
+ bbci.l a0, PS_UM_BIT, 1b # jump if kernel mode
+
+ rsr a0, debugcause
+ bbsi.l a0, DEBUGCAUSE_DBREAK_BIT, .Ldebug_save_dbreak
+
+ .set _index, 0
+ .rept XCHAL_NUM_DBREAK
+ l32i a0, a3, DT_DBREAKC_SAVE + _index * 4
+ wsr a0, SREG_DBREAKC + _index
+ .set _index, _index + 1
+ .endr
+
+ l32i a0, a3, DT_ICOUNT_LEVEL_SAVE
+ wsr a0, icountlevel
+
+ l32i a0, a3, DT_ICOUNT_SAVE
+ xsr a0, icount
+
+ l32i a0, a3, DT_DEBUG_SAVE
+ xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
+ rfi XCHAL_DEBUGLEVEL
+
+.Ldebug_save_dbreak:
+ .set _index, 0
+ .rept XCHAL_NUM_DBREAK
+ movi a0, 0
+ xsr a0, SREG_DBREAKC + _index
+ s32i a0, a3, DT_DBREAKC_SAVE + _index * 4
+ .set _index, _index + 1
+ .endr
+
+ movi a0, XCHAL_EXCM_LEVEL + 1
+ xsr a0, icountlevel
+ s32i a0, a3, DT_ICOUNT_LEVEL_SAVE
+
+ movi a0, 0xfffffffe
+ xsr a0, icount
+ s32i a0, a3, DT_ICOUNT_SAVE
+
+ l32i a0, a3, DT_DEBUG_SAVE
+ xsr a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
+ rfi XCHAL_DEBUGLEVEL
+#else
+ /* Debug exception while in exception mode. Should not happen. */
1: j 1b // FIXME!!
+#endif
ENDPROC(debug_exception)