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