1
2
3#include <linux/regset.h>
4#include <linux/hw_breakpoint.h>
5
6#include "ptrace-decl.h"
7
8void user_enable_single_step(struct task_struct *task)
9{
10 struct pt_regs *regs = task->thread.regs;
11
12 if (regs != NULL) {
13 task->thread.debug.dbcr0 &= ~DBCR0_BT;
14 task->thread.debug.dbcr0 |= DBCR0_IDM | DBCR0_IC;
15 regs_set_return_msr(regs, regs->msr | MSR_DE);
16 }
17 set_tsk_thread_flag(task, TIF_SINGLESTEP);
18}
19
20void user_enable_block_step(struct task_struct *task)
21{
22 struct pt_regs *regs = task->thread.regs;
23
24 if (regs != NULL) {
25 task->thread.debug.dbcr0 &= ~DBCR0_IC;
26 task->thread.debug.dbcr0 = DBCR0_IDM | DBCR0_BT;
27 regs_set_return_msr(regs, regs->msr | MSR_DE);
28 }
29 set_tsk_thread_flag(task, TIF_SINGLESTEP);
30}
31
32void user_disable_single_step(struct task_struct *task)
33{
34 struct pt_regs *regs = task->thread.regs;
35
36 if (regs != NULL) {
37
38
39
40
41
42
43 task->thread.debug.dbcr0 &= ~(DBCR0_IC | DBCR0_BT);
44
45
46
47 if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
48 task->thread.debug.dbcr1)) {
49
50
51
52 task->thread.debug.dbcr0 &= ~DBCR0_IDM;
53 regs_set_return_msr(regs, regs->msr & ~MSR_DE);
54 }
55 }
56 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
57}
58
59void ppc_gethwdinfo(struct ppc_debug_info *dbginfo)
60{
61 dbginfo->version = 1;
62 dbginfo->num_instruction_bps = CONFIG_PPC_ADV_DEBUG_IACS;
63 dbginfo->num_data_bps = CONFIG_PPC_ADV_DEBUG_DACS;
64 dbginfo->num_condition_regs = CONFIG_PPC_ADV_DEBUG_DVCS;
65 dbginfo->data_bp_alignment = 4;
66 dbginfo->sizeof_condition = 4;
67 dbginfo->features = PPC_DEBUG_FEATURE_INSN_BP_RANGE |
68 PPC_DEBUG_FEATURE_INSN_BP_MASK;
69 if (IS_ENABLED(CONFIG_PPC_ADV_DEBUG_DAC_RANGE))
70 dbginfo->features |= PPC_DEBUG_FEATURE_DATA_BP_RANGE |
71 PPC_DEBUG_FEATURE_DATA_BP_MASK;
72}
73
74int ptrace_get_debugreg(struct task_struct *child, unsigned long addr,
75 unsigned long __user *datalp)
76{
77
78 if (addr > 0)
79 return -EINVAL;
80 return put_user(child->thread.debug.dac1, datalp);
81}
82
83int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, unsigned long data)
84{
85 struct pt_regs *regs = task->thread.regs;
86#ifdef CONFIG_HAVE_HW_BREAKPOINT
87 int ret;
88 struct thread_struct *thread = &task->thread;
89 struct perf_event *bp;
90 struct perf_event_attr attr;
91#endif
92
93
94
95
96
97 if (addr > 0)
98 return -EINVAL;
99
100
101 if ((data & ~0x7UL) >= TASK_SIZE)
102 return -EIO;
103
104
105
106
107
108
109
110 task->thread.debug.dac1 = data & ~0x3UL;
111
112 if (task->thread.debug.dac1 == 0) {
113 dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
114 if (!DBCR_ACTIVE_EVENTS(task->thread.debug.dbcr0,
115 task->thread.debug.dbcr1)) {
116 regs_set_return_msr(regs, regs->msr & ~MSR_DE);
117 task->thread.debug.dbcr0 &= ~DBCR0_IDM;
118 }
119 return 0;
120 }
121
122
123
124 if (!(data & 0x3UL))
125 return -EINVAL;
126
127
128 task->thread.debug.dbcr0 |= DBCR0_IDM;
129
130
131 dbcr_dac(task) &= ~(DBCR_DAC1R | DBCR_DAC1W);
132 if (data & 0x1UL)
133 dbcr_dac(task) |= DBCR_DAC1R;
134 if (data & 0x2UL)
135 dbcr_dac(task) |= DBCR_DAC1W;
136 regs_set_return_msr(regs, regs->msr | MSR_DE);
137 return 0;
138}
139
140static long set_instruction_bp(struct task_struct *child,
141 struct ppc_hw_breakpoint *bp_info)
142{
143 int slot;
144 int slot1_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC1) != 0);
145 int slot2_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC2) != 0);
146 int slot3_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC3) != 0);
147 int slot4_in_use = ((child->thread.debug.dbcr0 & DBCR0_IAC4) != 0);
148
149 if (dbcr_iac_range(child) & DBCR_IAC12MODE)
150 slot2_in_use = 1;
151 if (dbcr_iac_range(child) & DBCR_IAC34MODE)
152 slot4_in_use = 1;
153
154 if (bp_info->addr >= TASK_SIZE)
155 return -EIO;
156
157 if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
158
159 if (bp_info->addr2 >= TASK_SIZE)
160 return -EIO;
161
162
163 if (!slot1_in_use && !slot2_in_use) {
164 slot = 1;
165 child->thread.debug.iac1 = bp_info->addr;
166 child->thread.debug.iac2 = bp_info->addr2;
167 child->thread.debug.dbcr0 |= DBCR0_IAC1;
168 if (bp_info->addr_mode ==
169 PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
170 dbcr_iac_range(child) |= DBCR_IAC12X;
171 else
172 dbcr_iac_range(child) |= DBCR_IAC12I;
173#if CONFIG_PPC_ADV_DEBUG_IACS > 2
174 } else if ((!slot3_in_use) && (!slot4_in_use)) {
175 slot = 3;
176 child->thread.debug.iac3 = bp_info->addr;
177 child->thread.debug.iac4 = bp_info->addr2;
178 child->thread.debug.dbcr0 |= DBCR0_IAC3;
179 if (bp_info->addr_mode ==
180 PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
181 dbcr_iac_range(child) |= DBCR_IAC34X;
182 else
183 dbcr_iac_range(child) |= DBCR_IAC34I;
184#endif
185 } else {
186 return -ENOSPC;
187 }
188 } else {
189
190
191
192 if (!slot1_in_use) {
193
194
195
196
197 if (slot2_in_use || slot3_in_use == slot4_in_use) {
198 slot = 1;
199 child->thread.debug.iac1 = bp_info->addr;
200 child->thread.debug.dbcr0 |= DBCR0_IAC1;
201 goto out;
202 }
203 }
204 if (!slot2_in_use) {
205 slot = 2;
206 child->thread.debug.iac2 = bp_info->addr;
207 child->thread.debug.dbcr0 |= DBCR0_IAC2;
208#if CONFIG_PPC_ADV_DEBUG_IACS > 2
209 } else if (!slot3_in_use) {
210 slot = 3;
211 child->thread.debug.iac3 = bp_info->addr;
212 child->thread.debug.dbcr0 |= DBCR0_IAC3;
213 } else if (!slot4_in_use) {
214 slot = 4;
215 child->thread.debug.iac4 = bp_info->addr;
216 child->thread.debug.dbcr0 |= DBCR0_IAC4;
217#endif
218 } else {
219 return -ENOSPC;
220 }
221 }
222out:
223 child->thread.debug.dbcr0 |= DBCR0_IDM;
224 regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
225
226 return slot;
227}
228
229static int del_instruction_bp(struct task_struct *child, int slot)
230{
231 switch (slot) {
232 case 1:
233 if ((child->thread.debug.dbcr0 & DBCR0_IAC1) == 0)
234 return -ENOENT;
235
236 if (dbcr_iac_range(child) & DBCR_IAC12MODE) {
237
238 child->thread.debug.iac2 = 0;
239 dbcr_iac_range(child) &= ~DBCR_IAC12MODE;
240 }
241 child->thread.debug.iac1 = 0;
242 child->thread.debug.dbcr0 &= ~DBCR0_IAC1;
243 break;
244 case 2:
245 if ((child->thread.debug.dbcr0 & DBCR0_IAC2) == 0)
246 return -ENOENT;
247
248 if (dbcr_iac_range(child) & DBCR_IAC12MODE)
249
250 return -EINVAL;
251 child->thread.debug.iac2 = 0;
252 child->thread.debug.dbcr0 &= ~DBCR0_IAC2;
253 break;
254#if CONFIG_PPC_ADV_DEBUG_IACS > 2
255 case 3:
256 if ((child->thread.debug.dbcr0 & DBCR0_IAC3) == 0)
257 return -ENOENT;
258
259 if (dbcr_iac_range(child) & DBCR_IAC34MODE) {
260
261 child->thread.debug.iac4 = 0;
262 dbcr_iac_range(child) &= ~DBCR_IAC34MODE;
263 }
264 child->thread.debug.iac3 = 0;
265 child->thread.debug.dbcr0 &= ~DBCR0_IAC3;
266 break;
267 case 4:
268 if ((child->thread.debug.dbcr0 & DBCR0_IAC4) == 0)
269 return -ENOENT;
270
271 if (dbcr_iac_range(child) & DBCR_IAC34MODE)
272
273 return -EINVAL;
274 child->thread.debug.iac4 = 0;
275 child->thread.debug.dbcr0 &= ~DBCR0_IAC4;
276 break;
277#endif
278 default:
279 return -EINVAL;
280 }
281 return 0;
282}
283
284static int set_dac(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
285{
286 int byte_enable =
287 (bp_info->condition_mode >> PPC_BREAKPOINT_CONDITION_BE_SHIFT)
288 & 0xf;
289 int condition_mode =
290 bp_info->condition_mode & PPC_BREAKPOINT_CONDITION_MODE;
291 int slot;
292
293 if (byte_enable && condition_mode == 0)
294 return -EINVAL;
295
296 if (bp_info->addr >= TASK_SIZE)
297 return -EIO;
298
299 if ((dbcr_dac(child) & (DBCR_DAC1R | DBCR_DAC1W)) == 0) {
300 slot = 1;
301 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
302 dbcr_dac(child) |= DBCR_DAC1R;
303 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
304 dbcr_dac(child) |= DBCR_DAC1W;
305 child->thread.debug.dac1 = (unsigned long)bp_info->addr;
306#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
307 if (byte_enable) {
308 child->thread.debug.dvc1 =
309 (unsigned long)bp_info->condition_value;
310 child->thread.debug.dbcr2 |=
311 ((byte_enable << DBCR2_DVC1BE_SHIFT) |
312 (condition_mode << DBCR2_DVC1M_SHIFT));
313 }
314#endif
315#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
316 } else if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
317
318 return -ENOSPC;
319#endif
320 } else if ((dbcr_dac(child) & (DBCR_DAC2R | DBCR_DAC2W)) == 0) {
321 slot = 2;
322 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
323 dbcr_dac(child) |= DBCR_DAC2R;
324 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
325 dbcr_dac(child) |= DBCR_DAC2W;
326 child->thread.debug.dac2 = (unsigned long)bp_info->addr;
327#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
328 if (byte_enable) {
329 child->thread.debug.dvc2 =
330 (unsigned long)bp_info->condition_value;
331 child->thread.debug.dbcr2 |=
332 ((byte_enable << DBCR2_DVC2BE_SHIFT) |
333 (condition_mode << DBCR2_DVC2M_SHIFT));
334 }
335#endif
336 } else {
337 return -ENOSPC;
338 }
339 child->thread.debug.dbcr0 |= DBCR0_IDM;
340 regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
341
342 return slot + 4;
343}
344
345static int del_dac(struct task_struct *child, int slot)
346{
347 if (slot == 1) {
348 if ((dbcr_dac(child) & (DBCR_DAC1R | DBCR_DAC1W)) == 0)
349 return -ENOENT;
350
351 child->thread.debug.dac1 = 0;
352 dbcr_dac(child) &= ~(DBCR_DAC1R | DBCR_DAC1W);
353#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
354 if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE) {
355 child->thread.debug.dac2 = 0;
356 child->thread.debug.dbcr2 &= ~DBCR2_DAC12MODE;
357 }
358 child->thread.debug.dbcr2 &= ~(DBCR2_DVC1M | DBCR2_DVC1BE);
359#endif
360#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
361 child->thread.debug.dvc1 = 0;
362#endif
363 } else if (slot == 2) {
364 if ((dbcr_dac(child) & (DBCR_DAC2R | DBCR_DAC2W)) == 0)
365 return -ENOENT;
366
367#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
368 if (child->thread.debug.dbcr2 & DBCR2_DAC12MODE)
369
370 return -EINVAL;
371 child->thread.debug.dbcr2 &= ~(DBCR2_DVC2M | DBCR2_DVC2BE);
372#endif
373#if CONFIG_PPC_ADV_DEBUG_DVCS > 0
374 child->thread.debug.dvc2 = 0;
375#endif
376 child->thread.debug.dac2 = 0;
377 dbcr_dac(child) &= ~(DBCR_DAC2R | DBCR_DAC2W);
378 } else {
379 return -EINVAL;
380 }
381
382 return 0;
383}
384
385#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
386static int set_dac_range(struct task_struct *child,
387 struct ppc_hw_breakpoint *bp_info)
388{
389 int mode = bp_info->addr_mode & PPC_BREAKPOINT_MODE_MASK;
390
391
392 if (bp_info->condition_mode)
393 return -EINVAL;
394
395
396
397
398
399
400
401 if (bp_info->addr >= TASK_SIZE)
402 return -EIO;
403 if (mode == PPC_BREAKPOINT_MODE_MASK) {
404
405
406
407
408 if (~((unsigned long)bp_info->addr2) >= TASK_SIZE)
409 return -EIO;
410 } else {
411
412
413
414 if (bp_info->addr2 >= TASK_SIZE)
415 return -EIO;
416 }
417
418 if (child->thread.debug.dbcr0 &
419 (DBCR0_DAC1R | DBCR0_DAC1W | DBCR0_DAC2R | DBCR0_DAC2W))
420 return -ENOSPC;
421
422 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ)
423 child->thread.debug.dbcr0 |= (DBCR0_DAC1R | DBCR0_IDM);
424 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
425 child->thread.debug.dbcr0 |= (DBCR0_DAC1W | DBCR0_IDM);
426 child->thread.debug.dac1 = bp_info->addr;
427 child->thread.debug.dac2 = bp_info->addr2;
428 if (mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
429 child->thread.debug.dbcr2 |= DBCR2_DAC12M;
430 else if (mode == PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE)
431 child->thread.debug.dbcr2 |= DBCR2_DAC12MX;
432 else
433 child->thread.debug.dbcr2 |= DBCR2_DAC12MM;
434 regs_set_return_msr(child->thread.regs, child->thread.regs->msr | MSR_DE);
435
436 return 5;
437}
438#endif
439
440long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_info)
441{
442 if (bp_info->version != 1)
443 return -ENOTSUPP;
444
445
446
447 if (bp_info->trigger_type == 0 ||
448 (bp_info->trigger_type & ~(PPC_BREAKPOINT_TRIGGER_EXECUTE |
449 PPC_BREAKPOINT_TRIGGER_RW)) ||
450 (bp_info->addr_mode & ~PPC_BREAKPOINT_MODE_MASK) ||
451 (bp_info->condition_mode &
452 ~(PPC_BREAKPOINT_CONDITION_MODE |
453 PPC_BREAKPOINT_CONDITION_BE_ALL)))
454 return -EINVAL;
455#if CONFIG_PPC_ADV_DEBUG_DVCS == 0
456 if (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
457 return -EINVAL;
458#endif
459
460 if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_EXECUTE) {
461 if (bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_EXECUTE ||
462 bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
463 return -EINVAL;
464 return set_instruction_bp(child, bp_info);
465 }
466 if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
467 return set_dac(child, bp_info);
468
469#ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE
470 return set_dac_range(child, bp_info);
471#else
472 return -EINVAL;
473#endif
474}
475
476long ppc_del_hwdebug(struct task_struct *child, long data)
477{
478 int rc;
479
480 if (data <= 4)
481 rc = del_instruction_bp(child, (int)data);
482 else
483 rc = del_dac(child, (int)data - 4);
484
485 if (!rc) {
486 if (!DBCR_ACTIVE_EVENTS(child->thread.debug.dbcr0,
487 child->thread.debug.dbcr1)) {
488 child->thread.debug.dbcr0 &= ~DBCR0_IDM;
489 regs_set_return_msr(child->thread.regs,
490 child->thread.regs->msr & ~MSR_DE);
491 }
492 }
493 return rc;
494}
495