diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 55 |
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? */ | ||
163 | static 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. */ |
163 | static int get_num_wrp_resources(void) | 169 | static 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 | |||
634 | out: | 657 | out: |
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; |