Lines Matching +full:wp +full:- +full:content

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>
36 /* Currently stepping a per-CPU kernel breakpoint. */
150 return -EINVAL; in debug_exception_level()
163 struct task_struct *tsk = bp->hw.target; in is_compat_bp()
166 * tsk can be NULL for per-cpu (non-ptrace) breakpoints. in is_compat_bp()
176 * hw_breakpoint_slot_setup - Find and setup a perf slot according to
186 * -ENOSPC if no slot is available/matches
187 * -EINVAL on wrong operations parameter
217 return -EINVAL; in hw_breakpoint_slot_setup()
220 return -ENOSPC; in hw_breakpoint_slot_setup()
228 struct debug_info *debug_info = &current->thread.debug; in hw_breakpoint_control()
230 enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege); in hw_breakpoint_control()
233 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in hw_breakpoint_control()
239 reg_enable = !debug_info->bps_disabled; in hw_breakpoint_control()
246 reg_enable = !debug_info->wps_disabled; in hw_breakpoint_control()
264 write_wb_reg(val_reg, i, info->address); in hw_breakpoint_control()
267 ctrl = encode_ctrl_reg(info->ctrl); in hw_breakpoint_control()
341 va = hw->address; in arch_check_bp_in_kernelspace()
342 len = get_hbp_len(hw->ctrl.len); in arch_check_bp_in_kernelspace()
344 return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); in arch_check_bp_in_kernelspace()
370 return -EINVAL; in arch_bp_generic_fields()
374 return -EINVAL; in arch_bp_generic_fields()
404 return -EINVAL; in arch_bp_generic_fields()
418 switch (attr->bp_type) { in arch_build_bp_info()
420 hw->ctrl.type = ARM_BREAKPOINT_EXECUTE; in arch_build_bp_info()
423 hw->ctrl.type = ARM_BREAKPOINT_LOAD; in arch_build_bp_info()
426 hw->ctrl.type = ARM_BREAKPOINT_STORE; in arch_build_bp_info()
429 hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; in arch_build_bp_info()
432 return -EINVAL; in arch_build_bp_info()
436 switch (attr->bp_len) { in arch_build_bp_info()
438 hw->ctrl.len = ARM_BREAKPOINT_LEN_1; in arch_build_bp_info()
441 hw->ctrl.len = ARM_BREAKPOINT_LEN_2; in arch_build_bp_info()
444 hw->ctrl.len = ARM_BREAKPOINT_LEN_3; in arch_build_bp_info()
447 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
450 hw->ctrl.len = ARM_BREAKPOINT_LEN_5; in arch_build_bp_info()
453 hw->ctrl.len = ARM_BREAKPOINT_LEN_6; in arch_build_bp_info()
456 hw->ctrl.len = ARM_BREAKPOINT_LEN_7; in arch_build_bp_info()
459 hw->ctrl.len = ARM_BREAKPOINT_LEN_8; in arch_build_bp_info()
462 return -EINVAL; in arch_build_bp_info()
470 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in arch_build_bp_info()
472 if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 && in arch_build_bp_info()
473 hw->ctrl.len != ARM_BREAKPOINT_LEN_4) in arch_build_bp_info()
474 return -EINVAL; in arch_build_bp_info()
475 } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) { in arch_build_bp_info()
480 * but we should probably return -EINVAL instead. in arch_build_bp_info()
482 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
487 hw->address = attr->bp_addr; in arch_build_bp_info()
495 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1; in arch_build_bp_info()
497 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0; in arch_build_bp_info()
500 hw->ctrl.enabled = !attr->disabled; in arch_build_bp_info()
506 * Validate the arch-specific HW Breakpoint register settings.
523 * because using 64-bit unaligned addresses is deprecated for in hw_breakpoint_arch_parse()
530 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8) in hw_breakpoint_arch_parse()
534 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
542 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2) in hw_breakpoint_arch_parse()
548 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1) in hw_breakpoint_arch_parse()
553 return -EINVAL; in hw_breakpoint_arch_parse()
556 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) in hw_breakpoint_arch_parse()
560 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
563 hw->address &= ~alignment_mask; in hw_breakpoint_arch_parse()
564 hw->ctrl.len <<= offset; in hw_breakpoint_arch_parse()
567 * Disallow per-task kernel breakpoints since these would in hw_breakpoint_arch_parse()
570 if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target) in hw_breakpoint_arch_parse()
571 return -EINVAL; in hw_breakpoint_arch_parse()
579 * This is used when single-stepping after a breakpoint exception.
604 privilege = counter_arch_bp(slots[i])->ctrl.privilege; in toggle_bp_registers()
633 debug_info = &current->thread.debug; in breakpoint_handler()
654 counter_arch_bp(bp)->trigger = addr; in breakpoint_handler()
668 debug_info->bps_disabled = 1; in breakpoint_handler()
672 if (debug_info->wps_disabled) in breakpoint_handler()
676 debug_info->suspended_step = 1; in breakpoint_handler()
702 * addresses. There is no straight-forward way, short of disassembling the
721 lens = __ffs(ctrl->len); in get_distance_from_watchpoint()
722 lene = __fls(ctrl->len); in get_distance_from_watchpoint()
727 return wp_low - addr; in get_distance_from_watchpoint()
729 return addr - wp_high; in get_distance_from_watchpoint()
734 static int watchpoint_report(struct perf_event *wp, unsigned long addr, in watchpoint_report() argument
737 int step = is_default_overflow_handler(wp); in watchpoint_report()
738 struct arch_hw_breakpoint *info = counter_arch_bp(wp); in watchpoint_report()
740 info->trigger = addr; in watchpoint_report()
747 if (!user_mode(regs) && info->ctrl.privilege == AARCH64_BREAKPOINT_EL0) in watchpoint_report()
750 perf_bp_event(wp, regs); in watchpoint_report()
759 u64 min_dist = -1, dist; in watchpoint_handler()
762 struct perf_event *wp, **slots; in watchpoint_handler() local
767 debug_info = &current->thread.debug; in watchpoint_handler()
775 wp = slots[i]; in watchpoint_handler()
776 if (wp == NULL) in watchpoint_handler()
785 if (!(access & hw_breakpoint_type(wp))) in watchpoint_handler()
801 step = watchpoint_report(wp, addr, regs); in watchpoint_handler()
805 if (min_dist > 0 && min_dist != -1) in watchpoint_handler()
820 debug_info->wps_disabled = 1; in watchpoint_handler()
823 if (debug_info->bps_disabled) in watchpoint_handler()
827 debug_info->suspended_step = 1; in watchpoint_handler()
850 * Handle single-step exception.
854 struct debug_info *debug_info = &current->thread.debug; in reinstall_suspended_bps()
860 * Called from single-step exception handler. in reinstall_suspended_bps()
865 if (debug_info->bps_disabled) { in reinstall_suspended_bps()
866 debug_info->bps_disabled = 0; in reinstall_suspended_bps()
871 if (debug_info->wps_disabled) { in reinstall_suspended_bps()
872 debug_info->wps_disabled = 0; in reinstall_suspended_bps()
878 if (debug_info->suspended_step) { in reinstall_suspended_bps()
879 debug_info->suspended_step = 0; in reinstall_suspended_bps()
880 /* Allow exception handling to fall-through. */ in reinstall_suspended_bps()
890 if (!debug_info->wps_disabled) in reinstall_suspended_bps()
908 * Context-switcher for restoring suspended breakpoints.
917 * 1 1 => NOTIFY_DONE. per-task bps will in hw_breakpoint_thread_switch()
923 current_debug_info = &current->thread.debug; in hw_breakpoint_thread_switch()
924 next_debug_info = &next->thread.debug; in hw_breakpoint_thread_switch()
927 if (current_debug_info->bps_disabled != next_debug_info->bps_disabled) in hw_breakpoint_thread_switch()
930 !next_debug_info->bps_disabled); in hw_breakpoint_thread_switch()
933 if (current_debug_info->wps_disabled != next_debug_info->wps_disabled) in hw_breakpoint_thread_switch()
936 !next_debug_info->wps_disabled); in hw_breakpoint_thread_switch()
947 * When a CPU goes through cold-boot, it does not have any installed in hw_breakpoint_reset()
952 * When this function is triggered on warm-boot through a CPU PM in hw_breakpoint_reset()
954 * reprogrammed according to the debug slots content. in hw_breakpoint_reset()
978 * One-time initialisation.
992 TRAP_HWBKPT, "hw-breakpoint handler"); in arch_hw_breakpoint_init()
994 TRAP_HWBKPT, "hw-watchpoint handler"); in arch_hw_breakpoint_init()