]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/arm64/debug_monitor.c
Implement pci_enable_msi() and pci_disable_msi() in the LinuxKPI.
[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 "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 }