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