aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2011-08-02 11:16:57 -0400
committerWill Deacon <will.deacon@arm.com>2011-08-31 05:42:48 -0400
commit6f26aa05c9edffff6a4c2cd71774bc659a5cceec (patch)
treea2db63a03389e2153004347ddd93805486d1076b /arch/arm/kernel/hw_breakpoint.c
parentc512de955f0982aafa49d3f00d5643052a6790e5 (diff)
ARM: hw_breakpoint: add support for multiple watchpoints
ARM debug architecture 7.1 mandates that the DFAR is updated on a watchpoint debug exception to contain the faulting virtual address of the memory access. This allows us to determine which watchpoints have fired and therefore report useful information to userspace. This patch adds support for using the DFAR in the watchpoint handler, which allows us to support multiple watchpoints on CPUs implementing the new debug architecture. Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel/hw_breakpoint.c')
-rw-r--r--arch/arm/kernel/hw_breakpoint.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 156b8af13571..448143e44b65 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -339,24 +339,10 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
339 val_base = ARM_BASE_BVR; 339 val_base = ARM_BASE_BVR;
340 slots = (struct perf_event **)__get_cpu_var(bp_on_reg); 340 slots = (struct perf_event **)__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 }
347 } else { 342 } else {
348 /* Watchpoint */ 343 /* Watchpoint */
349 if (info->step_ctrl.enabled) { 344 ctrl_base = ARM_BASE_WCR;
350 /* Install into the reserved breakpoint region. */ 345 val_base = ARM_BASE_WVR;
351 ctrl_base = ARM_BASE_BCR + core_num_brps;
352 val_base = ARM_BASE_BVR + core_num_brps;
353 /* Override the watchpoint data with the step data. */
354 addr = info->trigger & ~0x3;
355 ctrl = encode_ctrl_reg(info->step_ctrl);
356 } else {
357 ctrl_base = ARM_BASE_WCR;
358 val_base = ARM_BASE_WVR;
359 }
360 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 346 slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
361 max_slots = core_num_wrps; 347 max_slots = core_num_wrps;
362 } 348 }
@@ -375,6 +361,17 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
375 goto out; 361 goto out;
376 } 362 }
377 363
364 /* Override the breakpoint data with the step data. */
365 if (info->step_ctrl.enabled) {
366 addr = info->trigger & ~0x3;
367 ctrl = encode_ctrl_reg(info->step_ctrl);
368 if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) {
369 i = 0;
370 ctrl_base = ARM_BASE_BCR + core_num_brps;
371 val_base = ARM_BASE_BVR + core_num_brps;
372 }
373 }
374
378 /* Setup the address register. */ 375 /* Setup the address register. */
379 write_wb_reg(val_base + i, addr); 376 write_wb_reg(val_base + i, addr);
380 377
@@ -398,10 +395,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
398 max_slots = core_num_brps; 395 max_slots = core_num_brps;
399 } else { 396 } else {
400 /* Watchpoint */ 397 /* Watchpoint */
401 if (info->step_ctrl.enabled) 398 base = ARM_BASE_WCR;
402 base = ARM_BASE_BCR + core_num_brps;
403 else
404 base = ARM_BASE_WCR;
405 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 399 slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
406 max_slots = core_num_wrps; 400 max_slots = core_num_wrps;
407 } 401 }
@@ -419,6 +413,13 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
419 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) 413 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
420 return; 414 return;
421 415
416 /* Ensure that we disable the mismatch breakpoint. */
417 if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE &&
418 info->step_ctrl.enabled) {
419 i = 0;
420 base = ARM_BASE_BCR + core_num_brps;
421 }
422
422 /* Reset the control register. */ 423 /* Reset the control register. */
423 write_wb_reg(base + i, 0); 424 write_wb_reg(base + i, 0);
424} 425}
@@ -659,34 +660,62 @@ static void disable_single_step(struct perf_event *bp)
659 arch_install_hw_breakpoint(bp); 660 arch_install_hw_breakpoint(bp);
660} 661}
661 662
662static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) 663static void watchpoint_handler(unsigned long addr, unsigned int fsr,
664 struct pt_regs *regs)
663{ 665{
664 int i; 666 int i, access;
667 u32 val, ctrl_reg, alignment_mask;
665 struct perf_event *wp, **slots; 668 struct perf_event *wp, **slots;
666 struct arch_hw_breakpoint *info; 669 struct arch_hw_breakpoint *info;
670 struct arch_hw_breakpoint_ctrl ctrl;
667 671
668 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 672 slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
669 673
670 /* Without a disassembler, we can only handle 1 watchpoint. */
671 BUG_ON(core_num_wrps > 1);
672
673 for (i = 0; i < core_num_wrps; ++i) { 674 for (i = 0; i < core_num_wrps; ++i) {
674 rcu_read_lock(); 675 rcu_read_lock();
675 676
676 wp = slots[i]; 677 wp = slots[i];
677 678
678 if (wp == NULL) { 679 if (wp == NULL)
679 rcu_read_unlock(); 680 goto unlock;
680 continue;
681 }
682 681
682 info = counter_arch_bp(wp);
683 /* 683 /*
684 * The DFAR is an unknown value. Since we only allow a 684 * The DFAR is an unknown value on debug architectures prior
685 * single watchpoint, we can set the trigger to the lowest 685 * to 7.1. Since we only allow a single watchpoint on these
686 * possible faulting address. 686 * older CPUs, we can set the trigger to the lowest possible
687 * faulting address.
687 */ 688 */
688 info = counter_arch_bp(wp); 689 if (debug_arch < ARM_DEBUG_ARCH_V7_1) {
689 info->trigger = wp->attr.bp_addr; 690 BUG_ON(i > 0);
691 info->trigger = wp->attr.bp_addr;
692 } else {
693 if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
694 alignment_mask = 0x7;
695 else
696 alignment_mask = 0x3;
697
698 /* Check if the watchpoint value matches. */
699 val = read_wb_reg(ARM_BASE_WVR + i);
700 if (val != (addr & ~alignment_mask))
701 goto unlock;
702
703 /* Possible match, check the byte address select. */
704 ctrl_reg = read_wb_reg(ARM_BASE_WCR + i);
705 decode_ctrl_reg(ctrl_reg, &ctrl);
706 if (!((1 << (addr & alignment_mask)) & ctrl.len))
707 goto unlock;
708
709 /* Check that the access type matches. */
710 access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
711 HW_BREAKPOINT_R;
712 if (!(access & hw_breakpoint_type(wp)))
713 goto unlock;
714
715 /* We have a winner. */
716 info->trigger = addr;
717 }
718
690 pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); 719 pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
691 perf_bp_event(wp, regs); 720 perf_bp_event(wp, regs);
692 721
@@ -698,6 +727,7 @@ static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
698 if (!wp->overflow_handler) 727 if (!wp->overflow_handler)
699 enable_single_step(wp, instruction_pointer(regs)); 728 enable_single_step(wp, instruction_pointer(regs));
700 729
730unlock:
701 rcu_read_unlock(); 731 rcu_read_unlock();
702 } 732 }
703} 733}
@@ -813,7 +843,7 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
813 case ARM_ENTRY_ASYNC_WATCHPOINT: 843 case ARM_ENTRY_ASYNC_WATCHPOINT:
814 WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); 844 WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
815 case ARM_ENTRY_SYNC_WATCHPOINT: 845 case ARM_ENTRY_SYNC_WATCHPOINT:
816 watchpoint_handler(addr, regs); 846 watchpoint_handler(addr, fsr, regs);
817 break; 847 break;
818 default: 848 default:
819 ret = 1; /* Unhandled fault. */ 849 ret = 1; /* Unhandled fault. */