aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/kernel/hw_breakpoint.c57
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 }
612out: 617out:
613 return ret; 618 return ret;