Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 #include <linux/regset.h>
0004 #include <linux/hw_breakpoint.h>
0005 
0006 #include <asm/debug.h>
0007 
0008 #include "ptrace-decl.h"
0009 
0010 void user_enable_single_step(struct task_struct *task)
0011 {
0012     struct pt_regs *regs = task->thread.regs;
0013 
0014     if (regs != NULL)
0015         regs_set_return_msr(regs, (regs->msr & ~MSR_BE) | MSR_SE);
0016     set_tsk_thread_flag(task, TIF_SINGLESTEP);
0017 }
0018 
0019 void user_enable_block_step(struct task_struct *task)
0020 {
0021     struct pt_regs *regs = task->thread.regs;
0022 
0023     if (regs != NULL)
0024         regs_set_return_msr(regs, (regs->msr & ~MSR_SE) | MSR_BE);
0025     set_tsk_thread_flag(task, TIF_SINGLESTEP);
0026 }
0027 
0028 void user_disable_single_step(struct task_struct *task)
0029 {
0030     struct pt_regs *regs = task->thread.regs;
0031 
0032     if (regs != NULL)
0033         regs_set_return_msr(regs, regs->msr & ~(MSR_SE | MSR_BE));
0034 
0035     clear_tsk_thread_flag(task, TIF_SINGLESTEP);
0036 }
0037 
0038 void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
0039 {
0040     dbginfo->version = 1;
0041     dbginfo->num_instruction_bps = 0;
0042     if (ppc_breakpoint_available())
0043         dbginfo->num_data_bps = nr_wp_slots();
0044     else
0045         dbginfo->num_data_bps = 0;
0046     dbginfo->num_condition_regs = 0;
0047     dbginfo->data_bp_alignment = sizeof(long);
0048     dbginfo->sizeof_condition = 0;
0049     if (IS_ENABLED(CONFIG_HAVE_HW_BREAKPOINT)) {
0050         dbginfo->features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
0051         if (dawr_enabled())
0052             dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_DAWR;
0053     } else {
0054         dbginfo->features = 0;
0055     }
0056     if (cpu_has_feature(CPU_FTR_ARCH_31))
0057         dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_ARCH_31;
0058 }
0059 
0060 int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
0061             unsigned long __user *datalp)
0062 {
0063     unsigned long dabr_fake;
0064 
0065     /* We only support one DABR and no IABRS at the moment */
0066     if (addr > 0)
0067         return -EINVAL;
0068     dabr_fake = ((child->thread.hw_brk[0].address & (~HW_BRK_TYPE_DABR)) |
0069              (child->thread.hw_brk[0].type & HW_BRK_TYPE_DABR));
0070     return put_user(dabr_fake, datalp);
0071 }
0072 
0073 /*
0074  * ptrace_set_debugreg() fakes DABR and DABR is only one. So even if
0075  * internal hw supports more than one watchpoint, we support only one
0076  * watchpoint with this interface.
0077  */
0078 int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
0079 {
0080 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0081     int ret;
0082     struct thread_struct *thread = &task->thread;
0083     struct perf_event *bp;
0084     struct perf_event_attr attr;
0085 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0086     bool set_bp = true;
0087     struct arch_hw_breakpoint hw_brk;
0088 
0089     /* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
0090      *  For embedded processors we support one DAC and no IAC's at the
0091      *  moment.
0092      */
0093     if (addr > 0)
0094         return -EINVAL;
0095 
0096     /* The bottom 3 bits in dabr are flags */
0097     if ((data & ~0x7UL) >= TASK_SIZE)
0098         return -EIO;
0099 
0100     /* For processors using DABR (i.e. 970), the bottom 3 bits are flags.
0101      *  It was assumed, on previous implementations, that 3 bits were
0102      *  passed together with the data address, fitting the design of the
0103      *  DABR register, as follows:
0104      *
0105      *  bit 0: Read flag
0106      *  bit 1: Write flag
0107      *  bit 2: Breakpoint translation
0108      *
0109      *  Thus, we use them here as so.
0110      */
0111 
0112     /* Ensure breakpoint translation bit is set */
0113     if (data && !(data & HW_BRK_TYPE_TRANSLATE))
0114         return -EIO;
0115     hw_brk.address = data & (~HW_BRK_TYPE_DABR);
0116     hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
0117     hw_brk.len = DABR_MAX_LEN;
0118     hw_brk.hw_len = DABR_MAX_LEN;
0119     set_bp = (data) && (hw_brk.type & HW_BRK_TYPE_RDWR);
0120 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0121     bp = thread->ptrace_bps[0];
0122     if (!set_bp) {
0123         if (bp) {
0124             unregister_hw_breakpoint(bp);
0125             thread->ptrace_bps[0] = NULL;
0126         }
0127         return 0;
0128     }
0129     if (bp) {
0130         attr = bp->attr;
0131         attr.bp_addr = hw_brk.address;
0132         attr.bp_len = DABR_MAX_LEN;
0133         arch_bp_generic_fields(hw_brk.type, &attr.bp_type);
0134 
0135         /* Enable breakpoint */
0136         attr.disabled = false;
0137 
0138         ret =  modify_user_hw_breakpoint(bp, &attr);
0139         if (ret)
0140             return ret;
0141 
0142         thread->ptrace_bps[0] = bp;
0143         thread->hw_brk[0] = hw_brk;
0144         return 0;
0145     }
0146 
0147     /* Create a new breakpoint request if one doesn't exist already */
0148     hw_breakpoint_init(&attr);
0149     attr.bp_addr = hw_brk.address;
0150     attr.bp_len = DABR_MAX_LEN;
0151     arch_bp_generic_fields(hw_brk.type,
0152                    &attr.bp_type);
0153 
0154     thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
0155                            ptrace_triggered, NULL, task);
0156     if (IS_ERR(bp)) {
0157         thread->ptrace_bps[0] = NULL;
0158         return PTR_ERR(bp);
0159     }
0160 
0161 #else /* !CONFIG_HAVE_HW_BREAKPOINT */
0162     if (set_bp && (!ppc_breakpoint_available()))
0163         return -ENODEV;
0164 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0165     task->thread.hw_brk[0] = hw_brk;
0166     return 0;
0167 }
0168 
0169 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0170 static int find_empty_ptrace_bp(struct thread_struct *thread)
0171 {
0172     int i;
0173 
0174     for (i = 0; i < nr_wp_slots(); i++) {
0175         if (!thread->ptrace_bps[i])
0176             return i;
0177     }
0178     return -1;
0179 }
0180 #endif
0181 
0182 static int find_empty_hw_brk(struct thread_struct *thread)
0183 {
0184     int i;
0185 
0186     for (i = 0; i < nr_wp_slots(); i++) {
0187         if (!thread->hw_brk[i].address)
0188             return i;
0189     }
0190     return -1;
0191 }
0192 
0193 long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
0194 {
0195     int i;
0196 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0197     int len = 0;
0198     struct thread_struct *thread = &child->thread;
0199     struct perf_event *bp;
0200     struct perf_event_attr attr;
0201 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0202     struct arch_hw_breakpoint brk;
0203 
0204     if (bp_info->version != 1)
0205         return -ENOTSUPP;
0206     /*
0207      * We only support one data breakpoint
0208      */
0209     if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
0210         (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
0211         bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
0212         return -EINVAL;
0213 
0214     if ((unsigned long)bp_info->addr >= TASK_SIZE)
0215         return -EIO;
0216 
0217     brk.address = ALIGN_DOWN(bp_info->addr, HW_BREAKPOINT_SIZE);
0218     brk.type = HW_BRK_TYPE_TRANSLATE | HW_BRK_TYPE_PRIV_ALL;
0219     brk.len = DABR_MAX_LEN;
0220     brk.hw_len = DABR_MAX_LEN;
0221     if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
0222         brk.type |= HW_BRK_TYPE_READ;
0223     if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
0224         brk.type |= HW_BRK_TYPE_WRITE;
0225 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0226     if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
0227         len = bp_info->addr2 - bp_info->addr;
0228     else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
0229         len = 1;
0230     else
0231         return -EINVAL;
0232 
0233     i = find_empty_ptrace_bp(thread);
0234     if (i < 0)
0235         return -ENOSPC;
0236 
0237     /* Create a new breakpoint request if one doesn't exist already */
0238     hw_breakpoint_init(&attr);
0239     attr.bp_addr = (unsigned long)bp_info->addr;
0240     attr.bp_len = len;
0241     arch_bp_generic_fields(brk.type, &attr.bp_type);
0242 
0243     bp = register_user_hw_breakpoint(&attr, ptrace_triggered, NULL, child);
0244     thread->ptrace_bps[i] = bp;
0245     if (IS_ERR(bp)) {
0246         thread->ptrace_bps[i] = NULL;
0247         return PTR_ERR(bp);
0248     }
0249 
0250     return i + 1;
0251 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0252 
0253     if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
0254         return -EINVAL;
0255 
0256     i = find_empty_hw_brk(&child->thread);
0257     if (i < 0)
0258         return -ENOSPC;
0259 
0260     if (!ppc_breakpoint_available())
0261         return -ENODEV;
0262 
0263     child->thread.hw_brk[i] = brk;
0264 
0265     return i + 1;
0266 }
0267 
0268 long ppc_del_hwdebug(struct task_struct *child, long data)
0269 {
0270 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0271     int ret = 0;
0272     struct thread_struct *thread = &child->thread;
0273     struct perf_event *bp;
0274 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0275     if (data < 1 || data > nr_wp_slots())
0276         return -EINVAL;
0277 
0278 #ifdef CONFIG_HAVE_HW_BREAKPOINT
0279     bp = thread->ptrace_bps[data - 1];
0280     if (bp) {
0281         unregister_hw_breakpoint(bp);
0282         thread->ptrace_bps[data - 1] = NULL;
0283     } else {
0284         ret = -ENOENT;
0285     }
0286     return ret;
0287 #else /* CONFIG_HAVE_HW_BREAKPOINT */
0288     if (!(child->thread.hw_brk[data - 1].flags & HW_BRK_FLAG_DISABLED) &&
0289         child->thread.hw_brk[data - 1].address == 0)
0290         return -ENOENT;
0291 
0292     child->thread.hw_brk[data - 1].address = 0;
0293     child->thread.hw_brk[data - 1].type = 0;
0294     child->thread.hw_brk[data - 1].flags = 0;
0295 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
0296 
0297     return 0;
0298 }