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