aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2010-12-01 09:12:13 -0500
committerWill Deacon <will.deacon@arm.com>2010-12-06 06:55:57 -0500
commit9ebb3cbcc39d4e61ae6751167086acfb5c201e6f (patch)
tree4e88970d75cb2e7b3a5a2f1b50c58ab358d30339
parent93a04a3416da12647c47840ebe2bb812fcb801d0 (diff)
ARM: hw_breakpoint: unify single-stepping code for watchpoints and breakpoints
The single-stepping code is currently different depending on whether we are stepping over a breakpoint or a watchpoint. There is no good reason for this, so let's sort it out. This patch adds functions for enabling/disabling single-step for a particular hw_breakpoint and integrates this with the exception handling code. Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm/include/asm/hw_breakpoint.h4
-rw-r--r--arch/arm/kernel/hw_breakpoint.c81
2 files changed, 42 insertions, 43 deletions
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
index 881429d0b849..f389b2704d82 100644
--- a/arch/arm/include/asm/hw_breakpoint.h
+++ b/arch/arm/include/asm/hw_breakpoint.h
@@ -20,8 +20,8 @@ struct arch_hw_breakpoint_ctrl {
20struct arch_hw_breakpoint { 20struct arch_hw_breakpoint {
21 u32 address; 21 u32 address;
22 u32 trigger; 22 u32 trigger;
23 struct arch_hw_breakpoint_ctrl step_ctrl; 23 struct arch_hw_breakpoint_ctrl step_ctrl;
24 struct arch_hw_breakpoint_ctrl ctrl; 24 struct arch_hw_breakpoint_ctrl ctrl;
25}; 25};
26 26
27static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl) 27static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 81b63e94dfe0..36cd7680d3d2 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -339,6 +339,11 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
339 val_base = ARM_BASE_BVR; 339 val_base = ARM_BASE_BVR;
340 slots = __get_cpu_var(bp_on_reg); 340 slots = __get_cpu_var(bp_on_reg);
341 max_slots = core_num_brps; 341 max_slots = core_num_brps;
342 if (info->step_ctrl.enabled) {
343 /* Override the breakpoint data with the step data. */
344 addr = info->trigger & ~0x3;
345 ctrl = encode_ctrl_reg(info->step_ctrl);
346 }
342 } else { 347 } else {
343 /* Watchpoint */ 348 /* Watchpoint */
344 if (info->step_ctrl.enabled) { 349 if (info->step_ctrl.enabled) {
@@ -628,21 +633,28 @@ out:
628 return ret; 633 return ret;
629} 634}
630 635
631static void update_mismatch_flag(int idx, int flag) 636/*
637 * Enable/disable single-stepping over the breakpoint bp at address addr.
638 */
639static void enable_single_step(struct perf_event *bp, u32 addr)
632{ 640{
633 struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]); 641 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
634 struct arch_hw_breakpoint *info;
635
636 if (bp == NULL)
637 return;
638 642
639 info = counter_arch_bp(bp); 643 arch_uninstall_hw_breakpoint(bp);
644 info->step_ctrl.mismatch = 1;
645 info->step_ctrl.len = ARM_BREAKPOINT_LEN_4;
646 info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE;
647 info->step_ctrl.privilege = info->ctrl.privilege;
648 info->step_ctrl.enabled = 1;
649 info->trigger = addr;
650 arch_install_hw_breakpoint(bp);
651}
640 652
641 /* Update the mismatch field to enter/exit `single-step' mode */ 653static void disable_single_step(struct perf_event *bp)
642 if (!bp->overflow_handler && info->ctrl.mismatch != flag) { 654{
643 info->ctrl.mismatch = flag; 655 arch_uninstall_hw_breakpoint(bp);
644 write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1); 656 counter_arch_bp(bp)->step_ctrl.enabled = 0;
645 } 657 arch_install_hw_breakpoint(bp);
646} 658}
647 659
648static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) 660static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
@@ -679,16 +691,8 @@ static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
679 * mismatch breakpoint so we can single-step over the 691 * mismatch breakpoint so we can single-step over the
680 * watchpoint trigger. 692 * watchpoint trigger.
681 */ 693 */
682 if (!wp->overflow_handler) { 694 if (!wp->overflow_handler)
683 arch_uninstall_hw_breakpoint(wp); 695 enable_single_step(wp, instruction_pointer(regs));
684 info->step_ctrl.mismatch = 1;
685 info->step_ctrl.len = ARM_BREAKPOINT_LEN_4;
686 info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE;
687 info->step_ctrl.privilege = info->ctrl.privilege;
688 info->step_ctrl.enabled = 1;
689 info->trigger = regs->ARM_pc;
690 arch_install_hw_breakpoint(wp);
691 }
692 696
693 rcu_read_unlock(); 697 rcu_read_unlock();
694 } 698 }
@@ -716,11 +720,8 @@ static void watchpoint_single_step_handler(unsigned long pc)
716 * Restore the original watchpoint if we've completed the 720 * Restore the original watchpoint if we've completed the
717 * single-step. 721 * single-step.
718 */ 722 */
719 if (info->trigger != pc) { 723 if (info->trigger != pc)
720 arch_uninstall_hw_breakpoint(wp); 724 disable_single_step(wp);
721 info->step_ctrl.enabled = 0;
722 arch_install_hw_breakpoint(wp);
723 }
724 725
725unlock: 726unlock:
726 rcu_read_unlock(); 727 rcu_read_unlock();
@@ -730,7 +731,6 @@ unlock:
730static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) 731static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
731{ 732{
732 int i; 733 int i;
733 int mismatch;
734 u32 ctrl_reg, val, addr; 734 u32 ctrl_reg, val, addr;
735 struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg); 735 struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg);
736 struct arch_hw_breakpoint *info; 736 struct arch_hw_breakpoint *info;
@@ -745,34 +745,33 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
745 745
746 bp = slots[i]; 746 bp = slots[i];
747 747
748 if (bp == NULL) { 748 if (bp == NULL)
749 rcu_read_unlock(); 749 goto unlock;
750 continue;
751 }
752 750
753 mismatch = 0; 751 info = counter_arch_bp(bp);
754 752
755 /* Check if the breakpoint value matches. */ 753 /* Check if the breakpoint value matches. */
756 val = read_wb_reg(ARM_BASE_BVR + i); 754 val = read_wb_reg(ARM_BASE_BVR + i);
757 if (val != (addr & ~0x3)) 755 if (val != (addr & ~0x3))
758 goto unlock; 756 goto mismatch;
759 757
760 /* Possible match, check the byte address select to confirm. */ 758 /* Possible match, check the byte address select to confirm. */
761 ctrl_reg = read_wb_reg(ARM_BASE_BCR + i); 759 ctrl_reg = read_wb_reg(ARM_BASE_BCR + i);
762 decode_ctrl_reg(ctrl_reg, &ctrl); 760 decode_ctrl_reg(ctrl_reg, &ctrl);
763 if ((1 << (addr & 0x3)) & ctrl.len) { 761 if ((1 << (addr & 0x3)) & ctrl.len) {
764 mismatch = 1;
765 info = counter_arch_bp(bp);
766 info->trigger = addr; 762 info->trigger = addr;
767 }
768
769unlock:
770 if (mismatch && !info->ctrl.mismatch) {
771 pr_debug("breakpoint fired: address = 0x%x\n", addr); 763 pr_debug("breakpoint fired: address = 0x%x\n", addr);
772 perf_bp_event(bp, regs); 764 perf_bp_event(bp, regs);
765 if (!bp->overflow_handler)
766 enable_single_step(bp, addr);
767 goto unlock;
773 } 768 }
774 769
775 update_mismatch_flag(i, mismatch); 770mismatch:
771 /* If we're stepping a breakpoint, it can now be restored. */
772 if (info->step_ctrl.enabled)
773 disable_single_step(bp);
774unlock:
776 rcu_read_unlock(); 775 rcu_read_unlock();
777 } 776 }
778 777