Commit bf880114 authored by Will Deacon's avatar Will Deacon Committed by Russell King

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: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent a849088a
...@@ -159,6 +159,12 @@ static int debug_arch_supported(void) ...@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
arch >= ARM_DEBUG_ARCH_V7_1; arch >= ARM_DEBUG_ARCH_V7_1;
} }
/* Can we determine the watchpoint access type from the fsr? */
static int debug_exception_updates_fsr(void)
{
return 0;
}
/* Determine number of WRP registers available. */ /* Determine number of WRP registers available. */
static int get_num_wrp_resources(void) static int get_num_wrp_resources(void)
{ {
...@@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ...@@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
info->address &= ~alignment_mask; info->address &= ~alignment_mask;
info->ctrl.len <<= offset; info->ctrl.len <<= offset;
/* if (!bp->overflow_handler) {
* Currently we rely on an overflow handler to take /*
* care of single-stepping the breakpoint when it fires. * Mismatch breakpoints are required for single-stepping
* In the case of userspace breakpoints on a core with V7 debug, * breakpoints.
* we can use the mismatch feature as a poor-man's hardware */
* single-step, but this only works for per-task breakpoints. if (!core_has_mismatch_brps())
*/ return -EINVAL;
if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
!core_has_mismatch_brps() || !bp->hw.bp_target)) { /* We don't allow mismatch breakpoints in kernel space. */
pr_warning("overflow handler required but none found\n"); if (arch_check_bp_in_kernelspace(bp))
ret = -EINVAL; return -EPERM;
/*
* Per-cpu breakpoints are not supported by our stepping
* mechanism.
*/
if (!bp->hw.bp_target)
return -EINVAL;
/*
* 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: out:
return ret; return ret;
} }
...@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, ...@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
goto unlock; goto unlock;
/* Check that the access type matches. */ /* Check that the access type matches. */
access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : if (debug_exception_updates_fsr()) {
HW_BREAKPOINT_R; access = (fsr & ARM_FSR_ACCESS_MASK) ?
if (!(access & hw_breakpoint_type(wp))) HW_BREAKPOINT_W : HW_BREAKPOINT_R;
goto unlock; if (!(access & hw_breakpoint_type(wp)))
goto unlock;
}
/* We have a winner. */ /* We have a winner. */
info->trigger = addr; info->trigger = addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment