Commit | Line | Data |
---|---|---|
eee3af4a MM |
1 | /* |
2 | * Debug Store (DS) support | |
3 | * | |
4 | * This provides a low-level interface to the hardware's Debug Store | |
93fa7636 | 5 | * feature that is used for branch trace store (BTS) and |
eee3af4a MM |
6 | * precise-event based sampling (PEBS). |
7 | * | |
93fa7636 | 8 | * It manages: |
c2724775 | 9 | * - DS and BTS hardware configuration |
6abb11ae | 10 | * - buffer overflow handling (to be done) |
93fa7636 | 11 | * - buffer access |
eee3af4a | 12 | * |
c2724775 MM |
13 | * It does not do: |
14 | * - security checking (is the caller allowed to trace the task) | |
15 | * - buffer allocation (memory accounting) | |
eee3af4a | 16 | * |
eee3af4a | 17 | * |
93fa7636 MM |
18 | * Copyright (C) 2007-2008 Intel Corporation. |
19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 | |
eee3af4a MM |
20 | */ |
21 | ||
1965aae3 PA |
22 | #ifndef _ASM_X86_DS_H |
23 | #define _ASM_X86_DS_H | |
eee3af4a | 24 | |
93fa7636 | 25 | |
eee3af4a MM |
26 | #include <linux/types.h> |
27 | #include <linux/init.h> | |
ca0002a1 | 28 | #include <linux/err.h> |
eee3af4a | 29 | |
eee3af4a | 30 | |
e5e8ca63 MM |
31 | #ifdef CONFIG_X86_DS |
32 | ||
93fa7636 | 33 | struct task_struct; |
c2724775 | 34 | struct ds_context; |
ca0002a1 MM |
35 | struct ds_tracer; |
36 | struct bts_tracer; | |
37 | struct pebs_tracer; | |
38 | ||
39 | typedef void (*bts_ovfl_callback_t)(struct bts_tracer *); | |
40 | typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *); | |
eee3af4a | 41 | |
c2724775 MM |
42 | |
43 | /* | |
44 | * A list of features plus corresponding macros to talk about them in | |
45 | * the ds_request function's flags parameter. | |
46 | * | |
47 | * We use the enum to index an array of corresponding control bits; | |
48 | * we use the macro to index a flags bit-vector. | |
49 | */ | |
50 | enum ds_feature { | |
51 | dsf_bts = 0, | |
52 | dsf_bts_kernel, | |
53 | #define BTS_KERNEL (1 << dsf_bts_kernel) | |
54 | /* trace kernel-mode branches */ | |
55 | ||
56 | dsf_bts_user, | |
57 | #define BTS_USER (1 << dsf_bts_user) | |
58 | /* trace user-mode branches */ | |
59 | ||
60 | dsf_bts_overflow, | |
61 | dsf_bts_max, | |
62 | dsf_pebs = dsf_bts_max, | |
63 | ||
64 | dsf_pebs_max, | |
65 | dsf_ctl_max = dsf_pebs_max, | |
66 | dsf_bts_timestamps = dsf_ctl_max, | |
67 | #define BTS_TIMESTAMPS (1 << dsf_bts_timestamps) | |
68 | /* add timestamps into BTS trace */ | |
69 | ||
70 | #define BTS_USER_FLAGS (BTS_KERNEL | BTS_USER | BTS_TIMESTAMPS) | |
71 | }; | |
72 | ||
73 | ||
93fa7636 MM |
74 | /* |
75 | * Request BTS or PEBS | |
76 | * | |
77 | * Due to alignement constraints, the actual buffer may be slightly | |
78 | * smaller than the requested or provided buffer. | |
eee3af4a | 79 | * |
ca0002a1 MM |
80 | * Returns a pointer to a tracer structure on success, or |
81 | * ERR_PTR(errcode) on failure. | |
82 | * | |
83 | * The interrupt threshold is independent from the overflow callback | |
84 | * to allow users to use their own overflow interrupt handling mechanism. | |
93fa7636 MM |
85 | * |
86 | * task: the task to request recording for; | |
87 | * NULL for per-cpu recording on the current cpu | |
88 | * base: the base pointer for the (non-pageable) buffer; | |
6abb11ae | 89 | * size: the size of the provided buffer in bytes |
93fa7636 MM |
90 | * ovfl: pointer to a function to be called on buffer overflow; |
91 | * NULL if cyclic buffer requested | |
ca0002a1 MM |
92 | * th: the interrupt threshold in records from the end of the buffer; |
93 | * -1 if no interrupt threshold is requested. | |
c2724775 | 94 | * flags: a bit-mask of the above flags |
eee3af4a | 95 | */ |
ca0002a1 MM |
96 | extern struct bts_tracer *ds_request_bts(struct task_struct *task, |
97 | void *base, size_t size, | |
c2724775 MM |
98 | bts_ovfl_callback_t ovfl, |
99 | size_t th, unsigned int flags); | |
ca0002a1 MM |
100 | extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, |
101 | void *base, size_t size, | |
102 | pebs_ovfl_callback_t ovfl, | |
c2724775 | 103 | size_t th, unsigned int flags); |
93fa7636 MM |
104 | |
105 | /* | |
106 | * Release BTS or PEBS resources | |
c2724775 | 107 | * Suspend and resume BTS or PEBS tracing |
93fa7636 | 108 | * |
ca0002a1 | 109 | * tracer: the tracer handle returned from ds_request_~() |
93fa7636 | 110 | */ |
c2724775 MM |
111 | extern void ds_release_bts(struct bts_tracer *tracer); |
112 | extern void ds_suspend_bts(struct bts_tracer *tracer); | |
113 | extern void ds_resume_bts(struct bts_tracer *tracer); | |
114 | extern void ds_release_pebs(struct pebs_tracer *tracer); | |
115 | extern void ds_suspend_pebs(struct pebs_tracer *tracer); | |
116 | extern void ds_resume_pebs(struct pebs_tracer *tracer); | |
117 | ||
93fa7636 MM |
118 | |
119 | /* | |
c2724775 | 120 | * The raw DS buffer state as it is used for BTS and PEBS recording. |
93fa7636 | 121 | * |
c2724775 MM |
122 | * This is the low-level, arch-dependent interface for working |
123 | * directly on the raw trace data. | |
93fa7636 | 124 | */ |
c2724775 MM |
125 | struct ds_trace { |
126 | /* the number of bts/pebs records */ | |
127 | size_t n; | |
128 | /* the size of a bts/pebs record in bytes */ | |
129 | size_t size; | |
130 | /* pointers into the raw buffer: | |
131 | - to the first entry */ | |
132 | void *begin; | |
133 | /* - one beyond the last entry */ | |
134 | void *end; | |
135 | /* - one beyond the newest entry */ | |
136 | void *top; | |
137 | /* - the interrupt threshold */ | |
138 | void *ith; | |
139 | /* flags given on ds_request() */ | |
140 | unsigned int flags; | |
141 | }; | |
93fa7636 MM |
142 | |
143 | /* | |
c2724775 | 144 | * An arch-independent view on branch trace data. |
93fa7636 | 145 | */ |
c2724775 MM |
146 | enum bts_qualifier { |
147 | bts_invalid, | |
148 | #define BTS_INVALID bts_invalid | |
149 | ||
150 | bts_branch, | |
151 | #define BTS_BRANCH bts_branch | |
152 | ||
153 | bts_task_arrives, | |
154 | #define BTS_TASK_ARRIVES bts_task_arrives | |
155 | ||
156 | bts_task_departs, | |
157 | #define BTS_TASK_DEPARTS bts_task_departs | |
158 | ||
159 | bts_qual_bit_size = 4, | |
160 | bts_qual_max = (1 << bts_qual_bit_size), | |
161 | }; | |
162 | ||
163 | struct bts_struct { | |
164 | __u64 qualifier; | |
165 | union { | |
166 | /* BTS_BRANCH */ | |
167 | struct { | |
168 | __u64 from; | |
169 | __u64 to; | |
170 | } lbr; | |
171 | /* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */ | |
172 | struct { | |
173 | __u64 jiffies; | |
174 | pid_t pid; | |
175 | } timestamp; | |
176 | } variant; | |
177 | }; | |
178 | ||
93fa7636 MM |
179 | |
180 | /* | |
c2724775 | 181 | * The BTS state. |
93fa7636 | 182 | * |
c2724775 MM |
183 | * This gives access to the raw DS state and adds functions to provide |
184 | * an arch-independent view of the BTS data. | |
93fa7636 | 185 | */ |
c2724775 MM |
186 | struct bts_trace { |
187 | struct ds_trace ds; | |
188 | ||
189 | int (*read)(struct bts_tracer *tracer, const void *at, | |
190 | struct bts_struct *out); | |
191 | int (*write)(struct bts_tracer *tracer, const struct bts_struct *in); | |
192 | }; | |
193 | ||
93fa7636 MM |
194 | |
195 | /* | |
c2724775 | 196 | * The PEBS state. |
93fa7636 | 197 | * |
c2724775 MM |
198 | * This gives access to the raw DS state and the PEBS-specific counter |
199 | * reset value. | |
200 | */ | |
201 | struct pebs_trace { | |
202 | struct ds_trace ds; | |
203 | ||
204 | /* the PEBS reset value */ | |
205 | unsigned long long reset_value; | |
206 | }; | |
207 | ||
208 | ||
209 | /* | |
210 | * Read the BTS or PEBS trace. | |
93fa7636 | 211 | * |
c2724775 | 212 | * Returns a view on the trace collected for the parameter tracer. |
93fa7636 | 213 | * |
c2724775 MM |
214 | * The view remains valid as long as the traced task is not running or |
215 | * the tracer is suspended. | |
216 | * Writes into the trace buffer are not reflected. | |
93fa7636 | 217 | * |
ca0002a1 | 218 | * tracer: the tracer handle returned from ds_request_~() |
93fa7636 | 219 | */ |
c2724775 MM |
220 | extern const struct bts_trace *ds_read_bts(struct bts_tracer *tracer); |
221 | extern const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer); | |
222 | ||
93fa7636 | 223 | |
93fa7636 MM |
224 | /* |
225 | * Reset the write pointer of the BTS/PEBS buffer. | |
226 | * | |
227 | * Returns 0 on success; -Eerrno on error | |
228 | * | |
ca0002a1 | 229 | * tracer: the tracer handle returned from ds_request_~() |
93fa7636 | 230 | */ |
ca0002a1 MM |
231 | extern int ds_reset_bts(struct bts_tracer *tracer); |
232 | extern int ds_reset_pebs(struct pebs_tracer *tracer); | |
93fa7636 | 233 | |
93fa7636 MM |
234 | /* |
235 | * Set the PEBS counter reset value. | |
236 | * | |
237 | * Returns 0 on success; -Eerrno on error | |
238 | * | |
ca0002a1 | 239 | * tracer: the tracer handle returned from ds_request_pebs() |
93fa7636 MM |
240 | * value: the new counter reset value |
241 | */ | |
ca0002a1 | 242 | extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); |
93fa7636 MM |
243 | |
244 | /* | |
245 | * Initialization | |
246 | */ | |
247 | struct cpuinfo_x86; | |
248 | extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | |
249 | ||
93fa7636 | 250 | /* |
c2724775 | 251 | * Context switch work |
93fa7636 | 252 | */ |
c2724775 | 253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); |
93fa7636 | 254 | |
bf53de90 MM |
255 | /* |
256 | * Task clone/init and cleanup work | |
257 | */ | |
258 | extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father); | |
259 | extern void ds_exit_thread(struct task_struct *tsk); | |
260 | ||
93fa7636 MM |
261 | #else /* CONFIG_X86_DS */ |
262 | ||
e5e8ca63 MM |
263 | struct cpuinfo_x86; |
264 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} | |
c2724775 MM |
265 | static inline void ds_switch_to(struct task_struct *prev, |
266 | struct task_struct *next) {} | |
bf53de90 MM |
267 | static inline void ds_copy_thread(struct task_struct *tsk, |
268 | struct task_struct *father) {} | |
269 | static inline void ds_exit_thread(struct task_struct *tsk) {} | |
eee3af4a | 270 | |
93fa7636 | 271 | #endif /* CONFIG_X86_DS */ |
1965aae3 | 272 | #endif /* _ASM_X86_DS_H */ |