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 } 486