1 /*- 2 * Copyright (c) 2014 The FreeBSD Foundation 3 * 4 * This software was developed by Semihalf under 5 * the sponsorship of the FreeBSD Foundation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "opt_ddb.h" 30 #include "opt_gdb.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/proc.h> 40 #include <sys/systm.h> 41 #include <sys/sysent.h> 42 43 #include <machine/armreg.h> 44 #include <machine/cpu.h> 45 #include <machine/debug_monitor.h> 46 #include <machine/kdb.h> 47 48 #ifdef DDB 49 #include <ddb/ddb.h> 50 #include <ddb/db_sym.h> 51 #endif 52 53 enum dbg_t { 54 DBG_TYPE_BREAKPOINT = 0, 55 DBG_TYPE_WATCHPOINT = 1, 56 }; 57 58 static int dbg_watchpoint_num; 59 static int dbg_breakpoint_num; 60 static struct debug_monitor_state kernel_monitor = { 61 .dbg_flags = DBGMON_KERNEL 62 }; 63 64 /* Called from the exception handlers */ 65 void dbg_monitor_enter(struct thread *); 66 void dbg_monitor_exit(struct thread *, struct trapframe *); 67 68 /* Watchpoints/breakpoints control register bitfields */ 69 #define DBG_WATCH_CTRL_LEN_1 (0x1 << 5) 70 #define DBG_WATCH_CTRL_LEN_2 (0x3 << 5) 71 #define DBG_WATCH_CTRL_LEN_4 (0xf << 5) 72 #define DBG_WATCH_CTRL_LEN_8 (0xff << 5) 73 #define DBG_WATCH_CTRL_LEN_MASK(x) ((x) & (0xff << 5)) 74 #define DBG_WATCH_CTRL_EXEC (0x0 << 3) 75 #define DBG_WATCH_CTRL_LOAD (0x1 << 3) 76 #define DBG_WATCH_CTRL_STORE (0x2 << 3) 77 #define DBG_WATCH_CTRL_ACCESS_MASK(x) ((x) & (0x3 << 3)) 78 79 /* Common for breakpoint and watchpoint */ 80 #define DBG_WB_CTRL_EL1 (0x1 << 1) 81 #define DBG_WB_CTRL_EL0 (0x2 << 1) 82 #define DBG_WB_CTRL_ELX_MASK(x) ((x) & (0x3 << 1)) 83 #define DBG_WB_CTRL_E (0x1 << 0) 84 85 #define DBG_REG_BASE_BVR 0 86 #define DBG_REG_BASE_BCR (DBG_REG_BASE_BVR + 16) 87 #define DBG_REG_BASE_WVR (DBG_REG_BASE_BCR + 16) 88 #define DBG_REG_BASE_WCR (DBG_REG_BASE_WVR + 16) 89 90 /* Watchpoint/breakpoint helpers */ 91 #define DBG_WB_WVR "wvr" 92 #define DBG_WB_WCR "wcr" 93 #define DBG_WB_BVR "bvr" 94 #define DBG_WB_BCR "bcr" 95 96 #define DBG_WB_READ(reg, num, val) do { \ 97 __asm __volatile("mrs %0, dbg" reg #num "_el1" : "=r" (val)); \ 98 } while (0) 99 100 #define DBG_WB_WRITE(reg, num, val) do { \ 101 __asm __volatile("msr dbg" reg #num "_el1, %0" :: "r" (val)); \ 102 } while (0) 103 104 #define READ_WB_REG_CASE(reg, num, offset, val) \ 105 case (num + offset): \ 106 DBG_WB_READ(reg, num, val); \ 107 break 108 109 #define WRITE_WB_REG_CASE(reg, num, offset, val) \ 110 case (num + offset): \ 111 DBG_WB_WRITE(reg, num, val); \ 112 break 113 114 #define SWITCH_CASES_READ_WB_REG(reg, offset, val) \ 115 READ_WB_REG_CASE(reg, 0, offset, val); \ 116 READ_WB_REG_CASE(reg, 1, offset, val); \ 117 READ_WB_REG_CASE(reg, 2, offset, val); \ 118 READ_WB_REG_CASE(reg, 3, offset, val); \ 119 READ_WB_REG_CASE(reg, 4, offset, val); \ 120 READ_WB_REG_CASE(reg, 5, offset, val); \ 121 READ_WB_REG_CASE(reg, 6, offset, val); \ 122 READ_WB_REG_CASE(reg, 7, offset, val); \ 123 READ_WB_REG_CASE(reg, 8, offset, val); \ 124 READ_WB_REG_CASE(reg, 9, offset, val); \ 125 READ_WB_REG_CASE(reg, 10, offset, val); \ 126 READ_WB_REG_CASE(reg, 11, offset, val); \ 127 READ_WB_REG_CASE(reg, 12, offset, val); \ 128 READ_WB_REG_CASE(reg, 13, offset, val); \ 129 READ_WB_REG_CASE(reg, 14, offset, val); \ 130 READ_WB_REG_CASE(reg, 15, offset, val) 131 132 #define SWITCH_CASES_WRITE_WB_REG(reg, offset, val) \ 133 WRITE_WB_REG_CASE(reg, 0, offset, val); \ 134 WRITE_WB_REG_CASE(reg, 1, offset, val); \ 135 WRITE_WB_REG_CASE(reg, 2, offset, val); \ 136 WRITE_WB_REG_CASE(reg, 3, offset, val); \ 137 WRITE_WB_REG_CASE(reg, 4, offset, val); \ 138 WRITE_WB_REG_CASE(reg, 5, offset, val); \ 139 WRITE_WB_REG_CASE(reg, 6, offset, val); \ 140 WRITE_WB_REG_CASE(reg, 7, offset, val); \ 141 WRITE_WB_REG_CASE(reg, 8, offset, val); \ 142 WRITE_WB_REG_CASE(reg, 9, offset, val); \ 143 WRITE_WB_REG_CASE(reg, 10, offset, val); \ 144 WRITE_WB_REG_CASE(reg, 11, offset, val); \ 145 WRITE_WB_REG_CASE(reg, 12, offset, val); \ 146 WRITE_WB_REG_CASE(reg, 13, offset, val); \ 147 WRITE_WB_REG_CASE(reg, 14, offset, val); \ 148 WRITE_WB_REG_CASE(reg, 15, offset, val) 149 150 #ifdef DDB 151 static uint64_t 152 dbg_wb_read_reg(int reg, int n) 153 { 154 uint64_t val = 0; 155 156 switch (reg + n) { 157 SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val); 158 SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val); 159 SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val); 160 SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val); 161 default: 162 printf("trying to read from wrong debug register %d\n", n); 163 } 164 165 return val; 166 } 167 #endif /* DDB */ 168 169 static void 170 dbg_wb_write_reg(int reg, int n, uint64_t val) 171 { 172 switch (reg + n) { 173 SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, DBG_REG_BASE_WVR, val); 174 SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, DBG_REG_BASE_WCR, val); 175 SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, DBG_REG_BASE_BVR, val); 176 SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, DBG_REG_BASE_BCR, val); 177 default: 178 printf("trying to write to wrong debug register %d\n", n); 179 return; 180 } 181 isb(); 182 } 183 184 #if defined(DDB) || defined(GDB) 185 void 186 kdb_cpu_set_singlestep(void) 187 { 188 189 KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D, 190 ("%s: debug exceptions are not masked", __func__)); 191 192 kdb_frame->tf_spsr |= PSR_SS; 193 WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) | 194 MDSCR_SS | MDSCR_KDE); 195 196 /* 197 * Disable breakpoints and watchpoints, e.g. stepping 198 * over watched instruction will trigger break exception instead of 199 * single-step exception and locks CPU on that instruction for ever. 200 */ 201 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) { 202 WRITE_SPECIALREG(mdscr_el1, 203 READ_SPECIALREG(mdscr_el1) & ~MDSCR_MDE); 204 } 205 } 206 207 void 208 kdb_cpu_clear_singlestep(void) 209 { 210 211 KASSERT((READ_SPECIALREG(daif) & PSR_D) == PSR_D, 212 ("%s: debug exceptions are not masked", __func__)); 213 214 WRITE_SPECIALREG(mdscr_el1, READ_SPECIALREG(mdscr_el1) & 215 ~(MDSCR_SS | MDSCR_KDE)); 216 217 /* Restore breakpoints and watchpoints */ 218 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) { 219 WRITE_SPECIALREG(mdscr_el1, 220 READ_SPECIALREG(mdscr_el1) | MDSCR_MDE); 221 222 if ((kernel_monitor.dbg_flags & DBGMON_KERNEL) != 0) { 223 WRITE_SPECIALREG(mdscr_el1, 224 READ_SPECIALREG(mdscr_el1) | MDSCR_KDE); 225 } 226 } 227 } 228 229 int 230 kdb_cpu_set_watchpoint(vm_offset_t addr, vm_size_t size, int access) 231 { 232 enum dbg_access_t dbg_access; 233 234 switch (access) { 235 case KDB_DBG_ACCESS_R: 236 dbg_access = HW_BREAKPOINT_R; 237 break; 238 case KDB_DBG_ACCESS_W: 239 dbg_access = HW_BREAKPOINT_W; 240 break; 241 case KDB_DBG_ACCESS_RW: 242 dbg_access = HW_BREAKPOINT_RW; 243 break; 244 default: 245 return (EINVAL); 246 } 247 248 return (dbg_setup_watchpoint(NULL, addr, size, dbg_access)); 249 } 250 251 int 252 kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size) 253 { 254 255 return (dbg_remove_watchpoint(NULL, addr, size)); 256 } 257 #endif /* DDB || GDB */ 258 259 #ifdef DDB 260 static const char * 261 dbg_watchtype_str(uint32_t type) 262 { 263 switch (type) { 264 case DBG_WATCH_CTRL_EXEC: 265 return ("execute"); 266 case DBG_WATCH_CTRL_STORE: 267 return ("write"); 268 case DBG_WATCH_CTRL_LOAD: 269 return ("read"); 270 case DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE: 271 return ("read/write"); 272 default: 273 return ("invalid"); 274 } 275 } 276 277 static int 278 dbg_watchtype_len(uint32_t len) 279 { 280 switch (len) { 281 case DBG_WATCH_CTRL_LEN_1: 282 return (1); 283 case DBG_WATCH_CTRL_LEN_2: 284 return (2); 285 case DBG_WATCH_CTRL_LEN_4: 286 return (4); 287 case DBG_WATCH_CTRL_LEN_8: 288 return (8); 289 default: 290 return (0); 291 } 292 } 293 294 void 295 dbg_show_watchpoint(void) 296 { 297 uint32_t wcr, len, type; 298 uint64_t addr; 299 int i; 300 301 db_printf("\nhardware watchpoints:\n"); 302 db_printf(" watch status type len address symbol\n"); 303 db_printf(" ----- -------- ---------- --- ------------------ ------------------\n"); 304 for (i = 0; i < dbg_watchpoint_num; i++) { 305 wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); 306 if ((wcr & DBG_WB_CTRL_E) != 0) { 307 type = DBG_WATCH_CTRL_ACCESS_MASK(wcr); 308 len = DBG_WATCH_CTRL_LEN_MASK(wcr); 309 addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i); 310 db_printf(" %-5d %-8s %10s %3d 0x%16lx ", 311 i, "enabled", dbg_watchtype_str(type), 312 dbg_watchtype_len(len), addr); 313 db_printsym((db_addr_t)addr, DB_STGY_ANY); 314 db_printf("\n"); 315 } else { 316 db_printf(" %-5d disabled\n", i); 317 } 318 } 319 } 320 #endif /* DDB */ 321 322 static int 323 dbg_find_free_slot(struct debug_monitor_state *monitor, enum dbg_t type) 324 { 325 uint64_t *reg; 326 u_int max, i; 327 328 switch(type) { 329 case DBG_TYPE_BREAKPOINT: 330 max = dbg_breakpoint_num; 331 reg = monitor->dbg_bcr; 332 break; 333 case DBG_TYPE_WATCHPOINT: 334 max = dbg_watchpoint_num; 335 reg = monitor->dbg_wcr; 336 break; 337 default: 338 printf("Unsupported debug type\n"); 339 return (i); 340 } 341 342 for (i = 0; i < max; i++) { 343 if ((reg[i] & DBG_WB_CTRL_E) == 0) 344 return (i); 345 } 346 347 return (-1); 348 } 349 350 static int 351 dbg_find_slot(struct debug_monitor_state *monitor, enum dbg_t type, 352 vm_offset_t addr) 353 { 354 uint64_t *reg_addr, *reg_ctrl; 355 u_int max, i; 356 357 switch(type) { 358 case DBG_TYPE_BREAKPOINT: 359 max = dbg_breakpoint_num; 360 reg_addr = monitor->dbg_bvr; 361 reg_ctrl = monitor->dbg_bcr; 362 break; 363 case DBG_TYPE_WATCHPOINT: 364 max = dbg_watchpoint_num; 365 reg_addr = monitor->dbg_wvr; 366 reg_ctrl = monitor->dbg_wcr; 367 break; 368 default: 369 printf("Unsupported debug type\n"); 370 return (i); 371 } 372 373 for (i = 0; i < max; i++) { 374 if (reg_addr[i] == addr && 375 (reg_ctrl[i] & DBG_WB_CTRL_E) != 0) 376 return (i); 377 } 378 379 return (-1); 380 } 381 382 int 383 dbg_setup_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr, 384 vm_size_t size, enum dbg_access_t access) 385 { 386 uint64_t wcr_size, wcr_priv, wcr_access; 387 u_int i; 388 389 if (monitor == NULL) 390 monitor = &kernel_monitor; 391 392 i = dbg_find_free_slot(monitor, DBG_TYPE_WATCHPOINT); 393 if (i == -1) { 394 printf("Can not find slot for watchpoint, max %d" 395 " watchpoints supported\n", dbg_watchpoint_num); 396 return (EBUSY); 397 } 398 399 switch(size) { 400 case 1: 401 wcr_size = DBG_WATCH_CTRL_LEN_1; 402 break; 403 case 2: 404 wcr_size = DBG_WATCH_CTRL_LEN_2; 405 break; 406 case 4: 407 wcr_size = DBG_WATCH_CTRL_LEN_4; 408 break; 409 case 8: 410 wcr_size = DBG_WATCH_CTRL_LEN_8; 411 break; 412 default: 413 printf("Unsupported address size for watchpoint: %zu\n", size); 414 return (EINVAL); 415 } 416 417 if ((monitor->dbg_flags & DBGMON_KERNEL) == 0) 418 wcr_priv = DBG_WB_CTRL_EL0; 419 else 420 wcr_priv = DBG_WB_CTRL_EL1; 421 422 switch(access) { 423 case HW_BREAKPOINT_X: 424 wcr_access = DBG_WATCH_CTRL_EXEC; 425 break; 426 case HW_BREAKPOINT_R: 427 wcr_access = DBG_WATCH_CTRL_LOAD; 428 break; 429 case HW_BREAKPOINT_W: 430 wcr_access = DBG_WATCH_CTRL_STORE; 431 break; 432 case HW_BREAKPOINT_RW: 433 wcr_access = DBG_WATCH_CTRL_LOAD | DBG_WATCH_CTRL_STORE; 434 break; 435 default: 436 printf("Unsupported access type for watchpoint: %d\n", access); 437 return (EINVAL); 438 } 439 440 monitor->dbg_wvr[i] = addr; 441 monitor->dbg_wcr[i] = wcr_size | wcr_access | wcr_priv | DBG_WB_CTRL_E; 442 monitor->dbg_enable_count++; 443 monitor->dbg_flags |= DBGMON_ENABLED; 444 445 dbg_register_sync(monitor); 446 return (0); 447 } 448 449 int 450 dbg_remove_watchpoint(struct debug_monitor_state *monitor, vm_offset_t addr, 451 vm_size_t size) 452 { 453 u_int i; 454 455 if (monitor == NULL) 456 monitor = &kernel_monitor; 457 458 i = dbg_find_slot(monitor, DBG_TYPE_WATCHPOINT, addr); 459 if (i == -1) { 460 printf("Can not find watchpoint for address 0%lx\n", addr); 461 return (EINVAL); 462 } 463 464 monitor->dbg_wvr[i] = 0; 465 monitor->dbg_wcr[i] = 0; 466 monitor->dbg_enable_count--; 467 if (monitor->dbg_enable_count == 0) 468 monitor->dbg_flags &= ~DBGMON_ENABLED; 469 470 dbg_register_sync(monitor); 471 return (0); 472 } 473 474 void 475 dbg_register_sync(struct debug_monitor_state *monitor) 476 { 477 uint64_t mdscr; 478 int i; 479 480 if (monitor == NULL) 481 monitor = &kernel_monitor; 482 483 mdscr = READ_SPECIALREG(mdscr_el1); 484 if ((monitor->dbg_flags & DBGMON_ENABLED) == 0) { 485 mdscr &= ~(MDSCR_MDE | MDSCR_KDE); 486 } else { 487 for (i = 0; i < dbg_breakpoint_num; i++) { 488 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 489 monitor->dbg_bcr[i]); 490 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 491 monitor->dbg_bvr[i]); 492 } 493 494 for (i = 0; i < dbg_watchpoint_num; i++) { 495 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 496 monitor->dbg_wcr[i]); 497 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 498 monitor->dbg_wvr[i]); 499 } 500 mdscr |= MDSCR_MDE; 501 if ((monitor->dbg_flags & DBGMON_KERNEL) == DBGMON_KERNEL) 502 mdscr |= MDSCR_KDE; 503 } 504 WRITE_SPECIALREG(mdscr_el1, mdscr); 505 isb(); 506 } 507 508 void 509 dbg_monitor_init(void) 510 { 511 uint64_t aa64dfr0; 512 u_int i; 513 514 /* Find out many breakpoints and watchpoints we can use */ 515 aa64dfr0 = READ_SPECIALREG(id_aa64dfr0_el1); 516 dbg_watchpoint_num = ID_AA64DFR0_WRPs_VAL(aa64dfr0); 517 dbg_breakpoint_num = ID_AA64DFR0_BRPs_VAL(aa64dfr0); 518 519 if (bootverbose && PCPU_GET(cpuid) == 0) { 520 printf("%d watchpoints and %d breakpoints supported\n", 521 dbg_watchpoint_num, dbg_breakpoint_num); 522 } 523 524 /* 525 * We have limited number of {watch,break}points, each consists of 526 * two registers: 527 * - wcr/bcr regsiter configurates corresponding {watch,break}point 528 * behaviour 529 * - wvr/bvr register keeps address we are hunting for 530 * 531 * Reset all breakpoints and watchpoints. 532 */ 533 for (i = 0; i < dbg_watchpoint_num; i++) { 534 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0); 535 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0); 536 } 537 538 for (i = 0; i < dbg_breakpoint_num; i++) { 539 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0); 540 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0); 541 } 542 543 dbg_enable(); 544 } 545 546 void 547 dbg_monitor_enter(struct thread *thread) 548 { 549 int i; 550 551 if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) { 552 /* Install the kernel version of the registers */ 553 dbg_register_sync(&kernel_monitor); 554 } else if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) { 555 /* Disable the user breakpoints until we return to userspace */ 556 for (i = 0; i < dbg_watchpoint_num; i++) { 557 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0); 558 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0); 559 } 560 561 for (i = 0; i < dbg_breakpoint_num; ++i) { 562 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0); 563 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0); 564 } 565 WRITE_SPECIALREG(mdscr_el1, 566 READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE)); 567 isb(); 568 } 569 } 570 571 void 572 dbg_monitor_exit(struct thread *thread, struct trapframe *frame) 573 { 574 int i; 575 576 /* 577 * PSR_D is an aarch64-only flag. On aarch32, it switches 578 * the processor to big-endian, so avoid setting it for 579 * 32bits binaries. 580 */ 581 if (!(SV_PROC_FLAG(thread->td_proc, SV_ILP32))) 582 frame->tf_spsr |= PSR_D; 583 if ((thread->td_pcb->pcb_dbg_regs.dbg_flags & DBGMON_ENABLED) != 0) { 584 /* Install the thread's version of the registers */ 585 dbg_register_sync(&thread->td_pcb->pcb_dbg_regs); 586 frame->tf_spsr &= ~PSR_D; 587 } else if ((kernel_monitor.dbg_flags & DBGMON_ENABLED) != 0) { 588 /* Disable the kernel breakpoints until we re-enter */ 589 for (i = 0; i < dbg_watchpoint_num; i++) { 590 dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0); 591 dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0); 592 } 593 594 for (i = 0; i < dbg_breakpoint_num; ++i) { 595 dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0); 596 dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0); 597 } 598 WRITE_SPECIALREG(mdscr_el1, 599 READ_SPECIALREG(mdscr_el1) & ~(MDSCR_MDE | MDSCR_KDE)); 600 isb(); 601 } 602 } 603