xref: /freebsd/sys/arm64/arm64/debug_monitor.c (revision 42249ef2)
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/systm.h>
40 
41 #include <machine/armreg.h>
42 #include <machine/cpu.h>
43 #include <machine/debug_monitor.h>
44 #include <machine/kdb.h>
45 
46 #include <ddb/ddb.h>
47 #include <ddb/db_sym.h>
48 
49 enum dbg_t {
50 	DBG_TYPE_BREAKPOINT = 0,
51 	DBG_TYPE_WATCHPOINT = 1,
52 };
53 
54 static int dbg_watchpoint_num;
55 static int dbg_breakpoint_num;
56 static int dbg_ref_count_mde[MAXCPU];
57 static int dbg_ref_count_kde[MAXCPU];
58 
59 /* Watchpoints/breakpoints control register bitfields */
60 #define DBG_WATCH_CTRL_LEN_1		(0x1 << 5)
61 #define DBG_WATCH_CTRL_LEN_2		(0x3 << 5)
62 #define DBG_WATCH_CTRL_LEN_4		(0xf << 5)
63 #define DBG_WATCH_CTRL_LEN_8		(0xff << 5)
64 #define DBG_WATCH_CTRL_LEN_MASK(x)	((x) & (0xff << 5))
65 #define DBG_WATCH_CTRL_EXEC		(0x0 << 3)
66 #define DBG_WATCH_CTRL_LOAD		(0x1 << 3)
67 #define DBG_WATCH_CTRL_STORE		(0x2 << 3)
68 #define DBG_WATCH_CTRL_ACCESS_MASK(x)	((x) & (0x3 << 3))
69 
70 /* Common for breakpoint and watchpoint */
71 #define DBG_WB_CTRL_EL1		(0x1 << 1)
72 #define DBG_WB_CTRL_EL0		(0x2 << 1)
73 #define DBG_WB_CTRL_ELX_MASK(x)	((x) & (0x3 << 1))
74 #define DBG_WB_CTRL_E		(0x1 << 0)
75 
76 #define DBG_REG_BASE_BVR	0
77 #define DBG_REG_BASE_BCR	(DBG_REG_BASE_BVR + 16)
78 #define DBG_REG_BASE_WVR	(DBG_REG_BASE_BCR + 16)
79 #define DBG_REG_BASE_WCR	(DBG_REG_BASE_WVR + 16)
80 
81 /* Watchpoint/breakpoint helpers */
82 #define DBG_WB_WVR	"wvr"
83 #define DBG_WB_WCR	"wcr"
84 #define DBG_WB_BVR	"bvr"
85 #define DBG_WB_BCR	"bcr"
86 
87 #define DBG_WB_READ(reg, num, val) do {					\
88 	__asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val));	\
89 } while (0)
90 
91 #define DBG_WB_WRITE(reg, num, val) do {				\
92 	__asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val));	\
93 } while (0)
94 
95 #define READ_WB_REG_CASE(reg, num, offset, val)		\
96 	case (num + offset):				\
97 		DBG_WB_READ(reg, num, val);		\
98 		break
99 
100 #define WRITE_WB_REG_CASE(reg, num, offset, val)	\
101 	case (num + offset):				\
102 		DBG_WB_WRITE(reg, num, val);		\
103 		break
104 
105 #define SWITCH_CASES_READ_WB_REG(reg, offset, val)	\
106 	READ_WB_REG_CASE(reg,  0, offset, val);		\
107 	READ_WB_REG_CASE(reg,  1, offset, val);		\
108 	READ_WB_REG_CASE(reg,  2, offset, val);		\
109 	READ_WB_REG_CASE(reg,  3, offset, val);		\
110 	READ_WB_REG_CASE(reg,  4, offset, val);		\
111 	READ_WB_REG_CASE(reg,  5, offset, val);		\
112 	READ_WB_REG_CASE(reg,  6, offset, val);		\
113 	READ_WB_REG_CASE(reg,  7, offset, val);		\
114 	READ_WB_REG_CASE(reg,  8, offset, val);		\
115 	READ_WB_REG_CASE(reg,  9, offset, val);		\
116 	READ_WB_REG_CASE(reg, 10, offset, val);		\
117 	READ_WB_REG_CASE(reg, 11, offset, val);		\
118 	READ_WB_REG_CASE(reg, 12, offset, val);		\
119 	READ_WB_REG_CASE(reg, 13, offset, val);		\
120 	READ_WB_REG_CASE(reg, 14, offset, val);		\
121 	READ_WB_REG_CASE(reg, 15, offset, val)
122 
123 #define SWITCH_CASES_WRITE_WB_REG(reg, offset, val)	\
124 	WRITE_WB_REG_CASE(reg,  0, offset, val);	\
125 	WRITE_WB_REG_CASE(reg,  1, offset, val);	\
126 	WRITE_WB_REG_CASE(reg,  2, offset, val);	\
127 	WRITE_WB_REG_CASE(reg,  3, offset, val);	\
128 	WRITE_WB_REG_CASE(reg,  4, offset, val);	\
129 	WRITE_WB_REG_CASE(reg,  5, offset, val);	\
130 	WRITE_WB_REG_CASE(reg,  6, offset, val);	\
131 	WRITE_WB_REG_CASE(reg,  7, offset, val);	\
132 	WRITE_WB_REG_CASE(reg,  8, offset, val);	\
133 	WRITE_WB_REG_CASE(reg,  9, offset, val);	\
134 	WRITE_WB_REG_CASE(reg, 10, offset, val);	\
135 	WRITE_WB_REG_CASE(reg, 11, offset, val);	\
136 	WRITE_WB_REG_CASE(reg, 12, offset, val);	\
137 	WRITE_WB_REG_CASE(reg, 13, offset, val);	\
138 	WRITE_WB_REG_CASE(reg, 14, offset, val);	\
139 	WRITE_WB_REG_CASE(reg, 15, offset, val)
140 
141 static uint64_t
142 dbg_wb_read_reg(int reg, int n)
143 {
144 	uint64_t val = 0;
145 
146 	switch (reg + n) {
147 	SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
148 	SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
149 	SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
150 	SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
151 	default:
152 		db_printf("trying to read from wrong debug register %d\n", n);
153 	}
154 
155 	return val;
156 }
157 
158 static void
159 dbg_wb_write_reg(int reg, int n, uint64_t val)
160 {
161 	switch (reg + n) {
162 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val);
163 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val);
164 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val);
165 	SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val);
166 	default:
167 		db_printf("trying to write to wrong debug register %d\n", n);
168 	}
169 	isb();
170 }
171 
172 void
173 kdb_cpu_set_singlestep(void)
174 {
175 
176 	kdb_frame->tf_spsr |= DBG_SPSR_SS;
177 	WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) |
178 	    DBG_MDSCR_SS | DBG_MDSCR_KDE);
179 
180 	/*
181 	 * Disable breakpoints and watchpoints, e.g. stepping
182 	 * over watched instruction will trigger break exception instead of
183 	 * single-step exception and locks CPU on that instruction for ever.
184 	 */
185 	if (dbg_ref_count_mde[PCPU_GET(cpuid)] > 0) {
186 		WRITE_SPECIALREG(MDSCR_EL1,
187 		    READ_SPECIALREG(MDSCR_EL1) & ~DBG_MDSCR_MDE);
188 	}
189 }
190 
191 void
192 kdb_cpu_clear_singlestep(void)
193 {
194 
195 	WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) &
196 	    ~(DBG_MDSCR_SS | DBG_MDSCR_KDE));
197 
198 	/* Restore breakpoints and watchpoints */
199 	if (dbg_ref_count_mde[PCPU_GET(cpuid)] > 0) {
200 		WRITE_SPECIALREG(MDSCR_EL1,
201 		    READ_SPECIALREG(MDSCR_EL1) | DBG_MDSCR_MDE);
202 	}
203 
204 	if (dbg_ref_count_kde[PCPU_GET(cpuid)] > 0) {
205 		WRITE_SPECIALREG(MDSCR_EL1,
206 		    READ_SPECIALREG(MDSCR_EL1) | DBG_MDSCR_KDE);
207 	}
208 }
209 
210 static const char *
211 dbg_watchtype_str(uint32_t type)
212 {
213 	switch (type) {
214 		case DBG_WATCH_CTRL_EXEC:
215 			return ("execute");
216 		case DBG_WATCH_CTRL_STORE:
217 			return ("write");
218 		case DBG_WATCH_CTRL_LOAD:
219 			return ("read");
220 		case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE:
221 			return ("read/write");
222 		default:
223 			return ("invalid");
224 	}
225 }
226 
227 static int
228 dbg_watchtype_len(uint32_t len)
229 {
230 	switch (len) {
231 	case DBG_WATCH_CTRL_LEN_1:
232 		return (1);
233 	case DBG_WATCH_CTRL_LEN_2:
234 		return (2);
235 	case DBG_WATCH_CTRL_LEN_4:
236 		return (4);
237 	case DBG_WATCH_CTRL_LEN_8:
238 		return (8);
239 	default:
240 		return (0);
241 	}
242 }
243 
244 void
245 dbg_show_watchpoint(void)
246 {
247 	uint32_t wcr, len, type;
248 	uint64_t addr;
249 	int i;
250 
251 	db_printf("\nhardware watchpoints:\n");
252 	db_printf("  watch    status        type  len             address              symbol\n");
253 	db_printf("  -----  --------  ----------  ---  ------------------  ------------------\n");
254 	for (i = 0; i < dbg_watchpoint_num; i++) {
255 		wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i);
256 		if ((wcr & DBG_WB_CTRL_E) != 0) {
257 			type = DBG_WATCH_CTRL_ACCESS_MASK(wcr);
258 			len = DBG_WATCH_CTRL_LEN_MASK(wcr);
259 			addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i);
260 			db_printf("  %-5d  %-8s  %10s  %3d  0x%16lx  ",
261 			    i, "enabled", dbg_watchtype_str(type),
262 			    dbg_watchtype_len(len), addr);
263 			db_printsym((db_addr_t)addr, DB_STGY_ANY);
264 			db_printf("\n");
265 		} else {
266 			db_printf("  %-5d  disabled\n", i);
267 		}
268 	}
269 }
270 
271 
272 static int
273 dbg_find_free_slot(enum dbg_t type)
274 {
275 	u_int max, reg, i;
276 
277 	switch(type) {
278 	case DBG_TYPE_BREAKPOINT:
279 		max = dbg_breakpoint_num;
280 		reg = DBG_REG_BASE_BCR;
281 
282 		break;
283 	case DBG_TYPE_WATCHPOINT:
284 		max = dbg_watchpoint_num;
285 		reg = DBG_REG_BASE_WCR;
286 		break;
287 	default:
288 		db_printf("Unsupported debug type\n");
289 		return (i);
290 	}
291 
292 	for (i = 0; i < max; i++) {
293 		if ((dbg_wb_read_reg(reg, i) & DBG_WB_CTRL_E) == 0)
294 			return (i);
295 	}
296 
297 	return (-1);
298 }
299 
300 static int
301 dbg_find_slot(enum dbg_t type, db_expr_t addr)
302 {
303 	u_int max, reg_addr, reg_ctrl, i;
304 
305 	switch(type) {
306 	case DBG_TYPE_BREAKPOINT:
307 		max = dbg_breakpoint_num;
308 		reg_addr = DBG_REG_BASE_BVR;
309 		reg_ctrl = DBG_REG_BASE_BCR;
310 		break;
311 	case DBG_TYPE_WATCHPOINT:
312 		max = dbg_watchpoint_num;
313 		reg_addr = DBG_REG_BASE_WVR;
314 		reg_ctrl = DBG_REG_BASE_WCR;
315 		break;
316 	default:
317 		db_printf("Unsupported debug type\n");
318 		return (i);
319 	}
320 
321 	for (i = 0; i < max; i++) {
322 		if ((dbg_wb_read_reg(reg_addr, i) == addr) &&
323 		    ((dbg_wb_read_reg(reg_ctrl, i) & DBG_WB_CTRL_E) != 0))
324 			return (i);
325 	}
326 
327 	return (-1);
328 }
329 
330 static void
331 dbg_enable_monitor(enum dbg_el_t el)
332 {
333 	uint64_t reg_mdcr = 0;
334 
335 	/*
336 	 * There is no need to have debug monitor on permanently, thus we are
337 	 * refcounting and turn it on only if any of CPU is going to use that.
338 	 */
339 	if (atomic_fetchadd_int(&dbg_ref_count_mde[PCPU_GET(cpuid)], 1) == 0)
340 		reg_mdcr = DBG_MDSCR_MDE;
341 
342 	if ((el == DBG_FROM_EL1) &&
343 	    atomic_fetchadd_int(&dbg_ref_count_kde[PCPU_GET(cpuid)], 1) == 0)
344 		reg_mdcr |= DBG_MDSCR_KDE;
345 
346 	if (reg_mdcr)
347 		WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) | reg_mdcr);
348 }
349 
350 static void
351 dbg_disable_monitor(enum dbg_el_t el)
352 {
353 	uint64_t reg_mdcr = 0;
354 
355 	if (atomic_fetchadd_int(&dbg_ref_count_mde[PCPU_GET(cpuid)], -1) == 1)
356 		reg_mdcr = DBG_MDSCR_MDE;
357 
358 	if ((el == DBG_FROM_EL1) &&
359 	    atomic_fetchadd_int(&dbg_ref_count_kde[PCPU_GET(cpuid)], -1) == 1)
360 		reg_mdcr |= DBG_MDSCR_KDE;
361 
362 	if (reg_mdcr)
363 		WRITE_SPECIALREG(MDSCR_EL1, READ_SPECIALREG(MDSCR_EL1) & ~reg_mdcr);
364 }
365 
366 int
367 dbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el,
368     enum dbg_access_t access)
369 {
370 	uint64_t wcr_size, wcr_priv, wcr_access;
371 	u_int i;
372 
373 	i = dbg_find_free_slot(DBG_TYPE_WATCHPOINT);
374 	if (i == -1) {
375 		db_printf("Can not find slot for watchpoint, max %d"
376 		    " watchpoints supported\n", dbg_watchpoint_num);
377 		return (i);
378 	}
379 
380 	switch(size) {
381 	case 1:
382 		wcr_size = DBG_WATCH_CTRL_LEN_1;
383 		break;
384 	case 2:
385 		wcr_size = DBG_WATCH_CTRL_LEN_2;
386 		break;
387 	case 4:
388 		wcr_size = DBG_WATCH_CTRL_LEN_4;
389 		break;
390 	case 8:
391 		wcr_size = DBG_WATCH_CTRL_LEN_8;
392 		break;
393 	default:
394 		db_printf("Unsupported address size for watchpoint\n");
395 		return (-1);
396 	}
397 
398 	switch(el) {
399 	case DBG_FROM_EL0:
400 		wcr_priv = DBG_WB_CTRL_EL0;
401 		break;
402 	case DBG_FROM_EL1:
403 		wcr_priv = DBG_WB_CTRL_EL1;
404 		break;
405 	default:
406 		db_printf("Unsupported exception level for watchpoint\n");
407 		return (-1);
408 	}
409 
410 	switch(access) {
411 	case HW_BREAKPOINT_X:
412 		wcr_access = DBG_WATCH_CTRL_EXEC;
413 		break;
414 	case HW_BREAKPOINT_R:
415 		wcr_access = DBG_WATCH_CTRL_LOAD;
416 		break;
417 	case HW_BREAKPOINT_W:
418 		wcr_access = DBG_WATCH_CTRL_STORE;
419 		break;
420 	case HW_BREAKPOINT_RW:
421 		wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE;
422 		break;
423 	default:
424 		db_printf("Unsupported exception level for watchpoint\n");
425 		return (-1);
426 	}
427 
428 	dbg_wb_write_reg(DBG_REG_BASE_WVR, i, addr);
429 	dbg_wb_write_reg(DBG_REG_BASE_WCR, i, wcr_size | wcr_access | wcr_priv |
430 	    DBG_WB_CTRL_E);
431 	dbg_enable_monitor(el);
432 	return (0);
433 }
434 
435 int
436 dbg_remove_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_el_t el)
437 {
438 	u_int i;
439 
440 	i = dbg_find_slot(DBG_TYPE_WATCHPOINT, addr);
441 	if (i == -1) {
442 		db_printf("Can not find watchpoint for address 0%lx\n", addr);
443 		return (i);
444 	}
445 
446 	dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
447 	dbg_disable_monitor(el);
448 	return (0);
449 }
450 
451 void
452 dbg_monitor_init(void)
453 {
454 	u_int i;
455 
456 	/* Find out many breakpoints and watchpoints we can use */
457 	dbg_watchpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1;
458 	dbg_breakpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1;
459 
460 	if (bootverbose && PCPU_GET(cpuid) == 0) {
461 		printf("%d watchpoints and %d breakpoints supported\n",
462 		    dbg_watchpoint_num, dbg_breakpoint_num);
463 	}
464 
465 	/*
466 	 * We have limited number of {watch,break}points, each consists of
467 	 * two registers:
468 	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
469 	 *   behaviour
470 	 * - wvr/bvr register keeps address we are hunting for
471 	 *
472 	 * Reset all breakpoints and watchpoints.
473 	 */
474 	for (i = 0; i < dbg_watchpoint_num; ++i) {
475 		dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
476 		dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
477 	}
478 
479 	for (i = 0; i < dbg_breakpoint_num; ++i) {
480 		dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
481 		dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
482 	}
483 
484 	dbg_enable();
485 }
486