static int ptrace_hbp_get_ctrl(unsigned int note_type, struct task_struct *tsk, unsigned long idx, u32 *ctrl) { struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); if (IS_ERR(bp)) return PTR_ERR(bp); *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0; return 0; }
/* * Install a perf counter breakpoint. */ int arch_install_hw_breakpoint(struct perf_event *bp) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct perf_event **slot, **slots; struct debug_info *debug_info = ¤t->thread.debug; int i, max_slots, ctrl_reg, val_reg, reg_enable; u32 ctrl; if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { /* Breakpoint */ ctrl_reg = AARCH64_DBG_REG_BCR; val_reg = AARCH64_DBG_REG_BVR; slots = __get_cpu_var(bp_on_reg); max_slots = core_num_brps; reg_enable = !debug_info->bps_disabled; } else { /* Watchpoint */ ctrl_reg = AARCH64_DBG_REG_WCR; val_reg = AARCH64_DBG_REG_WVR; slots = __get_cpu_var(wp_on_reg); max_slots = core_num_wrps; reg_enable = !debug_info->wps_disabled; } for (i = 0; i < max_slots; ++i) { slot = &slots[i]; if (!*slot) { *slot = bp; break; } } if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) return -ENOSPC; /* Ensure debug monitors are enabled at the correct exception level. */ enable_debug_monitors(debug_exception_level(info->ctrl.privilege)); /* Setup the address register. */ write_wb_reg(val_reg, i, info->address); /* Setup the control register. */ ctrl = encode_ctrl_reg(info->ctrl); write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); return 0; }
static int ptrace_gethbpregs(struct task_struct *tsk, long num, unsigned long __user *data) { u32 reg; int idx, ret = 0; struct perf_event *bp; struct arch_hw_breakpoint_ctrl arch_ctrl; if (num == 0) { reg = ptrace_get_hbp_resource_info(); } else { idx = ptrace_hbp_num_to_idx(num); if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) { ret = -EINVAL; goto out; } bp = tsk->thread.debug.hbp[idx]; if (!bp) { reg = 0; goto put; } arch_ctrl = counter_arch_bp(bp)->ctrl; /* * Fix up the len because we may have adjusted it * to compensate for an unaligned address. */ while (!(arch_ctrl.len & 0x1)) arch_ctrl.len >>= 1; if (num & 0x1) reg = bp->attr.bp_addr; else reg = encode_ctrl_reg(arch_ctrl); } put: if (put_user(reg, data)) ret = -EFAULT; out: return ret; }
static int hw_breakpoint_control(struct perf_event *bp, enum hw_breakpoint_ops ops) { struct arch_hw_breakpoint *info = counter_arch_bp(bp); struct perf_event **slots; struct debug_info *debug_info = ¤t->thread.debug; int i, max_slots, ctrl_reg, val_reg, reg_enable; enum debug_el dbg_el = debug_exception_level(info->ctrl.privilege); u32 ctrl; if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { /* Breakpoint */ ctrl_reg = AARCH64_DBG_REG_BCR; val_reg = AARCH64_DBG_REG_BVR; slots = this_cpu_ptr(bp_on_reg); max_slots = core_num_brps; reg_enable = !debug_info->bps_disabled; } else { /* Watchpoint */ ctrl_reg = AARCH64_DBG_REG_WCR; val_reg = AARCH64_DBG_REG_WVR; slots = this_cpu_ptr(wp_on_reg); max_slots = core_num_wrps; reg_enable = !debug_info->wps_disabled; } i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops); if (WARN_ONCE(i < 0, "Can't find any breakpoint slot")) return i; switch (ops) { case HW_BREAKPOINT_INSTALL: /* * Ensure debug monitors are enabled at the correct exception * level. */ enable_debug_monitors(dbg_el); /* Fall through */ case HW_BREAKPOINT_RESTORE: /* Setup the address register. */ write_wb_reg(val_reg, i, info->address); /* Setup the control register. */ ctrl = encode_ctrl_reg(info->ctrl); write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); break; case HW_BREAKPOINT_UNINSTALL: /* Reset the control register. */ write_wb_reg(ctrl_reg, i, 0); /* * Release the debug monitors for the correct exception * level. */ disable_debug_monitors(dbg_el); break; } return 0; }