1294740Szbb/* 2294740Szbb * Copyright (c) 2015 Juniper Networks Inc. 3294740Szbb * All rights reserved. 4294740Szbb * 5294740Szbb * Developed by Semihalf. 6294740Szbb * 7294740Szbb * Redistribution and use in source and binary forms, with or without 8294740Szbb * modification, are permitted provided that the following conditions 9294740Szbb * are met: 10294740Szbb * 1. Redistributions of source code must retain the above copyright 11294740Szbb * notice, this list of conditions and the following disclaimer. 12294740Szbb * 2. Redistributions in binary form must reproduce the above copyright 13294740Szbb * notice, this list of conditions and the following disclaimer in the 14294740Szbb * documentation and/or other materials provided with the distribution. 15294740Szbb * 16294740Szbb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17294740Szbb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18294740Szbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19294740Szbb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20294740Szbb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21294740Szbb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22294740Szbb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23294740Szbb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24294740Szbb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25294740Szbb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26294740Szbb * SUCH DAMAGE. 27294740Szbb */ 28294740Szbb 29294740Szbb#include <sys/cdefs.h> 30294740Szbb__FBSDID("$FreeBSD: stable/11/sys/arm/arm/debug_monitor.c 317976 2017-05-08 20:09:23Z gonzo $"); 31294740Szbb 32294740Szbb#include "opt_ddb.h" 33294740Szbb 34294740Szbb#include <sys/param.h> 35294740Szbb#include <sys/types.h> 36294740Szbb#include <sys/kdb.h> 37294740Szbb#include <sys/pcpu.h> 38294987Szbb#include <sys/smp.h> 39294740Szbb#include <sys/systm.h> 40294740Szbb 41294987Szbb#include <machine/atomic.h> 42294740Szbb#include <machine/armreg.h> 43294740Szbb#include <machine/cpu.h> 44294740Szbb#include <machine/debug_monitor.h> 45294740Szbb#include <machine/kdb.h> 46294740Szbb#include <machine/pcb.h> 47294987Szbb#include <machine/reg.h> 48294740Szbb 49294740Szbb#include <ddb/ddb.h> 50294740Szbb#include <ddb/db_access.h> 51294740Szbb#include <ddb/db_sym.h> 52294740Szbb 53294740Szbbenum dbg_t { 54294740Szbb DBG_TYPE_BREAKPOINT = 0, 55294740Szbb DBG_TYPE_WATCHPOINT = 1, 56294740Szbb}; 57294740Szbb 58294740Szbbstruct dbg_wb_conf { 59294740Szbb enum dbg_t type; 60294740Szbb enum dbg_access_t access; 61294740Szbb db_addr_t address; 62294740Szbb db_expr_t size; 63294740Szbb u_int slot; 64294740Szbb}; 65294740Szbb 66294740Szbbstatic int dbg_reset_state(void); 67294740Szbbstatic int dbg_setup_breakpoint(db_expr_t, db_expr_t, u_int); 68294740Szbbstatic int dbg_remove_breakpoint(u_int); 69294740Szbbstatic u_int dbg_find_slot(enum dbg_t, db_expr_t); 70294740Szbbstatic boolean_t dbg_check_slot_free(enum dbg_t, u_int); 71294740Szbb 72294740Szbbstatic int dbg_remove_xpoint(struct dbg_wb_conf *); 73294740Szbbstatic int dbg_setup_xpoint(struct dbg_wb_conf *); 74294740Szbb 75300969Szbbstatic int dbg_capable_var; /* Indicates that machine is capable of using 76294740Szbb HW watchpoints/breakpoints */ 77294740Szbb 78294740Szbbstatic uint32_t dbg_model; /* Debug Arch. Model */ 79294740Szbbstatic boolean_t dbg_ossr; /* OS Save and Restore implemented */ 80294740Szbb 81294740Szbbstatic uint32_t dbg_watchpoint_num; 82294740Szbbstatic uint32_t dbg_breakpoint_num; 83294740Szbb 84294740Szbb/* ID_DFR0 - Debug Feature Register 0 */ 85294740Szbb#define ID_DFR0_CP_DEBUG_M_SHIFT 0 86294740Szbb#define ID_DFR0_CP_DEBUG_M_MASK (0xF << ID_DFR0_CP_DEBUG_M_SHIFT) 87294740Szbb#define ID_DFR0_CP_DEBUG_M_NS (0x0) /* Not supported */ 88294740Szbb#define ID_DFR0_CP_DEBUG_M_V6 (0x2) /* v6 Debug arch. CP14 access */ 89294740Szbb#define ID_DFR0_CP_DEBUG_M_V6_1 (0x3) /* v6.1 Debug arch. CP14 access */ 90294740Szbb#define ID_DFR0_CP_DEBUG_M_V7 (0x4) /* v7 Debug arch. CP14 access */ 91294740Szbb#define ID_DFR0_CP_DEBUG_M_V7_1 (0x5) /* v7.1 Debug arch. CP14 access */ 92294740Szbb 93294740Szbb/* DBGDIDR - Debug ID Register */ 94294740Szbb#define DBGDIDR_WRPS_SHIFT 28 95294740Szbb#define DBGDIDR_WRPS_MASK (0xF << DBGDIDR_WRPS_SHIFT) 96294740Szbb#define DBGDIDR_WRPS_NUM(reg) \ 97294740Szbb ((((reg) & DBGDIDR_WRPS_MASK) >> DBGDIDR_WRPS_SHIFT) + 1) 98294740Szbb 99294740Szbb#define DBGDIDR_BRPS_SHIFT 24 100294740Szbb#define DBGDIDR_BRPS_MASK (0xF << DBGDIDR_BRPS_SHIFT) 101294740Szbb#define DBGDIDR_BRPS_NUM(reg) \ 102294740Szbb ((((reg) & DBGDIDR_BRPS_MASK) >> DBGDIDR_BRPS_SHIFT) + 1) 103294740Szbb 104294740Szbb/* DBGPRSR - Device Powerdown and Reset Status Register */ 105294740Szbb#define DBGPRSR_PU (1 << 0) /* Powerup status */ 106294740Szbb 107294740Szbb/* DBGOSLSR - OS Lock Status Register */ 108294740Szbb#define DBGOSLSR_OSLM0 (1 << 0) 109294740Szbb 110294740Szbb/* DBGOSDLR - OS Double Lock Register */ 111294740Szbb#define DBGPRSR_DLK (1 << 0) /* OS Double Lock set */ 112294740Szbb 113294740Szbb/* DBGDSCR - Debug Status and Control Register */ 114294740Szbb#define DBGSCR_MDBG_EN (1 << 15) /* Monitor debug-mode enable */ 115294740Szbb 116294740Szbb/* DBGWVR - Watchpoint Value Register */ 117294740Szbb#define DBGWVR_ADDR_MASK (~0x3U) 118294740Szbb 119294740Szbb/* Watchpoints/breakpoints control register bitfields */ 120294740Szbb#define DBG_WB_CTRL_LEN_1 (0x1 << 5) 121294740Szbb#define DBG_WB_CTRL_LEN_2 (0x3 << 5) 122294740Szbb#define DBG_WB_CTRL_LEN_4 (0xf << 5) 123294740Szbb#define DBG_WB_CTRL_LEN_8 (0xff << 5) 124294740Szbb#define DBG_WB_CTRL_LEN_MASK(x) ((x) & (0xff << 5)) 125294740Szbb#define DBG_WB_CTRL_EXEC (0x0 << 3) 126294740Szbb#define DBG_WB_CTRL_LOAD (0x1 << 3) 127294740Szbb#define DBG_WB_CTRL_STORE (0x2 << 3) 128294740Szbb#define DBG_WB_CTRL_ACCESS_MASK(x) ((x) & (0x3 << 3)) 129294740Szbb 130294740Szbb/* Common for breakpoint and watchpoint */ 131294740Szbb#define DBG_WB_CTRL_PL1 (0x1 << 1) 132294740Szbb#define DBG_WB_CTRL_PL0 (0x2 << 1) 133294740Szbb#define DBG_WB_CTRL_PLX_MASK(x) ((x) & (0x3 << 1)) 134294740Szbb#define DBG_WB_CTRL_E (0x1 << 0) 135294740Szbb 136294740Szbb/* 137294740Szbb * Watchpoint/breakpoint helpers 138294740Szbb */ 139294740Szbb#define DBG_BKPT_BT_SLOT 0 /* Slot for branch taken */ 140294740Szbb#define DBG_BKPT_BNT_SLOT 1 /* Slot for branch not taken */ 141294740Szbb 142294740Szbb#define OP2_SHIFT 4 143294740Szbb 144294740Szbb/* Opc2 numbers for coprocessor instructions */ 145294740Szbb#define DBG_WB_BVR 4 146294740Szbb#define DBG_WB_BCR 5 147294740Szbb#define DBG_WB_WVR 6 148294740Szbb#define DBG_WB_WCR 7 149294740Szbb 150294740Szbb#define DBG_REG_BASE_BVR (DBG_WB_BVR << OP2_SHIFT) 151294740Szbb#define DBG_REG_BASE_BCR (DBG_WB_BCR << OP2_SHIFT) 152294740Szbb#define DBG_REG_BASE_WVR (DBG_WB_WVR << OP2_SHIFT) 153294740Szbb#define DBG_REG_BASE_WCR (DBG_WB_WCR << OP2_SHIFT) 154294740Szbb 155294740Szbb#define DBG_WB_READ(cn, cm, op2, val) do { \ 156294740Szbb __asm __volatile("mrc p14, 0, %0, " #cn "," #cm "," #op2 : "=r" (val)); \ 157294740Szbb} while (0) 158294740Szbb 159294740Szbb#define DBG_WB_WRITE(cn, cm, op2, val) do { \ 160294740Szbb __asm __volatile("mcr p14, 0, %0, " #cn "," #cm "," #op2 :: "r" (val)); \ 161294740Szbb} while (0) 162294740Szbb 163294740Szbb#define READ_WB_REG_CASE(op2, m, val) \ 164294740Szbb case (((op2) << OP2_SHIFT) + m): \ 165294740Szbb DBG_WB_READ(c0, c ## m, op2, val); \ 166294740Szbb break 167294740Szbb 168294740Szbb#define WRITE_WB_REG_CASE(op2, m, val) \ 169294740Szbb case (((op2) << OP2_SHIFT) + m): \ 170294740Szbb DBG_WB_WRITE(c0, c ## m, op2, val); \ 171294740Szbb break 172294740Szbb 173294740Szbb#define SWITCH_CASES_READ_WB_REG(op2, val) \ 174294740Szbb READ_WB_REG_CASE(op2, 0, val); \ 175294740Szbb READ_WB_REG_CASE(op2, 1, val); \ 176294740Szbb READ_WB_REG_CASE(op2, 2, val); \ 177294740Szbb READ_WB_REG_CASE(op2, 3, val); \ 178294740Szbb READ_WB_REG_CASE(op2, 4, val); \ 179294740Szbb READ_WB_REG_CASE(op2, 5, val); \ 180294740Szbb READ_WB_REG_CASE(op2, 6, val); \ 181294740Szbb READ_WB_REG_CASE(op2, 7, val); \ 182294740Szbb READ_WB_REG_CASE(op2, 8, val); \ 183294740Szbb READ_WB_REG_CASE(op2, 9, val); \ 184294740Szbb READ_WB_REG_CASE(op2, 10, val); \ 185294740Szbb READ_WB_REG_CASE(op2, 11, val); \ 186294740Szbb READ_WB_REG_CASE(op2, 12, val); \ 187294740Szbb READ_WB_REG_CASE(op2, 13, val); \ 188294740Szbb READ_WB_REG_CASE(op2, 14, val); \ 189294740Szbb READ_WB_REG_CASE(op2, 15, val) 190294740Szbb 191294740Szbb#define SWITCH_CASES_WRITE_WB_REG(op2, val) \ 192294740Szbb WRITE_WB_REG_CASE(op2, 0, val); \ 193294740Szbb WRITE_WB_REG_CASE(op2, 1, val); \ 194294740Szbb WRITE_WB_REG_CASE(op2, 2, val); \ 195294740Szbb WRITE_WB_REG_CASE(op2, 3, val); \ 196294740Szbb WRITE_WB_REG_CASE(op2, 4, val); \ 197294740Szbb WRITE_WB_REG_CASE(op2, 5, val); \ 198294740Szbb WRITE_WB_REG_CASE(op2, 6, val); \ 199294740Szbb WRITE_WB_REG_CASE(op2, 7, val); \ 200294740Szbb WRITE_WB_REG_CASE(op2, 8, val); \ 201294740Szbb WRITE_WB_REG_CASE(op2, 9, val); \ 202294740Szbb WRITE_WB_REG_CASE(op2, 10, val); \ 203294740Szbb WRITE_WB_REG_CASE(op2, 11, val); \ 204294740Szbb WRITE_WB_REG_CASE(op2, 12, val); \ 205294740Szbb WRITE_WB_REG_CASE(op2, 13, val); \ 206294740Szbb WRITE_WB_REG_CASE(op2, 14, val); \ 207294740Szbb WRITE_WB_REG_CASE(op2, 15, val) 208294740Szbb 209294740Szbbstatic uint32_t 210294740Szbbdbg_wb_read_reg(int reg, int n) 211294740Szbb{ 212294740Szbb uint32_t val; 213294740Szbb 214294740Szbb val = 0; 215294740Szbb 216294740Szbb switch (reg + n) { 217294740Szbb SWITCH_CASES_READ_WB_REG(DBG_WB_WVR, val); 218294740Szbb SWITCH_CASES_READ_WB_REG(DBG_WB_WCR, val); 219294740Szbb SWITCH_CASES_READ_WB_REG(DBG_WB_BVR, val); 220294740Szbb SWITCH_CASES_READ_WB_REG(DBG_WB_BCR, val); 221294740Szbb default: 222294740Szbb db_printf( 223294740Szbb "trying to read from CP14 reg. using wrong opc2 %d\n", 224294740Szbb reg >> OP2_SHIFT); 225294740Szbb } 226294740Szbb 227294740Szbb return (val); 228294740Szbb} 229294740Szbb 230294740Szbbstatic void 231294740Szbbdbg_wb_write_reg(int reg, int n, uint32_t val) 232294740Szbb{ 233294740Szbb 234294740Szbb switch (reg + n) { 235294740Szbb SWITCH_CASES_WRITE_WB_REG(DBG_WB_WVR, val); 236294740Szbb SWITCH_CASES_WRITE_WB_REG(DBG_WB_WCR, val); 237294740Szbb SWITCH_CASES_WRITE_WB_REG(DBG_WB_BVR, val); 238294740Szbb SWITCH_CASES_WRITE_WB_REG(DBG_WB_BCR, val); 239294740Szbb default: 240294740Szbb db_printf( 241294740Szbb "trying to write to CP14 reg. using wrong opc2 %d\n", 242294740Szbb reg >> OP2_SHIFT); 243294740Szbb } 244294740Szbb isb(); 245294740Szbb} 246294740Szbb 247300969Szbbstatic __inline boolean_t 248300969Szbbdbg_capable(void) 249300969Szbb{ 250300969Szbb 251300969Szbb return (atomic_cmpset_int(&dbg_capable_var, 0, 0) == 0); 252300969Szbb} 253300969Szbb 254294740Szbbboolean_t 255294740Szbbkdb_cpu_pc_is_singlestep(db_addr_t pc) 256294740Szbb{ 257300968Szbb /* 258300968Szbb * XXX: If the platform fails to enable its debug arch. 259300968Szbb * there will be no stepping capabilities 260300968Szbb * (SOFTWARE_SSTEP is not defined for __ARM_ARCH >= 6). 261300968Szbb */ 262300969Szbb if (!dbg_capable()) 263300968Szbb return (FALSE); 264294740Szbb 265294740Szbb if (dbg_find_slot(DBG_TYPE_BREAKPOINT, pc) != ~0U) 266294740Szbb return (TRUE); 267294740Szbb 268294740Szbb return (FALSE); 269294740Szbb} 270294740Szbb 271294740Szbbvoid 272294740Szbbkdb_cpu_set_singlestep(void) 273294740Szbb{ 274294740Szbb db_expr_t inst; 275294740Szbb db_addr_t pc, brpc; 276294740Szbb uint32_t wcr; 277294740Szbb u_int i; 278294740Szbb 279300969Szbb if (!dbg_capable()) 280300968Szbb return; 281300968Szbb 282294740Szbb /* 283294740Szbb * Disable watchpoints, e.g. stepping over watched instruction will 284294740Szbb * trigger break exception instead of single-step exception and locks 285294740Szbb * CPU on that instruction for ever. 286294740Szbb */ 287294740Szbb for (i = 0; i < dbg_watchpoint_num; i++) { 288294740Szbb wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); 289294740Szbb if ((wcr & DBG_WB_CTRL_E) != 0) { 290294740Szbb dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 291294740Szbb (wcr & ~DBG_WB_CTRL_E)); 292294740Szbb } 293294740Szbb } 294294740Szbb 295294740Szbb pc = PC_REGS(); 296294740Szbb 297294740Szbb inst = db_get_value(pc, sizeof(pc), FALSE); 298294740Szbb if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) { 299294740Szbb brpc = branch_taken(inst, pc); 300294740Szbb dbg_setup_breakpoint(brpc, INSN_SIZE, DBG_BKPT_BT_SLOT); 301294740Szbb } 302294740Szbb pc = next_instr_address(pc, 0); 303294740Szbb dbg_setup_breakpoint(pc, INSN_SIZE, DBG_BKPT_BNT_SLOT); 304294740Szbb} 305294740Szbb 306294740Szbbvoid 307294740Szbbkdb_cpu_clear_singlestep(void) 308294740Szbb{ 309294740Szbb uint32_t wvr, wcr; 310294740Szbb u_int i; 311294740Szbb 312300969Szbb if (!dbg_capable()) 313300968Szbb return; 314300968Szbb 315294740Szbb dbg_remove_breakpoint(DBG_BKPT_BT_SLOT); 316294740Szbb dbg_remove_breakpoint(DBG_BKPT_BNT_SLOT); 317294740Szbb 318294740Szbb /* Restore all watchpoints */ 319294740Szbb for (i = 0; i < dbg_watchpoint_num; i++) { 320294740Szbb wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); 321294740Szbb wvr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i); 322294740Szbb /* Watchpoint considered not empty if address value is not 0 */ 323294740Szbb if ((wvr & DBGWVR_ADDR_MASK) != 0) { 324294740Szbb dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 325294740Szbb (wcr | DBG_WB_CTRL_E)); 326294740Szbb } 327294740Szbb } 328294740Szbb} 329294740Szbb 330294740Szbbint 331294740Szbbdbg_setup_watchpoint(db_expr_t addr, db_expr_t size, enum dbg_access_t access) 332294740Szbb{ 333294740Szbb struct dbg_wb_conf conf; 334294740Szbb 335294740Szbb if (access == HW_BREAKPOINT_X) { 336294740Szbb db_printf("Invalid access type for watchpoint: %d\n", access); 337294740Szbb return (EINVAL); 338294740Szbb } 339294740Szbb 340294740Szbb conf.address = addr; 341294740Szbb conf.size = size; 342294740Szbb conf.access = access; 343294740Szbb conf.type = DBG_TYPE_WATCHPOINT; 344294740Szbb 345294740Szbb return (dbg_setup_xpoint(&conf)); 346294740Szbb} 347294740Szbb 348294740Szbbint 349294740Szbbdbg_remove_watchpoint(db_expr_t addr, db_expr_t size __unused) 350294740Szbb{ 351294740Szbb struct dbg_wb_conf conf; 352294740Szbb 353294740Szbb conf.address = addr; 354294740Szbb conf.type = DBG_TYPE_WATCHPOINT; 355294740Szbb 356294740Szbb return (dbg_remove_xpoint(&conf)); 357294740Szbb} 358294740Szbb 359294740Szbbstatic int 360294740Szbbdbg_setup_breakpoint(db_expr_t addr, db_expr_t size, u_int slot) 361294740Szbb{ 362294740Szbb struct dbg_wb_conf conf; 363294740Szbb 364294740Szbb conf.address = addr; 365294740Szbb conf.size = size; 366294740Szbb conf.access = HW_BREAKPOINT_X; 367294740Szbb conf.type = DBG_TYPE_BREAKPOINT; 368294740Szbb conf.slot = slot; 369294740Szbb 370294740Szbb return (dbg_setup_xpoint(&conf)); 371294740Szbb} 372294740Szbb 373294740Szbbstatic int 374294740Szbbdbg_remove_breakpoint(u_int slot) 375294740Szbb{ 376294740Szbb struct dbg_wb_conf conf; 377294740Szbb 378294740Szbb /* Slot already cleared. Don't recurse */ 379294740Szbb if (dbg_check_slot_free(DBG_TYPE_BREAKPOINT, slot)) 380294740Szbb return (0); 381294740Szbb 382294740Szbb conf.slot = slot; 383294740Szbb conf.type = DBG_TYPE_BREAKPOINT; 384294740Szbb 385294740Szbb return (dbg_remove_xpoint(&conf)); 386294740Szbb} 387294740Szbb 388294740Szbbstatic const char * 389294740Szbbdbg_watchtype_str(uint32_t type) 390294740Szbb{ 391294740Szbb 392294740Szbb switch (type) { 393294740Szbb case DBG_WB_CTRL_EXEC: 394294740Szbb return ("execute"); 395294740Szbb case DBG_WB_CTRL_STORE: 396294740Szbb return ("write"); 397294740Szbb case DBG_WB_CTRL_LOAD: 398294740Szbb return ("read"); 399294740Szbb case DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE: 400294740Szbb return ("read/write"); 401294740Szbb default: 402294740Szbb return ("invalid"); 403294740Szbb } 404294740Szbb} 405294740Szbb 406294740Szbbstatic int 407294740Szbbdbg_watchtype_len(uint32_t len) 408294740Szbb{ 409294740Szbb 410294740Szbb switch (len) { 411294740Szbb case DBG_WB_CTRL_LEN_1: 412294740Szbb return (1); 413294740Szbb case DBG_WB_CTRL_LEN_2: 414294740Szbb return (2); 415294740Szbb case DBG_WB_CTRL_LEN_4: 416294740Szbb return (4); 417294740Szbb case DBG_WB_CTRL_LEN_8: 418294740Szbb return (8); 419294740Szbb default: 420294740Szbb return (0); 421294740Szbb } 422294740Szbb} 423294740Szbb 424294740Szbbvoid 425294740Szbbdbg_show_watchpoint(void) 426294740Szbb{ 427294740Szbb uint32_t wcr, len, type; 428294740Szbb uint32_t addr; 429294740Szbb boolean_t is_enabled; 430294740Szbb int i; 431294740Szbb 432300969Szbb if (!dbg_capable()) { 433294740Szbb db_printf("Architecture does not support HW " 434294740Szbb "breakpoints/watchpoints\n"); 435294740Szbb return; 436294740Szbb } 437294740Szbb 438294740Szbb db_printf("\nhardware watchpoints:\n"); 439294740Szbb db_printf(" watch status type len address symbol\n"); 440294740Szbb db_printf(" ----- -------- ---------- --- ---------- ------------------\n"); 441294740Szbb for (i = 0; i < dbg_watchpoint_num; i++) { 442294740Szbb wcr = dbg_wb_read_reg(DBG_REG_BASE_WCR, i); 443294740Szbb if ((wcr & DBG_WB_CTRL_E) != 0) 444294740Szbb is_enabled = TRUE; 445294740Szbb else 446294740Szbb is_enabled = FALSE; 447294740Szbb 448294740Szbb type = DBG_WB_CTRL_ACCESS_MASK(wcr); 449294740Szbb len = DBG_WB_CTRL_LEN_MASK(wcr); 450294740Szbb addr = dbg_wb_read_reg(DBG_REG_BASE_WVR, i) & DBGWVR_ADDR_MASK; 451294740Szbb db_printf(" %-5d %-8s %10s %3d 0x%08x ", i, 452294740Szbb is_enabled ? "enabled" : "disabled", 453294740Szbb is_enabled ? dbg_watchtype_str(type) : "", 454294740Szbb is_enabled ? dbg_watchtype_len(len) : 0, 455294740Szbb addr); 456294740Szbb db_printsym((db_addr_t)addr, DB_STGY_ANY); 457294740Szbb db_printf("\n"); 458294740Szbb } 459294740Szbb} 460294740Szbb 461294740Szbbstatic boolean_t 462294740Szbbdbg_check_slot_free(enum dbg_t type, u_int slot) 463294740Szbb{ 464294740Szbb uint32_t cr, vr; 465294740Szbb uint32_t max; 466294740Szbb 467294740Szbb switch(type) { 468294740Szbb case DBG_TYPE_BREAKPOINT: 469294740Szbb max = dbg_breakpoint_num; 470294740Szbb cr = DBG_REG_BASE_BCR; 471294740Szbb vr = DBG_REG_BASE_BVR; 472294740Szbb break; 473294740Szbb case DBG_TYPE_WATCHPOINT: 474294740Szbb max = dbg_watchpoint_num; 475294740Szbb cr = DBG_REG_BASE_WCR; 476294740Szbb vr = DBG_REG_BASE_WVR; 477294740Szbb break; 478294740Szbb default: 479294740Szbb db_printf("%s: Unsupported event type %d\n", __func__, type); 480294740Szbb return (FALSE); 481294740Szbb } 482294740Szbb 483294740Szbb if (slot >= max) { 484294740Szbb db_printf("%s: Invalid slot number %d, max %d\n", 485294740Szbb __func__, slot, max - 1); 486294740Szbb return (FALSE); 487294740Szbb } 488294740Szbb 489294740Szbb if ((dbg_wb_read_reg(cr, slot) & DBG_WB_CTRL_E) == 0 && 490294740Szbb (dbg_wb_read_reg(vr, slot) & DBGWVR_ADDR_MASK) == 0) 491294740Szbb return (TRUE); 492294740Szbb 493294740Szbb return (FALSE); 494294740Szbb} 495294740Szbb 496294740Szbbstatic u_int 497294740Szbbdbg_find_free_slot(enum dbg_t type) 498294740Szbb{ 499294740Szbb u_int max, i; 500294740Szbb 501294740Szbb switch(type) { 502294740Szbb case DBG_TYPE_BREAKPOINT: 503294740Szbb max = dbg_breakpoint_num; 504294740Szbb break; 505294740Szbb case DBG_TYPE_WATCHPOINT: 506294740Szbb max = dbg_watchpoint_num; 507294740Szbb break; 508294740Szbb default: 509294740Szbb db_printf("Unsupported debug type\n"); 510294740Szbb return (~0U); 511294740Szbb } 512294740Szbb 513294740Szbb for (i = 0; i < max; i++) { 514294740Szbb if (dbg_check_slot_free(type, i)) 515294740Szbb return (i); 516294740Szbb } 517294740Szbb 518294740Szbb return (~0U); 519294740Szbb} 520294740Szbb 521294740Szbbstatic u_int 522294740Szbbdbg_find_slot(enum dbg_t type, db_expr_t addr) 523294740Szbb{ 524294740Szbb uint32_t reg_addr, reg_ctrl; 525294740Szbb u_int max, i; 526294740Szbb 527294740Szbb switch(type) { 528294740Szbb case DBG_TYPE_BREAKPOINT: 529294740Szbb max = dbg_breakpoint_num; 530294740Szbb reg_addr = DBG_REG_BASE_BVR; 531294740Szbb reg_ctrl = DBG_REG_BASE_BCR; 532294740Szbb break; 533294740Szbb case DBG_TYPE_WATCHPOINT: 534294740Szbb max = dbg_watchpoint_num; 535294740Szbb reg_addr = DBG_REG_BASE_WVR; 536294740Szbb reg_ctrl = DBG_REG_BASE_WCR; 537294740Szbb break; 538294740Szbb default: 539294740Szbb db_printf("Unsupported debug type\n"); 540294740Szbb return (~0U); 541294740Szbb } 542294740Szbb 543294740Szbb for (i = 0; i < max; i++) { 544294740Szbb if ((dbg_wb_read_reg(reg_addr, i) == addr) && 545294740Szbb ((dbg_wb_read_reg(reg_ctrl, i) & DBG_WB_CTRL_E) != 0)) 546294740Szbb return (i); 547294740Szbb } 548294740Szbb 549294740Szbb return (~0U); 550294740Szbb} 551294740Szbb 552294740Szbbstatic __inline boolean_t 553294740Szbbdbg_monitor_is_enabled(void) 554294740Szbb{ 555294740Szbb 556294740Szbb return ((cp14_dbgdscrint_get() & DBGSCR_MDBG_EN) != 0); 557294740Szbb} 558294740Szbb 559294740Szbbstatic int 560294740Szbbdbg_enable_monitor(void) 561294740Szbb{ 562294740Szbb uint32_t dbg_dscr; 563294740Szbb 564294987Szbb /* Already enabled? Just return */ 565294987Szbb if (dbg_monitor_is_enabled()) 566294740Szbb return (0); 567294740Szbb 568294740Szbb dbg_dscr = cp14_dbgdscrint_get(); 569294740Szbb 570294740Szbb switch (dbg_model) { 571294740Szbb case ID_DFR0_CP_DEBUG_M_V6: 572294740Szbb case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */ 573294740Szbb cp14_dbgdscr_v6_set(dbg_dscr | DBGSCR_MDBG_EN); 574294740Szbb break; 575294740Szbb case ID_DFR0_CP_DEBUG_M_V7: /* fall through */ 576294740Szbb case ID_DFR0_CP_DEBUG_M_V7_1: 577294740Szbb cp14_dbgdscr_v7_set(dbg_dscr | DBGSCR_MDBG_EN); 578294740Szbb break; 579294740Szbb default: 580294740Szbb break; 581294740Szbb } 582294740Szbb isb(); 583294740Szbb 584294740Szbb /* Verify that Monitor mode is set */ 585294987Szbb if (dbg_monitor_is_enabled()) 586294740Szbb return (0); 587294740Szbb 588294740Szbb return (ENXIO); 589294740Szbb} 590294740Szbb 591294740Szbbstatic int 592294740Szbbdbg_setup_xpoint(struct dbg_wb_conf *conf) 593294740Szbb{ 594294987Szbb struct pcpu *pcpu; 595294987Szbb struct dbreg *d; 596294740Szbb const char *typestr; 597294740Szbb uint32_t cr_size, cr_priv, cr_access; 598294740Szbb uint32_t reg_ctrl, reg_addr, ctrl, addr; 599294740Szbb boolean_t is_bkpt; 600300969Szbb u_int cpu; 601294740Szbb u_int i; 602294740Szbb 603300969Szbb if (!dbg_capable()) 604294740Szbb return (ENXIO); 605294740Szbb 606294740Szbb is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT); 607294740Szbb typestr = is_bkpt ? "breakpoint" : "watchpoint"; 608294740Szbb 609294740Szbb if (is_bkpt) { 610294740Szbb if (dbg_breakpoint_num == 0) { 611294740Szbb db_printf("Breakpoints not supported on this architecture\n"); 612294740Szbb return (ENXIO); 613294740Szbb } 614294740Szbb i = conf->slot; 615294740Szbb if (!dbg_check_slot_free(DBG_TYPE_BREAKPOINT, i)) { 616294740Szbb /* 617294740Szbb * This should never happen. If it does it means that 618294740Szbb * there is an erroneus scenario somewhere. Still, it can 619294740Szbb * be done but let's inform the user. 620294740Szbb */ 621294740Szbb db_printf("ERROR: Breakpoint already set. Replacing...\n"); 622294740Szbb } 623294740Szbb } else { 624294740Szbb i = dbg_find_free_slot(DBG_TYPE_WATCHPOINT); 625294740Szbb if (i == ~0U) { 626294740Szbb db_printf("Can not find slot for %s, max %d slots supported\n", 627294740Szbb typestr, dbg_watchpoint_num); 628294740Szbb return (ENXIO); 629294740Szbb } 630294740Szbb } 631294740Szbb 632294740Szbb /* Kernel access only */ 633294740Szbb cr_priv = DBG_WB_CTRL_PL1; 634294740Szbb 635294740Szbb switch(conf->size) { 636294740Szbb case 1: 637294740Szbb cr_size = DBG_WB_CTRL_LEN_1; 638294740Szbb break; 639294740Szbb case 2: 640294740Szbb cr_size = DBG_WB_CTRL_LEN_2; 641294740Szbb break; 642294740Szbb case 4: 643294740Szbb cr_size = DBG_WB_CTRL_LEN_4; 644294740Szbb break; 645294740Szbb case 8: 646294740Szbb cr_size = DBG_WB_CTRL_LEN_8; 647294740Szbb break; 648294740Szbb default: 649294740Szbb db_printf("Unsupported address size for %s\n", typestr); 650294740Szbb return (EINVAL); 651294740Szbb } 652294740Szbb 653294740Szbb if (is_bkpt) { 654294740Szbb cr_access = DBG_WB_CTRL_EXEC; 655294740Szbb reg_ctrl = DBG_REG_BASE_BCR; 656294740Szbb reg_addr = DBG_REG_BASE_BVR; 657294740Szbb /* Always unlinked BKPT */ 658294740Szbb ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E); 659294740Szbb } else { 660294740Szbb switch(conf->access) { 661294740Szbb case HW_WATCHPOINT_R: 662294740Szbb cr_access = DBG_WB_CTRL_LOAD; 663294740Szbb break; 664294740Szbb case HW_WATCHPOINT_W: 665294740Szbb cr_access = DBG_WB_CTRL_STORE; 666294740Szbb break; 667294740Szbb case HW_WATCHPOINT_RW: 668294740Szbb cr_access = DBG_WB_CTRL_LOAD | DBG_WB_CTRL_STORE; 669294740Szbb break; 670294740Szbb default: 671294740Szbb db_printf("Unsupported exception level for %s\n", typestr); 672294740Szbb return (EINVAL); 673294740Szbb } 674294740Szbb 675294740Szbb reg_ctrl = DBG_REG_BASE_WCR; 676294740Szbb reg_addr = DBG_REG_BASE_WVR; 677294740Szbb ctrl = (cr_size | cr_access | cr_priv | DBG_WB_CTRL_E); 678294740Szbb } 679294740Szbb 680294740Szbb addr = conf->address; 681294740Szbb 682294740Szbb dbg_wb_write_reg(reg_addr, i, addr); 683294740Szbb dbg_wb_write_reg(reg_ctrl, i, ctrl); 684294740Szbb 685294987Szbb /* 686294987Szbb * Save watchpoint settings for all CPUs. 687294987Szbb * We don't need to do the same with breakpoints since HW breakpoints 688294987Szbb * are only used to perform single stepping. 689294987Szbb */ 690294987Szbb if (!is_bkpt) { 691294987Szbb CPU_FOREACH(cpu) { 692294987Szbb pcpu = pcpu_find(cpu); 693294987Szbb /* Fill out the settings for watchpoint */ 694294987Szbb d = (struct dbreg *)pcpu->pc_dbreg; 695294987Szbb d->dbg_wvr[i] = addr; 696294987Szbb d->dbg_wcr[i] = ctrl; 697294987Szbb /* Skip update command for the current CPU */ 698300969Szbb if (cpu != PCPU_GET(cpuid)) 699294987Szbb pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD; 700294987Szbb } 701294987Szbb } 702294987Szbb /* Ensure all data is written before waking other CPUs */ 703294987Szbb atomic_thread_fence_rel(); 704294987Szbb 705294987Szbb return (0); 706294740Szbb} 707294740Szbb 708294740Szbbstatic int 709294740Szbbdbg_remove_xpoint(struct dbg_wb_conf *conf) 710294740Szbb{ 711294987Szbb struct pcpu *pcpu; 712294987Szbb struct dbreg *d; 713294740Szbb uint32_t reg_ctrl, reg_addr, addr; 714294987Szbb boolean_t is_bkpt; 715300969Szbb u_int cpu; 716294740Szbb u_int i; 717294740Szbb 718300969Szbb if (!dbg_capable()) 719294740Szbb return (ENXIO); 720294740Szbb 721294987Szbb is_bkpt = (conf->type == DBG_TYPE_BREAKPOINT); 722294740Szbb addr = conf->address; 723294740Szbb 724294987Szbb if (is_bkpt) { 725294740Szbb i = conf->slot; 726294740Szbb reg_ctrl = DBG_REG_BASE_BCR; 727294740Szbb reg_addr = DBG_REG_BASE_BVR; 728294740Szbb } else { 729294740Szbb i = dbg_find_slot(DBG_TYPE_WATCHPOINT, addr); 730294740Szbb if (i == ~0U) { 731294740Szbb db_printf("Can not find watchpoint for address 0%x\n", addr); 732294740Szbb return (EINVAL); 733294740Szbb } 734294740Szbb reg_ctrl = DBG_REG_BASE_WCR; 735294740Szbb reg_addr = DBG_REG_BASE_WVR; 736294740Szbb } 737294740Szbb 738294740Szbb dbg_wb_write_reg(reg_ctrl, i, 0); 739294740Szbb dbg_wb_write_reg(reg_addr, i, 0); 740294740Szbb 741294987Szbb /* 742294987Szbb * Save watchpoint settings for all CPUs. 743294987Szbb * We don't need to do the same with breakpoints since HW breakpoints 744294987Szbb * are only used to perform single stepping. 745294987Szbb */ 746294987Szbb if (!is_bkpt) { 747294987Szbb CPU_FOREACH(cpu) { 748294987Szbb pcpu = pcpu_find(cpu); 749294987Szbb /* Fill out the settings for watchpoint */ 750294987Szbb d = (struct dbreg *)pcpu->pc_dbreg; 751294987Szbb d->dbg_wvr[i] = 0; 752294987Szbb d->dbg_wcr[i] = 0; 753294987Szbb /* Skip update command for the current CPU */ 754300969Szbb if (cpu != PCPU_GET(cpuid)) 755294987Szbb pcpu->pc_dbreg_cmd = PC_DBREG_CMD_LOAD; 756294987Szbb } 757294987Szbb /* Ensure all data is written before waking other CPUs */ 758294987Szbb atomic_thread_fence_rel(); 759294987Szbb } 760294987Szbb 761294987Szbb return (0); 762294740Szbb} 763294740Szbb 764294740Szbbstatic __inline uint32_t 765294740Szbbdbg_get_debug_model(void) 766294740Szbb{ 767294740Szbb uint32_t dbg_m; 768294740Szbb 769294740Szbb dbg_m = ((cpuinfo.id_dfr0 & ID_DFR0_CP_DEBUG_M_MASK) >> 770294740Szbb ID_DFR0_CP_DEBUG_M_SHIFT); 771294740Szbb 772294740Szbb return (dbg_m); 773294740Szbb} 774294740Szbb 775294740Szbbstatic __inline boolean_t 776294740Szbbdbg_get_ossr(void) 777294740Szbb{ 778294740Szbb 779294740Szbb switch (dbg_model) { 780300968Szbb case ID_DFR0_CP_DEBUG_M_V7: 781294740Szbb if ((cp14_dbgoslsr_get() & DBGOSLSR_OSLM0) != 0) 782294740Szbb return (TRUE); 783294740Szbb 784294740Szbb return (FALSE); 785294740Szbb case ID_DFR0_CP_DEBUG_M_V7_1: 786294740Szbb return (TRUE); 787294740Szbb default: 788294740Szbb return (FALSE); 789294740Szbb } 790294740Szbb} 791294740Szbb 792294740Szbbstatic __inline boolean_t 793294740Szbbdbg_arch_supported(void) 794294740Szbb{ 795317976Sgonzo uint32_t dbg_didr; 796294740Szbb 797294740Szbb switch (dbg_model) { 798294740Szbb case ID_DFR0_CP_DEBUG_M_V6: 799294740Szbb case ID_DFR0_CP_DEBUG_M_V6_1: 800317976Sgonzo dbg_didr = cp14_dbgdidr_get(); 801317976Sgonzo /* 802317976Sgonzo * read-all-zeroes is used by QEMU 803317976Sgonzo * to indicate that ARMv6 debug support 804317976Sgonzo * is not implemented. Real hardware has at 805317976Sgonzo * least version bits set 806317976Sgonzo */ 807317976Sgonzo if (dbg_didr == 0) 808317976Sgonzo return (FALSE); 809317976Sgonzo return (TRUE); 810294740Szbb case ID_DFR0_CP_DEBUG_M_V7: 811294740Szbb case ID_DFR0_CP_DEBUG_M_V7_1: /* fall through */ 812294740Szbb return (TRUE); 813294740Szbb default: 814294740Szbb /* We only support valid v6.x/v7.x modes through CP14 */ 815294740Szbb return (FALSE); 816294740Szbb } 817294740Szbb} 818294740Szbb 819294740Szbbstatic __inline uint32_t 820294740Szbbdbg_get_wrp_num(void) 821294740Szbb{ 822294740Szbb uint32_t dbg_didr; 823294740Szbb 824294740Szbb dbg_didr = cp14_dbgdidr_get(); 825294740Szbb 826294740Szbb return (DBGDIDR_WRPS_NUM(dbg_didr)); 827294740Szbb} 828294740Szbb 829294740Szbbstatic __inline uint32_t 830294740Szbbdgb_get_brp_num(void) 831294740Szbb{ 832294740Szbb uint32_t dbg_didr; 833294740Szbb 834294740Szbb dbg_didr = cp14_dbgdidr_get(); 835294740Szbb 836294740Szbb return (DBGDIDR_BRPS_NUM(dbg_didr)); 837294740Szbb} 838294740Szbb 839294740Szbbstatic int 840294740Szbbdbg_reset_state(void) 841294740Szbb{ 842294740Szbb u_int cpuid; 843294740Szbb size_t i; 844294740Szbb int err; 845294740Szbb 846294740Szbb cpuid = PCPU_GET(cpuid); 847294740Szbb err = 0; 848294740Szbb 849294740Szbb switch (dbg_model) { 850294740Szbb case ID_DFR0_CP_DEBUG_M_V6: 851300968Szbb case ID_DFR0_CP_DEBUG_M_V6_1: /* fall through */ 852300968Szbb /* 853300968Szbb * Arch needs monitor mode selected and enabled 854300968Szbb * to be able to access breakpoint/watchpoint registers. 855300968Szbb */ 856300968Szbb err = dbg_enable_monitor(); 857300968Szbb if (err != 0) 858300968Szbb return (err); 859300968Szbb goto vectr_clr; 860300968Szbb case ID_DFR0_CP_DEBUG_M_V7: 861294740Szbb /* Is core power domain powered up? */ 862294740Szbb if ((cp14_dbgprsr_get() & DBGPRSR_PU) == 0) 863294740Szbb err = ENXIO; 864294740Szbb 865294740Szbb if (err != 0) 866294740Szbb break; 867294740Szbb 868294740Szbb if (dbg_ossr) 869294740Szbb goto vectr_clr; 870294740Szbb break; 871294740Szbb case ID_DFR0_CP_DEBUG_M_V7_1: 872294740Szbb /* Is double lock set? */ 873294740Szbb if ((cp14_dbgosdlr_get() & DBGPRSR_DLK) != 0) 874294740Szbb err = ENXIO; 875294740Szbb 876294740Szbb break; 877294740Szbb default: 878294740Szbb break; 879294740Szbb } 880294740Szbb 881294740Szbb if (err != 0) { 882294740Szbb db_printf("Debug facility locked (CPU%d)\n", cpuid); 883294740Szbb return (err); 884294740Szbb } 885294740Szbb 886294740Szbb /* 887294740Szbb * DBGOSLAR is always implemented for v7.1 Debug Arch. however is 888294740Szbb * optional for v7 (depends on OS save and restore support). 889294740Szbb */ 890294740Szbb if (((dbg_model & ID_DFR0_CP_DEBUG_M_V7_1) != 0) || dbg_ossr) { 891294740Szbb /* 892294740Szbb * Clear OS lock. 893294740Szbb * Writing any other value than 0xC5ACCESS will unlock. 894294740Szbb */ 895294740Szbb cp14_dbgoslar_set(0); 896294740Szbb isb(); 897294740Szbb } 898294740Szbb 899294740Szbbvectr_clr: 900294740Szbb /* 901294740Szbb * After reset we must ensure that DBGVCR has a defined value. 902294740Szbb * Disable all vector catch events. Safe to use - required in all 903294740Szbb * implementations. 904294740Szbb */ 905294740Szbb cp14_dbgvcr_set(0); 906294740Szbb isb(); 907294740Szbb 908294740Szbb /* 909294740Szbb * We have limited number of {watch,break}points, each consists of 910294740Szbb * two registers: 911294740Szbb * - wcr/bcr regsiter configurates corresponding {watch,break}point 912294740Szbb * behaviour 913294740Szbb * - wvr/bvr register keeps address we are hunting for 914294740Szbb * 915294740Szbb * Reset all breakpoints and watchpoints. 916294740Szbb */ 917294740Szbb for (i = 0; i < dbg_watchpoint_num; ++i) { 918294740Szbb dbg_wb_write_reg(DBG_REG_BASE_WCR, i, 0); 919294740Szbb dbg_wb_write_reg(DBG_REG_BASE_WVR, i, 0); 920294740Szbb } 921294740Szbb 922294740Szbb for (i = 0; i < dbg_breakpoint_num; ++i) { 923294740Szbb dbg_wb_write_reg(DBG_REG_BASE_BCR, i, 0); 924294740Szbb dbg_wb_write_reg(DBG_REG_BASE_BVR, i, 0); 925294740Szbb } 926294740Szbb 927294740Szbb return (0); 928294740Szbb} 929294740Szbb 930294740Szbbvoid 931294740Szbbdbg_monitor_init(void) 932294740Szbb{ 933294740Szbb int err; 934294740Szbb 935294740Szbb /* Fetch ARM Debug Architecture model */ 936294740Szbb dbg_model = dbg_get_debug_model(); 937294740Szbb 938294740Szbb if (!dbg_arch_supported()) { 939294740Szbb db_printf("ARM Debug Architecture not supported\n"); 940294740Szbb return; 941294740Szbb } 942294740Szbb 943294740Szbb if (bootverbose) { 944294740Szbb db_printf("ARM Debug Architecture %s\n", 945294740Szbb (dbg_model == ID_DFR0_CP_DEBUG_M_V6) ? "v6" : 946294740Szbb (dbg_model == ID_DFR0_CP_DEBUG_M_V6_1) ? "v6.1" : 947294740Szbb (dbg_model == ID_DFR0_CP_DEBUG_M_V7) ? "v7" : 948294740Szbb (dbg_model == ID_DFR0_CP_DEBUG_M_V7_1) ? "v7.1" : "unknown"); 949294740Szbb } 950294740Szbb 951294740Szbb /* Do we have OS Save and Restore mechanism? */ 952294740Szbb dbg_ossr = dbg_get_ossr(); 953294740Szbb 954294740Szbb /* Find out many breakpoints and watchpoints we can use */ 955294740Szbb dbg_watchpoint_num = dbg_get_wrp_num(); 956294740Szbb dbg_breakpoint_num = dgb_get_brp_num(); 957294740Szbb 958294740Szbb if (bootverbose) { 959294740Szbb db_printf("%d watchpoints and %d breakpoints supported\n", 960294740Szbb dbg_watchpoint_num, dbg_breakpoint_num); 961294740Szbb } 962294740Szbb 963294740Szbb err = dbg_reset_state(); 964294740Szbb if (err == 0) { 965300968Szbb err = dbg_enable_monitor(); 966300968Szbb if (err == 0) { 967300969Szbb atomic_set_int(&dbg_capable_var, 1); 968300968Szbb return; 969300968Szbb } 970294740Szbb } 971294740Szbb 972294740Szbb db_printf("HW Breakpoints/Watchpoints not enabled on CPU%d\n", 973294740Szbb PCPU_GET(cpuid)); 974294740Szbb} 975294987Szbb 976294987SzbbCTASSERT(sizeof(struct dbreg) == sizeof(((struct pcpu *)NULL)->pc_dbreg)); 977294987Szbb 978294987Szbbvoid 979300969Szbbdbg_monitor_init_secondary(void) 980300969Szbb{ 981300969Szbb u_int cpuid; 982300969Szbb int err; 983300969Szbb /* 984300969Szbb * This flag is set on the primary CPU 985300969Szbb * and its meaning is valid for other CPUs too. 986300969Szbb */ 987300969Szbb if (!dbg_capable()) 988300969Szbb return; 989300969Szbb 990300969Szbb cpuid = PCPU_GET(cpuid); 991300969Szbb 992300969Szbb err = dbg_reset_state(); 993300969Szbb if (err != 0) { 994300969Szbb /* 995300969Szbb * Something is very wrong. 996300969Szbb * WPs/BPs will not work correctly on this CPU. 997300969Szbb */ 998300969Szbb KASSERT(0, ("%s: Failed to reset Debug Architecture " 999300969Szbb "state on CPU%d", __func__, cpuid)); 1000300969Szbb /* Disable HW debug capabilities for all CPUs */ 1001300969Szbb atomic_set_int(&dbg_capable_var, 0); 1002300969Szbb return; 1003300969Szbb } 1004300969Szbb err = dbg_enable_monitor(); 1005300969Szbb if (err != 0) { 1006300969Szbb KASSERT(0, ("%s: Failed to enable Debug Monitor" 1007300969Szbb " on CPU%d", __func__, cpuid)); 1008300969Szbb atomic_set_int(&dbg_capable_var, 0); 1009300969Szbb } 1010300969Szbb} 1011300969Szbb 1012300969Szbbvoid 1013294987Szbbdbg_resume_dbreg(void) 1014294987Szbb{ 1015294987Szbb struct dbreg *d; 1016294987Szbb u_int i; 1017294987Szbb 1018294987Szbb /* 1019294987Szbb * This flag is set on the primary CPU 1020294987Szbb * and its meaning is valid for other CPUs too. 1021294987Szbb */ 1022300969Szbb if (!dbg_capable()) 1023294987Szbb return; 1024294987Szbb 1025294987Szbb atomic_thread_fence_acq(); 1026294987Szbb 1027294987Szbb switch (PCPU_GET(dbreg_cmd)) { 1028294987Szbb case PC_DBREG_CMD_LOAD: 1029294987Szbb d = (struct dbreg *)PCPU_PTR(dbreg); 1030294987Szbb 1031294987Szbb /* Restore watchpoints */ 1032294987Szbb for (i = 0; i < dbg_watchpoint_num; i++) { 1033294987Szbb dbg_wb_write_reg(DBG_REG_BASE_WVR, i, d->dbg_wvr[i]); 1034294987Szbb dbg_wb_write_reg(DBG_REG_BASE_WCR, i, d->dbg_wcr[i]); 1035294987Szbb } 1036294987Szbb 1037294987Szbb PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE); 1038294987Szbb break; 1039294987Szbb } 1040294987Szbb} 1041