aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-08-16 13:55:44 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-08-25 04:15:23 -0400
commitbf8801145c01ab600f8df66e8c879ac642fa5846 (patch)
treef43bfc09b092f13626cf7ae1f674f9af589904c7 /arch/arm
parenta849088aa1552b1a28eea3daff599ee22a734ae3 (diff)
ARM: 7496/1: hw_breakpoint: don't rely on dfsr to show watchpoint access type
From ARM debug architecture v7.1 onwards, a watchpoint exception causes the DFAR to be updated with the faulting data address. However, DFSR.WnR takes an UNKNOWN value and therefore cannot be used in general to determine the access type that triggered the watchpoint. This patch forbids watchpoints without an overflow handler from specifying a specific access type (load/store). Those with overflow handlers must be able to handle false positives potentially triggered by a watchpoint of a different access type on the same address. For SIGTRAP-based handlers (i.e. ptrace), this should have no impact. Cc: <stable@vger.kernel.org> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/hw_breakpoint.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index ba386bd94107..18d39ea4c02f 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
159 arch >= ARM_DEBUG_ARCH_V7_1; 159 arch >= ARM_DEBUG_ARCH_V7_1;
160} 160}
161 161
162/* Can we determine the watchpoint access type from the fsr? */
163static int debug_exception_updates_fsr(void)
164{
165 return 0;
166}
167
162/* Determine number of WRP registers available. */ 168/* Determine number of WRP registers available. */
163static int get_num_wrp_resources(void) 169static int get_num_wrp_resources(void)
164{ 170{
@@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
619 info->address &= ~alignment_mask; 625 info->address &= ~alignment_mask;
620 info->ctrl.len <<= offset; 626 info->ctrl.len <<= offset;
621 627
622 /* 628 if (!bp->overflow_handler) {
623 * Currently we rely on an overflow handler to take 629 /*
624 * care of single-stepping the breakpoint when it fires. 630 * Mismatch breakpoints are required for single-stepping
625 * In the case of userspace breakpoints on a core with V7 debug, 631 * breakpoints.
626 * we can use the mismatch feature as a poor-man's hardware 632 */
627 * single-step, but this only works for per-task breakpoints. 633 if (!core_has_mismatch_brps())
628 */ 634 return -EINVAL;
629 if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) || 635
630 !core_has_mismatch_brps() || !bp->hw.bp_target)) { 636 /* We don't allow mismatch breakpoints in kernel space. */
631 pr_warning("overflow handler required but none found\n"); 637 if (arch_check_bp_in_kernelspace(bp))
632 ret = -EINVAL; 638 return -EPERM;
639
640 /*
641 * Per-cpu breakpoints are not supported by our stepping
642 * mechanism.
643 */
644 if (!bp->hw.bp_target)
645 return -EINVAL;
646
647 /*
648 * We only support specific access types if the fsr
649 * reports them.
650 */
651 if (!debug_exception_updates_fsr() &&
652 (info->ctrl.type == ARM_BREAKPOINT_LOAD ||
653 info->ctrl.type == ARM_BREAKPOINT_STORE))
654 return -EINVAL;
633 } 655 }
656
634out: 657out:
635 return ret; 658 return ret;
636} 659}
@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
706 goto unlock; 729 goto unlock;
707 730
708 /* Check that the access type matches. */ 731 /* Check that the access type matches. */
709 access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : 732 if (debug_exception_updates_fsr()) {
710 HW_BREAKPOINT_R; 733 access = (fsr & ARM_FSR_ACCESS_MASK) ?
711 if (!(access & hw_breakpoint_type(wp))) 734 HW_BREAKPOINT_W : HW_BREAKPOINT_R;
712 goto unlock; 735 if (!(access & hw_breakpoint_type(wp)))
736 goto unlock;
737 }
713 738
714 /* We have a winner. */ 739 /* We have a winner. */
715 info->trigger = addr; 740 info->trigger = addr;