Lines Matching +full:bypass +full:- +full:slot +full:- +full:no

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>
35 /* Currently stepping a per-CPU kernel breakpoint. */
54 pr_warn("unknown slot type: %d\n", type); in hw_breakpoint_slots()
149 return -EINVAL; in debug_exception_level()
162 struct task_struct *tsk = bp->hw.target; in is_compat_bp()
165 * tsk can be NULL for per-cpu (non-ptrace) breakpoints. in is_compat_bp()
175 * hw_breakpoint_slot_setup - Find and setup a perf slot according to
181 * @ops: operation to be carried out on the slot
184 * slot index on success
185 * -ENOSPC if no slot is available/matches
186 * -EINVAL on wrong operations parameter
193 struct perf_event **slot; in hw_breakpoint_slot_setup() local
196 slot = &slots[i]; in hw_breakpoint_slot_setup()
199 if (!*slot) { in hw_breakpoint_slot_setup()
200 *slot = bp; in hw_breakpoint_slot_setup()
205 if (*slot == bp) { in hw_breakpoint_slot_setup()
206 *slot = NULL; in hw_breakpoint_slot_setup()
211 if (*slot == bp) in hw_breakpoint_slot_setup()
216 return -EINVAL; in hw_breakpoint_slot_setup()
219 return -ENOSPC; in hw_breakpoint_slot_setup()
227 struct debug_info *debug_info = &current->thread.debug; in hw_breakpoint_control()
229 enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege); in hw_breakpoint_control()
232 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in hw_breakpoint_control()
238 reg_enable = !debug_info->bps_disabled; in hw_breakpoint_control()
245 reg_enable = !debug_info->wps_disabled; in hw_breakpoint_control()
250 if (WARN_ONCE(i < 0, "Can't find any breakpoint slot")) in hw_breakpoint_control()
263 write_wb_reg(val_reg, i, info->address); in hw_breakpoint_control()
266 ctrl = encode_ctrl_reg(info->ctrl); in hw_breakpoint_control()
340 va = hw->address; in arch_check_bp_in_kernelspace()
341 len = get_hbp_len(hw->ctrl.len); in arch_check_bp_in_kernelspace()
343 return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); in arch_check_bp_in_kernelspace()
348 * Hopefully this will disappear when ptrace can bypass the conversion
369 return -EINVAL; in arch_bp_generic_fields()
373 return -EINVAL; in arch_bp_generic_fields()
403 return -EINVAL; in arch_bp_generic_fields()
417 switch (attr->bp_type) { in arch_build_bp_info()
419 hw->ctrl.type = ARM_BREAKPOINT_EXECUTE; in arch_build_bp_info()
422 hw->ctrl.type = ARM_BREAKPOINT_LOAD; in arch_build_bp_info()
425 hw->ctrl.type = ARM_BREAKPOINT_STORE; in arch_build_bp_info()
428 hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; in arch_build_bp_info()
431 return -EINVAL; in arch_build_bp_info()
435 switch (attr->bp_len) { in arch_build_bp_info()
437 hw->ctrl.len = ARM_BREAKPOINT_LEN_1; in arch_build_bp_info()
440 hw->ctrl.len = ARM_BREAKPOINT_LEN_2; in arch_build_bp_info()
443 hw->ctrl.len = ARM_BREAKPOINT_LEN_3; in arch_build_bp_info()
446 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
449 hw->ctrl.len = ARM_BREAKPOINT_LEN_5; in arch_build_bp_info()
452 hw->ctrl.len = ARM_BREAKPOINT_LEN_6; in arch_build_bp_info()
455 hw->ctrl.len = ARM_BREAKPOINT_LEN_7; in arch_build_bp_info()
458 hw->ctrl.len = ARM_BREAKPOINT_LEN_8; in arch_build_bp_info()
461 return -EINVAL; in arch_build_bp_info()
469 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) { in arch_build_bp_info()
471 if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 && in arch_build_bp_info()
472 hw->ctrl.len != ARM_BREAKPOINT_LEN_4) in arch_build_bp_info()
473 return -EINVAL; in arch_build_bp_info()
474 } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) { in arch_build_bp_info()
479 * but we should probably return -EINVAL instead. in arch_build_bp_info()
481 hw->ctrl.len = ARM_BREAKPOINT_LEN_4; in arch_build_bp_info()
486 hw->address = attr->bp_addr; in arch_build_bp_info()
494 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1; in arch_build_bp_info()
496 hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0; in arch_build_bp_info()
499 hw->ctrl.enabled = !attr->disabled; in arch_build_bp_info()
505 * Validate the arch-specific HW Breakpoint register settings.
522 * because using 64-bit unaligned addresses is deprecated for in hw_breakpoint_arch_parse()
529 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8) in hw_breakpoint_arch_parse()
533 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
541 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2) in hw_breakpoint_arch_parse()
547 if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1) in hw_breakpoint_arch_parse()
552 return -EINVAL; in hw_breakpoint_arch_parse()
555 if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) in hw_breakpoint_arch_parse()
559 offset = hw->address & alignment_mask; in hw_breakpoint_arch_parse()
562 hw->address &= ~alignment_mask; in hw_breakpoint_arch_parse()
563 hw->ctrl.len <<= offset; in hw_breakpoint_arch_parse()
566 * Disallow per-task kernel breakpoints since these would in hw_breakpoint_arch_parse()
569 if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target) in hw_breakpoint_arch_parse()
570 return -EINVAL; in hw_breakpoint_arch_parse()
578 * This is used when single-stepping after a breakpoint exception.
603 privilege = counter_arch_bp(slots[i])->ctrl.privilege; in toggle_bp_registers()
632 debug_info = &current->thread.debug; in breakpoint_handler()
653 counter_arch_bp(bp)->trigger = addr; in breakpoint_handler()
667 debug_info->bps_disabled = 1; in breakpoint_handler()
671 if (debug_info->wps_disabled) in breakpoint_handler()
675 debug_info->suspended_step = 1; in breakpoint_handler()
701 * addresses. There is no straight-forward way, short of disassembling the
720 lens = __ffs(ctrl->len); in get_distance_from_watchpoint()
721 lene = __fls(ctrl->len); in get_distance_from_watchpoint()
726 return wp_low - addr; in get_distance_from_watchpoint()
728 return addr - wp_high; in get_distance_from_watchpoint()
739 info->trigger = addr; in watchpoint_report()
746 if (!user_mode(regs) && info->ctrl.privilege == AARCH64_BREAKPOINT_EL0) in watchpoint_report()
758 u64 min_dist = -1, dist; in watchpoint_handler()
766 debug_info = &current->thread.debug; in watchpoint_handler()
769 * Find all watchpoints that match the reported address. If no exact in watchpoint_handler()
803 /* No exact match found? */ in watchpoint_handler()
804 if (min_dist > 0 && min_dist != -1) in watchpoint_handler()
819 debug_info->wps_disabled = 1; in watchpoint_handler()
822 if (debug_info->bps_disabled) in watchpoint_handler()
826 debug_info->suspended_step = 1; in watchpoint_handler()
849 * Handle single-step exception.
853 struct debug_info *debug_info = &current->thread.debug; in reinstall_suspended_bps()
859 * Called from single-step exception handler. in reinstall_suspended_bps()
864 if (debug_info->bps_disabled) { in reinstall_suspended_bps()
865 debug_info->bps_disabled = 0; in reinstall_suspended_bps()
870 if (debug_info->wps_disabled) { in reinstall_suspended_bps()
871 debug_info->wps_disabled = 0; in reinstall_suspended_bps()
877 if (debug_info->suspended_step) { in reinstall_suspended_bps()
878 debug_info->suspended_step = 0; in reinstall_suspended_bps()
879 /* Allow exception handling to fall-through. */ in reinstall_suspended_bps()
889 if (!debug_info->wps_disabled) in reinstall_suspended_bps()
907 * Context-switcher for restoring suspended breakpoints.
916 * 1 1 => NOTIFY_DONE. per-task bps will in hw_breakpoint_thread_switch()
922 current_debug_info = &current->thread.debug; in hw_breakpoint_thread_switch()
923 next_debug_info = &next->thread.debug; in hw_breakpoint_thread_switch()
926 if (current_debug_info->bps_disabled != next_debug_info->bps_disabled) in hw_breakpoint_thread_switch()
929 !next_debug_info->bps_disabled); in hw_breakpoint_thread_switch()
932 if (current_debug_info->wps_disabled != next_debug_info->wps_disabled) in hw_breakpoint_thread_switch()
935 !next_debug_info->wps_disabled); in hw_breakpoint_thread_switch()
946 * When a CPU goes through cold-boot, it does not have any installed in hw_breakpoint_reset()
947 * slot, so it is safe to share the same function for restoring and in hw_breakpoint_reset()
951 * When this function is triggered on warm-boot through a CPU PM in hw_breakpoint_reset()
985 * One-time initialisation.
999 TRAP_HWBKPT, "hw-breakpoint handler"); in arch_hw_breakpoint_init()
1001 TRAP_HWBKPT, "hw-watchpoint handler"); in arch_hw_breakpoint_init()