^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/regset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/hw_breakpoint.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <asm/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "ptrace-decl.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) void user_enable_single_step(struct task_struct *task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct pt_regs *regs = task->thread.regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) if (regs != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) regs->msr &= ~MSR_BE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) regs->msr |= MSR_SE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) set_tsk_thread_flag(task, TIF_SINGLESTEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) void user_enable_block_step(struct task_struct *task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct pt_regs *regs = task->thread.regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (regs != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) regs->msr &= ~MSR_SE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) regs->msr |= MSR_BE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) set_tsk_thread_flag(task, TIF_SINGLESTEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) void user_disable_single_step(struct task_struct *task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct pt_regs *regs = task->thread.regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (regs != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) regs->msr &= ~(MSR_SE | MSR_BE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) clear_tsk_thread_flag(task, TIF_SINGLESTEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) dbginfo->version = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) dbginfo->num_instruction_bps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (ppc_breakpoint_available())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) dbginfo->num_data_bps = nr_wp_slots();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) dbginfo->num_data_bps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) dbginfo->num_condition_regs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) dbginfo->data_bp_alignment = sizeof(long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) dbginfo->sizeof_condition = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (IS_ENABLED(CONFIG_HAVE_HW_BREAKPOINT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) dbginfo->features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (dawr_enabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_DAWR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) dbginfo->features = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (cpu_has_feature(CPU_FTR_ARCH_31))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_ARCH_31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned long __user *datalp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) unsigned long dabr_fake;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* We only support one DABR and no IABRS at the moment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (addr > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) dabr_fake = ((child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) (child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return put_user(dabr_fake, datalp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * ptrace_set_debugreg() fakes DABR and DABR is only one. So even if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * internal hw supports more than one watchpoint, we support only one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * watchpoint with this interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct thread_struct *thread = &task->thread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct perf_event *bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct perf_event_attr attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) bool set_bp = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct arch_hw_breakpoint hw_brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * For embedded processors we support one DAC and no IAC's at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * moment.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (addr > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* The bottom 3 bits in dabr are flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if ((data & ~0x7UL) >= TASK_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* For processors using DABR (i.e. 970), the bottom 3 bits are flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * It was assumed, on previous implementations, that 3 bits were
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * passed together with the data address, fitting the design of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * DABR register, as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * bit 0: Read flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * bit 1: Write flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * bit 2: Breakpoint translation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Thus, we use them here as so.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Ensure breakpoint translation bit is set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (data && !(data & HW_BRK_TYPE_TRANSLATE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) hw_brk.address = data & (~HW_BRK_TYPE_DABR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) hw_brk.len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) hw_brk.hw_len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) set_bp = (data) && (hw_brk.type & HW_BRK_TYPE_RDWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) bp = thread->ptrace_bps[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!set_bp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (bp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unregister_hw_breakpoint(bp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) thread->ptrace_bps[0] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (bp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) attr = bp->attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) attr.bp_addr = hw_brk.address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) attr.bp_len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) arch_bp_generic_fields(hw_brk.type, &attr.bp_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Enable breakpoint */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) attr.disabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ret = modify_user_hw_breakpoint(bp, &attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) thread->ptrace_bps[0] = bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) thread->hw_brk[0] = hw_brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Create a new breakpoint request if one doesn't exist already */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) hw_breakpoint_init(&attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) attr.bp_addr = hw_brk.address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) attr.bp_len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) arch_bp_generic_fields(hw_brk.type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) &attr.bp_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) ptrace_triggered, NULL, task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (IS_ERR(bp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) thread->ptrace_bps[0] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return PTR_ERR(bp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #else /* !CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (set_bp && (!ppc_breakpoint_available()))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) task->thread.hw_brk[0] = hw_brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static int find_empty_ptrace_bp(struct thread_struct *thread)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) for (i = 0; i < nr_wp_slots(); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (!thread->ptrace_bps[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static int find_empty_hw_brk(struct thread_struct *thread)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) for (i = 0; i < nr_wp_slots(); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!thread->hw_brk[i].address)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct thread_struct *thread = &child->thread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct perf_event *bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct perf_event_attr attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) struct arch_hw_breakpoint brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (bp_info->version != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * We only support one data breakpoint
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if ((unsigned long)bp_info->addr >= TASK_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) brk.address = ALIGN_DOWN(bp_info->addr, HW_BREAKPOINT_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) brk.type = HW_BRK_TYPE_TRANSLATE | HW_BRK_TYPE_PRIV_ALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) brk.len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) brk.hw_len = DABR_MAX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) brk.type |= HW_BRK_TYPE_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) brk.type |= HW_BRK_TYPE_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) len = bp_info->addr2 - bp_info->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) len = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) i = find_empty_ptrace_bp(thread);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (i < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* Create a new breakpoint request if one doesn't exist already */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) hw_breakpoint_init(&attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) attr.bp_addr = (unsigned long)bp_info->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) attr.bp_len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) arch_bp_generic_fields(brk.type, &attr.bp_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) bp = register_user_hw_breakpoint(&attr, ptrace_triggered, NULL, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) thread->ptrace_bps[i] = bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (IS_ERR(bp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) thread->ptrace_bps[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return PTR_ERR(bp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return i + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) i = find_empty_hw_brk(&child->thread);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (i < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (!ppc_breakpoint_available())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) child->thread.hw_brk[i] = brk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return i + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) long ppc_del_hwdebug(struct task_struct *child, long data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) struct thread_struct *thread = &child->thread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct perf_event *bp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (data < 1 || data > nr_wp_slots())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) #ifdef CONFIG_HAVE_HW_BREAKPOINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) bp = thread->ptrace_bps[data - 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (bp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) unregister_hw_breakpoint(bp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) thread->ptrace_bps[data - 1] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) #else /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!(child->thread.hw_brk[data - 1].flags & HW_BRK_FLAG_DISABLED) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) child->thread.hw_brk[data - 1].address == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) child->thread.hw_brk[data - 1].address = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) child->thread.hw_brk[data - 1].type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) child->thread.hw_brk[data - 1].flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) #endif /* CONFIG_HAVE_HW_BREAKPOINT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }