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; |
