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

ARM: hw_breakpoint: do not allocate new breakpoints with preemption disabled

The watchpoint single-stepping code calls register_user_hw_breakpoint to
register a mismatch breakpoint for stepping over the watchpoint. This is
performed with preemption disabled, which is unsafe as we may end up scheduling
whilst in_atomic(). Furthermore, using the perf API is rather overkill since
we are already in the hw-breakpoint backend and only require access to reserved
breakpoints anyway.

This patch reworks the watchpoint stepping code so that we don't require
another perf_event for the mismatch breakpoint. Instead, we hold a separate
arch_hw_breakpoint_ctrl struct inside the watchpoint which is used exclusively
for stepping. We can check whether or not stepping is enabled when installing
or uninstalling the watchpoint and operate on the breakpoint accordingly.

Signed-off-by: Will Deacon <will.deacon@arm.com>

+78 -58
+1 -1
arch/arm/include/asm/hw_breakpoint.h
··· 20 20 struct arch_hw_breakpoint { 21 21 u32 address; 22 22 u32 trigger; 23 - struct perf_event *suspended_wp; 23 + struct arch_hw_breakpoint_ctrl step_ctrl; 24 24 struct arch_hw_breakpoint_ctrl ctrl; 25 25 }; 26 26
+77 -57
arch/arm/kernel/hw_breakpoint.c
··· 316 316 } 317 317 318 318 /* 319 - * Handler for reactivating a suspended watchpoint when the single 320 - * step `mismatch' breakpoint is triggered. 321 - */ 322 - static void wp_single_step_handler(struct perf_event *bp, int unused, 323 - struct perf_sample_data *data, 324 - struct pt_regs *regs) 325 - { 326 - perf_event_enable(counter_arch_bp(bp)->suspended_wp); 327 - unregister_hw_breakpoint(bp); 328 - } 329 - 330 - static int bp_is_single_step(struct perf_event *bp) 331 - { 332 - return bp->overflow_handler == wp_single_step_handler; 333 - } 334 - 335 - /* 336 319 * Install a perf counter breakpoint. 337 320 */ 338 321 int arch_install_hw_breakpoint(struct perf_event *bp) ··· 323 340 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 324 341 struct perf_event **slot, **slots; 325 342 int i, max_slots, ctrl_base, val_base, ret = 0; 343 + u32 addr, ctrl; 326 344 327 345 /* Ensure that we are in monitor mode and halting mode is disabled. */ 328 346 ret = enable_monitor_mode(); 329 347 if (ret) 330 348 goto out; 349 + 350 + addr = info->address; 351 + ctrl = encode_ctrl_reg(info->ctrl) | 0x1; 331 352 332 353 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { 333 354 /* Breakpoint */ ··· 339 352 val_base = ARM_BASE_BVR; 340 353 slots = __get_cpu_var(bp_on_reg); 341 354 max_slots = core_num_brps; 342 - 343 - if (bp_is_single_step(bp)) { 344 - info->ctrl.mismatch = 1; 345 - i = max_slots; 346 - slots[i] = bp; 347 - goto setup; 348 - } 349 355 } else { 350 356 /* Watchpoint */ 351 - ctrl_base = ARM_BASE_WCR; 352 - val_base = ARM_BASE_WVR; 357 + if (info->step_ctrl.enabled) { 358 + /* Install into the reserved breakpoint region. */ 359 + ctrl_base = ARM_BASE_BCR + core_num_brps; 360 + val_base = ARM_BASE_BVR + core_num_brps; 361 + /* Override the watchpoint data with the step data. */ 362 + addr = info->trigger & ~0x3; 363 + ctrl = encode_ctrl_reg(info->step_ctrl); 364 + } else { 365 + ctrl_base = ARM_BASE_WCR; 366 + val_base = ARM_BASE_WVR; 367 + } 353 368 slots = __get_cpu_var(wp_on_reg); 354 369 max_slots = core_num_wrps; 355 370 } ··· 370 381 goto out; 371 382 } 372 383 373 - setup: 374 384 /* Setup the address register. */ 375 - write_wb_reg(val_base + i, info->address); 385 + write_wb_reg(val_base + i, addr); 376 386 377 387 /* Setup the control register. */ 378 - write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1); 388 + write_wb_reg(ctrl_base + i, ctrl); 379 389 380 390 out: 381 391 return ret; ··· 391 403 base = ARM_BASE_BCR; 392 404 slots = __get_cpu_var(bp_on_reg); 393 405 max_slots = core_num_brps; 394 - 395 - if (bp_is_single_step(bp)) { 396 - i = max_slots; 397 - slots[i] = NULL; 398 - goto reset; 399 - } 400 406 } else { 401 407 /* Watchpoint */ 402 - base = ARM_BASE_WCR; 408 + if (info->step_ctrl.enabled) 409 + base = ARM_BASE_BCR + core_num_brps; 410 + else 411 + base = ARM_BASE_WCR; 403 412 slots = __get_cpu_var(wp_on_reg); 404 413 max_slots = core_num_wrps; 405 414 } ··· 414 429 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) 415 430 return; 416 431 417 - reset: 418 432 /* Reset the control register. */ 419 433 write_wb_reg(base + i, 0); 420 434 } ··· 563 579 564 580 /* Privilege */ 565 581 info->ctrl.privilege = ARM_BREAKPOINT_USER; 566 - if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp)) 582 + if (arch_check_bp_in_kernelspace(bp)) 567 583 info->ctrl.privilege |= ARM_BREAKPOINT_PRIV; 568 584 569 585 /* Enabled? */ ··· 648 664 static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs) 649 665 { 650 666 int i; 651 - struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg); 667 + struct perf_event *wp, **slots = __get_cpu_var(wp_on_reg); 652 668 struct arch_hw_breakpoint *info; 653 - struct perf_event_attr attr; 654 669 655 670 /* Without a disassembler, we can only handle 1 watchpoint. */ 656 671 BUG_ON(core_num_wrps > 1); 657 672 658 - hw_breakpoint_init(&attr); 659 - attr.bp_addr = regs->ARM_pc & ~0x3; 660 - attr.bp_len = HW_BREAKPOINT_LEN_4; 661 - attr.bp_type = HW_BREAKPOINT_X; 662 - 663 673 for (i = 0; i < core_num_wrps; ++i) { 664 674 rcu_read_lock(); 665 675 666 - if (slots[i] == NULL) { 676 + wp = slots[i]; 677 + 678 + if (wp == NULL) { 667 679 rcu_read_unlock(); 668 680 continue; 669 681 } ··· 669 689 * single watchpoint, we can set the trigger to the lowest 670 690 * possible faulting address. 671 691 */ 672 - info = counter_arch_bp(slots[i]); 673 - info->trigger = slots[i]->attr.bp_addr; 692 + info = counter_arch_bp(wp); 693 + info->trigger = wp->attr.bp_addr; 674 694 pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); 675 - perf_bp_event(slots[i], regs); 695 + perf_bp_event(wp, regs); 676 696 677 697 /* 678 698 * If no overflow handler is present, insert a temporary 679 699 * mismatch breakpoint so we can single-step over the 680 700 * watchpoint trigger. 681 701 */ 682 - if (!slots[i]->overflow_handler) { 683 - bp = register_user_hw_breakpoint(&attr, 684 - wp_single_step_handler, 685 - current); 686 - counter_arch_bp(bp)->suspended_wp = slots[i]; 687 - perf_event_disable(slots[i]); 702 + if (!wp->overflow_handler) { 703 + arch_uninstall_hw_breakpoint(wp); 704 + info->step_ctrl.mismatch = 1; 705 + info->step_ctrl.len = ARM_BREAKPOINT_LEN_4; 706 + info->step_ctrl.type = ARM_BREAKPOINT_EXECUTE; 707 + info->step_ctrl.privilege = info->ctrl.privilege; 708 + info->step_ctrl.enabled = 1; 709 + info->trigger = regs->ARM_pc; 710 + arch_install_hw_breakpoint(wp); 688 711 } 689 712 713 + rcu_read_unlock(); 714 + } 715 + } 716 + 717 + static void watchpoint_single_step_handler(unsigned long pc) 718 + { 719 + int i; 720 + struct perf_event *wp, **slots = __get_cpu_var(wp_on_reg); 721 + struct arch_hw_breakpoint *info; 722 + 723 + for (i = 0; i < core_num_reserved_brps; ++i) { 724 + rcu_read_lock(); 725 + 726 + wp = slots[i]; 727 + 728 + if (wp == NULL) 729 + goto unlock; 730 + 731 + info = counter_arch_bp(wp); 732 + if (!info->step_ctrl.enabled) 733 + goto unlock; 734 + 735 + /* 736 + * Restore the original watchpoint if we've completed the 737 + * single-step. 738 + */ 739 + if (info->trigger != pc) { 740 + arch_uninstall_hw_breakpoint(wp); 741 + info->step_ctrl.enabled = 0; 742 + arch_install_hw_breakpoint(wp); 743 + } 744 + 745 + unlock: 690 746 rcu_read_unlock(); 691 747 } 692 748 } ··· 739 723 /* The exception entry code places the amended lr in the PC. */ 740 724 addr = regs->ARM_pc; 741 725 742 - for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { 726 + /* Check the currently installed breakpoints first. */ 727 + for (i = 0; i < core_num_brps; ++i) { 743 728 rcu_read_lock(); 744 729 745 730 bp = slots[i]; ··· 767 750 } 768 751 769 752 unlock: 770 - if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) { 753 + if (mismatch && !info->ctrl.mismatch) { 771 754 pr_debug("breakpoint fired: address = 0x%x\n", addr); 772 755 perf_bp_event(bp, regs); 773 756 } ··· 775 758 update_mismatch_flag(i, mismatch); 776 759 rcu_read_unlock(); 777 760 } 761 + 762 + /* Handle any pending watchpoint single-step breakpoints. */ 763 + watchpoint_single_step_handler(addr); 778 764 } 779 765 780 766 /*