162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2009, 2010 ARM Limited 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author: Will Deacon <will.deacon@arm.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, 1162306a36Sopenharmony_ci * using the CPU's debug registers. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#define pr_fmt(fmt) "hw-breakpoint: " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/hardirq.h> 1762306a36Sopenharmony_ci#include <linux/perf_event.h> 1862306a36Sopenharmony_ci#include <linux/hw_breakpoint.h> 1962306a36Sopenharmony_ci#include <linux/smp.h> 2062306a36Sopenharmony_ci#include <linux/cpu_pm.h> 2162306a36Sopenharmony_ci#include <linux/coresight.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/cacheflush.h> 2462306a36Sopenharmony_ci#include <asm/cputype.h> 2562306a36Sopenharmony_ci#include <asm/current.h> 2662306a36Sopenharmony_ci#include <asm/hw_breakpoint.h> 2762306a36Sopenharmony_ci#include <asm/traps.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Breakpoint currently in use for each BRP. */ 3062306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Watchpoint currently in use for each WRP. */ 3362306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Number of BRP/WRP registers on this CPU. */ 3662306a36Sopenharmony_cistatic int core_num_brps __ro_after_init; 3762306a36Sopenharmony_cistatic int core_num_wrps __ro_after_init; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Debug architecture version. */ 4062306a36Sopenharmony_cistatic u8 debug_arch __ro_after_init; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Does debug architecture support OS Save and Restore? */ 4362306a36Sopenharmony_cistatic bool has_ossr __ro_after_init; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Maximum supported watchpoint length. */ 4662306a36Sopenharmony_cistatic u8 max_watchpoint_len __ro_after_init; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define READ_WB_REG_CASE(OP2, M, VAL) \ 4962306a36Sopenharmony_ci case ((OP2 << 4) + M): \ 5062306a36Sopenharmony_ci ARM_DBG_READ(c0, c ## M, OP2, VAL); \ 5162306a36Sopenharmony_ci break 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define WRITE_WB_REG_CASE(OP2, M, VAL) \ 5462306a36Sopenharmony_ci case ((OP2 << 4) + M): \ 5562306a36Sopenharmony_ci ARM_DBG_WRITE(c0, c ## M, OP2, VAL); \ 5662306a36Sopenharmony_ci break 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define GEN_READ_WB_REG_CASES(OP2, VAL) \ 5962306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 0, VAL); \ 6062306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 1, VAL); \ 6162306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 2, VAL); \ 6262306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 3, VAL); \ 6362306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 4, VAL); \ 6462306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 5, VAL); \ 6562306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 6, VAL); \ 6662306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 7, VAL); \ 6762306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 8, VAL); \ 6862306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 9, VAL); \ 6962306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 10, VAL); \ 7062306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 11, VAL); \ 7162306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 12, VAL); \ 7262306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 13, VAL); \ 7362306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 14, VAL); \ 7462306a36Sopenharmony_ci READ_WB_REG_CASE(OP2, 15, VAL) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define GEN_WRITE_WB_REG_CASES(OP2, VAL) \ 7762306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 0, VAL); \ 7862306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 1, VAL); \ 7962306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 2, VAL); \ 8062306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 3, VAL); \ 8162306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 4, VAL); \ 8262306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 5, VAL); \ 8362306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 6, VAL); \ 8462306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 7, VAL); \ 8562306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 8, VAL); \ 8662306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 9, VAL); \ 8762306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 10, VAL); \ 8862306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 11, VAL); \ 8962306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 12, VAL); \ 9062306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 13, VAL); \ 9162306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 14, VAL); \ 9262306a36Sopenharmony_ci WRITE_WB_REG_CASE(OP2, 15, VAL) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic u32 read_wb_reg(int n) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci u32 val = 0; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci switch (n) { 9962306a36Sopenharmony_ci GEN_READ_WB_REG_CASES(ARM_OP2_BVR, val); 10062306a36Sopenharmony_ci GEN_READ_WB_REG_CASES(ARM_OP2_BCR, val); 10162306a36Sopenharmony_ci GEN_READ_WB_REG_CASES(ARM_OP2_WVR, val); 10262306a36Sopenharmony_ci GEN_READ_WB_REG_CASES(ARM_OP2_WCR, val); 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci pr_warn("attempt to read from unknown breakpoint register %d\n", 10562306a36Sopenharmony_ci n); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return val; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void write_wb_reg(int n, u32 val) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci switch (n) { 11462306a36Sopenharmony_ci GEN_WRITE_WB_REG_CASES(ARM_OP2_BVR, val); 11562306a36Sopenharmony_ci GEN_WRITE_WB_REG_CASES(ARM_OP2_BCR, val); 11662306a36Sopenharmony_ci GEN_WRITE_WB_REG_CASES(ARM_OP2_WVR, val); 11762306a36Sopenharmony_ci GEN_WRITE_WB_REG_CASES(ARM_OP2_WCR, val); 11862306a36Sopenharmony_ci default: 11962306a36Sopenharmony_ci pr_warn("attempt to write to unknown breakpoint register %d\n", 12062306a36Sopenharmony_ci n); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci isb(); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Determine debug architecture. */ 12662306a36Sopenharmony_cistatic u8 get_debug_arch(void) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci u32 didr; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Do we implement the extended CPUID interface? */ 13162306a36Sopenharmony_ci if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { 13262306a36Sopenharmony_ci pr_warn_once("CPUID feature registers not supported. " 13362306a36Sopenharmony_ci "Assuming v6 debug is present.\n"); 13462306a36Sopenharmony_ci return ARM_DEBUG_ARCH_V6; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ARM_DBG_READ(c0, c0, 0, didr); 13862306a36Sopenharmony_ci return (didr >> 16) & 0xf; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciu8 arch_get_debug_arch(void) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return debug_arch; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int debug_arch_supported(void) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci u8 arch = get_debug_arch(); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* We don't support the memory-mapped interface. */ 15162306a36Sopenharmony_ci return (arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14) || 15262306a36Sopenharmony_ci arch >= ARM_DEBUG_ARCH_V7_1; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Can we determine the watchpoint access type from the fsr? */ 15662306a36Sopenharmony_cistatic int debug_exception_updates_fsr(void) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci return get_debug_arch() >= ARM_DEBUG_ARCH_V8; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* Determine number of WRP registers available. */ 16262306a36Sopenharmony_cistatic int get_num_wrp_resources(void) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci u32 didr; 16562306a36Sopenharmony_ci ARM_DBG_READ(c0, c0, 0, didr); 16662306a36Sopenharmony_ci return ((didr >> 28) & 0xf) + 1; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* Determine number of BRP registers available. */ 17062306a36Sopenharmony_cistatic int get_num_brp_resources(void) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci u32 didr; 17362306a36Sopenharmony_ci ARM_DBG_READ(c0, c0, 0, didr); 17462306a36Sopenharmony_ci return ((didr >> 24) & 0xf) + 1; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* Does this core support mismatch breakpoints? */ 17862306a36Sopenharmony_cistatic int core_has_mismatch_brps(void) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 && 18162306a36Sopenharmony_ci get_num_brp_resources() > 1); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* Determine number of usable WRPs available. */ 18562306a36Sopenharmony_cistatic int get_num_wrps(void) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * On debug architectures prior to 7.1, when a watchpoint fires, the 18962306a36Sopenharmony_ci * only way to work out which watchpoint it was is by disassembling 19062306a36Sopenharmony_ci * the faulting instruction and working out the address of the memory 19162306a36Sopenharmony_ci * access. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Furthermore, we can only do this if the watchpoint was precise 19462306a36Sopenharmony_ci * since imprecise watchpoints prevent us from calculating register 19562306a36Sopenharmony_ci * based addresses. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Providing we have more than 1 breakpoint register, we only report 19862306a36Sopenharmony_ci * a single watchpoint register for the time being. This way, we always 19962306a36Sopenharmony_ci * know which watchpoint fired. In the future we can either add a 20062306a36Sopenharmony_ci * disassembler and address generation emulator, or we can insert a 20162306a36Sopenharmony_ci * check to see if the DFAR is set on watchpoint exception entry 20262306a36Sopenharmony_ci * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows 20362306a36Sopenharmony_ci * that it is set on some implementations]. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci if (get_debug_arch() < ARM_DEBUG_ARCH_V7_1) 20662306a36Sopenharmony_ci return 1; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return get_num_wrp_resources(); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* Determine number of usable BRPs available. */ 21262306a36Sopenharmony_cistatic int get_num_brps(void) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci int brps = get_num_brp_resources(); 21562306a36Sopenharmony_ci return core_has_mismatch_brps() ? brps - 1 : brps; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * In order to access the breakpoint/watchpoint control registers, 22062306a36Sopenharmony_ci * we must be running in debug monitor mode. Unfortunately, we can 22162306a36Sopenharmony_ci * be put into halting debug mode at any time by an external debugger 22262306a36Sopenharmony_ci * but there is nothing we can do to prevent that. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic int monitor_mode_enabled(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci u32 dscr; 22762306a36Sopenharmony_ci ARM_DBG_READ(c0, c1, 0, dscr); 22862306a36Sopenharmony_ci return !!(dscr & ARM_DSCR_MDBGEN); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int enable_monitor_mode(void) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 dscr; 23462306a36Sopenharmony_ci ARM_DBG_READ(c0, c1, 0, dscr); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* If monitor mode is already enabled, just return. */ 23762306a36Sopenharmony_ci if (dscr & ARM_DSCR_MDBGEN) 23862306a36Sopenharmony_ci goto out; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Write to the corresponding DSCR. */ 24162306a36Sopenharmony_ci switch (get_debug_arch()) { 24262306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V6: 24362306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V6_1: 24462306a36Sopenharmony_ci ARM_DBG_WRITE(c0, c1, 0, (dscr | ARM_DSCR_MDBGEN)); 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_ECP14: 24762306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_1: 24862306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V8: 24962306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V8_1: 25062306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V8_2: 25162306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V8_4: 25262306a36Sopenharmony_ci ARM_DBG_WRITE(c0, c2, 2, (dscr | ARM_DSCR_MDBGEN)); 25362306a36Sopenharmony_ci isb(); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci default: 25662306a36Sopenharmony_ci return -ENODEV; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Check that the write made it through. */ 26062306a36Sopenharmony_ci ARM_DBG_READ(c0, c1, 0, dscr); 26162306a36Sopenharmony_ci if (!(dscr & ARM_DSCR_MDBGEN)) { 26262306a36Sopenharmony_ci pr_warn_once("Failed to enable monitor mode on CPU %d.\n", 26362306a36Sopenharmony_ci smp_processor_id()); 26462306a36Sopenharmony_ci return -EPERM; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciout: 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint hw_breakpoint_slots(int type) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci if (!debug_arch_supported()) 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * We can be called early, so don't rely on 27862306a36Sopenharmony_ci * our static variables being initialised. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci switch (type) { 28162306a36Sopenharmony_ci case TYPE_INST: 28262306a36Sopenharmony_ci return get_num_brps(); 28362306a36Sopenharmony_ci case TYPE_DATA: 28462306a36Sopenharmony_ci return get_num_wrps(); 28562306a36Sopenharmony_ci default: 28662306a36Sopenharmony_ci pr_warn("unknown slot type: %d\n", type); 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * Check if 8-bit byte-address select is available. 29362306a36Sopenharmony_ci * This clobbers WRP 0. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_cistatic u8 get_max_wp_len(void) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci u32 ctrl_reg; 29862306a36Sopenharmony_ci struct arch_hw_breakpoint_ctrl ctrl; 29962306a36Sopenharmony_ci u8 size = 4; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14) 30262306a36Sopenharmony_ci goto out; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci memset(&ctrl, 0, sizeof(ctrl)); 30562306a36Sopenharmony_ci ctrl.len = ARM_BREAKPOINT_LEN_8; 30662306a36Sopenharmony_ci ctrl_reg = encode_ctrl_reg(ctrl); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci write_wb_reg(ARM_BASE_WVR, 0); 30962306a36Sopenharmony_ci write_wb_reg(ARM_BASE_WCR, ctrl_reg); 31062306a36Sopenharmony_ci if ((read_wb_reg(ARM_BASE_WCR) & ctrl_reg) == ctrl_reg) 31162306a36Sopenharmony_ci size = 8; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ciout: 31462306a36Sopenharmony_ci return size; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciu8 arch_get_max_wp_len(void) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci return max_watchpoint_len; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* 32362306a36Sopenharmony_ci * Install a perf counter breakpoint. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ciint arch_install_hw_breakpoint(struct perf_event *bp) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct arch_hw_breakpoint *info = counter_arch_bp(bp); 32862306a36Sopenharmony_ci struct perf_event **slot, **slots; 32962306a36Sopenharmony_ci int i, max_slots, ctrl_base, val_base; 33062306a36Sopenharmony_ci u32 addr, ctrl; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci addr = info->address; 33362306a36Sopenharmony_ci ctrl = encode_ctrl_reg(info->ctrl) | 0x1; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { 33662306a36Sopenharmony_ci /* Breakpoint */ 33762306a36Sopenharmony_ci ctrl_base = ARM_BASE_BCR; 33862306a36Sopenharmony_ci val_base = ARM_BASE_BVR; 33962306a36Sopenharmony_ci slots = this_cpu_ptr(bp_on_reg); 34062306a36Sopenharmony_ci max_slots = core_num_brps; 34162306a36Sopenharmony_ci } else { 34262306a36Sopenharmony_ci /* Watchpoint */ 34362306a36Sopenharmony_ci ctrl_base = ARM_BASE_WCR; 34462306a36Sopenharmony_ci val_base = ARM_BASE_WVR; 34562306a36Sopenharmony_ci slots = this_cpu_ptr(wp_on_reg); 34662306a36Sopenharmony_ci max_slots = core_num_wrps; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci for (i = 0; i < max_slots; ++i) { 35062306a36Sopenharmony_ci slot = &slots[i]; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (!*slot) { 35362306a36Sopenharmony_ci *slot = bp; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (i == max_slots) { 35962306a36Sopenharmony_ci pr_warn("Can't find any breakpoint slot\n"); 36062306a36Sopenharmony_ci return -EBUSY; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Override the breakpoint data with the step data. */ 36462306a36Sopenharmony_ci if (info->step_ctrl.enabled) { 36562306a36Sopenharmony_ci addr = info->trigger & ~0x3; 36662306a36Sopenharmony_ci ctrl = encode_ctrl_reg(info->step_ctrl); 36762306a36Sopenharmony_ci if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) { 36862306a36Sopenharmony_ci i = 0; 36962306a36Sopenharmony_ci ctrl_base = ARM_BASE_BCR + core_num_brps; 37062306a36Sopenharmony_ci val_base = ARM_BASE_BVR + core_num_brps; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Setup the address register. */ 37562306a36Sopenharmony_ci write_wb_reg(val_base + i, addr); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* Setup the control register. */ 37862306a36Sopenharmony_ci write_wb_reg(ctrl_base + i, ctrl); 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_civoid arch_uninstall_hw_breakpoint(struct perf_event *bp) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct arch_hw_breakpoint *info = counter_arch_bp(bp); 38562306a36Sopenharmony_ci struct perf_event **slot, **slots; 38662306a36Sopenharmony_ci int i, max_slots, base; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { 38962306a36Sopenharmony_ci /* Breakpoint */ 39062306a36Sopenharmony_ci base = ARM_BASE_BCR; 39162306a36Sopenharmony_ci slots = this_cpu_ptr(bp_on_reg); 39262306a36Sopenharmony_ci max_slots = core_num_brps; 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci /* Watchpoint */ 39562306a36Sopenharmony_ci base = ARM_BASE_WCR; 39662306a36Sopenharmony_ci slots = this_cpu_ptr(wp_on_reg); 39762306a36Sopenharmony_ci max_slots = core_num_wrps; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Remove the breakpoint. */ 40162306a36Sopenharmony_ci for (i = 0; i < max_slots; ++i) { 40262306a36Sopenharmony_ci slot = &slots[i]; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (*slot == bp) { 40562306a36Sopenharmony_ci *slot = NULL; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (i == max_slots) { 41162306a36Sopenharmony_ci pr_warn("Can't find any breakpoint slot\n"); 41262306a36Sopenharmony_ci return; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Ensure that we disable the mismatch breakpoint. */ 41662306a36Sopenharmony_ci if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE && 41762306a36Sopenharmony_ci info->step_ctrl.enabled) { 41862306a36Sopenharmony_ci i = 0; 41962306a36Sopenharmony_ci base = ARM_BASE_BCR + core_num_brps; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Reset the control register. */ 42362306a36Sopenharmony_ci write_wb_reg(base + i, 0); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int get_hbp_len(u8 hbp_len) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci unsigned int len_in_bytes = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci switch (hbp_len) { 43162306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_1: 43262306a36Sopenharmony_ci len_in_bytes = 1; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_2: 43562306a36Sopenharmony_ci len_in_bytes = 2; 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_4: 43862306a36Sopenharmony_ci len_in_bytes = 4; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_8: 44162306a36Sopenharmony_ci len_in_bytes = 8; 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return len_in_bytes; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* 44962306a36Sopenharmony_ci * Check whether bp virtual address is in kernel space. 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_ciint arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci unsigned int len; 45462306a36Sopenharmony_ci unsigned long va; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci va = hw->address; 45762306a36Sopenharmony_ci len = get_hbp_len(hw->ctrl.len); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* 46362306a36Sopenharmony_ci * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl. 46462306a36Sopenharmony_ci * Hopefully this will disappear when ptrace can bypass the conversion 46562306a36Sopenharmony_ci * to generic breakpoint descriptions. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ciint arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 46862306a36Sopenharmony_ci int *gen_len, int *gen_type) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci /* Type */ 47162306a36Sopenharmony_ci switch (ctrl.type) { 47262306a36Sopenharmony_ci case ARM_BREAKPOINT_EXECUTE: 47362306a36Sopenharmony_ci *gen_type = HW_BREAKPOINT_X; 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci case ARM_BREAKPOINT_LOAD: 47662306a36Sopenharmony_ci *gen_type = HW_BREAKPOINT_R; 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case ARM_BREAKPOINT_STORE: 47962306a36Sopenharmony_ci *gen_type = HW_BREAKPOINT_W; 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE: 48262306a36Sopenharmony_ci *gen_type = HW_BREAKPOINT_RW; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Len */ 48962306a36Sopenharmony_ci switch (ctrl.len) { 49062306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_1: 49162306a36Sopenharmony_ci *gen_len = HW_BREAKPOINT_LEN_1; 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_2: 49462306a36Sopenharmony_ci *gen_len = HW_BREAKPOINT_LEN_2; 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_4: 49762306a36Sopenharmony_ci *gen_len = HW_BREAKPOINT_LEN_4; 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case ARM_BREAKPOINT_LEN_8: 50062306a36Sopenharmony_ci *gen_len = HW_BREAKPOINT_LEN_8; 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci default: 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci/* 51062306a36Sopenharmony_ci * Construct an arch_hw_breakpoint from a perf_event. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_cistatic int arch_build_bp_info(struct perf_event *bp, 51362306a36Sopenharmony_ci const struct perf_event_attr *attr, 51462306a36Sopenharmony_ci struct arch_hw_breakpoint *hw) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci /* Type */ 51762306a36Sopenharmony_ci switch (attr->bp_type) { 51862306a36Sopenharmony_ci case HW_BREAKPOINT_X: 51962306a36Sopenharmony_ci hw->ctrl.type = ARM_BREAKPOINT_EXECUTE; 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci case HW_BREAKPOINT_R: 52262306a36Sopenharmony_ci hw->ctrl.type = ARM_BREAKPOINT_LOAD; 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci case HW_BREAKPOINT_W: 52562306a36Sopenharmony_ci hw->ctrl.type = ARM_BREAKPOINT_STORE; 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci case HW_BREAKPOINT_RW: 52862306a36Sopenharmony_ci hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci default: 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Len */ 53562306a36Sopenharmony_ci switch (attr->bp_len) { 53662306a36Sopenharmony_ci case HW_BREAKPOINT_LEN_1: 53762306a36Sopenharmony_ci hw->ctrl.len = ARM_BREAKPOINT_LEN_1; 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci case HW_BREAKPOINT_LEN_2: 54062306a36Sopenharmony_ci hw->ctrl.len = ARM_BREAKPOINT_LEN_2; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case HW_BREAKPOINT_LEN_4: 54362306a36Sopenharmony_ci hw->ctrl.len = ARM_BREAKPOINT_LEN_4; 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci case HW_BREAKPOINT_LEN_8: 54662306a36Sopenharmony_ci hw->ctrl.len = ARM_BREAKPOINT_LEN_8; 54762306a36Sopenharmony_ci if ((hw->ctrl.type != ARM_BREAKPOINT_EXECUTE) 54862306a36Sopenharmony_ci && max_watchpoint_len >= 8) 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci fallthrough; 55162306a36Sopenharmony_ci default: 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* 55662306a36Sopenharmony_ci * Breakpoints must be of length 2 (thumb) or 4 (ARM) bytes. 55762306a36Sopenharmony_ci * Watchpoints can be of length 1, 2, 4 or 8 bytes if supported 55862306a36Sopenharmony_ci * by the hardware and must be aligned to the appropriate number of 55962306a36Sopenharmony_ci * bytes. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE && 56262306a36Sopenharmony_ci hw->ctrl.len != ARM_BREAKPOINT_LEN_2 && 56362306a36Sopenharmony_ci hw->ctrl.len != ARM_BREAKPOINT_LEN_4) 56462306a36Sopenharmony_ci return -EINVAL; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Address */ 56762306a36Sopenharmony_ci hw->address = attr->bp_addr; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Privilege */ 57062306a36Sopenharmony_ci hw->ctrl.privilege = ARM_BREAKPOINT_USER; 57162306a36Sopenharmony_ci if (arch_check_bp_in_kernelspace(hw)) 57262306a36Sopenharmony_ci hw->ctrl.privilege |= ARM_BREAKPOINT_PRIV; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Enabled? */ 57562306a36Sopenharmony_ci hw->ctrl.enabled = !attr->disabled; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Mismatch */ 57862306a36Sopenharmony_ci hw->ctrl.mismatch = 0; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* 58462306a36Sopenharmony_ci * Validate the arch-specific HW Breakpoint register settings. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ciint hw_breakpoint_arch_parse(struct perf_event *bp, 58762306a36Sopenharmony_ci const struct perf_event_attr *attr, 58862306a36Sopenharmony_ci struct arch_hw_breakpoint *hw) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci int ret = 0; 59162306a36Sopenharmony_ci u32 offset, alignment_mask = 0x3; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Ensure that we are in monitor debug mode. */ 59462306a36Sopenharmony_ci if (!monitor_mode_enabled()) 59562306a36Sopenharmony_ci return -ENODEV; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Build the arch_hw_breakpoint. */ 59862306a36Sopenharmony_ci ret = arch_build_bp_info(bp, attr, hw); 59962306a36Sopenharmony_ci if (ret) 60062306a36Sopenharmony_ci goto out; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Check address alignment. */ 60362306a36Sopenharmony_ci if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8) 60462306a36Sopenharmony_ci alignment_mask = 0x7; 60562306a36Sopenharmony_ci offset = hw->address & alignment_mask; 60662306a36Sopenharmony_ci switch (offset) { 60762306a36Sopenharmony_ci case 0: 60862306a36Sopenharmony_ci /* Aligned */ 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case 1: 61162306a36Sopenharmony_ci case 2: 61262306a36Sopenharmony_ci /* Allow halfword watchpoints and breakpoints. */ 61362306a36Sopenharmony_ci if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2) 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci fallthrough; 61662306a36Sopenharmony_ci case 3: 61762306a36Sopenharmony_ci /* Allow single byte watchpoint. */ 61862306a36Sopenharmony_ci if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1) 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci fallthrough; 62162306a36Sopenharmony_ci default: 62262306a36Sopenharmony_ci ret = -EINVAL; 62362306a36Sopenharmony_ci goto out; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci hw->address &= ~alignment_mask; 62762306a36Sopenharmony_ci hw->ctrl.len <<= offset; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (uses_default_overflow_handler(bp)) { 63062306a36Sopenharmony_ci /* 63162306a36Sopenharmony_ci * Mismatch breakpoints are required for single-stepping 63262306a36Sopenharmony_ci * breakpoints. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci if (!core_has_mismatch_brps()) 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* We don't allow mismatch breakpoints in kernel space. */ 63862306a36Sopenharmony_ci if (arch_check_bp_in_kernelspace(hw)) 63962306a36Sopenharmony_ci return -EPERM; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* 64262306a36Sopenharmony_ci * Per-cpu breakpoints are not supported by our stepping 64362306a36Sopenharmony_ci * mechanism. 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_ci if (!bp->hw.target) 64662306a36Sopenharmony_ci return -EINVAL; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * We only support specific access types if the fsr 65062306a36Sopenharmony_ci * reports them. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if (!debug_exception_updates_fsr() && 65362306a36Sopenharmony_ci (hw->ctrl.type == ARM_BREAKPOINT_LOAD || 65462306a36Sopenharmony_ci hw->ctrl.type == ARM_BREAKPOINT_STORE)) 65562306a36Sopenharmony_ci return -EINVAL; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ciout: 65962306a36Sopenharmony_ci return ret; 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* 66362306a36Sopenharmony_ci * Enable/disable single-stepping over the breakpoint bp at address addr. 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_cistatic void enable_single_step(struct perf_event *bp, u32 addr) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct arch_hw_breakpoint *info = counter_arch_bp(bp); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci arch_uninstall_hw_breakpoint(bp); 67062306a36Sopenharmony_ci info->step_ctrl.mismatch = 1; 67162306a36Sopenharmony_ci info->step_ctrl.len = ARM_BREAKPOINT_LEN_4; 67262306a36Sopenharmony_ci info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE; 67362306a36Sopenharmony_ci info->step_ctrl.privilege = info->ctrl.privilege; 67462306a36Sopenharmony_ci info->step_ctrl.enabled = 1; 67562306a36Sopenharmony_ci info->trigger = addr; 67662306a36Sopenharmony_ci arch_install_hw_breakpoint(bp); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic void disable_single_step(struct perf_event *bp) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci arch_uninstall_hw_breakpoint(bp); 68262306a36Sopenharmony_ci counter_arch_bp(bp)->step_ctrl.enabled = 0; 68362306a36Sopenharmony_ci arch_install_hw_breakpoint(bp); 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci/* 68762306a36Sopenharmony_ci * Arm32 hardware does not always report a watchpoint hit address that matches 68862306a36Sopenharmony_ci * one of the watchpoints set. It can also report an address "near" the 68962306a36Sopenharmony_ci * watchpoint if a single instruction access both watched and unwatched 69062306a36Sopenharmony_ci * addresses. There is no straight-forward way, short of disassembling the 69162306a36Sopenharmony_ci * offending instruction, to map that address back to the watchpoint. This 69262306a36Sopenharmony_ci * function computes the distance of the memory access from the watchpoint as a 69362306a36Sopenharmony_ci * heuristic for the likelyhood that a given access triggered the watchpoint. 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * See this same function in the arm64 platform code, which has the same 69662306a36Sopenharmony_ci * problem. 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci * The function returns the distance of the address from the bytes watched by 69962306a36Sopenharmony_ci * the watchpoint. In case of an exact match, it returns 0. 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_cistatic u32 get_distance_from_watchpoint(unsigned long addr, u32 val, 70262306a36Sopenharmony_ci struct arch_hw_breakpoint_ctrl *ctrl) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci u32 wp_low, wp_high; 70562306a36Sopenharmony_ci u32 lens, lene; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci lens = __ffs(ctrl->len); 70862306a36Sopenharmony_ci lene = __fls(ctrl->len); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci wp_low = val + lens; 71162306a36Sopenharmony_ci wp_high = val + lene; 71262306a36Sopenharmony_ci if (addr < wp_low) 71362306a36Sopenharmony_ci return wp_low - addr; 71462306a36Sopenharmony_ci else if (addr > wp_high) 71562306a36Sopenharmony_ci return addr - wp_high; 71662306a36Sopenharmony_ci else 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int watchpoint_fault_on_uaccess(struct pt_regs *regs, 72162306a36Sopenharmony_ci struct arch_hw_breakpoint *info) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void watchpoint_handler(unsigned long addr, unsigned int fsr, 72762306a36Sopenharmony_ci struct pt_regs *regs) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci int i, access, closest_match = 0; 73062306a36Sopenharmony_ci u32 min_dist = -1, dist; 73162306a36Sopenharmony_ci u32 val, ctrl_reg; 73262306a36Sopenharmony_ci struct perf_event *wp, **slots; 73362306a36Sopenharmony_ci struct arch_hw_breakpoint *info; 73462306a36Sopenharmony_ci struct arch_hw_breakpoint_ctrl ctrl; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci slots = this_cpu_ptr(wp_on_reg); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * Find all watchpoints that match the reported address. If no exact 74062306a36Sopenharmony_ci * match is found. Attribute the hit to the closest watchpoint. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci rcu_read_lock(); 74362306a36Sopenharmony_ci for (i = 0; i < core_num_wrps; ++i) { 74462306a36Sopenharmony_ci wp = slots[i]; 74562306a36Sopenharmony_ci if (wp == NULL) 74662306a36Sopenharmony_ci continue; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* 74962306a36Sopenharmony_ci * The DFAR is an unknown value on debug architectures prior 75062306a36Sopenharmony_ci * to 7.1. Since we only allow a single watchpoint on these 75162306a36Sopenharmony_ci * older CPUs, we can set the trigger to the lowest possible 75262306a36Sopenharmony_ci * faulting address. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci if (debug_arch < ARM_DEBUG_ARCH_V7_1) { 75562306a36Sopenharmony_ci BUG_ON(i > 0); 75662306a36Sopenharmony_ci info = counter_arch_bp(wp); 75762306a36Sopenharmony_ci info->trigger = wp->attr.bp_addr; 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci /* Check that the access type matches. */ 76062306a36Sopenharmony_ci if (debug_exception_updates_fsr()) { 76162306a36Sopenharmony_ci access = (fsr & ARM_FSR_ACCESS_MASK) ? 76262306a36Sopenharmony_ci HW_BREAKPOINT_W : HW_BREAKPOINT_R; 76362306a36Sopenharmony_ci if (!(access & hw_breakpoint_type(wp))) 76462306a36Sopenharmony_ci continue; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci val = read_wb_reg(ARM_BASE_WVR + i); 76862306a36Sopenharmony_ci ctrl_reg = read_wb_reg(ARM_BASE_WCR + i); 76962306a36Sopenharmony_ci decode_ctrl_reg(ctrl_reg, &ctrl); 77062306a36Sopenharmony_ci dist = get_distance_from_watchpoint(addr, val, &ctrl); 77162306a36Sopenharmony_ci if (dist < min_dist) { 77262306a36Sopenharmony_ci min_dist = dist; 77362306a36Sopenharmony_ci closest_match = i; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci /* Is this an exact match? */ 77662306a36Sopenharmony_ci if (dist != 0) 77762306a36Sopenharmony_ci continue; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* We have a winner. */ 78062306a36Sopenharmony_ci info = counter_arch_bp(wp); 78162306a36Sopenharmony_ci info->trigger = addr; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* 78762306a36Sopenharmony_ci * If we triggered a user watchpoint from a uaccess routine, 78862306a36Sopenharmony_ci * then handle the stepping ourselves since userspace really 78962306a36Sopenharmony_ci * can't help us with this. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_ci if (watchpoint_fault_on_uaccess(regs, info)) 79262306a36Sopenharmony_ci goto step; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci perf_bp_event(wp, regs); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* 79762306a36Sopenharmony_ci * Defer stepping to the overflow handler if one is installed. 79862306a36Sopenharmony_ci * Otherwise, insert a temporary mismatch breakpoint so that 79962306a36Sopenharmony_ci * we can single-step over the watchpoint trigger. 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci if (!uses_default_overflow_handler(wp)) 80262306a36Sopenharmony_ci continue; 80362306a36Sopenharmony_cistep: 80462306a36Sopenharmony_ci enable_single_step(wp, instruction_pointer(regs)); 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (min_dist > 0 && min_dist != -1) { 80862306a36Sopenharmony_ci /* No exact match found. */ 80962306a36Sopenharmony_ci wp = slots[closest_match]; 81062306a36Sopenharmony_ci info = counter_arch_bp(wp); 81162306a36Sopenharmony_ci info->trigger = addr; 81262306a36Sopenharmony_ci pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); 81362306a36Sopenharmony_ci perf_bp_event(wp, regs); 81462306a36Sopenharmony_ci if (uses_default_overflow_handler(wp)) 81562306a36Sopenharmony_ci enable_single_step(wp, instruction_pointer(regs)); 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci rcu_read_unlock(); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void watchpoint_single_step_handler(unsigned long pc) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci int i; 82462306a36Sopenharmony_ci struct perf_event *wp, **slots; 82562306a36Sopenharmony_ci struct arch_hw_breakpoint *info; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci slots = this_cpu_ptr(wp_on_reg); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci for (i = 0; i < core_num_wrps; ++i) { 83062306a36Sopenharmony_ci rcu_read_lock(); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci wp = slots[i]; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (wp == NULL) 83562306a36Sopenharmony_ci goto unlock; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci info = counter_arch_bp(wp); 83862306a36Sopenharmony_ci if (!info->step_ctrl.enabled) 83962306a36Sopenharmony_ci goto unlock; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* 84262306a36Sopenharmony_ci * Restore the original watchpoint if we've completed the 84362306a36Sopenharmony_ci * single-step. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci if (info->trigger != pc) 84662306a36Sopenharmony_ci disable_single_step(wp); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ciunlock: 84962306a36Sopenharmony_ci rcu_read_unlock(); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci int i; 85662306a36Sopenharmony_ci u32 ctrl_reg, val, addr; 85762306a36Sopenharmony_ci struct perf_event *bp, **slots; 85862306a36Sopenharmony_ci struct arch_hw_breakpoint *info; 85962306a36Sopenharmony_ci struct arch_hw_breakpoint_ctrl ctrl; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci slots = this_cpu_ptr(bp_on_reg); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* The exception entry code places the amended lr in the PC. */ 86462306a36Sopenharmony_ci addr = regs->ARM_pc; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* Check the currently installed breakpoints first. */ 86762306a36Sopenharmony_ci for (i = 0; i < core_num_brps; ++i) { 86862306a36Sopenharmony_ci rcu_read_lock(); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci bp = slots[i]; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (bp == NULL) 87362306a36Sopenharmony_ci goto unlock; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci info = counter_arch_bp(bp); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* Check if the breakpoint value matches. */ 87862306a36Sopenharmony_ci val = read_wb_reg(ARM_BASE_BVR + i); 87962306a36Sopenharmony_ci if (val != (addr & ~0x3)) 88062306a36Sopenharmony_ci goto mismatch; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Possible match, check the byte address select to confirm. */ 88362306a36Sopenharmony_ci ctrl_reg = read_wb_reg(ARM_BASE_BCR + i); 88462306a36Sopenharmony_ci decode_ctrl_reg(ctrl_reg, &ctrl); 88562306a36Sopenharmony_ci if ((1 << (addr & 0x3)) & ctrl.len) { 88662306a36Sopenharmony_ci info->trigger = addr; 88762306a36Sopenharmony_ci pr_debug("breakpoint fired: address = 0x%x\n", addr); 88862306a36Sopenharmony_ci perf_bp_event(bp, regs); 88962306a36Sopenharmony_ci if (uses_default_overflow_handler(bp)) 89062306a36Sopenharmony_ci enable_single_step(bp, addr); 89162306a36Sopenharmony_ci goto unlock; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cimismatch: 89562306a36Sopenharmony_ci /* If we're stepping a breakpoint, it can now be restored. */ 89662306a36Sopenharmony_ci if (info->step_ctrl.enabled) 89762306a36Sopenharmony_ci disable_single_step(bp); 89862306a36Sopenharmony_ciunlock: 89962306a36Sopenharmony_ci rcu_read_unlock(); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* Handle any pending watchpoint single-step breakpoints. */ 90362306a36Sopenharmony_ci watchpoint_single_step_handler(addr); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci/* 90762306a36Sopenharmony_ci * Called from either the Data Abort Handler [watchpoint] or the 90862306a36Sopenharmony_ci * Prefetch Abort Handler [breakpoint] with interrupts disabled. 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_cistatic int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, 91162306a36Sopenharmony_ci struct pt_regs *regs) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci int ret = 0; 91462306a36Sopenharmony_ci u32 dscr; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci preempt_disable(); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (interrupts_enabled(regs)) 91962306a36Sopenharmony_ci local_irq_enable(); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* We only handle watchpoints and hardware breakpoints. */ 92262306a36Sopenharmony_ci ARM_DBG_READ(c0, c1, 0, dscr); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Perform perf callbacks. */ 92562306a36Sopenharmony_ci switch (ARM_DSCR_MOE(dscr)) { 92662306a36Sopenharmony_ci case ARM_ENTRY_BREAKPOINT: 92762306a36Sopenharmony_ci breakpoint_handler(addr, regs); 92862306a36Sopenharmony_ci break; 92962306a36Sopenharmony_ci case ARM_ENTRY_ASYNC_WATCHPOINT: 93062306a36Sopenharmony_ci WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); 93162306a36Sopenharmony_ci fallthrough; 93262306a36Sopenharmony_ci case ARM_ENTRY_SYNC_WATCHPOINT: 93362306a36Sopenharmony_ci watchpoint_handler(addr, fsr, regs); 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci default: 93662306a36Sopenharmony_ci ret = 1; /* Unhandled fault. */ 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci preempt_enable(); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return ret; 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764319 94562306a36Sopenharmony_cistatic int oslsr_fault; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int debug_oslsr_trap(struct pt_regs *regs, unsigned int instr) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci oslsr_fault = 1; 95062306a36Sopenharmony_ci instruction_pointer(regs) += 4; 95162306a36Sopenharmony_ci return 0; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic struct undef_hook debug_oslsr_hook = { 95562306a36Sopenharmony_ci .instr_mask = 0xffffffff, 95662306a36Sopenharmony_ci .instr_val = 0xee115e91, 95762306a36Sopenharmony_ci .fn = debug_oslsr_trap, 95862306a36Sopenharmony_ci}; 95962306a36Sopenharmony_ci#endif 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/* 96262306a36Sopenharmony_ci * One-time initialisation. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_cistatic cpumask_t debug_err_mask; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic int debug_reg_trap(struct pt_regs *regs, unsigned int instr) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci int cpu = smp_processor_id(); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci pr_warn("Debug register access (0x%x) caused undefined instruction on CPU %d\n", 97162306a36Sopenharmony_ci instr, cpu); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* Set the error flag for this CPU and skip the faulting instruction. */ 97462306a36Sopenharmony_ci cpumask_set_cpu(cpu, &debug_err_mask); 97562306a36Sopenharmony_ci instruction_pointer(regs) += 4; 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic struct undef_hook debug_reg_hook = { 98062306a36Sopenharmony_ci .instr_mask = 0x0fe80f10, 98162306a36Sopenharmony_ci .instr_val = 0x0e000e10, 98262306a36Sopenharmony_ci .fn = debug_reg_trap, 98362306a36Sopenharmony_ci}; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/* Does this core support OS Save and Restore? */ 98662306a36Sopenharmony_cistatic bool core_has_os_save_restore(void) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci u32 oslsr; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci switch (get_debug_arch()) { 99162306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_1: 99262306a36Sopenharmony_ci return true; 99362306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_ECP14: 99462306a36Sopenharmony_ci#ifdef CONFIG_ARM_ERRATA_764319 99562306a36Sopenharmony_ci oslsr_fault = 0; 99662306a36Sopenharmony_ci register_undef_hook(&debug_oslsr_hook); 99762306a36Sopenharmony_ci ARM_DBG_READ(c1, c1, 4, oslsr); 99862306a36Sopenharmony_ci unregister_undef_hook(&debug_oslsr_hook); 99962306a36Sopenharmony_ci if (oslsr_fault) 100062306a36Sopenharmony_ci return false; 100162306a36Sopenharmony_ci#else 100262306a36Sopenharmony_ci ARM_DBG_READ(c1, c1, 4, oslsr); 100362306a36Sopenharmony_ci#endif 100462306a36Sopenharmony_ci if (oslsr & ARM_OSLSR_OSLM0) 100562306a36Sopenharmony_ci return true; 100662306a36Sopenharmony_ci fallthrough; 100762306a36Sopenharmony_ci default: 100862306a36Sopenharmony_ci return false; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic void reset_ctrl_regs(unsigned int cpu) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci int i, raw_num_brps, err = 0; 101562306a36Sopenharmony_ci u32 val; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci /* 101862306a36Sopenharmony_ci * v7 debug contains save and restore registers so that debug state 101962306a36Sopenharmony_ci * can be maintained across low-power modes without leaving the debug 102062306a36Sopenharmony_ci * logic powered up. It is IMPLEMENTATION DEFINED whether we can access 102162306a36Sopenharmony_ci * the debug registers out of reset, so we must unlock the OS Lock 102262306a36Sopenharmony_ci * Access Register to avoid taking undefined instruction exceptions 102362306a36Sopenharmony_ci * later on. 102462306a36Sopenharmony_ci */ 102562306a36Sopenharmony_ci switch (debug_arch) { 102662306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V6: 102762306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V6_1: 102862306a36Sopenharmony_ci /* ARMv6 cores clear the registers out of reset. */ 102962306a36Sopenharmony_ci goto out_mdbgen; 103062306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_ECP14: 103162306a36Sopenharmony_ci /* 103262306a36Sopenharmony_ci * Ensure sticky power-down is clear (i.e. debug logic is 103362306a36Sopenharmony_ci * powered up). 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci ARM_DBG_READ(c1, c5, 4, val); 103662306a36Sopenharmony_ci if ((val & 0x1) == 0) 103762306a36Sopenharmony_ci err = -EPERM; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (!has_ossr) 104062306a36Sopenharmony_ci goto clear_vcr; 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case ARM_DEBUG_ARCH_V7_1: 104362306a36Sopenharmony_ci /* 104462306a36Sopenharmony_ci * Ensure the OS double lock is clear. 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci ARM_DBG_READ(c1, c3, 4, val); 104762306a36Sopenharmony_ci if ((val & 0x1) == 1) 104862306a36Sopenharmony_ci err = -EPERM; 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (err) { 105362306a36Sopenharmony_ci pr_warn_once("CPU %d debug is powered down!\n", cpu); 105462306a36Sopenharmony_ci cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); 105562306a36Sopenharmony_ci return; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* 105962306a36Sopenharmony_ci * Unconditionally clear the OS lock by writing a value 106062306a36Sopenharmony_ci * other than CS_LAR_KEY to the access register. 106162306a36Sopenharmony_ci */ 106262306a36Sopenharmony_ci ARM_DBG_WRITE(c1, c0, 4, ~CORESIGHT_UNLOCK); 106362306a36Sopenharmony_ci isb(); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* 106662306a36Sopenharmony_ci * Clear any configured vector-catch events before 106762306a36Sopenharmony_ci * enabling monitor mode. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ciclear_vcr: 107062306a36Sopenharmony_ci ARM_DBG_WRITE(c0, c7, 0, 0); 107162306a36Sopenharmony_ci isb(); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { 107462306a36Sopenharmony_ci pr_warn_once("CPU %d failed to disable vector catch\n", cpu); 107562306a36Sopenharmony_ci return; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* 107962306a36Sopenharmony_ci * The control/value register pairs are UNKNOWN out of reset so 108062306a36Sopenharmony_ci * clear them to avoid spurious debug events. 108162306a36Sopenharmony_ci */ 108262306a36Sopenharmony_ci raw_num_brps = get_num_brp_resources(); 108362306a36Sopenharmony_ci for (i = 0; i < raw_num_brps; ++i) { 108462306a36Sopenharmony_ci write_wb_reg(ARM_BASE_BCR + i, 0UL); 108562306a36Sopenharmony_ci write_wb_reg(ARM_BASE_BVR + i, 0UL); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci for (i = 0; i < core_num_wrps; ++i) { 108962306a36Sopenharmony_ci write_wb_reg(ARM_BASE_WCR + i, 0UL); 109062306a36Sopenharmony_ci write_wb_reg(ARM_BASE_WVR + i, 0UL); 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { 109462306a36Sopenharmony_ci pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu); 109562306a36Sopenharmony_ci return; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* 109962306a36Sopenharmony_ci * Have a crack at enabling monitor mode. We don't actually need 110062306a36Sopenharmony_ci * it yet, but reporting an error early is useful if it fails. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_ciout_mdbgen: 110362306a36Sopenharmony_ci if (enable_monitor_mode()) 110462306a36Sopenharmony_ci cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic int dbg_reset_online(unsigned int cpu) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci local_irq_disable(); 111062306a36Sopenharmony_ci reset_ctrl_regs(cpu); 111162306a36Sopenharmony_ci local_irq_enable(); 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci#ifdef CONFIG_CPU_PM 111662306a36Sopenharmony_cistatic int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action, 111762306a36Sopenharmony_ci void *v) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci if (action == CPU_PM_EXIT) 112062306a36Sopenharmony_ci reset_ctrl_regs(smp_processor_id()); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return NOTIFY_OK; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic struct notifier_block dbg_cpu_pm_nb = { 112662306a36Sopenharmony_ci .notifier_call = dbg_cpu_pm_notify, 112762306a36Sopenharmony_ci}; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void __init pm_init(void) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci cpu_pm_register_notifier(&dbg_cpu_pm_nb); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci#else 113462306a36Sopenharmony_cistatic inline void pm_init(void) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci#endif 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic int __init arch_hw_breakpoint_init(void) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci int ret; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci debug_arch = get_debug_arch(); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if (!debug_arch_supported()) { 114662306a36Sopenharmony_ci pr_info("debug architecture 0x%x unsupported.\n", debug_arch); 114762306a36Sopenharmony_ci return 0; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* 115162306a36Sopenharmony_ci * Scorpion CPUs (at least those in APQ8060) seem to set DBGPRSR.SPD 115262306a36Sopenharmony_ci * whenever a WFI is issued, even if the core is not powered down, in 115362306a36Sopenharmony_ci * violation of the architecture. When DBGPRSR.SPD is set, accesses to 115462306a36Sopenharmony_ci * breakpoint and watchpoint registers are treated as undefined, so 115562306a36Sopenharmony_ci * this results in boot time and runtime failures when these are 115662306a36Sopenharmony_ci * accessed and we unexpectedly take a trap. 115762306a36Sopenharmony_ci * 115862306a36Sopenharmony_ci * It's not clear if/how this can be worked around, so we blacklist 115962306a36Sopenharmony_ci * Scorpion CPUs to avoid these issues. 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci if (read_cpuid_part() == ARM_CPU_PART_SCORPION) { 116262306a36Sopenharmony_ci pr_info("Scorpion CPU detected. Hardware breakpoints and watchpoints disabled\n"); 116362306a36Sopenharmony_ci return 0; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci has_ossr = core_has_os_save_restore(); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* Determine how many BRPs/WRPs are available. */ 116962306a36Sopenharmony_ci core_num_brps = get_num_brps(); 117062306a36Sopenharmony_ci core_num_wrps = get_num_wrps(); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci /* 117362306a36Sopenharmony_ci * We need to tread carefully here because DBGSWENABLE may be 117462306a36Sopenharmony_ci * driven low on this core and there isn't an architected way to 117562306a36Sopenharmony_ci * determine that. 117662306a36Sopenharmony_ci */ 117762306a36Sopenharmony_ci cpus_read_lock(); 117862306a36Sopenharmony_ci register_undef_hook(&debug_reg_hook); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* 118162306a36Sopenharmony_ci * Register CPU notifier which resets the breakpoint resources. We 118262306a36Sopenharmony_ci * assume that a halting debugger will leave the world in a nice state 118362306a36Sopenharmony_ci * for us. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci ret = cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, 118662306a36Sopenharmony_ci "arm/hw_breakpoint:online", 118762306a36Sopenharmony_ci dbg_reset_online, NULL); 118862306a36Sopenharmony_ci unregister_undef_hook(&debug_reg_hook); 118962306a36Sopenharmony_ci if (WARN_ON(ret < 0) || !cpumask_empty(&debug_err_mask)) { 119062306a36Sopenharmony_ci core_num_brps = 0; 119162306a36Sopenharmony_ci core_num_wrps = 0; 119262306a36Sopenharmony_ci if (ret > 0) 119362306a36Sopenharmony_ci cpuhp_remove_state_nocalls_cpuslocked(ret); 119462306a36Sopenharmony_ci cpus_read_unlock(); 119562306a36Sopenharmony_ci return 0; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n", 119962306a36Sopenharmony_ci core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " : 120062306a36Sopenharmony_ci "", core_num_wrps); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* Work out the maximum supported watchpoint length. */ 120362306a36Sopenharmony_ci max_watchpoint_len = get_max_wp_len(); 120462306a36Sopenharmony_ci pr_info("maximum watchpoint size is %u bytes.\n", 120562306a36Sopenharmony_ci max_watchpoint_len); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci /* Register debug fault handler. */ 120862306a36Sopenharmony_ci hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, 120962306a36Sopenharmony_ci TRAP_HWBKPT, "watchpoint debug exception"); 121062306a36Sopenharmony_ci hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, 121162306a36Sopenharmony_ci TRAP_HWBKPT, "breakpoint debug exception"); 121262306a36Sopenharmony_ci cpus_read_unlock(); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* Register PM notifiers. */ 121562306a36Sopenharmony_ci pm_init(); 121662306a36Sopenharmony_ci return 0; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ciarch_initcall(arch_hw_breakpoint_init); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_civoid hw_breakpoint_pmu_read(struct perf_event *bp) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* 122562306a36Sopenharmony_ci * Dummy function to register with die_notifier. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ciint hw_breakpoint_exceptions_notify(struct notifier_block *unused, 122862306a36Sopenharmony_ci unsigned long val, void *data) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci return NOTIFY_DONE; 123162306a36Sopenharmony_ci} 1232