2 * Copyright (c) 2014 The FreeBSD Foundation
5 * This software was developed by Semihalf under
6 * the sponsorship of the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/param.h>
36 #include <sys/types.h>
40 #include <sys/systm.h>
41 #include <sys/sysent.h>
43 #include <machine/armreg.h>
44 #include <machine/cpu.h>
45 #include <machine/debug_monitor.h>
46 #include <machine/kdb.h>
50 #include <ddb/db_sym.h>
54 DBG_TYPE_BREAKPOINT = 0,
55 DBG_TYPE_WATCHPOINT = 1,
58 static int dbg_watchpoint_num;
59 static int dbg_breakpoint_num;
60 static struct debug_monitor_state kernel_monitor = {
61 .dbg_flags = DBGMON_KERNEL
64 /* Called from the exception handlers */
65 void dbg_monitor_enter(struct thread *);
66 void dbg_monitor_exit(struct thread *, struct trapframe *);
68 /* Watchpoints/breakpoints control register bitfields */
69 #define DBG_WATCH_CTRL_LEN_1 (0x1 << 5)
70 #define DBG_WATCH_CTRL_LEN_2 (0x3 << 5)
71 #define DBG_WATCH_CTRL_LEN_4 (0xf << 5)
72 #define DBG_WATCH_CTRL_LEN_8 (0xff << 5)
73 #define DBG_WATCH_CTRL_LEN_MASK(x) ((x) & (0xff << 5))
74 #define DBG_WATCH_CTRL_EXEC (0x0 << 3)
75 #define DBG_WATCH_CTRL_LOAD (0x1 << 3)
76 #define DBG_WATCH_CTRL_STORE (0x2 << 3)
77 #define DBG_WATCH_CTRL_ACCESS_MASK(x) ((x) & (0x3 << 3))
79 /* Common for breakpoint and watchpoint */
80 #define DBG_WB_CTRL_EL1 (0x1 << 1)
81 #define DBG_WB_CTRL_EL0 (0x2 << 1)
82 #define DBG_WB_CTRL_ELX_MASK(x) ((x) & (0x3 << 1))
83 #define DBG_WB_CTRL_E (0x1 << 0)
85 #define DBG_REG_BASE_BVR 0
86 #define DBG_REG_BASE_BCR (DBG_REG_BASE_BVR + 16)
87 #define DBG_REG_BASE_WVR (DBG_REG_BASE_BCR + 16)
88 #define DBG_REG_BASE_WCR (DBG_REG_BASE_WVR + 16)
90 /* Watchpoint/breakpoint helpers */
91 #define DBG_WB_WVR "wvr"
92 #define DBG_WB_WCR "wcr"
93 #define DBG_WB_BVR "bvr"
94 #define DBG_WB_BCR "bcr"
96 #define DBG_WB_READ(reg, num, val) do { \
97 __asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val)); \
100 #define DBG_WB_WRITE(reg, num, val) do { \
101 __asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val)); \
104 #define READ_WB_REG_CASE(reg, num, offset, val) \
105 case (num + offset): \
106 DBG_WB_READ(reg, num, val); \
109 #define WRITE_WB_REG_CASE(reg, num, offset, val) \
110 case (num + offset): \
111 DBG_WB_WRITE(reg, num, val); \
114 #define SWITCH_CASES_READ_WB_REG(reg, offset, val) \
115 READ_WB_REG_CASE(reg, 0, offset, val); \
116 READ_WB_REG_CASE(reg, 1, offset, val); \
117 READ_WB_REG_CASE(reg, 2, offset, val); \
118 READ_WB_REG_CASE(reg, 3, offset, val); \
119 READ_WB_REG_CASE(reg, 4, offset, val); \
120 READ_WB_REG_CASE(reg, 5, offset, val); \
121 READ_WB_REG_CASE(reg, 6, offset, val); \
122 READ_WB_REG_CASE(reg, 7, offset, val); \
123 READ_WB_REG_CASE(reg, 8, offset, val); \
124 READ_WB_REG_CASE(reg, 9, offset, val); \
125 READ_WB_REG_CASE(reg, 10, offset, val); \
126 READ_WB_REG_CASE(reg, 11, offset, val); \
127 READ_WB_REG_CASE(reg, 12, offset, val); \
128 READ_WB_REG_CASE(reg, 13, offset, val); \
129 READ_WB_REG_CASE(reg, 14, offset, val); \
130 READ_WB_REG_CASE(reg, 15, offset, val)
132 #define SWITCH_CASES_WRITE_WB_REG(reg, offset, val) \
133 WRITE_WB_REG_CASE(reg, 0, offset, val); \
134 WRITE_WB_REG_CASE(reg, 1, offset, val); \
135 WRITE_WB_REG_CASE(reg, 2, offset, val); \
136 WRITE_WB_REG_CASE(reg, 3, offset, val); \
137 WRITE_WB_REG_CASE(reg, 4, offset, val); \
138 WRITE_WB_REG_CASE(reg, 5, offset, val); \
139 WRITE_WB_REG_CASE(reg, 6, offset, val); \
140 WRITE_WB_REG_CASE(reg, 7, offset, val); \
141 WRITE_WB_REG_CASE(reg, 8, offset, val); \
142 WRITE_WB_REG_CASE(reg, 9, offset, val); \
143 WRITE_WB_REG_CASE(reg, 10, offset, val); \
144 WRITE_WB_REG_CASE(reg, 11, offset, val); \
145 WRITE_WB_REG_CASE(reg, 12, offset, val); \
146 WRITE_WB_REG_CASE(reg, 13, offset, val); \
147 WRITE_WB_REG_CASE(reg, 14, offset, val); \
148 WRITE_WB_REG_CASE(reg, 15, offset, val)
152 dbg_wb_read_reg(int reg, int n)
157 SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
158 SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
159 SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
160 SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
162 printf("trying to read from wrong debug register %d\n", n);
170 dbg_wb_write_reg(int reg, int n, uint64_t val)
173 SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
174 SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
175 SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
176 SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
178 printf("trying to write to wrong debug register %d\n", n);
186 kdb_cpu_set_singlestep(void)
189 kdb_frame->tf_spsr |= DBG_SPSR_SS;
190 WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
191 DBG_MDSCR_SS | DBG_MDSCR_KDE);
194 * Disable breakpoints and watchpoints, e.g. stepping
195 * over watched instruction will trigger break exception instead of
196 * single-step exception and locks CPU on that instruction for ever.
198 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
199 WRITE_SPECIALREG(mdscr_el1,
200 READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_MDE);
205 kdb_cpu_clear_singlestep(void)
208 WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
209 ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
211 /* Restore breakpoints and watchpoints */
212 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
213 WRITE_SPECIALREG(mdscr_el1,
214 READ_SPECIALREG(mdscr_el1) | DBG_MDSCR_MDE);
216 if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) {
217 WRITE_SPECIALREG(mdscr_el1,
218 READ_SPECIALREG(mdscr_el1) | DBG_MDSCR_KDE);
224 dbg_watchtype_str(uint32_t type)
227 case DBG_WATCH_CTRL_EXEC:
229 case DBG_WATCH_CTRL_STORE:
231 case DBG_WATCH_CTRL_LOAD:
233 case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
234 return ("read/write");
241 dbg_watchtype_len(uint32_t len)
244 case DBG_WATCH_CTRL_LEN_1:
246 case DBG_WATCH_CTRL_LEN_2:
248 case DBG_WATCH_CTRL_LEN_4:
250 case DBG_WATCH_CTRL_LEN_8:
258 dbg_show_watchpoint(void)
260 uint32_t wcr, len, type;
264 db_printf("\nhardware watchpoints:\n");
265 db_printf(" watch status type len address symbol\n");
266 db_printf(" ----- -------- ---------- --- ------------------ ------------------\n");
267 for (i = 0; i < dbg_watchpoint_num; i++) {
268 wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
269 if ((wcr & DBG_WB_CTRL_E) != 0) {
270 type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
271 len = DBG_WATCH_CTRL_LEN_MASK(wcr);
272 addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
273 db_printf(" %-5d %-8s %10s %3d 0x%16lx ",
274 i, "enabled", dbg_watchtype_str(type),
275 dbg_watchtype_len(len), addr);
276 db_printsym((db_addr_t)addr, DB_STGY_ANY);
279 db_printf(" %-5d disabled\n", i);
286 dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type)
292 case DBG_TYPE_BREAKPOINT:
293 max = dbg_breakpoint_num;
294 reg = monitor->dbg_bcr;
296 case DBG_TYPE_WATCHPOINT:
297 max = dbg_watchpoint_num;
298 reg = monitor->dbg_wcr;
301 printf("Unsupported debug type\n");
305 for (i = 0; i < max; i++) {
306 if ((reg[i] & DBG_WB_CTRL_E) == 0)
314 dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type,
317 uint64_t *reg_addr, *reg_ctrl;
321 case DBG_TYPE_BREAKPOINT:
322 max = dbg_breakpoint_num;
323 reg_addr = monitor->dbg_bvr;
324 reg_ctrl = monitor->dbg_bcr;
326 case DBG_TYPE_WATCHPOINT:
327 max = dbg_watchpoint_num;
328 reg_addr = monitor->dbg_wvr;
329 reg_ctrl = monitor->dbg_wcr;
332 printf("Unsupported debug type\n");
336 for (i = 0; i < max; i++) {
337 if (reg_addr[i] == addr &&
338 (reg_ctrl[i] & DBG_WB_CTRL_E) != 0)
346 dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
347 vm_size_t size, enum dbg_access_t access)
349 uint64_t wcr_size, wcr_priv, wcr_access;
353 monitor = &kernel_monitor;
355 i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT);
357 printf("Can not find slot for watchpoint, max %d"
358 " watchpoints supported\n", dbg_watchpoint_num);
364 wcr_size = DBG_WATCH_CTRL_LEN_1;
367 wcr_size = DBG_WATCH_CTRL_LEN_2;
370 wcr_size = DBG_WATCH_CTRL_LEN_4;
373 wcr_size = DBG_WATCH_CTRL_LEN_8;
376 printf("Unsupported address size for watchpoint\n");
380 if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
381 wcr_priv = DBG_WB_CTRL_EL0;
383 wcr_priv = DBG_WB_CTRL_EL1;
386 case HW_BREAKPOINT_X:
387 wcr_access = DBG_WATCH_CTRL_EXEC;
389 case HW_BREAKPOINT_R:
390 wcr_access = DBG_WATCH_CTRL_LOAD;
392 case HW_BREAKPOINT_W:
393 wcr_access = DBG_WATCH_CTRL_STORE;
395 case HW_BREAKPOINT_RW:
396 wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
399 printf("Unsupported exception level for watchpoint\n");
403 monitor->dbg_wvr[i] = addr;
404 monitor->dbg_wcr[i] = wcr_size | wcr_access | wcr_priv | DBG_WB_CTRL_E;
405 monitor->dbg_enable_count++;
406 monitor->dbg_flags |= DBGMON_ENABLED;
408 dbg_register_sync(monitor);
413 dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
419 monitor = &kernel_monitor;
421 i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr);
423 printf("Can not find watchpoint for address 0%lx\n", addr);
427 monitor->dbg_wvr[i] = 0;
428 monitor->dbg_wcr[i] = 0;
429 monitor->dbg_enable_count--;
430 if (monitor->dbg_enable_count == 0)
431 monitor->dbg_flags &= ~DBGMON_ENABLED;
433 dbg_register_sync(monitor);
438 dbg_register_sync(struct debug_monitor_state *monitor)
444 monitor = &kernel_monitor;
446 mdscr = READ_SPECIALREG(mdscr_el1);
447 if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) {
448 mdscr &= ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE);
450 for (i = 0; i < dbg_breakpoint_num; i++) {
451 dbg_wb_write_reg(DBG_REG_BASE_BCR, i,
452 monitor->dbg_bcr[i]);
453 dbg_wb_write_reg(DBG_REG_BASE_BVR, i,
454 monitor->dbg_bvr[i]);
457 for (i = 0; i < dbg_watchpoint_num; i++) {
458 dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
459 monitor->dbg_wcr[i]);
460 dbg_wb_write_reg(DBG_REG_BASE_WVR, i,
461 monitor->dbg_wvr[i]);
463 mdscr |= DBG_MDSCR_MDE;
464 if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL)
465 mdscr |= DBG_MDSCR_KDE;
467 WRITE_SPECIALREG(mdscr_el1, mdscr);
472 dbg_monitor_init(void)
476 /* Find out many breakpoints and watchpoints we can use */
477 dbg_watchpoint_num = ((READ_SPECIALREG(id_aa64dfr0_el1) >> 20) & 0xf) + 1;
478 dbg_breakpoint_num = ((READ_SPECIALREG(id_aa64dfr0_el1) >> 12) & 0xf) + 1;
480 if (bootverbose && PCPU_GET(cpuid) == 0) {
481 printf("%d watchpoints and %d breakpoints supported\n",
482 dbg_watchpoint_num, dbg_breakpoint_num);
486 * We have limited number of {watch,break}points, each consists of
488 * - wcr/bcr regsiter configurates corresponding {watch,break}point
490 * - wvr/bvr register keeps address we are hunting for
492 * Reset all breakpoints and watchpoints.
494 for (i = 0; i < dbg_watchpoint_num; i++) {
495 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
496 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
499 for (i = 0; i < dbg_breakpoint_num; i++) {
500 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
501 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
508 dbg_monitor_enter(struct thread *thread)
512 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
513 /* Install the kernel version of the registers */
514 dbg_register_sync(&kernel_monitor);
515 } else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
516 /* Disable the user breakpoints until we return to userspace */
517 for (i = 0; i < dbg_watchpoint_num; i++) {
518 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
519 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
522 for (i = 0; i < dbg_breakpoint_num; ++i) {
523 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
524 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
526 WRITE_SPECIALREG(mdscr_el1,
527 READ_SPECIALREG(mdscr_el1) &
528 ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
534 dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
539 * PSR_D is an aarch64-only flag. On aarch32, it switches
540 * the processor to big-endian, so avoid setting it for
543 if (!(SV_PROC_FLAG(thread->td_proc, SV_ILP32)))
544 frame->tf_spsr |= PSR_D;
545 if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
546 /* Install the kernel version of the registers */
547 dbg_register_sync(&thread->td_pcb->pcb_dbg_regs);
548 frame->tf_spsr &= ~PSR_D;
549 } else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
550 /* Disable the user breakpoints until we return to userspace */
551 for (i = 0; i < dbg_watchpoint_num; i++) {
552 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
553 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
556 for (i = 0; i < dbg_breakpoint_num; ++i) {
557 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
558 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
560 WRITE_SPECIALREG(mdscr_el1,
561 READ_SPECIALREG(mdscr_el1) &
562 ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));