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
54enum dbg_t {
55	DBG_TYPE_BREAKPOINT = 0,
56	DBG_TYPE_WATCHPOINT = 1,
57};
58
59static int dbg_watchpoint_num;
60static int dbg_breakpoint_num;
61static struct debug_monitor_state kernel_monitor = {
62	.dbg_flags = DBGMON_KERNEL
63};
64
65static int dbg_setup_breakpoint(struct debug_monitor_state *monitor,
66    vm_offset_t addr);
67static int dbg_remove_breakpoint(struct debug_monitor_state *monitor,
68    vm_offset_t addr);
69static int dbg_setup_watchpoint(struct debug_monitor_state *, vm_offset_t,
70    vm_size_t, enum dbg_access_t);
71static int dbg_remove_watchpoint(struct debug_monitor_state *, vm_offset_t,
72    vm_size_t);
73
74/* Called from the exception handlers */
75void dbg_monitor_enter(struct thread *);
76void 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
162static uint64_t
163dbg_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
180static void
181dbg_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)
196int
197kdb_cpu_set_breakpoint(vm_offset_t addr)
198{
199	return (dbg_setup_breakpoint(NULL, addr));
200}
201
202int
203kdb_cpu_clr_breakpoint(vm_offset_t addr)
204{
205	return (dbg_remove_breakpoint(NULL, addr));
206}
207
208void
209kdb_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
239void
240kdb_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
264int
265kdb_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
286int
287kdb_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
295void
296dbg_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
322static const char *
323dbg_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
339static int
340dbg_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
356void
357dbg_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
384static int
385dbg_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
412static int
413dbg_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
444static int
445dbg_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
476static int
477dbg_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
500static int
501dbg_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
569static int
570dbg_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
594void
595dbg_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
629void
630dbg_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
667void
668dbg_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
692void
693dbg_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