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