Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2da3e160 FW |
2 | #ifndef _LINUX_HW_BREAKPOINT_H |
3 | #define _LINUX_HW_BREAKPOINT_H | |
b332828c | 4 | |
e6db4876 | 5 | #include <linux/perf_event.h> |
d2709c7c | 6 | #include <uapi/linux/hw_breakpoint.h> |
e6db4876 | 7 | |
fa7c27ee FW |
8 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
9 | ||
3c502e7a JW |
10 | extern int __init init_hw_breakpoint(void); |
11 | ||
dd1853c3 FW |
12 | static inline void hw_breakpoint_init(struct perf_event_attr *attr) |
13 | { | |
ed872d09 FW |
14 | memset(attr, 0, sizeof(*attr)); |
15 | ||
dd1853c3 FW |
16 | attr->type = PERF_TYPE_BREAKPOINT; |
17 | attr->size = sizeof(*attr); | |
b326e956 FW |
18 | /* |
19 | * As it's for in-kernel or ptrace use, we want it to be pinned | |
20 | * and to call its callback every hits. | |
21 | */ | |
dd1853c3 | 22 | attr->pinned = 1; |
b326e956 | 23 | attr->sample_period = 1; |
73266fc1 FW |
24 | } |
25 | ||
26 | static inline void ptrace_breakpoint_init(struct perf_event_attr *attr) | |
27 | { | |
28 | hw_breakpoint_init(attr); | |
29 | attr->exclude_kernel = 1; | |
dd1853c3 FW |
30 | } |
31 | ||
24f1e32c FW |
32 | static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) |
33 | { | |
34 | return bp->attr.bp_addr; | |
35 | } | |
36 | ||
37 | static inline int hw_breakpoint_type(struct perf_event *bp) | |
38 | { | |
39 | return bp->attr.bp_type; | |
40 | } | |
41 | ||
cd757645 | 42 | static inline unsigned long hw_breakpoint_len(struct perf_event *bp) |
24f1e32c FW |
43 | { |
44 | return bp->attr.bp_len; | |
45 | } | |
46 | ||
24f1e32c | 47 | extern struct perf_event * |
5fa10b28 | 48 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
b326e956 | 49 | perf_overflow_handler_t triggered, |
4dc0da86 | 50 | void *context, |
5fa10b28 | 51 | struct task_struct *tsk); |
24f1e32c FW |
52 | |
53 | /* FIXME: only change from the attr, and don't unregister */ | |
44234adc | 54 | extern int |
2f0993e0 | 55 | modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); |
32ff77e8 MC |
56 | extern int |
57 | modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr, | |
58 | bool check); | |
b332828c | 59 | |
b332828c P |
60 | /* |
61 | * Kernel breakpoints are not associated with any particular thread. | |
62 | */ | |
24f1e32c | 63 | extern struct perf_event * |
dd1853c3 | 64 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
b326e956 | 65 | perf_overflow_handler_t triggered, |
4dc0da86 | 66 | void *context, |
dd1853c3 | 67 | int cpu); |
24f1e32c | 68 | |
44ee6358 | 69 | extern struct perf_event * __percpu * |
dd1853c3 | 70 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
4dc0da86 AK |
71 | perf_overflow_handler_t triggered, |
72 | void *context); | |
24f1e32c FW |
73 | |
74 | extern int register_perf_hw_breakpoint(struct perf_event *bp); | |
75 | extern int __register_perf_hw_breakpoint(struct perf_event *bp); | |
76 | extern void unregister_hw_breakpoint(struct perf_event *bp); | |
44ee6358 | 77 | extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); |
24f1e32c | 78 | |
5352ae63 JW |
79 | extern int dbg_reserve_bp_slot(struct perf_event *bp); |
80 | extern int dbg_release_bp_slot(struct perf_event *bp); | |
24f1e32c FW |
81 | extern int reserve_bp_slot(struct perf_event *bp); |
82 | extern void release_bp_slot(struct perf_event *bp); | |
83 | ||
84 | extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); | |
85 | ||
687b16fb FW |
86 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) |
87 | { | |
88 | return &bp->hw.info; | |
89 | } | |
90 | ||
24f1e32c FW |
91 | #else /* !CONFIG_HAVE_HW_BREAKPOINT */ |
92 | ||
3c502e7a JW |
93 | static inline int __init init_hw_breakpoint(void) { return 0; } |
94 | ||
24f1e32c | 95 | static inline struct perf_event * |
5fa10b28 | 96 | register_user_hw_breakpoint(struct perf_event_attr *attr, |
b326e956 | 97 | perf_overflow_handler_t triggered, |
4dc0da86 | 98 | void *context, |
5fa10b28 | 99 | struct task_struct *tsk) { return NULL; } |
44234adc | 100 | static inline int |
24f1e32c | 101 | modify_user_hw_breakpoint(struct perf_event *bp, |
99ac64c8 | 102 | struct perf_event_attr *attr) { return -ENOSYS; } |
32ff77e8 MC |
103 | static inline int |
104 | modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr, | |
105 | bool check) { return -ENOSYS; } | |
106 | ||
24f1e32c | 107 | static inline struct perf_event * |
dd1853c3 | 108 | register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, |
b326e956 | 109 | perf_overflow_handler_t triggered, |
4dc0da86 | 110 | void *context, |
dd1853c3 | 111 | int cpu) { return NULL; } |
44ee6358 | 112 | static inline struct perf_event * __percpu * |
dd1853c3 | 113 | register_wide_hw_breakpoint(struct perf_event_attr *attr, |
4dc0da86 AK |
114 | perf_overflow_handler_t triggered, |
115 | void *context) { return NULL; } | |
24f1e32c FW |
116 | static inline int |
117 | register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | |
118 | static inline int | |
119 | __register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } | |
120 | static inline void unregister_hw_breakpoint(struct perf_event *bp) { } | |
121 | static inline void | |
44ee6358 | 122 | unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) { } |
24f1e32c FW |
123 | static inline int |
124 | reserve_bp_slot(struct perf_event *bp) {return -ENOSYS; } | |
125 | static inline void release_bp_slot(struct perf_event *bp) { } | |
126 | ||
127 | static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } | |
b332828c | 128 | |
687b16fb FW |
129 | static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) |
130 | { | |
131 | return NULL; | |
132 | } | |
133 | ||
24f1e32c | 134 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
24f1e32c | 135 | #endif /* _LINUX_HW_BREAKPOINT_H */ |