]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/debug_monitor.c
Import NetBSD's blacklist source from vendor tree
[FreeBSD/FreeBSD.git] / sys / arm64 / arm64 / debug_monitor.c
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 }