Lines Matching +full:no +full:- +full:wp
1 // SPDX-License-Identifier: GPL-2.0-only
3 * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
10 #define pr_fmt(fmt) "hw-breakpoint: " fmt
23 #include <asm/debug-monitors.h>
37 /* Currently stepping a per-CPU kernel breakpoint. */
151 return -EINVAL; in debug_exception_level()
164 struct task_struct *tsk = bp->hw.target; in is_compat_bp()
167 * tsk can be NULL for per-cpu (non-ptrace) breakpoints. in is_compat_bp()
177 * hw_breakpoint_slot_setup - Find and setup a perf slot according to
187 * -ENOSPC if no slot is available/matches
188 * -EINVAL on wrong operations parameter
218 return -EINVAL; in hw_breakpoint_slot_setup()
221 return -ENOSPC; in hw_breakpoint_slot_setup()
229 struct debug_info *debug_info = ¤t->thread.debug; in hw_breakpoint_control()
231 enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege); in hw_breakpoint_control()
234 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in hw_breakpoint_control()
240 reg_enable = !debug_info->bps_disabled; in hw_breakpoint_control()
247 reg_enable = !debug_info->wps_disabled; in hw_breakpoint_control()
265 write_wb_reg(val_reg, i, info->address); in hw_breakpoint_control()
268 ctrl = encode_ctrl_reg(info->ctrl); in hw_breakpoint_control()
342 va = hw->address; in arch_check_bp_in_kernelspace()
343 len = get_hbp_len(hw->ctrl.len); in arch_check_bp_in_kernelspace()
345 return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); in arch_check_bp_in_kernelspace()
371 return -EINVAL; in arch_bp_generic_fields()
375 return -EINVAL; in arch_bp_generic_fields()
405 return -EINVAL; in arch_bp_generic_fields()
419 switch (attr->bp_type) { in arch_build_bp_info()
421 hw->ctrl.type = ARM_BREAKPOINT_EXECUTE; in arch_build_bp_info()
424 hw->ctrl.type = ARM_BREAKPOINT_LOAD; in arch_build_bp_info()
427 hw->ctrl.type = ARM_BREAKPOINT_STORE; in arch_build_bp_info()
430 hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; in arch_build_bp_info()
433 return -EINVAL; in arch_build_bp_info()
437 switch (attr->bp_len) { in arch_build_bp_info()
439 hw->ctrl.len = ARM_BREAKPOINT_LEN_1; in arch_build_bp_info()
442 hw->ctrl.len = ARM_BREAKPOINT_LEN_2; in arch_build_bp_info()
445 hw->ctrl.len = ARM_BREAKPOINT_LEN_3; in arch_build_bp_info()
448 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
451 hw->ctrl.len = ARM_BREAKPOINT_LEN_5; in arch_build_bp_info()
454 hw->ctrl.len = ARM_BREAKPOINT_LEN_6; in arch_build_bp_info()
457 hw->ctrl.len = ARM_BREAKPOINT_LEN_7; in arch_build_bp_info()
460 hw->ctrl.len = ARM_BREAKPOINT_LEN_8; in arch_build_bp_info()
463 return -EINVAL; in arch_build_bp_info()
471 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in arch_build_bp_info()
473 if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 && in arch_build_bp_info()
474 hw->ctrl.len != ARM_BREAKPOINT_LEN_4) in arch_build_bp_info()
475 return -EINVAL; in arch_build_bp_info()
476 } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) { in arch_build_bp_info()
481 * but we should probably return -EINVAL instead. in arch_build_bp_info()
483 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
488 hw->address = attr->bp_addr; in arch_build_bp_info()
496 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1; in arch_build_bp_info()
498 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0; in arch_build_bp_info()
501 hw->ctrl.enabled = !attr->disabled; in arch_build_bp_info()
507 * Validate the arch-specific HW Breakpoint register settings.
524 * because using 64-bit unaligned addresses is deprecated for in hw_breakpoint_arch_parse()
531 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8) in hw_breakpoint_arch_parse()
535 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
543 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2) in hw_breakpoint_arch_parse()
549 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1) in hw_breakpoint_arch_parse()
554 return -EINVAL; in hw_breakpoint_arch_parse()
557 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) in hw_breakpoint_arch_parse()
561 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
564 hw->address &= ~alignment_mask; in hw_breakpoint_arch_parse()
565 hw->ctrl.len <<= offset; in hw_breakpoint_arch_parse()
568 * Disallow per-task kernel breakpoints since these would in hw_breakpoint_arch_parse()
571 if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target) in hw_breakpoint_arch_parse()
572 return -EINVAL; in hw_breakpoint_arch_parse()
580 * This is used when single-stepping after a breakpoint exception.
605 privilege = counter_arch_bp(slots[i])->ctrl.privilege; in toggle_bp_registers()
633 debug_info = ¤t->thread.debug; in do_breakpoint()
654 counter_arch_bp(bp)->trigger = addr; in do_breakpoint()
668 debug_info->bps_disabled = 1; in do_breakpoint()
672 if (debug_info->wps_disabled) in do_breakpoint()
676 debug_info->suspended_step = 1; in do_breakpoint()
700 * addresses. There is no straight-forward way, short of disassembling the
719 lens = __ffs(ctrl->len); in get_distance_from_watchpoint()
720 lene = __fls(ctrl->len); in get_distance_from_watchpoint()
725 return wp_low - addr; in get_distance_from_watchpoint()
727 return addr - wp_high; in get_distance_from_watchpoint()
732 static int watchpoint_report(struct perf_event *wp, unsigned long addr, in watchpoint_report() argument
735 int step = is_default_overflow_handler(wp); in watchpoint_report()
736 struct arch_hw_breakpoint *info = counter_arch_bp(wp); in watchpoint_report()
738 info->trigger = addr; in watchpoint_report()
745 if (!user_mode(regs) && info->ctrl.privilege == AARCH64_BREAKPOINT_EL0) in watchpoint_report()
748 perf_bp_event(wp, regs); in watchpoint_report()
756 u64 min_dist = -1, dist; in do_watchpoint()
759 struct perf_event *wp, **slots; in do_watchpoint() local
764 debug_info = ¤t->thread.debug; in do_watchpoint()
767 * Find all watchpoints that match the reported address. If no exact in do_watchpoint()
772 wp = slots[i]; in do_watchpoint()
773 if (wp == NULL) in do_watchpoint()
782 if (!(access & hw_breakpoint_type(wp))) in do_watchpoint()
798 step = watchpoint_report(wp, addr, regs); in do_watchpoint()
801 /* No exact match found? */ in do_watchpoint()
802 if (min_dist > 0 && min_dist != -1) in do_watchpoint()
817 debug_info->wps_disabled = 1; in do_watchpoint()
820 if (debug_info->bps_disabled) in do_watchpoint()
824 debug_info->suspended_step = 1; in do_watchpoint()
845 * Handle single-step exception.
849 struct debug_info *debug_info = ¤t->thread.debug; in try_step_suspended_breakpoints()
854 * Called from single-step exception entry. in try_step_suspended_breakpoints()
856 * false if we need to handle a single-step. in try_step_suspended_breakpoints()
859 if (debug_info->bps_disabled) { in try_step_suspended_breakpoints()
860 debug_info->bps_disabled = 0; in try_step_suspended_breakpoints()
865 if (debug_info->wps_disabled) { in try_step_suspended_breakpoints()
866 debug_info->wps_disabled = 0; in try_step_suspended_breakpoints()
872 if (debug_info->suspended_step) { in try_step_suspended_breakpoints()
873 debug_info->suspended_step = 0; in try_step_suspended_breakpoints()
874 /* Allow exception handling to fall-through. */ in try_step_suspended_breakpoints()
884 if (!debug_info->wps_disabled) in try_step_suspended_breakpoints()
902 * Context-switcher for restoring suspended breakpoints.
911 * 1 1 => NOTIFY_DONE. per-task bps will in hw_breakpoint_thread_switch()
917 current_debug_info = ¤t->thread.debug; in hw_breakpoint_thread_switch()
918 next_debug_info = &next->thread.debug; in hw_breakpoint_thread_switch()
921 if (current_debug_info->bps_disabled != next_debug_info->bps_disabled) in hw_breakpoint_thread_switch()
924 !next_debug_info->bps_disabled); in hw_breakpoint_thread_switch()
927 if (current_debug_info->wps_disabled != next_debug_info->wps_disabled) in hw_breakpoint_thread_switch()
930 !next_debug_info->wps_disabled); in hw_breakpoint_thread_switch()
941 * When a CPU goes through cold-boot, it does not have any installed in hw_breakpoint_reset()
946 * When this function is triggered on warm-boot through a CPU PM in hw_breakpoint_reset()
972 * One-time initialisation.