diff options
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 515a3c44c11..d37ed3501e5 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c | |||
@@ -537,6 +537,17 @@ static int arch_build_bp_info(struct perf_event *bp) | |||
537 | return -EINVAL; | 537 | return -EINVAL; |
538 | } | 538 | } |
539 | 539 | ||
540 | /* | ||
541 | * Breakpoints must be of length 2 (thumb) or 4 (ARM) bytes. | ||
542 | * Watchpoints can be of length 1, 2, 4 or 8 bytes if supported | ||
543 | * by the hardware and must be aligned to the appropriate number of | ||
544 | * bytes. | ||
545 | */ | ||
546 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE && | ||
547 | info->ctrl.len != ARM_BREAKPOINT_LEN_2 && | ||
548 | info->ctrl.len != ARM_BREAKPOINT_LEN_4) | ||
549 | return -EINVAL; | ||
550 | |||
540 | /* Address */ | 551 | /* Address */ |
541 | info->address = bp->attr.bp_addr; | 552 | info->address = bp->attr.bp_addr; |
542 | 553 | ||
@@ -561,7 +572,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
561 | { | 572 | { |
562 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | 573 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); |
563 | int ret = 0; | 574 | int ret = 0; |
564 | u32 bytelen, max_len, offset, alignment_mask = 0x3; | 575 | u32 offset, alignment_mask = 0x3; |
565 | 576 | ||
566 | /* Build the arch_hw_breakpoint. */ | 577 | /* Build the arch_hw_breakpoint. */ |
567 | ret = arch_build_bp_info(bp); | 578 | ret = arch_build_bp_info(bp); |
@@ -571,32 +582,27 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
571 | /* Check address alignment. */ | 582 | /* Check address alignment. */ |
572 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) | 583 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) |
573 | alignment_mask = 0x7; | 584 | alignment_mask = 0x7; |
574 | if (info->address & alignment_mask) { | 585 | offset = info->address & alignment_mask; |
575 | /* | 586 | switch (offset) { |
576 | * Try to fix the alignment. This may result in a length | 587 | case 0: |
577 | * that is too large, so we must check for that. | 588 | /* Aligned */ |
578 | */ | 589 | break; |
579 | bytelen = get_hbp_len(info->ctrl.len); | 590 | case 1: |
580 | max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 : | 591 | /* Allow single byte watchpoint. */ |
581 | max_watchpoint_len; | 592 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) |
582 | 593 | break; | |
583 | if (max_len >= 8) | 594 | case 2: |
584 | offset = info->address & 0x7; | 595 | /* Allow halfword watchpoints and breakpoints. */ |
585 | else | 596 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) |
586 | offset = info->address & 0x3; | 597 | break; |
587 | 598 | default: | |
588 | if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) { | 599 | ret = -EINVAL; |
589 | ret = -EFBIG; | 600 | goto out; |
590 | goto out; | ||
591 | } | ||
592 | |||
593 | info->ctrl.len <<= offset; | ||
594 | info->address &= ~offset; | ||
595 | |||
596 | pr_debug("breakpoint alignment fixup: length = 0x%x, " | ||
597 | "address = 0x%x\n", info->ctrl.len, info->address); | ||
598 | } | 601 | } |
599 | 602 | ||
603 | info->address &= ~alignment_mask; | ||
604 | info->ctrl.len <<= offset; | ||
605 | |||
600 | /* | 606 | /* |
601 | * Currently we rely on an overflow handler to take | 607 | * Currently we rely on an overflow handler to take |
602 | * care of single-stepping the breakpoint when it fires. | 608 | * care of single-stepping the breakpoint when it fires. |
@@ -607,7 +613,6 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
607 | (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()), | 613 | (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()), |
608 | "overflow handler required but none found")) { | 614 | "overflow handler required but none found")) { |
609 | ret = -EINVAL; | 615 | ret = -EINVAL; |
610 | goto out; | ||
611 | } | 616 | } |
612 | out: | 617 | out: |
613 | return ret; | 618 | return ret; |