Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+67 -36
+1
arch/arm/include/asm/hw_breakpoint.h
··· 58 58 /* Watchpoints */ 59 59 #define ARM_BREAKPOINT_LOAD 1 60 60 #define ARM_BREAKPOINT_STORE 2 61 + #define ARM_FSR_ACCESS_MASK (1 << 11) 61 62 62 63 /* Privilege Levels */ 63 64 #define ARM_BREAKPOINT_PRIV 1
+66 -36
arch/arm/kernel/hw_breakpoint.c
··· 339 339 val_base = ARM_BASE_BVR; 340 340 slots = (struct perf_event **)__get_cpu_var(bp_on_reg); 341 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 342 } else { 348 343 /* Watchpoint */ 349 - if (info->step_ctrl.enabled) { 350 - /* Install into the reserved breakpoint region. */ 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 - } 344 + ctrl_base = ARM_BASE_WCR; 345 + val_base = ARM_BASE_WVR; 360 346 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 361 347 max_slots = core_num_wrps; 362 348 } ··· 359 373 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) { 360 374 ret = -EBUSY; 361 375 goto out; 376 + } 377 + 378 + /* Override the breakpoint data with the step data. */ 379 + if (info->step_ctrl.enabled) { 380 + addr = info->trigger & ~0x3; 381 + ctrl = encode_ctrl_reg(info->step_ctrl); 382 + if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) { 383 + i = 0; 384 + ctrl_base = ARM_BASE_BCR + core_num_brps; 385 + val_base = ARM_BASE_BVR + core_num_brps; 386 + } 362 387 } 363 388 364 389 /* Setup the address register. */ ··· 395 398 max_slots = core_num_brps; 396 399 } else { 397 400 /* Watchpoint */ 398 - if (info->step_ctrl.enabled) 399 - base = ARM_BASE_BCR + core_num_brps; 400 - else 401 - base = ARM_BASE_WCR; 401 + base = ARM_BASE_WCR; 402 402 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 403 403 max_slots = core_num_wrps; 404 404 } ··· 412 418 413 419 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n")) 414 420 return; 421 + 422 + /* Ensure that we disable the mismatch breakpoint. */ 423 + if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE && 424 + info->step_ctrl.enabled) { 425 + i = 0; 426 + base = ARM_BASE_BCR + core_num_brps; 427 + } 415 428 416 429 /* Reset the control register. */ 417 430 write_wb_reg(base + i, 0); ··· 660 659 arch_install_hw_breakpoint(bp); 661 660 } 662 661 663 - static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) 662 + static void watchpoint_handler(unsigned long addr, unsigned int fsr, 663 + struct pt_regs *regs) 664 664 { 665 - int i; 665 + int i, access; 666 + u32 val, ctrl_reg, alignment_mask; 666 667 struct perf_event *wp, **slots; 667 668 struct arch_hw_breakpoint *info; 669 + struct arch_hw_breakpoint_ctrl ctrl; 668 670 669 671 slots = (struct perf_event **)__get_cpu_var(wp_on_reg); 670 - 671 - /* Without a disassembler, we can only handle 1 watchpoint. */ 672 - BUG_ON(core_num_wrps > 1); 673 672 674 673 for (i = 0; i < core_num_wrps; ++i) { 675 674 rcu_read_lock(); 676 675 677 676 wp = slots[i]; 678 677 679 - if (wp == NULL) { 680 - rcu_read_unlock(); 681 - continue; 678 + if (wp == NULL) 679 + goto unlock; 680 + 681 + info = counter_arch_bp(wp); 682 + /* 683 + * The DFAR is an unknown value on debug architectures prior 684 + * to 7.1. Since we only allow a single watchpoint on these 685 + * older CPUs, we can set the trigger to the lowest possible 686 + * faulting address. 687 + */ 688 + if (debug_arch < ARM_DEBUG_ARCH_V7_1) { 689 + BUG_ON(i > 0); 690 + info->trigger = wp->attr.bp_addr; 691 + } else { 692 + if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) 693 + alignment_mask = 0x7; 694 + else 695 + alignment_mask = 0x3; 696 + 697 + /* Check if the watchpoint value matches. */ 698 + val = read_wb_reg(ARM_BASE_WVR + i); 699 + if (val != (addr & ~alignment_mask)) 700 + goto unlock; 701 + 702 + /* Possible match, check the byte address select. */ 703 + ctrl_reg = read_wb_reg(ARM_BASE_WCR + i); 704 + decode_ctrl_reg(ctrl_reg, &ctrl); 705 + if (!((1 << (addr & alignment_mask)) & ctrl.len)) 706 + goto unlock; 707 + 708 + /* Check that the access type matches. */ 709 + access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : 710 + HW_BREAKPOINT_R; 711 + if (!(access & hw_breakpoint_type(wp))) 712 + goto unlock; 713 + 714 + /* We have a winner. */ 715 + info->trigger = addr; 682 716 } 683 717 684 - /* 685 - * The DFAR is an unknown value. Since we only allow a 686 - * single watchpoint, we can set the trigger to the lowest 687 - * possible faulting address. 688 - */ 689 - info = counter_arch_bp(wp); 690 - info->trigger = wp->attr.bp_addr; 691 718 pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); 692 719 perf_bp_event(wp, regs); 693 720 ··· 727 698 if (!wp->overflow_handler) 728 699 enable_single_step(wp, instruction_pointer(regs)); 729 700 701 + unlock: 730 702 rcu_read_unlock(); 731 703 } 732 704 } ··· 843 813 case ARM_ENTRY_ASYNC_WATCHPOINT: 844 814 WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n"); 845 815 case ARM_ENTRY_SYNC_WATCHPOINT: 846 - watchpoint_handler(addr, regs); 816 + watchpoint_handler(addr, fsr, regs); 847 817 break; 848 818 default: 849 819 ret = 1; /* Unhandled fault. */