Skip to content

Commit bf88011

Browse files
wildea01Russell King
authored andcommitted
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>
1 parent a849088 commit bf88011

File tree

1 file changed

+40
-15
lines changed

1 file changed

+40
-15
lines changed

arch/arm/kernel/hw_breakpoint.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
159159
arch >= ARM_DEBUG_ARCH_V7_1;
160160
}
161161

162+
/* Can we determine the watchpoint access type from the fsr? */
163+
static int debug_exception_updates_fsr(void)
164+
{
165+
return 0;
166+
}
167+
162168
/* Determine number of WRP registers available. */
163169
static int get_num_wrp_resources(void)
164170
{
@@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
619625
info->address &= ~alignment_mask;
620626
info->ctrl.len <<= offset;
621627

622-
/*
623-
* Currently we rely on an overflow handler to take
624-
* care of single-stepping the breakpoint when it fires.
625-
* In the case of userspace breakpoints on a core with V7 debug,
626-
* we can use the mismatch feature as a poor-man's hardware
627-
* single-step, but this only works for per-task breakpoints.
628-
*/
629-
if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
630-
!core_has_mismatch_brps() || !bp->hw.bp_target)) {
631-
pr_warning("overflow handler required but none found\n");
632-
ret = -EINVAL;
628+
if (!bp->overflow_handler) {
629+
/*
630+
* Mismatch breakpoints are required for single-stepping
631+
* breakpoints.
632+
*/
633+
if (!core_has_mismatch_brps())
634+
return -EINVAL;
635+
636+
/* We don't allow mismatch breakpoints in kernel space. */
637+
if (arch_check_bp_in_kernelspace(bp))
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;
633655
}
656+
634657
out:
635658
return ret;
636659
}
@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
706729
goto unlock;
707730

708731
/* Check that the access type matches. */
709-
access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
710-
HW_BREAKPOINT_R;
711-
if (!(access & hw_breakpoint_type(wp)))
712-
goto unlock;
732+
if (debug_exception_updates_fsr()) {
733+
access = (fsr & ARM_FSR_ACCESS_MASK) ?
734+
HW_BREAKPOINT_W : HW_BREAKPOINT_R;
735+
if (!(access & hw_breakpoint_type(wp)))
736+
goto unlock;
737+
}
713738

714739
/* We have a winner. */
715740
info->trigger = addr;

0 commit comments

Comments
 (0)