Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Debug Store (DS) support |
| 3 | * |
| 4 | * This provides a low-level interface to the hardware's Debug Store |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 5 | * feature that is used for branch trace store (BTS) and |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 6 | * precise-event based sampling (PEBS). |
| 7 | * |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 8 | * It manages: |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 9 | * - DS and BTS hardware configuration |
Markus Metzger | 6abb11a | 2008-11-25 09:05:27 +0100 | [diff] [blame] | 10 | * - buffer overflow handling (to be done) |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 11 | * - buffer access |
| 12 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 13 | * It does not do: |
| 14 | * - security checking (is the caller allowed to trace the task) |
| 15 | * - buffer allocation (memory accounting) |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 16 | * |
| 17 | * |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 18 | * Copyright (C) 2007-2008 Intel Corporation. |
| 19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 20 | */ |
| 21 | |
H. Peter Anvin | 1965aae | 2008-10-22 22:26:29 -0700 | [diff] [blame] | 22 | #ifndef _ASM_X86_DS_H |
| 23 | #define _ASM_X86_DS_H |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 24 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 25 | |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 26 | #include <linux/types.h> |
| 27 | #include <linux/init.h> |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 28 | #include <linux/err.h> |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 29 | |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 30 | |
Markus Metzger | e5e8ca6 | 2008-11-25 08:47:19 +0100 | [diff] [blame] | 31 | #ifdef CONFIG_X86_DS |
| 32 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 33 | struct task_struct; |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 34 | struct ds_context; |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 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 *); |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 41 | |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 74 | /* |
| 75 | * Request BTS or PEBS |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 76 | * |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 77 | * Due to alignement constraints, the actual buffer may be slightly |
| 78 | * smaller than the requested or provided buffer. |
| 79 | * |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 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. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 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; |
Markus Metzger | 6abb11a | 2008-11-25 09:05:27 +0100 | [diff] [blame] | 89 | * size: the size of the provided buffer in bytes |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 90 | * ovfl: pointer to a function to be called on buffer overflow; |
| 91 | * NULL if cyclic buffer requested |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 92 | * th: the interrupt threshold in records from the end of the buffer; |
| 93 | * -1 if no interrupt threshold is requested. |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 94 | * flags: a bit-mask of the above flags |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 95 | */ |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 96 | extern struct bts_tracer *ds_request_bts(struct task_struct *task, |
| 97 | void *base, size_t size, |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 98 | bts_ovfl_callback_t ovfl, |
| 99 | size_t th, unsigned int flags); |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 100 | extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, |
| 101 | void *base, size_t size, |
| 102 | pebs_ovfl_callback_t ovfl, |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 103 | size_t th, unsigned int flags); |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 104 | |
| 105 | /* |
| 106 | * Release BTS or PEBS resources |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 107 | * Suspend and resume BTS or PEBS tracing |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 108 | * |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 109 | * tracer: the tracer handle returned from ds_request_~() |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 110 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 118 | |
| 119 | /* |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 120 | * The raw DS buffer state as it is used for BTS and PEBS recording. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 121 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 122 | * This is the low-level, arch-dependent interface for working |
| 123 | * directly on the raw trace data. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 124 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | }; |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 142 | |
| 143 | /* |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 144 | * An arch-independent view on branch trace data. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 145 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 179 | |
| 180 | /* |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 181 | * The BTS state. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 182 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 183 | * This gives access to the raw DS state and adds functions to provide |
| 184 | * an arch-independent view of the BTS data. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 185 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 194 | |
| 195 | /* |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 196 | * The PEBS state. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 197 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 211 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 212 | * Returns a view on the trace collected for the parameter tracer. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 213 | * |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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. |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 217 | * |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 218 | * tracer: the tracer handle returned from ds_request_~() |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 219 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 223 | |
| 224 | /* |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 225 | * Reset the write pointer of the BTS/PEBS buffer. |
| 226 | * |
| 227 | * Returns 0 on success; -Eerrno on error |
| 228 | * |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 229 | * tracer: the tracer handle returned from ds_request_~() |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 230 | */ |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 231 | extern int ds_reset_bts(struct bts_tracer *tracer); |
| 232 | extern int ds_reset_pebs(struct pebs_tracer *tracer); |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 233 | |
| 234 | /* |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 235 | * Set the PEBS counter reset value. |
| 236 | * |
| 237 | * Returns 0 on success; -Eerrno on error |
| 238 | * |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 239 | * tracer: the tracer handle returned from ds_request_pebs() |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 240 | * value: the new counter reset value |
| 241 | */ |
Markus Metzger | ca0002a | 2008-11-25 09:01:25 +0100 | [diff] [blame] | 242 | extern int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value); |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 243 | |
| 244 | /* |
| 245 | * Initialization |
| 246 | */ |
| 247 | struct cpuinfo_x86; |
| 248 | extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); |
| 249 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 250 | /* |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 251 | * Context switch work |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 252 | */ |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 253 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 254 | |
Markus Metzger | bf53de9 | 2008-12-19 15:10:24 +0100 | [diff] [blame^] | 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 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 261 | #else /* CONFIG_X86_DS */ |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 262 | |
Markus Metzger | e5e8ca6 | 2008-11-25 08:47:19 +0100 | [diff] [blame] | 263 | struct cpuinfo_x86; |
| 264 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} |
Markus Metzger | c272477 | 2008-12-11 13:49:59 +0100 | [diff] [blame] | 265 | static inline void ds_switch_to(struct task_struct *prev, |
| 266 | struct task_struct *next) {} |
Markus Metzger | bf53de9 | 2008-12-19 15:10:24 +0100 | [diff] [blame^] | 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) {} |
Markus Metzger | eee3af4 | 2008-01-30 13:31:09 +0100 | [diff] [blame] | 270 | |
Markus Metzger | 93fa763 | 2008-04-08 11:01:58 +0200 | [diff] [blame] | 271 | #endif /* CONFIG_X86_DS */ |
H. Peter Anvin | 1965aae | 2008-10-22 22:26:29 -0700 | [diff] [blame] | 272 | #endif /* _ASM_X86_DS_H */ |