diff options
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
| -rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 872 |
1 files changed, 579 insertions, 293 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 21e3a4ab3b8..4d963fb66e3 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -24,17 +24,19 @@ #define pr_fmt(fmt) "hw-breakpoint: " fmt #include <linux/errno.h> +#include <linux/hardirq.h> #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <linux/smp.h> +#include <linux/cpu_pm.h> #include <asm/cacheflush.h> #include <asm/cputype.h> #include <asm/current.h> #include <asm/hw_breakpoint.h> #include <asm/kdebug.h> -#include <asm/system.h> #include <asm/traps.h> +#include <asm/hardware/coresight.h> /* Breakpoint currently in use for each BRP. */ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); @@ -49,98 +51,20 @@ static int core_num_wrps; /* Debug architecture version. */ static u8 debug_arch; +/* Does debug architecture support OS Save and Restore? */ +static bool has_ossr; + /* Maximum supported watchpoint length. */ static u8 max_watchpoint_len; -/* Determine number of BRP registers available. */ -static int get_num_brps(void) -{ - u32 didr; - ARM_DBG_READ(c0, 0, didr); - return ((didr >> 24) & 0xf) + 1; -} - -/* Determine number of WRP registers available. */ -static int get_num_wrps(void) -{ - /* - * FIXME: When a watchpoint fires, the only way to work out which - * watchpoint it was is by disassembling the faulting instruction - * and working out the address of the memory access. - * - * Furthermore, we can only do this if the watchpoint was precise - * since imprecise watchpoints prevent us from calculating register - * based addresses. - * - * For the time being, we only report 1 watchpoint register so we - * always know which watchpoint fired. In the future we can either - * add a disassembler and address generation emulator, or we can - * insert a check to see if the DFAR is set on watchpoint exception - * entry [the ARM ARM states that the DFAR is UNKNOWN, but - * experience shows that it is set on some implementations]. - */ - -#if 0 - u32 didr, wrps; - ARM_DBG_READ(c0, 0, didr); - return ((didr >> 28) & 0xf) + 1; -#endif - - return 1; -} - -int hw_breakpoint_slots(int type) -{ - /* - * We can be called early, so don't rely on - * our static variables being initialised. - */ - switch (type) { - case TYPE_INST: - return get_num_brps(); - case TYPE_DATA: - return get_num_wrps(); - default: - pr_warning("unknown slot type: %d\n", type); - return 0; - } -} - -/* Determine debug architecture. */ -static u8 get_debug_arch(void) -{ - u32 didr; - - /* Do we implement the extended CPUID interface? */ - if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { - pr_warning("CPUID feature registers not supported. " - "Assuming v6 debug is present.\n"); - return ARM_DEBUG_ARCH_V6; - } - - ARM_DBG_READ(c0, 0, didr); - return (didr >> 16) & 0xf; -} - -/* Does this core support mismatch breakpoints? */ -static int core_has_mismatch_bps(void) -{ - return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1; -} - -u8 arch_get_debug_arch(void) -{ - return debug_arch; -} - -#define READ_WB_REG_CASE(OP2, M, VAL) \ - case ((OP2 << 4) + M): \ - ARM_DBG_READ(c ## M, OP2, VAL); \ +#define READ_WB_REG_CASE(OP2, M, VAL) \ + case ((OP2 << 4) + M): \ + ARM_DBG_READ(c0, c ## M, OP2, VAL); \ break -#define WRITE_WB_REG_CASE(OP2, M, VAL) \ - case ((OP2 << 4) + M): \ - ARM_DBG_WRITE(c ## M, OP2, VAL);\ +#define WRITE_WB_REG_CASE(OP2, M, VAL) \ + case ((OP2 << 4) + M): \ + ARM_DBG_WRITE(c0, c ## M, OP2, VAL); \ break #define GEN_READ_WB_REG_CASES(OP2, VAL) \ @@ -210,49 +134,167 @@ static void write_wb_reg(int n, u32 val) isb(); } +/* Determine debug architecture. */ +static u8 get_debug_arch(void) +{ + u32 didr; + + /* Do we implement the extended CPUID interface? */ + if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { + pr_warn_once("CPUID feature registers not supported. " + "Assuming v6 debug is present.\n"); + return ARM_DEBUG_ARCH_V6; + } + + ARM_DBG_READ(c0, c0, 0, didr); + return (didr >> 16) & 0xf; +} + +u8 arch_get_debug_arch(void) +{ + return debug_arch; +} + +static int debug_arch_supported(void) +{ + u8 arch = get_debug_arch(); + + /* We don't support the memory-mapped interface. */ + return (arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14) || + arch >= ARM_DEBUG_ARCH_V7_1; +} + +/* Can we determine the watchpoint access type from the fsr? */ +static int debug_exception_updates_fsr(void) +{ + return get_debug_arch() >= ARM_DEBUG_ARCH_V8; +} + +/* Determine number of WRP registers available. */ +static int get_num_wrp_resources(void) +{ + u32 didr; + ARM_DBG_READ(c0, c0, 0, didr); + return ((didr >> 28) & 0xf) + 1; +} + +/* Determine number of BRP registers available. */ +static int get_num_brp_resources(void) +{ + u32 didr; + ARM_DBG_READ(c0, c0, 0, didr); + return ((didr >> 24) & 0xf) + 1; +} + +/* Does this core support mismatch breakpoints? */ +static int core_has_mismatch_brps(void) +{ + return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 && + get_num_brp_resources() > 1); +} + +/* Determine number of usable WRPs available. */ +static int get_num_wrps(void) +{ + /* + * On debug architectures prior to 7.1, when a watchpoint fires, the + * only way to work out which watchpoint it was is by disassembling + * the faulting instruction and working out the address of the memory + * access. + * + * Furthermore, we can only do this if the watchpoint was precise + * since imprecise watchpoints prevent us from calculating register + * based addresses. + * + * Providing we have more than 1 breakpoint register, we only report + * a single watchpoint register for the time being. This way, we always + * know which watchpoint fired. In the future we can either add a + * disassembler and address generation emulator, or we can insert a + * check to see if the DFAR is set on watchpoint exception entry + * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows + * that it is set on some implementations]. + */ + if (get_debug_arch() < ARM_DEBUG_ARCH_V7_1) + return 1; + + return get_num_wrp_resources(); +} + +/* Determine number of usable BRPs available. */ +static int get_num_brps(void) +{ + int brps = get_num_brp_resources(); + return core_has_mismatch_brps() ? brps - 1 : brps; +} + /* * In order to access the breakpoint/watchpoint control registers, * we must be running in debug monitor mode. Unfortunately, we can * be put into halting debug mode at any time by an external debugger * but there is nothing we can do to prevent that. */ -static int enable_monitor_mode(void) +static int monitor_mode_enabled(void) { u32 dscr; - int ret = 0; + ARM_DBG_READ(c0, c1, 0, dscr); + return !!(dscr & ARM_DSCR_MDBGEN); +} - ARM_DBG_READ(c1, 0, dscr); +static int enable_monitor_mode(void) +{ + u32 dscr; + ARM_DBG_READ(c0, c1, 0, dscr); - /* Ensure that halting mode is disabled. */ - if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled." - "Unable to access hardware resources.")) { - ret = -EPERM; + /* If monitor mode is already enabled, just return. */ + if (dscr & ARM_DSCR_MDBGEN) goto out; - } /* Write to the corresponding DSCR. */ - switch (debug_arch) { + switch (get_debug_arch()) { case ARM_DEBUG_ARCH_V6: case ARM_DEBUG_ARCH_V6_1: - ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN)); + ARM_DBG_WRITE(c0, c1, 0, (dscr | ARM_DSCR_MDBGEN)); break; case ARM_DEBUG_ARCH_V7_ECP14: - ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN)); + case ARM_DEBUG_ARCH_V7_1: + case ARM_DEBUG_ARCH_V8: + ARM_DBG_WRITE(c0, c2, 2, (dscr | ARM_DSCR_MDBGEN)); + isb(); break; default: - ret = -ENODEV; - goto out; + return -ENODEV; } /* Check that the write made it through. */ - ARM_DBG_READ(c1, 0, dscr); - if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN), - "failed to enable monitor mode.")) { - ret = -EPERM; + ARM_DBG_READ(c0, c1, 0, dscr); + if (!(dscr & ARM_DSCR_MDBGEN)) { + pr_warn_once("Failed to enable monitor mode on CPU %d.\n", + smp_processor_id()); + return -EPERM; } out: - return ret; + return 0; +} + +int hw_breakpoint_slots(int type) +{ + if (!debug_arch_supported()) + return 0; + + /* + * We can be called early, so don't rely on + * our static variables being initialised. + */ + switch (type) { + case TYPE_INST: + return get_num_brps(); + case TYPE_DATA: + return get_num_wrps(); + default: + pr_warning("unknown slot type: %d\n", type); + return 0; + } } /* @@ -268,9 +310,6 @@ static u8 get_max_wp_len(void) if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14) goto out; - if (enable_monitor_mode()) - goto out; - memset(&ctrl, 0, sizeof(ctrl)); ctrl.len = ARM_BREAKPOINT_LEN_8; ctrl_reg = encode_ctrl_reg(ctrl); @@ -290,54 +329,29 @@ u8 arch_get_max_wp_len(void) } /* - * Handler for reactivating a suspended watchpoint when the single - * step `mismatch' breakpoint is triggered. - */ -static void wp_single_step_handler(struct perf_event *bp, int unused, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - perf_event_enable(counter_arch_bp(bp)->suspended_wp); - unregister_hw_breakpoint(bp); -} - -static int bp_is_single_step(struct perf_event *bp) -{ - return bp->overflow_handler == wp_single_step_handler; -} - -/* * Install a perf counter breakpoint. */ int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct perf_event **slot, **slots; - int i, max_slots, ctrl_base, val_base, ret = 0; + int i, max_slots, ctrl_base, val_base; + u32 addr, ctrl; - /* Ensure that we are in monitor mode and halting mode is disabled. */ - ret = enable_monitor_mode(); - if (ret) - goto out; + addr = info->address; + ctrl = encode_ctrl_reg(info->ctrl) | 0x1; if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { /* Breakpoint */ ctrl_base = ARM_BASE_BCR; val_base = ARM_BASE_BVR; - slots = __get_cpu_var(bp_on_reg); - max_slots = core_num_brps - 1; - - if (bp_is_single_step(bp)) { - info->ctrl.mismatch = 1; - i = max_slots; - slots[i] = bp; - goto setup; - } + slots = this_cpu_ptr(bp_on_reg); + max_slots = core_num_brps; } else { /* Watchpoint */ ctrl_base = ARM_BASE_WCR; val_base = ARM_BASE_WVR; - slots = __get_cpu_var(wp_on_reg); + slots = this_cpu_ptr(wp_on_reg); max_slots = core_num_wrps; } @@ -350,20 +364,28 @@ int arch_install_hw_breakpoint(struct perf_event *bp) } } - if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) { - ret = -EBUSY; - goto out; + if (i == max_slots) { + pr_warning("Can't find any breakpoint slot\n"); + return -EBUSY; + } + + /* Override the breakpoint data with the step data. */ + if (info->step_ctrl.enabled) { + addr = info->trigger & ~0x3; + ctrl = encode_ctrl_reg(info->step_ctrl); + if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) { + i = 0; + ctrl_base = ARM_BASE_BCR + core_num_brps; + val_base = ARM_BASE_BVR + core_num_brps; + } } -setup: /* Setup the address register. */ - write_wb_reg(val_base + i, info->address); + write_wb_reg(val_base + i, addr); /* Setup the control register. */ - write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1); - -out: - return ret; + write_wb_reg(ctrl_base + i, ctrl); + return 0; } void arch_uninstall_hw_breakpoint(struct perf_event *bp) @@ -375,18 +397,12 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { /* Breakpoint */ base = ARM_BASE_BCR; - slots = __get_cpu_var(bp_on_reg); - max_slots = core_num_brps - 1; - - if (bp_is_single_step(bp)) { - i = max_slots; - slots[i] = NULL; - goto reset; - } + slots = this_cpu_ptr(bp_on_reg); + max_slots = core_num_brps; } else { /* Watchpoint */ base = ARM_BASE_WCR; - slots = __get_cpu_var(wp_on_reg); + slots = this_cpu_ptr(wp_on_reg); max_slots = core_num_wrps; } @@ -400,10 +416,18 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) } } - if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) + if (i == max_slots) { + pr_warning("Can't find any breakpoint slot\n"); return; + } + + /* Ensure that we disable the mismatch breakpoint. */ + if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE && + info->step_ctrl.enabled) { + i = 0; + base = ARM_BASE_BCR + core_num_brps; + } -reset: /* Reset the control register. */ write_wb_reg(base + i, 0); } @@ -537,12 +561,23 @@ static int arch_build_bp_info(struct perf_event *bp) return -EINVAL; } + /* + * Breakpoints must be of length 2 (thumb) or 4 (ARM) bytes. + * Watchpoints can be of length 1, 2, 4 or 8 bytes if supported + * by the hardware and must be aligned to the appropriate number of + * bytes. + */ + if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE && + info->ctrl.len != ARM_BREAKPOINT_LEN_2 && + info->ctrl.len != ARM_BREAKPOINT_LEN_4) + return -EINVAL; + /* Address */ info->address = bp->attr.bp_addr; /* Privilege */ info->ctrl.privilege = ARM_BREAKPOINT_USER; - if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp)) + if (arch_check_bp_in_kernelspace(bp)) info->ctrl.privilege |= ARM_BREAKPOINT_PRIV; /* Enabled? */ @@ -561,7 +596,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); int ret = 0; - u32 bytelen, max_len, offset, alignment_mask = 0x3; + u32 offset, alignment_mask = 0x3; + + /* Ensure that we are in monitor debug mode. */ + if (!monitor_mode_enabled()) + return -ENODEV; /* Build the arch_hw_breakpoint. */ ret = arch_build_bp_info(bp); @@ -571,111 +610,187 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) /* Check address alignment. */ if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) alignment_mask = 0x7; - if (info->address & alignment_mask) { + offset = info->address & alignment_mask; + switch (offset) { + case 0: + /* Aligned */ + break; + case 1: + case 2: + /* Allow halfword watchpoints and breakpoints. */ + if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) + break; + case 3: + /* Allow single byte watchpoint. */ + if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) + break; + default: + ret = -EINVAL; + goto out; + } + + info->address &= ~alignment_mask; + info->ctrl.len <<= offset; + + if (!bp->overflow_handler) { /* - * Try to fix the alignment. This may result in a length - * that is too large, so we must check for that. + * Mismatch breakpoints are required for single-stepping + * breakpoints. */ - bytelen = get_hbp_len(info->ctrl.len); - max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 : - max_watchpoint_len; - - if (max_len >= 8) - offset = info->address & 0x7; - else - offset = info->address & 0x3; - - if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) { - ret = -EFBIG; - goto out; - } + if (!core_has_mismatch_brps()) + return -EINVAL; - info->ctrl.len <<= offset; - info->address &= ~offset; + /* We don't allow mismatch breakpoints in kernel space. */ + if (arch_check_bp_in_kernelspace(bp)) + return -EPERM; - pr_debug("breakpoint alignment fixup: length = 0x%x, " - "address = 0x%x\n", info->ctrl.len, info->address); - } + /* + * Per-cpu breakpoints are not supported by our stepping + * mechanism. + */ + if (!bp->hw.bp_target) + return -EINVAL; - /* - * Currently we rely on an overflow handler to take - * care of single-stepping the breakpoint when it fires. - * In the case of userspace breakpoints on a core with V7 debug, - * we can use the mismatch feature as a poor-man's hardware single-step. - */ - if (WARN_ONCE(!bp->overflow_handler && - (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()), - "overflow handler required but none found")) { - ret = -EINVAL; - goto out; + /* + * We only support specific access types if the fsr + * reports them. + */ + if (!debug_exception_updates_fsr() && + (info->ctrl.type == ARM_BREAKPOINT_LOAD || + info->ctrl.type == ARM_BREAKPOINT_STORE)) + return -EINVAL; } + out: return ret; } -static void update_mismatch_flag(int idx, int flag) +/* + * Enable/disable single-stepping over the breakpoint bp at address addr. + */ +static void enable_single_step(struct perf_event *bp, u32 addr) { - struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]); - struct arch_hw_breakpoint *info; - - if (bp == NULL) - return; + struct arch_hw_breakpoint *info = counter_arch_bp(bp); - info = counter_arch_bp(bp); + arch_uninstall_hw_breakpoint(bp); + info->step_ctrl.mismatch = 1; + info->step_ctrl.len = ARM_BREAKPOINT_LEN_4; + info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE; + info->step_ctrl.privilege = info->ctrl.privilege; + info->step_ctrl.enabled = 1; + info->trigger = addr; + arch_install_hw_breakpoint(bp); +} - /* Update the mismatch field to enter/exit `single-step' mode */ - if (!bp->overflow_handler && info->ctrl.mismatch != flag) { - info->ctrl.mismatch = flag; - write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1); - } +static void disable_single_step(struct perf_event *bp) +{ + arch_uninstall_hw_breakpoint(bp); + counter_arch_bp(bp)->step_ctrl.enabled = 0; + arch_install_hw_breakpoint(bp); } -static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) +static void watchpoint_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) { - int i; - struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg); + int i, access; + u32 val, ctrl_reg, alignment_mask; + struct perf_event *wp, **slots; struct arch_hw_breakpoint *info; - struct perf_event_attr attr; - - /* Without a disassembler, we can only handle 1 watchpoint. */ - BUG_ON(core_num_wrps > 1); + struct arch_hw_breakpoint_ctrl ctrl; - hw_breakpoint_init(&attr); - attr.bp_addr = regs->ARM_pc & ~0x3; - attr.bp_len = HW_BREAKPOINT_LEN_4; - attr.bp_type = HW_BREAKPOINT_X; + slots = this_cpu_ptr(wp_on_reg); for (i = 0; i < core_num_wrps; ++i) { rcu_read_lock(); - if (slots[i] == NULL) { - rcu_read_unlock(); - continue; - } + wp = slots[i]; + if (wp == NULL) + goto unlock; + + info = counter_arch_bp(wp); /* - * The DFAR is an unknown value. Since we only allow a - * single watchpoint, we can set the trigger to the lowest - * possible faulting address. + * The DFAR is an unknown value on debug architectures prior + * to 7.1. Since we only allow a single watchpoint on these + * older CPUs, we can set the trigger to the lowest possible + * faulting address. */ - info = counter_arch_bp(slots[i]); - info->trigger = slots[i]->attr.bp_addr; + if (debug_arch < ARM_DEBUG_ARCH_V7_1) { + BUG_ON(i > 0); + info->trigger = wp->attr.bp_addr; + } else { + if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) + alignment_mask = 0x7; + else + alignment_mask = 0x3; + + /* Check if the watchpoint value matches. */ + val = read_wb_reg(ARM_BASE_WVR + i); + if (val != (addr & ~alignment_mask)) + goto unlock; + + /* Possible match, check the byte address select. */ + ctrl_reg = read_wb_reg(ARM_BASE_WCR + i); + decode_ctrl_reg(ctrl_reg, &ctrl); + if (!((1 << (addr & alignment_mask)) & ctrl.len)) + goto unlock; + + /* Check that the access type matches. */ + if (debug_exception_updates_fsr()) { + access = (fsr & ARM_FSR_ACCESS_MASK) ? + HW_BREAKPOINT_W : HW_BREAKPOINT_R; + if (!(access & hw_breakpoint_type(wp))) + goto unlock; + } + + /* We have a winner. */ + info->trigger = addr; + } + pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); - perf_bp_event(slots[i], regs); + perf_bp_event(wp, regs); /* * If no overflow handler is present, insert a temporary * mismatch breakpoint so we can single-step over the * watchpoint trigger. */ - if (!slots[i]->overflow_handler) { - bp = register_user_hw_breakpoint(&attr, - wp_single_step_handler, - current); - counter_arch_bp(bp)->suspended_wp = slots[i]; - perf_event_disable(slots[i]); - } + if (!wp->overflow_handler) + enable_single_step(wp, instruction_pointer(regs)); +unlock: + rcu_read_unlock(); + } +} + +static void watchpoint_single_step_handler(unsigned long pc) +{ + int i; + struct perf_event *wp, **slots; + struct arch_hw_breakpoint *info; + + slots = this_cpu_ptr(wp_on_reg); + + for (i = 0; i < core_num_wrps; ++i) { + rcu_read_lock(); + + wp = slots[i]; + + if (wp == NULL) + goto unlock; + + info = counter_arch_bp(wp); + if (!info->step_ctrl.enabled) + goto unlock; + + /* + * Restore the original watchpoint if we've completed the + * single-step. + */ + if (info->trigger != pc) + disable_single_step(wp); + +unlock: rcu_read_unlock(); } } @@ -683,64 +798,73 @@ static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) { int i; - int mismatch; u32 ctrl_reg, val, addr; - struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg); + struct perf_event *bp, **slots; struct arch_hw_breakpoint *info; struct arch_hw_breakpoint_ctrl ctrl; + slots = this_cpu_ptr(bp_on_reg); + /* The exception entry code places the amended lr in the PC. */ addr = regs->ARM_pc; + /* Check the currently installed breakpoints first. */ for (i = 0; i < core_num_brps; ++i) { rcu_read_lock(); bp = slots[i]; - if (bp == NULL) { - rcu_read_unlock(); - continue; - } + if (bp == NULL) + goto unlock; - mismatch = 0; + info = counter_arch_bp(bp); /* Check if the breakpoint value matches. */ val = read_wb_reg(ARM_BASE_BVR + i); if (val != (addr & ~0x3)) - goto unlock; + goto mismatch; /* Possible match, check the byte address select to confirm. */ ctrl_reg = read_wb_reg(ARM_BASE_BCR + i); decode_ctrl_reg(ctrl_reg, &ctrl); if ((1 << (addr & 0x3)) & ctrl.len) { - mismatch = 1; - info = counter_arch_bp(bp); info->trigger = addr; - } - -unlock: - if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) { pr_debug("breakpoint fired: address = 0x%x\n", addr); perf_bp_event(bp, regs); + if (!bp->overflow_handler) + enable_single_step(bp, addr); + goto unlock; } - update_mismatch_flag(i, mismatch); +mismatch: + /* If we're stepping a breakpoint, it can now be restored. */ + if (info->step_ctrl.enabled) + disable_single_step(bp); +unlock: rcu_read_unlock(); } + + /* Handle any pending watchpoint single-step breakpoints. */ + watchpoint_single_step_handler(addr); } /* * Called from either the Data Abort Handler [watchpoint] or the - * Prefetch Abort Handler [breakpoint]. + * Prefetch Abort Handler [breakpoint] with interrupts disabled. */ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { - int ret = 1; /* Unhandled fault. */ + int ret = 0; u32 dscr; + preempt_disable(); + + if (interrupts_enabled(regs)) + local_irq_enable(); + /* We only handle watchpoints and hardware breakpoints. */ - ARM_DBG_READ(c1, 0, dscr); + ARM_DBG_READ(c0, c1, 0, dscr); /* Perform perf callbacks. */ switch (ARM_DSCR_MOE(dscr)) { @@ -750,28 +874,130 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr, case ARM_ENTRY_ASYNC_WATCHPOINT: WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); case ARM_ENTRY_SYNC_WATCHPOINT: - watchpoint_handler(addr, regs); + watchpoint_handler(addr, fsr, regs); break; default: - goto out; + ret = 1; /* Unhandled fault. */ } - ret = 0; -out: + preempt_enable(); + return ret; } /* * One-time initialisation. */ -static void __init reset_ctrl_regs(void *unused) +static cpumask_t debug_err_mask; + +static int debug_reg_trap(struct pt_regs *regs, unsigned int instr) { - int i; + int cpu = smp_processor_id(); - if (enable_monitor_mode()) + pr_warning("Debug register access (0x%x) caused undefined instruction on CPU %d\n", + instr, cpu); + + /* Set the error flag for this CPU and skip the faulting instruction. */ + cpumask_set_cpu(cpu, &debug_err_mask); + instruction_pointer(regs) += 4; + return 0; +} + +static struct undef_hook debug_reg_hook = { + .instr_mask = 0x0fe80f10, + .instr_val = 0x0e000e10, + .fn = debug_reg_trap, +}; + +/* Does this core support OS Save and Restore? */ +static bool core_has_os_save_restore(void) +{ + u32 oslsr; + + switch (get_debug_arch()) { + case ARM_DEBUG_ARCH_V7_1: + return true; + case ARM_DEBUG_ARCH_V7_ECP14: + ARM_DBG_READ(c1, c1, 4, oslsr); + if (oslsr & ARM_OSLSR_OSLM0) + return true; + default: + return false; + } +} + +static void reset_ctrl_regs(void *unused) +{ + int i, raw_num_brps, err = 0, cpu = smp_processor_id(); + u32 val; + + /* + * v7 debug contains save and restore registers so that debug state + * can be maintained across low-power modes without leaving the debug + * logic powered up. It is IMPLEMENTATION DEFINED whether we can access + * the debug registers out of reset, so we must unlock the OS Lock + * Access Register to avoid taking undefined instruction exceptions + * later on. + */ + switch (debug_arch) { + case ARM_DEBUG_ARCH_V6: + case ARM_DEBUG_ARCH_V6_1: + /* ARMv6 cores clear the registers out of reset. */ + goto out_mdbgen; + case ARM_DEBUG_ARCH_V7_ECP14: + /* + * Ensure sticky power-down is clear (i.e. debug logic is + * powered up). + */ + ARM_DBG_READ(c1, c5, 4, val); + if ((val & 0x1) == 0) + err = -EPERM; + + if (!has_ossr) + goto clear_vcr; + break; + case ARM_DEBUG_ARCH_V7_1: + /* + * Ensure the OS double lock is clear. + */ + ARM_DBG_READ(c1, c3, 4, val); + if ((val & 0x1) == 1) + err = -EPERM; + break; + } + + if (err) { + pr_warn_once("CPU %d debug is powered down!\n", cpu); + cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); return; + } - for (i = 0; i < core_num_brps; ++i) { + /* + * Unconditionally clear the OS lock by writing a value + * other than CS_LAR_KEY to the access register. + */ + ARM_DBG_WRITE(c1, c0, 4, ~CS_LAR_KEY); + isb(); + + /* + * Clear any configured vector-catch events before + * enabling monitor mode. + */ +clear_vcr: + ARM_DBG_WRITE(c0, c7, 0, 0); + isb(); + + if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { + pr_warn_once("CPU %d failed to disable vector catch\n", cpu); + return; + } + + /* + * The control/value register pairs are UNKNOWN out of reset so + * clear them to avoid spurious debug events. + */ + raw_num_brps = get_num_brp_resources(); + for (i = 0; i < raw_num_brps; ++i) { write_wb_reg(ARM_BASE_BCR + i, 0UL); write_wb_reg(ARM_BASE_BVR + i, 0UL); } @@ -780,57 +1006,117 @@ static void __init reset_ctrl_regs(void *unused) write_wb_reg(ARM_BASE_WCR + i, 0UL); write_wb_reg(ARM_BASE_WVR + i, 0UL); } + + if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) { + pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu); + return; + } + + /* + * Have a crack at enabling monitor mode. We don't actually need + * it yet, but reporting an error early is useful if it fails. + */ +out_mdbgen: + if (enable_monitor_mode()) + cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu)); } -static int __init arch_hw_breakpoint_init(void) +static int dbg_reset_notify(struct notifier_block *self, + unsigned long action, void *cpu) { - int ret = 0; - u32 dscr; + if ((action & ~CPU_TASKS_FROZEN) == CPU_ONLINE) + smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1); + + return NOTIFY_OK; +} + +static struct notifier_block dbg_reset_nb = { + .notifier_call = dbg_reset_notify, +}; + +#ifdef CONFIG_CPU_PM +static int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action, + void *v) +{ + if (action == CPU_PM_EXIT) + reset_ctrl_regs(NULL); + + return NOTIFY_OK; +} + +static struct notifier_block dbg_cpu_pm_nb = { + .notifier_call = dbg_cpu_pm_notify, +}; + +static void __init pm_init(void) +{ + cpu_pm_register_notifier(&dbg_cpu_pm_nb); +} +#else +static inline void pm_init(void) +{ +} +#endif +static int __init arch_hw_breakpoint_init(void) +{ debug_arch = get_debug_arch(); - if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) { + if (!debug_arch_supported()) { pr_info("debug architecture 0x%x unsupported.\n", debug_arch); - ret = -ENODEV; - goto out; + return 0; } + has_ossr = core_has_os_save_restore(); + /* Determine how many BRPs/WRPs are available. */ core_num_brps = get_num_brps(); core_num_wrps = get_num_wrps(); - pr_info("found %d breakpoint and %d watchpoint registers.\n", - core_num_brps, core_num_wrps); - - if (core_has_mismatch_bps()) - pr_info("1 breakpoint reserved for watchpoint single-step.\n"); + cpu_notifier_register_begin(); - ARM_DBG_READ(c1, 0, dscr); - if (dscr & ARM_DSCR_HDBGEN) { - pr_warning("halting debug mode enabled. Assuming maximum " - "watchpoint size of 4 bytes."); - } else { - /* Work out the maximum supported watchpoint length. */ - max_watchpoint_len = get_max_wp_len(); - pr_info("maximum watchpoint size is %u bytes.\n", - max_watchpoint_len); + /* + * We need to tread carefully here because DBGSWENABLE may be + * driven low on this core and there isn't an architected way to + * determine that. + */ + register_undef_hook(&debug_reg_hook); - /* - * Reset the breakpoint resources. We assume that a halting - * debugger will leave the world in a nice state for us. - */ - smp_call_function(reset_ctrl_regs, NULL, 1); - reset_ctrl_regs(NULL); + /* + * Reset the breakpoint resources. We assume that a halting + * debugger will leave the world in a nice state for us. + */ + on_each_cpu(reset_ctrl_regs, NULL, 1); + unregister_undef_hook(&debug_reg_hook); + if (!cpumask_empty(&debug_err_mask)) { + core_num_brps = 0; + core_num_wrps = 0; + cpu_notifier_register_done(); + return 0; } + pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n", + core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " : + "", core_num_wrps); + + /* Work out the maximum supported watchpoint length. */ + max_watchpoint_len = get_max_wp_len(); + pr_info("maximum watchpoint size is %u bytes.\n", + max_watchpoint_len); + /* Register debug fault handler. */ - hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, - "watchpoint debug exception"); - hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT, - "breakpoint debug exception"); + hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, + TRAP_HWBKPT, "watchpoint debug exception"); + hook_ifault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP, + TRAP_HWBKPT, "breakpoint debug exception"); -out: - return ret; + /* Register hotplug and PM notifiers. */ + __register_cpu_notifier(&dbg_reset_nb); + + cpu_notifier_register_done(); + + pm_init(); + return 0; } arch_initcall(arch_hw_breakpoint_init); |
