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