1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
22da3e160SFrederic Weisbecker #ifndef _LINUX_HW_BREAKPOINT_H
32da3e160SFrederic Weisbecker #define _LINUX_HW_BREAKPOINT_H
42da3e160SFrederic Weisbecker
5e6db4876SFrederic Weisbecker #include <linux/perf_event.h>
6d2709c7cSDavid Howells #include <uapi/linux/hw_breakpoint.h>
7e6db4876SFrederic Weisbecker
8fa7c27eeSFrederic Weisbecker #ifdef CONFIG_HAVE_HW_BREAKPOINT
9fa7c27eeSFrederic Weisbecker
10*d3c7ec75SPalmer Dabbelt enum bp_type_idx {
11*d3c7ec75SPalmer Dabbelt TYPE_INST = 0,
12*d3c7ec75SPalmer Dabbelt #if defined(CONFIG_HAVE_MIXED_BREAKPOINTS_REGS)
13*d3c7ec75SPalmer Dabbelt TYPE_DATA = 0,
14*d3c7ec75SPalmer Dabbelt #else
15*d3c7ec75SPalmer Dabbelt TYPE_DATA = 1,
16*d3c7ec75SPalmer Dabbelt #endif
17*d3c7ec75SPalmer Dabbelt TYPE_MAX
18*d3c7ec75SPalmer Dabbelt };
19*d3c7ec75SPalmer Dabbelt
203c502e7aSJason Wessel extern int __init init_hw_breakpoint(void);
213c502e7aSJason Wessel
hw_breakpoint_init(struct perf_event_attr * attr)22dd1853c3SFrederic Weisbecker static inline void hw_breakpoint_init(struct perf_event_attr *attr)
23dd1853c3SFrederic Weisbecker {
24ed872d09SFrederic Weisbecker memset(attr, 0, sizeof(*attr));
25ed872d09SFrederic Weisbecker
26dd1853c3SFrederic Weisbecker attr->type = PERF_TYPE_BREAKPOINT;
27dd1853c3SFrederic Weisbecker attr->size = sizeof(*attr);
28b326e956SFrederic Weisbecker /*
29b326e956SFrederic Weisbecker * As it's for in-kernel or ptrace use, we want it to be pinned
30b326e956SFrederic Weisbecker * and to call its callback every hits.
31b326e956SFrederic Weisbecker */
32dd1853c3SFrederic Weisbecker attr->pinned = 1;
33b326e956SFrederic Weisbecker attr->sample_period = 1;
34dd1853c3SFrederic Weisbecker }
35dd1853c3SFrederic Weisbecker
ptrace_breakpoint_init(struct perf_event_attr * attr)3673266fc1SFrederic Weisbecker static inline void ptrace_breakpoint_init(struct perf_event_attr *attr)
3773266fc1SFrederic Weisbecker {
3873266fc1SFrederic Weisbecker hw_breakpoint_init(attr);
3973266fc1SFrederic Weisbecker attr->exclude_kernel = 1;
4073266fc1SFrederic Weisbecker }
4173266fc1SFrederic Weisbecker
hw_breakpoint_addr(struct perf_event * bp)4224f1e32cSFrederic Weisbecker static inline unsigned long hw_breakpoint_addr(struct perf_event *bp)
4324f1e32cSFrederic Weisbecker {
4424f1e32cSFrederic Weisbecker return bp->attr.bp_addr;
4524f1e32cSFrederic Weisbecker }
4624f1e32cSFrederic Weisbecker
hw_breakpoint_type(struct perf_event * bp)4724f1e32cSFrederic Weisbecker static inline int hw_breakpoint_type(struct perf_event *bp)
4824f1e32cSFrederic Weisbecker {
4924f1e32cSFrederic Weisbecker return bp->attr.bp_type;
5024f1e32cSFrederic Weisbecker }
5124f1e32cSFrederic Weisbecker
hw_breakpoint_len(struct perf_event * bp)52cd757645SMahesh Salgaonkar static inline unsigned long hw_breakpoint_len(struct perf_event *bp)
5324f1e32cSFrederic Weisbecker {
5424f1e32cSFrederic Weisbecker return bp->attr.bp_len;
5524f1e32cSFrederic Weisbecker }
5624f1e32cSFrederic Weisbecker
5724f1e32cSFrederic Weisbecker extern struct perf_event *
585fa10b28SFrederic Weisbecker register_user_hw_breakpoint(struct perf_event_attr *attr,
59b326e956SFrederic Weisbecker perf_overflow_handler_t triggered,
604dc0da86SAvi Kivity void *context,
615fa10b28SFrederic Weisbecker struct task_struct *tsk);
6224f1e32cSFrederic Weisbecker
6324f1e32cSFrederic Weisbecker /* FIXME: only change from the attr, and don't unregister */
6444234adcSFrederic Weisbecker extern int
652f0993e0SFrederic Weisbecker modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr);
6632ff77e8SMilind Chabbi extern int
6732ff77e8SMilind Chabbi modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr,
6832ff77e8SMilind Chabbi bool check);
6924f1e32cSFrederic Weisbecker
702da3e160SFrederic Weisbecker /*
712da3e160SFrederic Weisbecker * Kernel breakpoints are not associated with any particular thread.
722da3e160SFrederic Weisbecker */
7324f1e32cSFrederic Weisbecker extern struct perf_event *
74dd1853c3SFrederic Weisbecker register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
75b326e956SFrederic Weisbecker perf_overflow_handler_t triggered,
764dc0da86SAvi Kivity void *context,
77dd1853c3SFrederic Weisbecker int cpu);
782da3e160SFrederic Weisbecker
7944ee6358STejun Heo extern struct perf_event * __percpu *
80dd1853c3SFrederic Weisbecker register_wide_hw_breakpoint(struct perf_event_attr *attr,
814dc0da86SAvi Kivity perf_overflow_handler_t triggered,
824dc0da86SAvi Kivity void *context);
832da3e160SFrederic Weisbecker
8424f1e32cSFrederic Weisbecker extern int register_perf_hw_breakpoint(struct perf_event *bp);
8524f1e32cSFrederic Weisbecker extern void unregister_hw_breakpoint(struct perf_event *bp);
8644ee6358STejun Heo extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events);
87c5b81449SMarco Elver extern bool hw_breakpoint_is_used(void);
8824f1e32cSFrederic Weisbecker
895352ae63SJason Wessel extern int dbg_reserve_bp_slot(struct perf_event *bp);
905352ae63SJason Wessel extern int dbg_release_bp_slot(struct perf_event *bp);
9124f1e32cSFrederic Weisbecker extern int reserve_bp_slot(struct perf_event *bp);
9224f1e32cSFrederic Weisbecker extern void release_bp_slot(struct perf_event *bp);
9324f1e32cSFrederic Weisbecker
9424f1e32cSFrederic Weisbecker extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
9524f1e32cSFrederic Weisbecker
counter_arch_bp(struct perf_event * bp)96687b16fbSFrederic Weisbecker static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
97687b16fbSFrederic Weisbecker {
98687b16fbSFrederic Weisbecker return &bp->hw.info;
99687b16fbSFrederic Weisbecker }
100687b16fbSFrederic Weisbecker
10124f1e32cSFrederic Weisbecker #else /* !CONFIG_HAVE_HW_BREAKPOINT */
10224f1e32cSFrederic Weisbecker
init_hw_breakpoint(void)1033c502e7aSJason Wessel static inline int __init init_hw_breakpoint(void) { return 0; }
1043c502e7aSJason Wessel
10524f1e32cSFrederic Weisbecker static inline struct perf_event *
register_user_hw_breakpoint(struct perf_event_attr * attr,perf_overflow_handler_t triggered,void * context,struct task_struct * tsk)1065fa10b28SFrederic Weisbecker register_user_hw_breakpoint(struct perf_event_attr *attr,
107b326e956SFrederic Weisbecker perf_overflow_handler_t triggered,
1084dc0da86SAvi Kivity void *context,
1095fa10b28SFrederic Weisbecker struct task_struct *tsk) { return NULL; }
11044234adcSFrederic Weisbecker static inline int
modify_user_hw_breakpoint(struct perf_event * bp,struct perf_event_attr * attr)11124f1e32cSFrederic Weisbecker modify_user_hw_breakpoint(struct perf_event *bp,
11299ac64c8SFrederic Weisbecker struct perf_event_attr *attr) { return -ENOSYS; }
11332ff77e8SMilind Chabbi static inline int
modify_user_hw_breakpoint_check(struct perf_event * bp,struct perf_event_attr * attr,bool check)11432ff77e8SMilind Chabbi modify_user_hw_breakpoint_check(struct perf_event *bp, struct perf_event_attr *attr,
11532ff77e8SMilind Chabbi bool check) { return -ENOSYS; }
11632ff77e8SMilind Chabbi
11724f1e32cSFrederic Weisbecker static inline struct perf_event *
register_wide_hw_breakpoint_cpu(struct perf_event_attr * attr,perf_overflow_handler_t triggered,void * context,int cpu)118dd1853c3SFrederic Weisbecker register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
119b326e956SFrederic Weisbecker perf_overflow_handler_t triggered,
1204dc0da86SAvi Kivity void *context,
121dd1853c3SFrederic Weisbecker int cpu) { return NULL; }
12244ee6358STejun Heo static inline struct perf_event * __percpu *
register_wide_hw_breakpoint(struct perf_event_attr * attr,perf_overflow_handler_t triggered,void * context)123dd1853c3SFrederic Weisbecker register_wide_hw_breakpoint(struct perf_event_attr *attr,
1244dc0da86SAvi Kivity perf_overflow_handler_t triggered,
1254dc0da86SAvi Kivity void *context) { return NULL; }
12624f1e32cSFrederic Weisbecker static inline int
register_perf_hw_breakpoint(struct perf_event * bp)12724f1e32cSFrederic Weisbecker register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; }
unregister_hw_breakpoint(struct perf_event * bp)12824f1e32cSFrederic Weisbecker static inline void unregister_hw_breakpoint(struct perf_event *bp) { }
12924f1e32cSFrederic Weisbecker static inline void
unregister_wide_hw_breakpoint(struct perf_event * __percpu * cpu_events)13044ee6358STejun Heo unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) { }
hw_breakpoint_is_used(void)131c5b81449SMarco Elver static inline bool hw_breakpoint_is_used(void) { return false; }
132c5b81449SMarco Elver
13324f1e32cSFrederic Weisbecker static inline int
reserve_bp_slot(struct perf_event * bp)13424f1e32cSFrederic Weisbecker reserve_bp_slot(struct perf_event *bp) {return -ENOSYS; }
release_bp_slot(struct perf_event * bp)13524f1e32cSFrederic Weisbecker static inline void release_bp_slot(struct perf_event *bp) { }
13624f1e32cSFrederic Weisbecker
flush_ptrace_hw_breakpoint(struct task_struct * tsk)13724f1e32cSFrederic Weisbecker static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { }
13824f1e32cSFrederic Weisbecker
counter_arch_bp(struct perf_event * bp)139687b16fbSFrederic Weisbecker static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
140687b16fbSFrederic Weisbecker {
141687b16fbSFrederic Weisbecker return NULL;
142687b16fbSFrederic Weisbecker }
143687b16fbSFrederic Weisbecker
14424f1e32cSFrederic Weisbecker #endif /* CONFIG_HAVE_HW_BREAKPOINT */
1452da3e160SFrederic Weisbecker #endif /* _LINUX_HW_BREAKPOINT_H */
146