debug_monitor.c revision 305774
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: releng/11.0/sys/arm64/arm64/debug_monitor.c 305774 2016-09-13 16:31:20Z andrew $");
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
49enum dbg_t {
50	DBG_TYPE_BREAKPOINT = 0,
51	DBG_TYPE_WATCHPOINT = 1,
52};
53
54static int dbg_watchpoint_num;
55static int dbg_breakpoint_num;
56static int dbg_ref_count_mde[MAXCPU];
57static 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
141static uint64_t
142dbg_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
158static void
159dbg_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
172void
173kdb_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
191void
192kdb_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
210static const char *
211dbg_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
227static int
228dbg_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
244void
245dbg_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
272static int
273dbg_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
300static int
301dbg_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
330static void
331dbg_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
350static void
351dbg_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
366int
367dbg_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
435int
436dbg_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
451void
452dbg_monitor_init(void)
453{
454	u_int i;
455
456	/* Clear OS lock */
457	WRITE_SPECIALREG(OSLAR_EL1, 0);
458
459	/* Find out many breakpoints and watchpoints we can use */
460	dbg_watchpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1;
461	dbg_breakpoint_num = ((READ_SPECIALREG(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1;
462
463	if (bootverbose && PCPU_GET(cpuid) == 0) {
464		db_printf("%d watchpoints and %d breakpoints supported\n",
465		    dbg_watchpoint_num, dbg_breakpoint_num);
466	}
467
468	/*
469	 * We have limited number of {watch,break}points, each consists of
470	 * two registers:
471	 * - wcr/bcr regsiter configurates corresponding {watch,break}point
472	 *   behaviour
473	 * - wvr/bvr register keeps address we are hunting for
474	 *
475	 * Reset all breakpoints and watchpoints.
476	 */
477	for (i = 0; i < dbg_watchpoint_num; ++i) {
478		dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0);
479		dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0);
480	}
481
482	for (i = 0; i < dbg_breakpoint_num; ++i) {
483		dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0);
484		dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0);
485	}
486
487	dbg_enable();
488}
489