1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <linux/irqflags.h>
34#include <linux/kallsyms.h>
35#include <linux/notifier.h>
36#include <linux/kprobes.h>
37#include <linux/kdebug.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/percpu.h>
41#include <linux/sched.h>
42#include <linux/init.h>
43#include <linux/slab.h>
44#include <linux/list.h>
45#include <linux/cpu.h>
46#include <linux/smp.h>
47
48#include <linux/hw_breakpoint.h>
49
50
51
52
53
54
55
56static DEFINE_PER_CPU(unsigned int, nr_cpu_bp_pinned[TYPE_MAX]);
57
58
59static DEFINE_PER_CPU(unsigned int *, nr_task_bp_pinned[TYPE_MAX]);
60
61
62static DEFINE_PER_CPU(unsigned int, nr_bp_flexible[TYPE_MAX]);
63
64static int nr_slots[TYPE_MAX];
65
66
67static LIST_HEAD(bp_task_head);
68
69static int constraints_initialized;
70
71
72struct bp_busy_slots {
73 unsigned int pinned;
74 unsigned int flexible;
75};
76
77
78static DEFINE_MUTEX(nr_bp_mutex);
79
80__weak int hw_breakpoint_weight(struct perf_event *bp)
81{
82 return 1;
83}
84
85static inline enum bp_type_idx find_slot_idx(struct perf_event *bp)
86{
87 if (bp->attr.bp_type & HW_BREAKPOINT_RW)
88 return TYPE_DATA;
89
90 return TYPE_INST;
91}
92
93
94
95
96
97static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
98{
99 int i;
100 unsigned int *tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);
101
102 for (i = nr_slots[type] - 1; i >= 0; i--) {
103 if (tsk_pinned[i] > 0)
104 return i + 1;
105 }
106
107 return 0;
108}
109
110
111
112
113
114static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type)
115{
116 struct task_struct *tsk = bp->hw.bp_target;
117 struct perf_event *iter;
118 int count = 0;
119
120 list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
121 if (iter->hw.bp_target == tsk && find_slot_idx(iter) == type)
122 count += hw_breakpoint_weight(iter);
123 }
124
125 return count;
126}
127
128
129
130
131
132static void
133fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
134 enum bp_type_idx type)
135{
136 int cpu = bp->cpu;
137 struct task_struct *tsk = bp->hw.bp_target;
138
139 if (cpu >= 0) {
140 slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu);
141 if (!tsk)
142 slots->pinned += max_task_bp_pinned(cpu, type);
143 else
144 slots->pinned += task_bp_pinned(bp, type);
145 slots->flexible = per_cpu(nr_bp_flexible[type], cpu);
146
147 return;
148 }
149
150 for_each_online_cpu(cpu) {
151 unsigned int nr;
152
153 nr = per_cpu(nr_cpu_bp_pinned[type], cpu);
154 if (!tsk)
155 nr += max_task_bp_pinned(cpu, type);
156 else
157 nr += task_bp_pinned(bp, type);
158
159 if (nr > slots->pinned)
160 slots->pinned = nr;
161
162 nr = per_cpu(nr_bp_flexible[type], cpu);
163
164 if (nr > slots->flexible)
165 slots->flexible = nr;
166 }
167}
168
169
170
171
172
173
174static void
175fetch_this_slot(struct bp_busy_slots *slots, int weight)
176{
177 slots->pinned += weight;
178}
179
180
181
182
183static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable,
184 enum bp_type_idx type, int weight)
185{
186 unsigned int *tsk_pinned;
187 int old_count = 0;
188 int old_idx = 0;
189 int idx = 0;
190
191 old_count = task_bp_pinned(bp, type);
192 old_idx = old_count - 1;
193 idx = old_idx + weight;
194
195
196 tsk_pinned = per_cpu(nr_task_bp_pinned[type], cpu);
197 if (enable) {
198 tsk_pinned[idx]++;
199 if (old_count > 0)
200 tsk_pinned[old_idx]--;
201 } else {
202 tsk_pinned[idx]--;
203 if (old_count > 0)
204 tsk_pinned[old_idx]++;
205 }
206}
207
208
209
210
211static void
212toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
213 int weight)
214{
215 int cpu = bp->cpu;
216 struct task_struct *tsk = bp->hw.bp_target;
217
218
219 if (!tsk) {
220
221 if (enable)
222 per_cpu(nr_cpu_bp_pinned[type], bp->cpu) += weight;
223 else
224 per_cpu(nr_cpu_bp_pinned[type], bp->cpu) -= weight;
225 return;
226 }
227
228
229
230 if (!enable)
231 list_del(&bp->hw.bp_list);
232
233 if (cpu >= 0) {
234 toggle_bp_task_slot(bp, cpu, enable, type, weight);
235 } else {
236 for_each_online_cpu(cpu)
237 toggle_bp_task_slot(bp, cpu, enable, type, weight);
238 }
239
240 if (enable)
241 list_add_tail(&bp->hw.bp_list, &bp_task_head);
242}
243
244
245
246
247__weak void arch_unregister_hw_breakpoint(struct perf_event *bp)
248{
249
250
251
252
253}
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296static int __reserve_bp_slot(struct perf_event *bp)
297{
298 struct bp_busy_slots slots = {0};
299 enum bp_type_idx type;
300 int weight;
301
302
303 if (!constraints_initialized)
304 return -ENOMEM;
305
306
307 if (bp->attr.bp_type == HW_BREAKPOINT_EMPTY ||
308 bp->attr.bp_type == HW_BREAKPOINT_INVALID)
309 return -EINVAL;
310
311 type = find_slot_idx(bp);
312 weight = hw_breakpoint_weight(bp);
313
314 fetch_bp_busy_slots(&slots, bp, type);
315
316
317
318
319 fetch_this_slot(&slots, weight);
320
321
322 if (slots.pinned + (!!slots.flexible) > nr_slots[type])
323 return -ENOSPC;
324
325 toggle_bp_slot(bp, true, type, weight);
326
327 return 0;
328}
329
330int reserve_bp_slot(struct perf_event *bp)
331{
332 int ret;
333
334 mutex_lock(&nr_bp_mutex);
335
336 ret = __reserve_bp_slot(bp);
337
338 mutex_unlock(&nr_bp_mutex);
339
340 return ret;
341}
342
343static void __release_bp_slot(struct perf_event *bp)
344{
345 enum bp_type_idx type;
346 int weight;
347
348 type = find_slot_idx(bp);
349 weight = hw_breakpoint_weight(bp);
350 toggle_bp_slot(bp, false, type, weight);
351}
352
353void release_bp_slot(struct perf_event *bp)
354{
355 mutex_lock(&nr_bp_mutex);
356
357 arch_unregister_hw_breakpoint(bp);
358 __release_bp_slot(bp);
359
360 mutex_unlock(&nr_bp_mutex);
361}
362
363
364
365
366
367
368int dbg_reserve_bp_slot(struct perf_event *bp)
369{
370 if (mutex_is_locked(&nr_bp_mutex))
371 return -1;
372
373 return __reserve_bp_slot(bp);
374}
375
376int dbg_release_bp_slot(struct perf_event *bp)
377{
378 if (mutex_is_locked(&nr_bp_mutex))
379 return -1;
380
381 __release_bp_slot(bp);
382
383 return 0;
384}
385
386static int validate_hw_breakpoint(struct perf_event *bp)
387{
388 int ret;
389
390 ret = arch_validate_hwbkpt_settings(bp);
391 if (ret)
392 return ret;
393
394 if (arch_check_bp_in_kernelspace(bp)) {
395 if (bp->attr.exclude_kernel)
396 return -EINVAL;
397
398
399
400
401 if (!capable(CAP_SYS_ADMIN))
402 return -EPERM;
403 }
404
405 return 0;
406}
407
408int register_perf_hw_breakpoint(struct perf_event *bp)
409{
410 int ret;
411
412 ret = reserve_bp_slot(bp);
413 if (ret)
414 return ret;
415
416 ret = validate_hw_breakpoint(bp);
417
418
419 if (ret)
420 release_bp_slot(bp);
421
422 return ret;
423}
424
425
426
427
428
429
430
431struct perf_event *
432register_user_hw_breakpoint(struct perf_event_attr *attr,
433 perf_overflow_handler_t triggered,
434 void *context,
435 struct task_struct *tsk)
436{
437 return perf_event_create_kernel_counter(attr, -1, tsk, triggered,
438 context);
439}
440EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
441
442
443
444
445
446
447
448
449int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
450{
451 u64 old_addr = bp->attr.bp_addr;
452 u64 old_len = bp->attr.bp_len;
453 int old_type = bp->attr.bp_type;
454 int err = 0;
455
456
457
458
459
460
461
462 if (irqs_disabled() && bp->ctx && bp->ctx->task == current)
463 __perf_event_disable(bp);
464 else
465 perf_event_disable(bp);
466
467 bp->attr.bp_addr = attr->bp_addr;
468 bp->attr.bp_type = attr->bp_type;
469 bp->attr.bp_len = attr->bp_len;
470
471 if (attr->disabled)
472 goto end;
473
474 err = validate_hw_breakpoint(bp);
475 if (!err)
476 perf_event_enable(bp);
477
478 if (err) {
479 bp->attr.bp_addr = old_addr;
480 bp->attr.bp_type = old_type;
481 bp->attr.bp_len = old_len;
482 if (!bp->attr.disabled)
483 perf_event_enable(bp);
484
485 return err;
486 }
487
488end:
489 bp->attr.disabled = attr->disabled;
490
491 return 0;
492}
493EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
494
495
496
497
498
499void unregister_hw_breakpoint(struct perf_event *bp)
500{
501 if (!bp)
502 return;
503 perf_event_release_kernel(bp);
504}
505EXPORT_SYMBOL_GPL(unregister_hw_breakpoint);
506
507
508
509
510
511
512
513
514struct perf_event * __percpu *
515register_wide_hw_breakpoint(struct perf_event_attr *attr,
516 perf_overflow_handler_t triggered,
517 void *context)
518{
519 struct perf_event * __percpu *cpu_events, **pevent, *bp;
520 long err;
521 int cpu;
522
523 cpu_events = alloc_percpu(typeof(*cpu_events));
524 if (!cpu_events)
525 return (void __percpu __force *)ERR_PTR(-ENOMEM);
526
527 get_online_cpus();
528 for_each_online_cpu(cpu) {
529 pevent = per_cpu_ptr(cpu_events, cpu);
530 bp = perf_event_create_kernel_counter(attr, cpu, NULL,
531 triggered, context);
532
533 *pevent = bp;
534
535 if (IS_ERR(bp)) {
536 err = PTR_ERR(bp);
537 goto fail;
538 }
539 }
540 put_online_cpus();
541
542 return cpu_events;
543
544fail:
545 for_each_online_cpu(cpu) {
546 pevent = per_cpu_ptr(cpu_events, cpu);
547 if (IS_ERR(*pevent))
548 break;
549 unregister_hw_breakpoint(*pevent);
550 }
551 put_online_cpus();
552
553 free_percpu(cpu_events);
554 return (void __percpu __force *)ERR_PTR(err);
555}
556EXPORT_SYMBOL_GPL(register_wide_hw_breakpoint);
557
558
559
560
561
562void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events)
563{
564 int cpu;
565 struct perf_event **pevent;
566
567 for_each_possible_cpu(cpu) {
568 pevent = per_cpu_ptr(cpu_events, cpu);
569 unregister_hw_breakpoint(*pevent);
570 }
571 free_percpu(cpu_events);
572}
573EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint);
574
575static struct notifier_block hw_breakpoint_exceptions_nb = {
576 .notifier_call = hw_breakpoint_exceptions_notify,
577
578 .priority = 0x7fffffff
579};
580
581static void bp_perf_event_destroy(struct perf_event *event)
582{
583 release_bp_slot(event);
584}
585
586static int hw_breakpoint_event_init(struct perf_event *bp)
587{
588 int err;
589
590 if (bp->attr.type != PERF_TYPE_BREAKPOINT)
591 return -ENOENT;
592
593
594
595
596 if (has_branch_stack(bp))
597 return -EOPNOTSUPP;
598
599 err = register_perf_hw_breakpoint(bp);
600 if (err)
601 return err;
602
603 bp->destroy = bp_perf_event_destroy;
604
605 return 0;
606}
607
608static int hw_breakpoint_add(struct perf_event *bp, int flags)
609{
610 if (!(flags & PERF_EF_START))
611 bp->hw.state = PERF_HES_STOPPED;
612
613 return arch_install_hw_breakpoint(bp);
614}
615
616static void hw_breakpoint_del(struct perf_event *bp, int flags)
617{
618 arch_uninstall_hw_breakpoint(bp);
619}
620
621static void hw_breakpoint_start(struct perf_event *bp, int flags)
622{
623 bp->hw.state = 0;
624}
625
626static void hw_breakpoint_stop(struct perf_event *bp, int flags)
627{
628 bp->hw.state = PERF_HES_STOPPED;
629}
630
631static int hw_breakpoint_event_idx(struct perf_event *bp)
632{
633 return 0;
634}
635
636static struct pmu perf_breakpoint = {
637 .task_ctx_nr = perf_sw_context,
638
639 .event_init = hw_breakpoint_event_init,
640 .add = hw_breakpoint_add,
641 .del = hw_breakpoint_del,
642 .start = hw_breakpoint_start,
643 .stop = hw_breakpoint_stop,
644 .read = hw_breakpoint_pmu_read,
645
646 .event_idx = hw_breakpoint_event_idx,
647};
648
649int __init init_hw_breakpoint(void)
650{
651 unsigned int **task_bp_pinned;
652 int cpu, err_cpu;
653 int i;
654
655 for (i = 0; i < TYPE_MAX; i++)
656 nr_slots[i] = hw_breakpoint_slots(i);
657
658 for_each_possible_cpu(cpu) {
659 for (i = 0; i < TYPE_MAX; i++) {
660 task_bp_pinned = &per_cpu(nr_task_bp_pinned[i], cpu);
661 *task_bp_pinned = kzalloc(sizeof(int) * nr_slots[i],
662 GFP_KERNEL);
663 if (!*task_bp_pinned)
664 goto err_alloc;
665 }
666 }
667
668 constraints_initialized = 1;
669
670 perf_pmu_register(&perf_breakpoint, "breakpoint", PERF_TYPE_BREAKPOINT);
671
672 return register_die_notifier(&hw_breakpoint_exceptions_nb);
673
674 err_alloc:
675 for_each_possible_cpu(err_cpu) {
676 for (i = 0; i < TYPE_MAX; i++)
677 kfree(per_cpu(nr_task_bp_pinned[i], cpu));
678 if (err_cpu == cpu)
679 break;
680 }
681
682 return -ENOMEM;
683}
684
685
686