1/*-
2 * Copyright (c) 2014 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Semihalf under
6 * the sponsorship of the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30#include "opt_ddb.h"
31#include "opt_gdb.h"
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/kdb.h>
39#include <sys/pcpu.h>
40#include <sys/proc.h>
41#include <sys/systm.h>
42#include <sys/sysent.h>
43
44#include <machine/armreg.h>
45#include <machine/cpu.h>
46#include <machine/debug_monitor.h>
47#include <machine/kdb.h>
48
49#ifdef DDB
50#include <ddb/ddb.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
65/* Called from the exception handlers */
66void dbg_monitor_enter(struct thread *);
67void dbg_monitor_exit(struct thread *, struct trapframe *);
68
69/* Watchpoints/breakpoints control register bitfields */
70#define DBG_WATCH_CTRL_LEN_1		(0x1 << 5)
71#define DBG_WATCH_CTRL_LEN_2		(0x3 << 5)
72#define DBG_WATCH_CTRL_LEN_4		(0xf << 5)
73#define DBG_WATCH_CTRL_LEN_8		(0xff << 5)
74#define DBG_WATCH_CTRL_LEN_MASK(x)	((x) & (0xff << 5))
75#define DBG_WATCH_CTRL_EXEC		(0x0 << 3)
76#define DBG_WATCH_CTRL_LOAD		(0x1 << 3)
77#define DBG_WATCH_CTRL_STORE		(0x2 << 3)
78#define DBG_WATCH_CTRL_ACCESS_MASK(x)	((x) & (0x3 << 3))
79
80/* Common for breakpoint and watchpoint */
81#define DBG_WB_CTRL_EL1		(0x1 << 1)
82#define DBG_WB_CTRL_EL0		(0x2 << 1)
83#define DBG_WB_CTRL_ELX_MASK(x)	((x) & (0x3 << 1))
84#define DBG_WB_CTRL_E		(0x1 << 0)
85
86#define DBG_REG_BASE_BVR	0
87#define DBG_REG_BASE_BCR	(DBG_REG_BASE_BVR + 16)
88#define DBG_REG_BASE_WVR	(DBG_REG_BASE_BCR + 16)
89#define DBG_REG_BASE_WCR	(DBG_REG_BASE_WVR + 16)
90
91/* Watchpoint/breakpoint helpers */
92#define DBG_WB_WVR	"wvr"
93#define DBG_WB_WCR	"wcr"
94#define DBG_WB_BVR	"bvr"
95#define DBG_WB_BCR	"bcr"
96
97#define DBG_WB_READ(reg, num, val) do {					\
98	__asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val));	\
99} while (0)
100
101#define DBG_WB_WRITE(reg, num, val) do {				\
102	__asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val));	\
103} while (0)
104
105#define READ_WB_REG_CASE(reg, num, offset, val)		\
106	case (num + offset):				\
107		DBG_WB_READ(reg, num, val);		\
108		break
109
110#define WRITE_WB_REG_CASE(reg, num, offset, val)	\
111	case (num + offset):				\
112		DBG_WB_WRITE(reg, num, val);		\
113		break
114
115#define SWITCH_CASES_READ_WB_REG(reg, offset, val)	\
116	READ_WB_REG_CASE(reg,  0, offset, val);		\
117	READ_WB_REG_CASE(reg,  1, offset, val);		\
118	READ_WB_REG_CASE(reg,  2, offset, val);		\
119	READ_WB_REG_CASE(reg,  3, offset, val);		\
120	READ_WB_REG_CASE(reg,  4, offset, val);		\
121	READ_WB_REG_CASE(reg,  5, offset, val);		\
122	READ_WB_REG_CASE(reg,  6, offset, val);		\
123	READ_WB_REG_CASE(reg,  7, offset, val);		\
124	READ_WB_REG_CASE(reg,  8, offset, val);		\
125	READ_WB_REG_CASE(reg,  9, offset, val);		\
126	READ_WB_REG_CASE(reg, 10, offset, val);		\
127	READ_WB_REG_CASE(reg, 11, offset, val);		\
128	READ_WB_REG_CASE(reg, 12, offset, val);		\
129	READ_WB_REG_CASE(reg, 13, offset, val);		\
130	READ_WB_REG_CASE(reg, 14, offset, val);		\
131	READ_WB_REG_CASE(reg, 15, offset, val)
132
133#define SWITCH_CASES_WRITE_WB_REG(reg, offset, val)	\
134	WRITE_WB_REG_CASE(reg,  0, offset, val);	\
135	WRITE_WB_REG_CASE(reg,  1, offset, val);	\
136	WRITE_WB_REG_CASE(reg,  2, offset, val);	\
137	WRITE_WB_REG_CASE(reg,  3, offset, val);	\
138	WRITE_WB_REG_CASE(reg,  4, offset, val);	\
139	WRITE_WB_REG_CASE(reg,  5, offset, val);	\
140	WRITE_WB_REG_CASE(reg,  6, offset, val);	\
141	WRITE_WB_REG_CASE(reg,  7, offset, val);	\
142	WRITE_WB_REG_CASE(reg,  8, offset, val);	\
143	WRITE_WB_REG_CASE(reg,  9, offset, val);	\
144	WRITE_WB_REG_CASE(reg, 10, offset, val);	\
145	WRITE_WB_REG_CASE(reg, 11, offset, val);	\
146	WRITE_WB_REG_CASE(reg, 12, offset, val);	\
147	WRITE_WB_REG_CASE(reg, 13, offset, val);	\
148	WRITE_WB_REG_CASE(reg, 14, offset, val);	\
149	WRITE_WB_REG_CASE(reg, 15, offset, val)
150
151#ifdef DDB
152static uint64_t
153dbg_wb_read_reg(int reg, int n)
154{
155	uint64_t val = 0;
156
157	switch (reg + n) {
158	SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
159	SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
160	SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
161	SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
162	default:
163		printf("trying to read from wrong debug register %d\n", n);
164	}
165
166	return val;
167}
168#endif /* DDB */
169
170static void
171dbg_wb_write_reg(int reg, int n, uint64_t val)
172{
173	switch (reg + n) {
174	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
175	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
176	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
177	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
178	default:
179		printf("trying to write to wrong debug register %d\n", n);
180		return;
181	}
182	isb();
183}
184
185#if defined(DDB) || defined(GDB)
186void
187kdb_cpu_set_singlestep(void)
188{
189
190	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
191	    ("%s: debug exceptions are not masked", __func__));
192
193	kdb_frame->tf_spsr |= DBG_SPSR_SS;
194	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
195	    DBG_MDSCR_SS | DBG_MDSCR_KDE);
196
197	/*
198	 * Disable breakpoints and watchpoints, e.g. stepping
199	 * over watched instruction will trigger break exception instead of
200	 * single-step exception and locks CPU on that instruction for ever.
201	 */
202	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
203		WRITE_SPECIALREG(mdscr_el1,
204		    READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_MDE);
205	}
206}
207
208void
209kdb_cpu_clear_singlestep(void)
210{
211
212	KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D,
213	    ("%s: debug exceptions are not masked", __func__));
214
215	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
216	    ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
217
218	/* Restore breakpoints and watchpoints */
219	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
220		WRITE_SPECIALREG(mdscr_el1,
221		    READ_SPECIALREG(mdscr_el1) | DBG_MDSCR_MDE);
222
223		if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) {
224			WRITE_SPECIALREG(mdscr_el1,
225			    READ_SPECIALREG(mdscr_el1) | DBG_MDSCR_KDE);
226		}
227	}
228}
229
230int
231kdb_cpu_set_watchpoint(vm_offset_t addr, vm_size_t size, int access)
232{
233	enum dbg_access_t dbg_access;
234
235	switch (access) {
236	case KDB_DBG_ACCESS_R:
237		dbg_access = HW_BREAKPOINT_R;
238		break;
239	case KDB_DBG_ACCESS_W:
240		dbg_access = HW_BREAKPOINT_W;
241		break;
242	case KDB_DBG_ACCESS_RW:
243		dbg_access = HW_BREAKPOINT_RW;
244		break;
245	default:
246		return (EINVAL);
247	}
248
249	return (dbg_setup_watchpoint(NULL, addr, size, dbg_access));
250}
251
252int
253kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size)
254{
255
256	return (dbg_remove_watchpoint(NULL, addr, size));
257}
258#endif /* DDB || GDB */
259
260#ifdef DDB
261static const char *
262dbg_watchtype_str(uint32_t type)
263{
264	switch (type) {
265		case DBG_WATCH_CTRL_EXEC:
266			return ("execute");
267		case DBG_WATCH_CTRL_STORE:
268			return ("write");
269		case DBG_WATCH_CTRL_LOAD:
270			return ("read");
271		case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
272			return ("read/write");
273		default:
274			return ("invalid");
275	}
276}
277
278static int
279dbg_watchtype_len(uint32_t len)
280{
281	switch (len) {
282	case DBG_WATCH_CTRL_LEN_1:
283		return (1);
284	case DBG_WATCH_CTRL_LEN_2:
285		return (2);
286	case DBG_WATCH_CTRL_LEN_4:
287		return (4);
288	case DBG_WATCH_CTRL_LEN_8:
289		return (8);
290	default:
291		return (0);
292	}
293}
294
295void
296dbg_show_watchpoint(void)
297{
298	uint32_t wcr, len, type;
299	uint64_t addr;
300	int i;
301
302	db_printf("\nhardware watchpoints:\n");
303	db_printf("  watch    status        type  len             address              symbol\n");
304	db_printf("  -----  --------  ----------  ---  ------------------  ------------------\n");
305	for (i = 0; i < dbg_watchpoint_num; i++) {
306		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
307		if ((wcr & DBG_WB_CTRL_E) != 0) {
308			type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
309			len = DBG_WATCH_CTRL_LEN_MASK(wcr);
310			addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
311			db_printf("  %-5d  %-8s  %10s  %3d  0x%16lx  ",
312			    i, "enabled", dbg_watchtype_str(type),
313			    dbg_watchtype_len(len), 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#endif /* DDB */
322
323static int
324dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type)
325{
326	uint64_t *reg;
327	u_int max, i;
328
329	switch(type) {
330	case DBG_TYPE_BREAKPOINT:
331		max = dbg_breakpoint_num;
332		reg = monitor->dbg_bcr;
333		break;
334	case DBG_TYPE_WATCHPOINT:
335		max = dbg_watchpoint_num;
336		reg = monitor->dbg_wcr;
337		break;
338	default:
339		printf("Unsupported debug type\n");
340		return (i);
341	}
342
343	for (i = 0; i < max; i++) {
344		if ((reg[i] & DBG_WB_CTRL_E) == 0)
345			return (i);
346	}
347
348	return (-1);
349}
350
351static int
352dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type,
353    vm_offset_t addr)
354{
355	uint64_t *reg_addr, *reg_ctrl;
356	u_int max, i;
357
358	switch(type) {
359	case DBG_TYPE_BREAKPOINT:
360		max = dbg_breakpoint_num;
361		reg_addr = monitor->dbg_bvr;
362		reg_ctrl = monitor->dbg_bcr;
363		break;
364	case DBG_TYPE_WATCHPOINT:
365		max = dbg_watchpoint_num;
366		reg_addr = monitor->dbg_wvr;
367		reg_ctrl = monitor->dbg_wcr;
368		break;
369	default:
370		printf("Unsupported debug type\n");
371		return (i);
372	}
373
374	for (i = 0; i < max; i++) {
375		if (reg_addr[i] == addr &&
376		    (reg_ctrl[i] & DBG_WB_CTRL_E) != 0)
377			return (i);
378	}
379
380	return (-1);
381}
382
383int
384dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
385    vm_size_t size, enum dbg_access_t access)
386{
387	uint64_t wcr_size, wcr_priv, wcr_access;
388	u_int i;
389
390	if (monitor == NULL)
391		monitor = &kernel_monitor;
392
393	i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT);
394	if (i == -1) {
395		printf("Can not find slot for watchpoint, max %d"
396		    " watchpoints supported\n", dbg_watchpoint_num);
397		return (EBUSY);
398	}
399
400	switch(size) {
401	case 1:
402		wcr_size = DBG_WATCH_CTRL_LEN_1;
403		break;
404	case 2:
405		wcr_size = DBG_WATCH_CTRL_LEN_2;
406		break;
407	case 4:
408		wcr_size = DBG_WATCH_CTRL_LEN_4;
409		break;
410	case 8:
411		wcr_size = DBG_WATCH_CTRL_LEN_8;
412		break;
413	default:
414		printf("Unsupported address size for watchpoint: %zu\n", size);
415		return (EINVAL);
416	}
417
418	if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
419		wcr_priv = DBG_WB_CTRL_EL0;
420	else
421		wcr_priv = DBG_WB_CTRL_EL1;
422
423	switch(access) {
424	case HW_BREAKPOINT_X:
425		wcr_access = DBG_WATCH_CTRL_EXEC;
426		break;
427	case HW_BREAKPOINT_R:
428		wcr_access = DBG_WATCH_CTRL_LOAD;
429		break;
430	case HW_BREAKPOINT_W:
431		wcr_access = DBG_WATCH_CTRL_STORE;
432		break;
433	case HW_BREAKPOINT_RW:
434		wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
435		break;
436	default:
437		printf("Unsupported access type for watchpoint: %d\n", access);
438		return (EINVAL);
439	}
440
441	monitor->dbg_wvr[i] = addr;
442	monitor->dbg_wcr[i] = wcr_size | wcr_access | wcr_priv | DBG_WB_CTRL_E;
443	monitor->dbg_enable_count++;
444	monitor->dbg_flags |= DBGMON_ENABLED;
445
446	dbg_register_sync(monitor);
447	return (0);
448}
449
450int
451dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
452    vm_size_t size)
453{
454	u_int i;
455
456	if (monitor == NULL)
457		monitor = &kernel_monitor;
458
459	i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr);
460	if (i == -1) {
461		printf("Can not find watchpoint for address 0%lx\n", addr);
462		return (EINVAL);
463	}
464
465	monitor->dbg_wvr[i] = 0;
466	monitor->dbg_wcr[i] = 0;
467	monitor->dbg_enable_count--;
468	if (monitor->dbg_enable_count == 0)
469		monitor->dbg_flags &= ~DBGMON_ENABLED;
470
471	dbg_register_sync(monitor);
472	return (0);
473}
474
475void
476dbg_register_sync(struct debug_monitor_state *monitor)
477{
478	uint64_t mdscr;
479	int i;
480
481	if (monitor == NULL)
482		monitor = &kernel_monitor;
483
484	mdscr = READ_SPECIALREG(mdscr_el1);
485	if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) {
486		mdscr &= ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE);
487	} else {
488		for (i = 0; i < dbg_breakpoint_num; i++) {
489			dbg_wb_write_reg(DBG_REG_BASE_BCR, i,
490			    monitor->dbg_bcr[i]);
491			dbg_wb_write_reg(DBG_REG_BASE_BVR, i,
492			    monitor->dbg_bvr[i]);
493		}
494
495		for (i = 0; i < dbg_watchpoint_num; i++) {
496			dbg_wb_write_reg(DBG_REG_BASE_WCR, i,
497			    monitor->dbg_wcr[i]);
498			dbg_wb_write_reg(DBG_REG_BASE_WVR, i,
499			    monitor->dbg_wvr[i]);
500		}
501		mdscr |= DBG_MDSCR_MDE;
502		if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL)
503			mdscr |= DBG_MDSCR_KDE;
504	}
505	WRITE_SPECIALREG(mdscr_el1, mdscr);
506	isb();
507}
508
509void
510dbg_monitor_init(void)
511{
512	u_int i;
513
514	/* Find out many breakpoints and watchpoints we can use */
515	dbg_watchpoint_num = ((READ_SPECIALREG(id_aa64dfr0_el1) >> 20) & 0xf) + 1;
516	dbg_breakpoint_num = ((READ_SPECIALREG(id_aa64dfr0_el1) >> 12) & 0xf) + 1;
517
518	if (bootverbose && PCPU_GET(cpuid) == 0) {
519		printf("%d watchpoints and %d breakpoints supported\n",
520		    dbg_watchpoint_num, dbg_breakpoint_num);
521	}
522
523	/*
524	 * We have limited number of {watch,break}points, each consists of
525	 * two registers:
526	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
527	 *   behaviour
528	 * - wvr/bvr register keeps address we are hunting for
529	 *
530	 * Reset all breakpoints and watchpoints.
531	 */
532	for (i = 0; i < dbg_watchpoint_num; i++) {
533		dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
534		dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
535	}
536
537	for (i = 0; i < dbg_breakpoint_num; i++) {
538		dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
539		dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
540	}
541
542	dbg_enable();
543}
544
545void
546dbg_monitor_enter(struct thread *thread)
547{
548	int i;
549
550	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
551		/* Install the kernel version of the registers */
552		dbg_register_sync(&kernel_monitor);
553	} else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
554		/* Disable the user breakpoints until we return to userspace */
555		for (i = 0; i < dbg_watchpoint_num; i++) {
556			dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
557			dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
558		}
559
560		for (i = 0; i < dbg_breakpoint_num; ++i) {
561			dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
562			dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
563		}
564		WRITE_SPECIALREG(mdscr_el1,
565		    READ_SPECIALREG(mdscr_el1) &
566		    ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
567		isb();
568	}
569}
570
571void
572dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
573{
574	int i;
575
576	/*
577	 * PSR_D is an aarch64-only flag. On aarch32, it switches
578	 * the processor to big-endian, so avoid setting it for
579	 * 32bits binaries.
580	 */
581	if (!(SV_PROC_FLAG(thread->td_proc, SV_ILP32)))
582		frame->tf_spsr |= PSR_D;
583	if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) {
584		/* Install the thread's version of the registers */
585		dbg_register_sync(&thread->td_pcb->pcb_dbg_regs);
586		frame->tf_spsr &= ~PSR_D;
587	} else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
588		/* Disable the kernel breakpoints until we re-enter */
589		for (i = 0; i < dbg_watchpoint_num; i++) {
590			dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
591			dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
592		}
593
594		for (i = 0; i < dbg_breakpoint_num; ++i) {
595			dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
596			dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
597		}
598		WRITE_SPECIALREG(mdscr_el1,
599		    READ_SPECIALREG(mdscr_el1) &
600		    ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
601		isb();
602	}
603}
604