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