xref: /freebsd/sys/arm64/arm64/debug_monitor.c (revision e17f5b1d)
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 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/kdb.h>
38 #include <sys/pcpu.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 #include <sys/sysent.h>
42 
43 #include <machine/armreg.h>
44 #include <machine/cpu.h>
45 #include <machine/debug_monitor.h>
46 #include <machine/kdb.h>
47 
48 #ifdef DDB
49 #include <ddb/ddb.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 /* Called from the exception handlers */
65 void dbg_monitor_enter(struct thread *);
66 void dbg_monitor_exit(struct thread *, struct trapframe *);
67 
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))
78 
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)
84 
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)
89 
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"
95 
96 #define DBG_WB_READ(reg, num, val) do {					\
97 	__asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val));	\
98 } while (0)
99 
100 #define DBG_WB_WRITE(reg, num, val) do {				\
101 	__asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val));	\
102 } while (0)
103 
104 #define READ_WB_REG_CASE(reg, num, offset, val)		\
105 	case (num + offset):				\
106 		DBG_WB_READ(reg, num, val);		\
107 		break
108 
109 #define WRITE_WB_REG_CASE(reg, num, offset, val)	\
110 	case (num + offset):				\
111 		DBG_WB_WRITE(reg, num, val);		\
112 		break
113 
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)
131 
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)
149 
150 #ifdef DDB
151 static uint64_t
152 dbg_wb_read_reg(int reg, int n)
153 {
154 	uint64_t val = 0;
155 
156 	switch (reg + 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);
161 	default:
162 		printf("trying to read from wrong debug register %d\n", n);
163 	}
164 
165 	return val;
166 }
167 #endif /* DDB */
168 
169 static void
170 dbg_wb_write_reg(int reg, int n, uint64_t val)
171 {
172 	switch (reg + n) {
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);
177 	default:
178 		printf("trying to write to wrong debug register %d\n", n);
179 		return;
180 	}
181 	isb();
182 }
183 
184 #ifdef DDB
185 void
186 kdb_cpu_set_singlestep(void)
187 {
188 
189 	kdb_frame->tf_spsr |= DBG_SPSR_SS;
190 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) |
191 	    DBG_MDSCR_SS | DBG_MDSCR_KDE);
192 
193 	/*
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.
197 	 */
198 	if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) {
199 		WRITE_SPECIALREG(mdscr_el1,
200 		    READ_SPECIALREG(mdscr_el1) & ~DBG_MDSCR_MDE);
201 	}
202 }
203 
204 void
205 kdb_cpu_clear_singlestep(void)
206 {
207 
208 	WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) &
209 	    ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
210 
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);
215 
216 		if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) {
217 			WRITE_SPECIALREG(mdscr_el1,
218 			    READ_SPECIALREG(mdscr_el1) | DBG_MDSCR_KDE);
219 		}
220 	}
221 }
222 
223 static const char *
224 dbg_watchtype_str(uint32_t type)
225 {
226 	switch (type) {
227 		case DBG_WATCH_CTRL_EXEC:
228 			return ("execute");
229 		case DBG_WATCH_CTRL_STORE:
230 			return ("write");
231 		case DBG_WATCH_CTRL_LOAD:
232 			return ("read");
233 		case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
234 			return ("read/write");
235 		default:
236 			return ("invalid");
237 	}
238 }
239 
240 static int
241 dbg_watchtype_len(uint32_t len)
242 {
243 	switch (len) {
244 	case DBG_WATCH_CTRL_LEN_1:
245 		return (1);
246 	case DBG_WATCH_CTRL_LEN_2:
247 		return (2);
248 	case DBG_WATCH_CTRL_LEN_4:
249 		return (4);
250 	case DBG_WATCH_CTRL_LEN_8:
251 		return (8);
252 	default:
253 		return (0);
254 	}
255 }
256 
257 void
258 dbg_show_watchpoint(void)
259 {
260 	uint32_t wcr, len, type;
261 	uint64_t addr;
262 	int i;
263 
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);
277 			db_printf("\n");
278 		} else {
279 			db_printf("  %-5d  disabled\n", i);
280 		}
281 	}
282 }
283 #endif /* DDB */
284 
285 static int
286 dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type)
287 {
288 	uint64_t *reg;
289 	u_int max, i;
290 
291 	switch(type) {
292 	case DBG_TYPE_BREAKPOINT:
293 		max = dbg_breakpoint_num;
294 		reg = monitor->dbg_bcr;
295 		break;
296 	case DBG_TYPE_WATCHPOINT:
297 		max = dbg_watchpoint_num;
298 		reg = monitor->dbg_wcr;
299 		break;
300 	default:
301 		printf("Unsupported debug type\n");
302 		return (i);
303 	}
304 
305 	for (i = 0; i < max; i++) {
306 		if ((reg[i] & DBG_WB_CTRL_E) == 0)
307 			return (i);
308 	}
309 
310 	return (-1);
311 }
312 
313 static int
314 dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type,
315     vm_offset_t addr)
316 {
317 	uint64_t *reg_addr, *reg_ctrl;
318 	u_int max, i;
319 
320 	switch(type) {
321 	case DBG_TYPE_BREAKPOINT:
322 		max = dbg_breakpoint_num;
323 		reg_addr = monitor->dbg_bvr;
324 		reg_ctrl = monitor->dbg_bcr;
325 		break;
326 	case DBG_TYPE_WATCHPOINT:
327 		max = dbg_watchpoint_num;
328 		reg_addr = monitor->dbg_wvr;
329 		reg_ctrl = monitor->dbg_wcr;
330 		break;
331 	default:
332 		printf("Unsupported debug type\n");
333 		return (i);
334 	}
335 
336 	for (i = 0; i < max; i++) {
337 		if (reg_addr[i] == addr &&
338 		    (reg_ctrl[i] & DBG_WB_CTRL_E) != 0)
339 			return (i);
340 	}
341 
342 	return (-1);
343 }
344 
345 int
346 dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
347     vm_size_t size, enum dbg_access_t access)
348 {
349 	uint64_t wcr_size, wcr_priv, wcr_access;
350 	u_int i;
351 
352 	if (monitor == NULL)
353 		monitor = &kernel_monitor;
354 
355 	i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT);
356 	if (i == -1) {
357 		printf("Can not find slot for watchpoint, max %d"
358 		    " watchpoints supported\n", dbg_watchpoint_num);
359 		return (i);
360 	}
361 
362 	switch(size) {
363 	case 1:
364 		wcr_size = DBG_WATCH_CTRL_LEN_1;
365 		break;
366 	case 2:
367 		wcr_size = DBG_WATCH_CTRL_LEN_2;
368 		break;
369 	case 4:
370 		wcr_size = DBG_WATCH_CTRL_LEN_4;
371 		break;
372 	case 8:
373 		wcr_size = DBG_WATCH_CTRL_LEN_8;
374 		break;
375 	default:
376 		printf("Unsupported address size for watchpoint\n");
377 		return (-1);
378 	}
379 
380 	if ((monitor->dbg_flags & DBGMON_KERNEL) == 0)
381 		wcr_priv = DBG_WB_CTRL_EL0;
382 	else
383 		wcr_priv = DBG_WB_CTRL_EL1;
384 
385 	switch(access) {
386 	case HW_BREAKPOINT_X:
387 		wcr_access = DBG_WATCH_CTRL_EXEC;
388 		break;
389 	case HW_BREAKPOINT_R:
390 		wcr_access = DBG_WATCH_CTRL_LOAD;
391 		break;
392 	case HW_BREAKPOINT_W:
393 		wcr_access = DBG_WATCH_CTRL_STORE;
394 		break;
395 	case HW_BREAKPOINT_RW:
396 		wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
397 		break;
398 	default:
399 		printf("Unsupported exception level for watchpoint\n");
400 		return (-1);
401 	}
402 
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;
407 
408 	dbg_register_sync(monitor);
409 	return (0);
410 }
411 
412 int
413 dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr,
414     vm_size_t size)
415 {
416 	u_int i;
417 
418 	if (monitor == NULL)
419 		monitor = &kernel_monitor;
420 
421 	i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr);
422 	if (i == -1) {
423 		printf("Can not find watchpoint for address 0%lx\n", addr);
424 		return (i);
425 	}
426 
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;
432 
433 	dbg_register_sync(monitor);
434 	return (0);
435 }
436 
437 void
438 dbg_register_sync(struct debug_monitor_state *monitor)
439 {
440 	uint64_t mdscr;
441 	int i;
442 
443 	if (monitor == NULL)
444 		monitor = &kernel_monitor;
445 
446 	mdscr = READ_SPECIALREG(mdscr_el1);
447 	if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) {
448 		mdscr &= ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE);
449 	} else {
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]);
455 		}
456 
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]);
462 		}
463 		mdscr |= DBG_MDSCR_MDE;
464 		if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL)
465 			mdscr |= DBG_MDSCR_KDE;
466 	}
467 	WRITE_SPECIALREG(mdscr_el1, mdscr);
468 	isb();
469 }
470 
471 void
472 dbg_monitor_init(void)
473 {
474 	u_int i;
475 
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;
479 
480 	if (bootverbose && PCPU_GET(cpuid) == 0) {
481 		printf("%d watchpoints and %d breakpoints supported\n",
482 		    dbg_watchpoint_num, dbg_breakpoint_num);
483 	}
484 
485 	/*
486 	 * We have limited number of {watch,break}points, each consists of
487 	 * two registers:
488 	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
489 	 *   behaviour
490 	 * - wvr/bvr register keeps address we are hunting for
491 	 *
492 	 * Reset all breakpoints and watchpoints.
493 	 */
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);
497 	}
498 
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);
502 	}
503 
504 	dbg_enable();
505 }
506 
507 void
508 dbg_monitor_enter(struct thread *thread)
509 {
510 	int i;
511 
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);
520 		}
521 
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);
525 		}
526 		WRITE_SPECIALREG(mdscr_el1,
527 		    READ_SPECIALREG(mdscr_el1) &
528 		    ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
529 		isb();
530 	}
531 }
532 
533 void
534 dbg_monitor_exit(struct thread *thread, struct trapframe *frame)
535 {
536 	int i;
537 
538 	/*
539 	 * PSR_D is an aarch64-only flag. On aarch32, it switches
540 	 * the processor to big-endian, so avoid setting it for
541 	 * 32bits binaries.
542 	 */
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);
554 		}
555 
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);
559 		}
560 		WRITE_SPECIALREG(mdscr_el1,
561 		    READ_SPECIALREG(mdscr_el1) &
562 		    ~(DBG_MDSCR_MDE | DBG_MDSCR_KDE));
563 		isb();
564 	}
565 }
566