xref: /freebsd/sys/arm64/arm64/debug_monitor.c (revision 1719886f)
1 /*-
2  * Copyright (c) 2014 The FreeBSD Foundation
3  *
4  * This software was developed by Semihalf under
5  * the sponsorship of the FreeBSD Foundation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "opt_ddb.h"
30 #include "opt_gdb.h"
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/kdb.h>
35 #include <sys/pcpu.h>
36 #include <sys/proc.h>
37 #include <sys/systm.h>
38 #include <sys/sysent.h>
39 
40 #include <machine/armreg.h>
41 #include <machine/cpu.h>
42 #include <machine/debug_monitor.h>
43 #include <machine/kdb.h>
44 #include <machine/pcb.h>
45 
46 #ifdef DDB
47 #include <vm/vm.h>
48 #include <ddb/ddb.h>
49 #include <ddb/db_break.h>
50 #include <ddb/db_sym.h>
51 #endif
52 
53 enum dbg_t {
54 	DBG_TYPE_BREAKPOINT = 0,
55 	DBG_TYPE_WATCHPOINT = 1,
56 };
57 
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
62 };
63 
64 static int dbg_setup_breakpoint(struct debug_monitor_state *monitor,
65     vm_offset_t addr);
66 static int dbg_remove_breakpoint(struct debug_monitor_state *monitor,
67     vm_offset_t addr);
68 static int dbg_setup_watchpoint(struct debug_monitor_state *, vm_offset_t,
69     vm_size_t, enum dbg_access_t);
70 static int dbg_remove_watchpoint(struct debug_monitor_state *, vm_offset_t,
71     vm_size_t);
72 
73 /* Called from the exception handlers */
74 void dbg_monitor_enter(struct thread *);
75 void dbg_monitor_exit(struct thread *, struct trapframe *);
76 
77 /* Watchpoints/breakpoints control register bitfields */
78 #define DBG_WATCH_CTRL_LEN_1		(0x1 << 5)
79 #define DBG_WATCH_CTRL_LEN_2		(0x3 << 5)
80 #define DBG_WATCH_CTRL_LEN_4		(0xf << 5)
81 #define DBG_WATCH_CTRL_LEN_8		(0xff << 5)
82 #define DBG_WATCH_CTRL_LEN_MASK(x)	((x) & (0xff << 5))
83 #define DBG_WATCH_CTRL_EXEC		(0x0 << 3)
84 #define DBG_WATCH_CTRL_LOAD		(0x1 << 3)
85 #define DBG_WATCH_CTRL_STORE		(0x2 << 3)
86 #define DBG_WATCH_CTRL_ACCESS_MASK(x)	((x) & (0x3 << 3))
87 
88 /* Common for breakpoint and watchpoint */
89 #define DBG_WB_CTRL_EL1		(0x1 << 1)
90 #define DBG_WB_CTRL_EL0		(0x2 << 1)
91 #define DBG_WB_CTRL_ELX_MASK(x)	((x) & (0x3 << 1))
92 #define DBG_WB_CTRL_E		(0x1 << 0)
93 
94 #define DBG_REG_BASE_BVR	0
95 #define DBG_REG_BASE_BCR	(DBG_REG_BASE_BVR + 16)
96 #define DBG_REG_BASE_WVR	(DBG_REG_BASE_BCR + 16)
97 #define DBG_REG_BASE_WCR	(DBG_REG_BASE_WVR + 16)
98 
99 /* Watchpoint/breakpoint helpers */
100 #define DBG_WB_WVR	"wvr"
101 #define DBG_WB_WCR	"wcr"
102 #define DBG_WB_BVR	"bvr"
103 #define DBG_WB_BCR	"bcr"
104 
105 #define DBG_WB_READ(reg, num, val) do {					\
106 	__asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val));	\
107 } while (0)
108 
109 #define DBG_WB_WRITE(reg, num, val) do {				\
110 	__asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val));	\
111 } while (0)
112 
113 #define READ_WB_REG_CASE(reg, num, offset, val)		\
114 	case (num + offset):				\
115 		DBG_WB_READ(reg, num, val);		\
116 		break
117 
118 #define WRITE_WB_REG_CASE(reg, num, offset, val)	\
119 	case (num + offset):				\
120 		DBG_WB_WRITE(reg, num, val);		\
121 		break
122 
123 #define SWITCH_CASES_READ_WB_REG(reg, offset, val)	\
124 	READ_WB_REG_CASE(reg,  0, offset, val);		\
125 	READ_WB_REG_CASE(reg,  1, offset, val);		\
126 	READ_WB_REG_CASE(reg,  2, offset, val);		\
127 	READ_WB_REG_CASE(reg,  3, offset, val);		\
128 	READ_WB_REG_CASE(reg,  4, offset, val);		\
129 	READ_WB_REG_CASE(reg,  5, offset, val);		\
130 	READ_WB_REG_CASE(reg,  6, offset, val);		\
131 	READ_WB_REG_CASE(reg,  7, offset, val);		\
132 	READ_WB_REG_CASE(reg,  8, offset, val);		\
133 	READ_WB_REG_CASE(reg,  9, offset, val);		\
134 	READ_WB_REG_CASE(reg, 10, offset, val);		\
135 	READ_WB_REG_CASE(reg, 11, offset, val);		\
136 	READ_WB_REG_CASE(reg, 12, offset, val);		\
137 	READ_WB_REG_CASE(reg, 13, offset, val);		\
138 	READ_WB_REG_CASE(reg, 14, offset, val);		\
139 	READ_WB_REG_CASE(reg, 15, offset, val)
140 
141 #define SWITCH_CASES_WRITE_WB_REG(reg, offset, val)	\
142 	WRITE_WB_REG_CASE(reg,  0, offset, val);	\
143 	WRITE_WB_REG_CASE(reg,  1, offset, val);	\
144 	WRITE_WB_REG_CASE(reg,  2, offset, val);	\
145 	WRITE_WB_REG_CASE(reg,  3, offset, val);	\
146 	WRITE_WB_REG_CASE(reg,  4, offset, val);	\
147 	WRITE_WB_REG_CASE(reg,  5, offset, val);	\
148 	WRITE_WB_REG_CASE(reg,  6, offset, val);	\
149 	WRITE_WB_REG_CASE(reg,  7, offset, val);	\
150 	WRITE_WB_REG_CASE(reg,  8, offset, val);	\
151 	WRITE_WB_REG_CASE(reg,  9, offset, val);	\
152 	WRITE_WB_REG_CASE(reg, 10, offset, val);	\
153 	WRITE_WB_REG_CASE(reg, 11, offset, val);	\
154 	WRITE_WB_REG_CASE(reg, 12, offset, val);	\
155 	WRITE_WB_REG_CASE(reg, 13, offset, val);	\
156 	WRITE_WB_REG_CASE(reg, 14, offset, val);	\
157 	WRITE_WB_REG_CASE(reg, 15, offset, val)
158 
159 #ifdef DDB
160 static uint64_t
161 dbg_wb_read_reg(int reg, int n)
162 {
163 	uint64_t val = 0;
164 
165 	switch (reg + n) {
166 	SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
167 	SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
168 	SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
169 	SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
170 	default:
171 		printf("trying to read from wrong debug register %d\n", n);
172 	}
173 
174 	return val;
175 }
176 #endif /* DDB */
177 
178 static void
179 dbg_wb_write_reg(int reg, int n, uint64_t val)
180 {
181 	switch (reg + n) {
182 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
183 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
184 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
185 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
186 	default:
187 		printf("trying to write to wrong debug register %d\n", n);
188 		return;
189 	}
190 	isb();
191 }
192 
193 #if defined(DDB) || defined(GDB)
194 int
195 kdb_cpu_set_breakpoint(vm_offset_t addr)
196 {
197 	return (dbg_setup_breakpoint(NULL, addr));
198 }
199 
200 int
201 kdb_cpu_clr_breakpoint(vm_offset_t addr)
202 {
203 	return (dbg_remove_breakpoint(NULL, addr));
204 }
205 
206 void
207 kdb_cpu_set_singlestep(void)
208 {
209 
210 	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
211 	    ("%s: debug exceptions are not masked", __func__));
212 
213 	kdb_frame->tf_spsr |= PSR_SS;
214 
215 	/*
216 	 * TODO: Handle single stepping over instructions that access
217 	 * the DAIF values. On a read the value will be incorrect.
218 	 */
219 	kernel_monitor.dbg_flags &= ~PSR_DAIF;
220 	kernel_monitor.dbg_flags |= kdb_frame->tf_spsr & PSR_DAIF;
221 	kdb_frame->tf_spsr |= (PSR_A | PSR_I | PSR_F);
222 
223 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
224 	    MDSCR_SS | MDSCR_KDE);
225 
226 	/*
227 	 * Disable breakpoints and watchpoints, e.g. stepping
228 	 * over watched instruction will trigger break exception instead of
229 	 * single-step exception and locks CPU on that instruction for ever.
230 	 */
231 	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
232 		WRITE_SPECIALREG(mdscr_el1,
233 		    READ_SPECIALREG(mdscr_el1) & ~MDSCR_MDE);
234 	}
235 }
236 
237 void
238 kdb_cpu_clear_singlestep(void)
239 {
240 
241 	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
242 	    ("%s: debug exceptions are not masked", __func__));
243 
244 	kdb_frame->tf_spsr &= ~PSR_DAIF;
245 	kdb_frame->tf_spsr |= kernel_monitor.dbg_flags & PSR_DAIF;
246 
247 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
248 	    ~(MDSCR_SS | MDSCR_KDE));
249 
250 	/* Restore breakpoints and watchpoints */
251 	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
252 		WRITE_SPECIALREG(mdscr_el1,
253 		    READ_SPECIALREG(mdscr_el1) | MDSCR_MDE);
254 
255 		if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) {
256 			WRITE_SPECIALREG(mdscr_el1,
257 			    READ_SPECIALREG(mdscr_el1) | MDSCR_KDE);
258 		}
259 	}
260 }
261 
262 int
263 kdb_cpu_set_watchpoint(vm_offset_t addr, vm_size_t size, int access)
264 {
265 	enum dbg_access_t dbg_access;
266 
267 	switch (access) {
268 	case KDB_DBG_ACCESS_R:
269 		dbg_access = HW_BREAKPOINT_R;
270 		break;
271 	case KDB_DBG_ACCESS_W:
272 		dbg_access = HW_BREAKPOINT_W;
273 		break;
274 	case KDB_DBG_ACCESS_RW:
275 		dbg_access = HW_BREAKPOINT_RW;
276 		break;
277 	default:
278 		return (EINVAL);
279 	}
280 
281 	return (dbg_setup_watchpoint(NULL, addr, size, dbg_access));
282 }
283 
284 int
285 kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size)
286 {
287 
288 	return (dbg_remove_watchpoint(NULL, addr, size));
289 }
290 #endif /* DDB || GDB */
291 
292 #ifdef DDB
293 void
294 dbg_show_breakpoint(void)
295 {
296 	db_breakpoint_t bkpt;
297 	uint32_t bcr;
298 	uint64_t addr;
299 	int i;
300 
301 	db_printf("\nhardware breakpoints:\n");
302 	db_printf("  break    status  count             address              symbol\n");
303 	db_printf("  -----  --------  -----  ------------------  ------------------\n");
304 	for (i = 0; i < dbg_breakpoint_num; i++) {
305 		bcr = dbg_wb_read_reg(DBG_REG_BASE_BCR, i);
306 		if ((bcr & DBG_WB_CTRL_E) != 0) {
307 			addr = dbg_wb_read_reg(DBG_REG_BASE_BVR, i);
308 			bkpt = db_find_breakpoint_here(addr);
309 			db_printf("  %-5d  %-8s  %-5d  0x%16lx  ",
310 			    i, "enabled", bkpt == NULL ? -1 : bkpt->count,
311 			    addr);
312 			db_printsym((db_addr_t)addr, DB_STGY_ANY);
313 			db_printf("\n");
314 		} else {
315 			db_printf("  %-5d  disabled\n", i);
316 		}
317 	}
318 }
319 
320 static const char *
321 dbg_watchtype_str(uint32_t type)
322 {
323 	switch (type) {
324 		case DBG_WATCH_CTRL_EXEC:
325 			return ("execute");
326 		case DBG_WATCH_CTRL_STORE:
327 			return ("write");
328 		case DBG_WATCH_CTRL_LOAD:
329 			return ("read");
330 		case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
331 			return ("read/write");
332 		default:
333 			return ("invalid");
334 	}
335 }
336 
337 static int
338 dbg_watchtype_len(uint32_t len)
339 {
340 	switch (len) {
341 	case DBG_WATCH_CTRL_LEN_1:
342 		return (1);
343 	case DBG_WATCH_CTRL_LEN_2:
344 		return (2);
345 	case DBG_WATCH_CTRL_LEN_4:
346 		return (4);
347 	case DBG_WATCH_CTRL_LEN_8:
348 		return (8);
349 	default:
350 		return (0);
351 	}
352 }
353 
354 void
355 dbg_show_watchpoint(void)
356 {
357 	uint32_t wcr, len, type;
358 	uint64_t addr;
359 	int i;
360 
361 	db_printf("\nhardware watchpoints:\n");
362 	db_printf("  watch    status        type  len             address              symbol\n");
363 	db_printf("  -----  --------  ----------  ---  ------------------  ------------------\n");
364 	for (i = 0; i < dbg_watchpoint_num; i++) {
365 		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
366 		if ((wcr & DBG_WB_CTRL_E) != 0) {
367 			type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
368 			len = DBG_WATCH_CTRL_LEN_MASK(wcr);
369 			addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
370 			db_printf("  %-5d  %-8s  %10s  %3d  0x%16lx  ",
371 			    i, "enabled", dbg_watchtype_str(type),
372 			    dbg_watchtype_len(len), addr);
373 			db_printsym((db_addr_t)addr, DB_STGY_ANY);
374 			db_printf("\n");
375 		} else {
376 			db_printf("  %-5d  disabled\n", i);
377 		}
378 	}
379 }
380 #endif /* DDB */
381 
382 static int
383 dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type)
384 {
385 	uint64_t *reg;
386 	u_int max, i;
387 
388 	switch(type) {
389 	case DBG_TYPE_BREAKPOINT:
390 		max = dbg_breakpoint_num;
391 		reg = monitor->dbg_bcr;
392 		break;
393 	case DBG_TYPE_WATCHPOINT:
394 		max = dbg_watchpoint_num;
395 		reg = monitor->dbg_wcr;
396 		break;
397 	default:
398 		printf("Unsupported debug type\n");
399 		return (i);
400 	}
401 
402 	for (i = 0; i < max; i++) {
403 		if ((reg[i] & DBG_WB_CTRL_E) == 0)
404 			return (i);
405 	}
406 
407 	return (-1);
408 }
409 
410 static int
411 dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type,
412     vm_offset_t addr)
413 {
414 	uint64_t *reg_addr, *reg_ctrl;
415 	u_int max, i;
416 
417 	switch(type) {
418 	case DBG_TYPE_BREAKPOINT:
419 		max = dbg_breakpoint_num;
420 		reg_addr = monitor->dbg_bvr;
421 		reg_ctrl = monitor->dbg_bcr;
422 		break;
423 	case DBG_TYPE_WATCHPOINT:
424 		max = dbg_watchpoint_num;
425 		reg_addr = monitor->dbg_wvr;
426 		reg_ctrl = monitor->dbg_wcr;
427 		break;
428 	default:
429 		printf("Unsupported debug type\n");
430 		return (i);
431 	}
432 
433 	for (i = 0; i < max; i++) {
434 		if (reg_addr[i] == addr &&
435 		    (reg_ctrl[i] & DBG_WB_CTRL_E) != 0)
436 			return (i);
437 	}
438 
439 	return (-1);
440 }
441 
442 static int
443 dbg_setup_breakpoint(struct debug_monitor_state *monitor, vm_offset_t addr)
444 {
445 	uint64_t bcr_priv;
446 	u_int i;
447 
448 	if (monitor == NULL)
449 		monitor = &kernel_monitor;
450 
451 	i = dbg_find_free_slot(monitor, DBG_TYPE_BREAKPOINT);
452 	if (i == -1) {
453 		printf("Can not find slot for breakpoint, max %d"
454 		    " breakpoints supported\n", dbg_breakpoint_num);
455 		return (EBUSY);
456 	}
457 
458 	if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
459 		bcr_priv = DBG_WB_CTRL_EL0;
460 	else
461 		bcr_priv = DBG_WB_CTRL_EL1;
462 
463 	monitor->dbg_bvr[i] = addr;
464 	monitor->dbg_bcr[i] = (0xf << 5) | bcr_priv | DBG_WB_CTRL_E;
465 	monitor->dbg_enable_count++;
466 	monitor->dbg_flags |= DBGMON_ENABLED;
467 	dbg_register_sync(monitor);
468 
469 	return (0);
470 }
471 
472 static int
473 dbg_remove_breakpoint(struct debug_monitor_state *monitor, vm_offset_t addr)
474 {
475 	u_int i;
476 
477 	if (monitor == NULL)
478 		monitor = &kernel_monitor;
479 
480 	i = dbg_find_slot(monitor, DBG_TYPE_BREAKPOINT, addr);
481 	if (i == -1) {
482 		printf("Can not find breakpoint for address 0%lx\n", addr);
483 		return (i);
484 	}
485 
486 	monitor->dbg_bvr[i] = 0;
487 	monitor->dbg_bcr[i] = 0;
488 	monitor->dbg_enable_count--;
489 	if (monitor->dbg_enable_count == 0)
490 		monitor->dbg_flags &= ~DBGMON_ENABLED;
491 	dbg_register_sync(monitor);
492 
493 	return (0);
494 }
495 
496 static int
497 dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
498     vm_size_t size, enum dbg_access_t access)
499 {
500 	uint64_t wcr_size, wcr_priv, wcr_access;
501 	u_int i;
502 
503 	if (monitor == NULL)
504 		monitor = &kernel_monitor;
505 
506 	i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT);
507 	if (i == -1) {
508 		printf("Can not find slot for watchpoint, max %d"
509 		    " watchpoints supported\n", dbg_watchpoint_num);
510 		return (EBUSY);
511 	}
512 
513 	switch(size) {
514 	case 1:
515 		wcr_size = DBG_WATCH_CTRL_LEN_1;
516 		break;
517 	case 2:
518 		wcr_size = DBG_WATCH_CTRL_LEN_2;
519 		break;
520 	case 4:
521 		wcr_size = DBG_WATCH_CTRL_LEN_4;
522 		break;
523 	case 8:
524 		wcr_size = DBG_WATCH_CTRL_LEN_8;
525 		break;
526 	default:
527 		printf("Unsupported address size for watchpoint: %zu\n", size);
528 		return (EINVAL);
529 	}
530 
531 	if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
532 		wcr_priv = DBG_WB_CTRL_EL0;
533 	else
534 		wcr_priv = DBG_WB_CTRL_EL1;
535 
536 	switch(access) {
537 	case HW_BREAKPOINT_X:
538 		wcr_access = DBG_WATCH_CTRL_EXEC;
539 		break;
540 	case HW_BREAKPOINT_R:
541 		wcr_access = DBG_WATCH_CTRL_LOAD;
542 		break;
543 	case HW_BREAKPOINT_W:
544 		wcr_access = DBG_WATCH_CTRL_STORE;
545 		break;
546 	case HW_BREAKPOINT_RW:
547 		wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
548 		break;
549 	default:
550 		printf("Unsupported access type for watchpoint: %d\n", access);
551 		return (EINVAL);
552 	}
553 
554 	monitor->dbg_wvr[i] = addr;
555 	monitor->dbg_wcr[i] = wcr_size | wcr_access | wcr_priv | DBG_WB_CTRL_E;
556 	monitor->dbg_enable_count++;
557 	monitor->dbg_flags |= DBGMON_ENABLED;
558 
559 	dbg_register_sync(monitor);
560 	return (0);
561 }
562 
563 static int
564 dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
565     vm_size_t size)
566 {
567 	u_int i;
568 
569 	if (monitor == NULL)
570 		monitor = &kernel_monitor;
571 
572 	i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr);
573 	if (i == -1) {
574 		printf("Can not find watchpoint for address 0%lx\n", addr);
575 		return (EINVAL);
576 	}
577 
578 	monitor->dbg_wvr[i] = 0;
579 	monitor->dbg_wcr[i] = 0;
580 	monitor->dbg_enable_count--;
581 	if (monitor->dbg_enable_count == 0)
582 		monitor->dbg_flags &= ~DBGMON_ENABLED;
583 
584 	dbg_register_sync(monitor);
585 	return (0);
586 }
587 
588 void
589 dbg_register_sync(struct debug_monitor_state *monitor)
590 {
591 	uint64_t mdscr;
592 	int i;
593 
594 	if (monitor == NULL)
595 		monitor = &kernel_monitor;
596 
597 	for (i = 0; i < dbg_breakpoint_num; i++) {
598 		dbg_wb_write_reg(DBG_REG_BASE_BCR, i,
599 		    monitor->dbg_bcr[i]);
600 		dbg_wb_write_reg(DBG_REG_BASE_BVR, i,
601 		    monitor->dbg_bvr[i]);
602 	}
603 
604 	for (i = 0; i < dbg_watchpoint_num; i++) {
605 		dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
606 		    monitor->dbg_wcr[i]);
607 		dbg_wb_write_reg(DBG_REG_BASE_WVR, i,
608 		    monitor->dbg_wvr[i]);
609 	}
610 
611 	mdscr = READ_SPECIALREG(mdscr_el1);
612 	if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) {
613 		mdscr &= ~(MDSCR_MDE | MDSCR_KDE);
614 	} else {
615 		mdscr |= MDSCR_MDE;
616 		if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL)
617 			mdscr |= MDSCR_KDE;
618 	}
619 	WRITE_SPECIALREG(mdscr_el1, mdscr);
620 	isb();
621 }
622 
623 void
624 dbg_monitor_init(void)
625 {
626 	uint64_t aa64dfr0;
627 	u_int i;
628 
629 	/* Find out many breakpoints and watchpoints we can use */
630 	aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1);
631 	dbg_watchpoint_num = ID_AA64DFR0_WRPs_VAL(aa64dfr0);
632 	dbg_breakpoint_num = ID_AA64DFR0_BRPs_VAL(aa64dfr0);
633 
634 	if (bootverbose && PCPU_GET(cpuid) == 0) {
635 		printf("%d watchpoints and %d breakpoints supported\n",
636 		    dbg_watchpoint_num, dbg_breakpoint_num);
637 	}
638 
639 	/*
640 	 * We have limited number of {watch,break}points, each consists of
641 	 * two registers:
642 	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
643 	 *   behaviour
644 	 * - wvr/bvr register keeps address we are hunting for
645 	 *
646 	 * Reset all breakpoints and watchpoints.
647 	 */
648 	for (i = 0; i < dbg_watchpoint_num; i++) {
649 		dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
650 		dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
651 	}
652 
653 	for (i = 0; i < dbg_breakpoint_num; i++) {
654 		dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
655 		dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
656 	}
657 
658 	dbg_enable();
659 }
660 
661 void
662 dbg_monitor_enter(struct thread *thread)
663 {
664 	int i;
665 
666 	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
667 		/* Install the kernel version of the registers */
668 		dbg_register_sync(&kernel_monitor);
669 	} else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
670 		/* Disable the user breakpoints until we return to userspace */
671 		for (i = 0; i < dbg_watchpoint_num; i++) {
672 			dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
673 			dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
674 		}
675 
676 		for (i = 0; i < dbg_breakpoint_num; ++i) {
677 			dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
678 			dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
679 		}
680 		WRITE_SPECIALREG(mdscr_el1,
681 		    READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE));
682 		isb();
683 	}
684 }
685 
686 void
687 dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
688 {
689 	int i;
690 
691 	/*
692 	 * PSR_D is an aarch64-only flag. On aarch32, it switches
693 	 * the processor to big-endian, so avoid setting it for
694 	 * 32bits binaries.
695 	 */
696 	if (!(SV_PROC_FLAG(thread->td_proc, SV_ILP32)))
697 		frame->tf_spsr |= PSR_D;
698 	if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
699 		/* Install the thread's version of the registers */
700 		dbg_register_sync(&thread->td_pcb->pcb_dbg_regs);
701 		frame->tf_spsr &= ~PSR_D;
702 	} else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
703 		/* Disable the kernel breakpoints until we re-enter */
704 		for (i = 0; i < dbg_watchpoint_num; i++) {
705 			dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
706 			dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
707 		}
708 
709 		for (i = 0; i < dbg_breakpoint_num; ++i) {
710 			dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
711 			dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
712 		}
713 		WRITE_SPECIALREG(mdscr_el1,
714 		    READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE));
715 		isb();
716 	}
717 }
718