diff options
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index ba386bd94107..281bf3301241 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 | { |
@@ -604,13 +610,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
604 | /* Aligned */ | 610 | /* Aligned */ |
605 | break; | 611 | break; |
606 | case 1: | 612 | case 1: |
607 | /* Allow single byte watchpoint. */ | ||
608 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) | ||
609 | break; | ||
610 | case 2: | 613 | case 2: |
611 | /* Allow halfword watchpoints and breakpoints. */ | 614 | /* Allow halfword watchpoints and breakpoints. */ |
612 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) | 615 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) |
613 | break; | 616 | break; |
617 | case 3: | ||
618 | /* Allow single byte watchpoint. */ | ||
619 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) | ||
620 | break; | ||
614 | default: | 621 | default: |
615 | ret = -EINVAL; | 622 | ret = -EINVAL; |
616 | goto out; | 623 | goto out; |
@@ -619,18 +626,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
619 | info->address &= ~alignment_mask; | 626 | info->address &= ~alignment_mask; |
620 | info->ctrl.len <<= offset; | 627 | info->ctrl.len <<= offset; |
621 | 628 | ||
622 | /* | 629 | if (!bp->overflow_handler) { |
623 | * Currently we rely on an overflow handler to take | 630 | /* |
624 | * care of single-stepping the breakpoint when it fires. | 631 | * Mismatch breakpoints are required for single-stepping |
625 | * In the case of userspace breakpoints on a core with V7 debug, | 632 | * breakpoints. |
626 | * we can use the mismatch feature as a poor-man's hardware | 633 | */ |
627 | * single-step, but this only works for per-task breakpoints. | 634 | if (!core_has_mismatch_brps()) |
628 | */ | 635 | return -EINVAL; |
629 | if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) || | 636 | |
630 | !core_has_mismatch_brps() || !bp->hw.bp_target)) { | 637 | /* We don't allow mismatch breakpoints in kernel space. */ |
631 | pr_warning("overflow handler required but none found\n"); | 638 | if (arch_check_bp_in_kernelspace(bp)) |
632 | ret = -EINVAL; | 639 | return -EPERM; |
640 | |||
641 | /* | ||
642 | * Per-cpu breakpoints are not supported by our stepping | ||
643 | * mechanism. | ||
644 | */ | ||
645 | if (!bp->hw.bp_target) | ||
646 | return -EINVAL; | ||
647 | |||
648 | /* | ||
649 | * We only support specific access types if the fsr | ||
650 | * reports them. | ||
651 | */ | ||
652 | if (!debug_exception_updates_fsr() && | ||
653 | (info->ctrl.type == ARM_BREAKPOINT_LOAD || | ||
654 | info->ctrl.type == ARM_BREAKPOINT_STORE)) | ||
655 | return -EINVAL; | ||
633 | } | 656 | } |
657 | |||
634 | out: | 658 | out: |
635 | return ret; | 659 | return ret; |
636 | } | 660 | } |
@@ -706,10 +730,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, | |||
706 | goto unlock; | 730 | goto unlock; |
707 | 731 | ||
708 | /* Check that the access type matches. */ | 732 | /* Check that the access type matches. */ |
709 | access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : | 733 | if (debug_exception_updates_fsr()) { |
710 | HW_BREAKPOINT_R; | 734 | access = (fsr & ARM_FSR_ACCESS_MASK) ? |
711 | if (!(access & hw_breakpoint_type(wp))) | 735 | HW_BREAKPOINT_W : HW_BREAKPOINT_R; |
712 | goto unlock; | 736 | if (!(access & hw_breakpoint_type(wp))) |
737 | goto unlock; | ||
738 | } | ||
713 | 739 | ||
714 | /* We have a winner. */ | 740 | /* We have a winner. */ |
715 | info->trigger = addr; | 741 | info->trigger = addr; |