diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-x86/ds.h | 258 | ||||
-rw-r--r-- | include/asm-x86/processor.h | 12 | ||||
-rw-r--r-- | include/asm-x86/ptrace-abi.h | 14 | ||||
-rw-r--r-- | include/asm-x86/ptrace.h | 38 |
4 files changed, 265 insertions, 57 deletions
diff --git a/include/asm-x86/ds.h b/include/asm-x86/ds.h index 7881368142fa..72c5a190bf48 100644 --- a/include/asm-x86/ds.h +++ b/include/asm-x86/ds.h | |||
@@ -2,71 +2,237 @@ | |||
2 | * Debug Store (DS) support | 2 | * Debug Store (DS) support |
3 | * | 3 | * |
4 | * This provides a low-level interface to the hardware's Debug Store | 4 | * This provides a low-level interface to the hardware's Debug Store |
5 | * feature that is used for last branch recording (LBR) and | 5 | * feature that is used for branch trace store (BTS) and |
6 | * precise-event based sampling (PEBS). | 6 | * precise-event based sampling (PEBS). |
7 | * | 7 | * |
8 | * Different architectures use a different DS layout/pointer size. | 8 | * It manages: |
9 | * The below functions therefore work on a void*. | 9 | * - per-thread and per-cpu allocation of BTS and PEBS |
10 | * - buffer memory allocation (optional) | ||
11 | * - buffer overflow handling | ||
12 | * - buffer access | ||
10 | * | 13 | * |
14 | * It assumes: | ||
15 | * - get_task_struct on all parameter tasks | ||
16 | * - current is allowed to trace parameter tasks | ||
11 | * | 17 | * |
12 | * Since there is no user for PEBS, yet, only LBR (or branch | ||
13 | * trace store, BTS) is supported. | ||
14 | * | 18 | * |
15 | * | 19 | * Copyright (C) 2007-2008 Intel Corporation. |
16 | * Copyright (C) 2007 Intel Corporation. | 20 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 |
17 | * Markus Metzger <markus.t.metzger@intel.com>, Dec 2007 | ||
18 | */ | 21 | */ |
19 | 22 | ||
20 | #ifndef _ASM_X86_DS_H | 23 | #ifndef _ASM_X86_DS_H |
21 | #define _ASM_X86_DS_H | 24 | #define _ASM_X86_DS_H |
22 | 25 | ||
26 | #ifdef CONFIG_X86_DS | ||
27 | |||
23 | #include <linux/types.h> | 28 | #include <linux/types.h> |
24 | #include <linux/init.h> | 29 | #include <linux/init.h> |
25 | 30 | ||
26 | struct cpuinfo_x86; | ||
27 | 31 | ||
32 | struct task_struct; | ||
28 | 33 | ||
29 | /* a branch trace record entry | 34 | /* |
35 | * Request BTS or PEBS | ||
36 | * | ||
37 | * Due to alignement constraints, the actual buffer may be slightly | ||
38 | * smaller than the requested or provided buffer. | ||
30 | * | 39 | * |
31 | * In order to unify the interface between various processor versions, | 40 | * Returns 0 on success; -Eerrno otherwise |
32 | * we use the below data structure for all processors. | 41 | * |
42 | * task: the task to request recording for; | ||
43 | * NULL for per-cpu recording on the current cpu | ||
44 | * base: the base pointer for the (non-pageable) buffer; | ||
45 | * NULL if buffer allocation requested | ||
46 | * size: the size of the requested or provided buffer | ||
47 | * ovfl: pointer to a function to be called on buffer overflow; | ||
48 | * NULL if cyclic buffer requested | ||
33 | */ | 49 | */ |
34 | enum bts_qualifier { | 50 | typedef void (*ds_ovfl_callback_t)(struct task_struct *); |
35 | BTS_INVALID = 0, | 51 | extern int ds_request_bts(struct task_struct *task, void *base, size_t size, |
36 | BTS_BRANCH, | 52 | ds_ovfl_callback_t ovfl); |
37 | BTS_TASK_ARRIVES, | 53 | extern int ds_request_pebs(struct task_struct *task, void *base, size_t size, |
38 | BTS_TASK_DEPARTS | 54 | ds_ovfl_callback_t ovfl); |
39 | }; | 55 | |
56 | /* | ||
57 | * Release BTS or PEBS resources | ||
58 | * | ||
59 | * Frees buffers allocated on ds_request. | ||
60 | * | ||
61 | * Returns 0 on success; -Eerrno otherwise | ||
62 | * | ||
63 | * task: the task to release resources for; | ||
64 | * NULL to release resources for the current cpu | ||
65 | */ | ||
66 | extern int ds_release_bts(struct task_struct *task); | ||
67 | extern int ds_release_pebs(struct task_struct *task); | ||
68 | |||
69 | /* | ||
70 | * Return the (array) index of the write pointer. | ||
71 | * (assuming an array of BTS/PEBS records) | ||
72 | * | ||
73 | * Returns -Eerrno on error | ||
74 | * | ||
75 | * task: the task to access; | ||
76 | * NULL to access the current cpu | ||
77 | * pos (out): if not NULL, will hold the result | ||
78 | */ | ||
79 | extern int ds_get_bts_index(struct task_struct *task, size_t *pos); | ||
80 | extern int ds_get_pebs_index(struct task_struct *task, size_t *pos); | ||
81 | |||
82 | /* | ||
83 | * Return the (array) index one record beyond the end of the array. | ||
84 | * (assuming an array of BTS/PEBS records) | ||
85 | * | ||
86 | * Returns -Eerrno on error | ||
87 | * | ||
88 | * task: the task to access; | ||
89 | * NULL to access the current cpu | ||
90 | * pos (out): if not NULL, will hold the result | ||
91 | */ | ||
92 | extern int ds_get_bts_end(struct task_struct *task, size_t *pos); | ||
93 | extern int ds_get_pebs_end(struct task_struct *task, size_t *pos); | ||
94 | |||
95 | /* | ||
96 | * Provide a pointer to the BTS/PEBS record at parameter index. | ||
97 | * (assuming an array of BTS/PEBS records) | ||
98 | * | ||
99 | * The pointer points directly into the buffer. The user is | ||
100 | * responsible for copying the record. | ||
101 | * | ||
102 | * Returns the size of a single record on success; -Eerrno on error | ||
103 | * | ||
104 | * task: the task to access; | ||
105 | * NULL to access the current cpu | ||
106 | * index: the index of the requested record | ||
107 | * record (out): pointer to the requested record | ||
108 | */ | ||
109 | extern int ds_access_bts(struct task_struct *task, | ||
110 | size_t index, const void **record); | ||
111 | extern int ds_access_pebs(struct task_struct *task, | ||
112 | size_t index, const void **record); | ||
113 | |||
114 | /* | ||
115 | * Write one or more BTS/PEBS records at the write pointer index and | ||
116 | * advance the write pointer. | ||
117 | * | ||
118 | * If size is not a multiple of the record size, trailing bytes are | ||
119 | * zeroed out. | ||
120 | * | ||
121 | * May result in one or more overflow notifications. | ||
122 | * | ||
123 | * If called during overflow handling, that is, with index >= | ||
124 | * interrupt threshold, the write will wrap around. | ||
125 | * | ||
126 | * An overflow notification is given if and when the interrupt | ||
127 | * threshold is reached during or after the write. | ||
128 | * | ||
129 | * Returns the number of bytes written or -Eerrno. | ||
130 | * | ||
131 | * task: the task to access; | ||
132 | * NULL to access the current cpu | ||
133 | * buffer: the buffer to write | ||
134 | * size: the size of the buffer | ||
135 | */ | ||
136 | extern int ds_write_bts(struct task_struct *task, | ||
137 | const void *buffer, size_t size); | ||
138 | extern int ds_write_pebs(struct task_struct *task, | ||
139 | const void *buffer, size_t size); | ||
140 | |||
141 | /* | ||
142 | * Same as ds_write_bts/pebs, but omit ownership checks. | ||
143 | * | ||
144 | * This is needed to have some other task than the owner of the | ||
145 | * BTS/PEBS buffer or the parameter task itself write into the | ||
146 | * respective buffer. | ||
147 | */ | ||
148 | extern int ds_unchecked_write_bts(struct task_struct *task, | ||
149 | const void *buffer, size_t size); | ||
150 | extern int ds_unchecked_write_pebs(struct task_struct *task, | ||
151 | const void *buffer, size_t size); | ||
152 | |||
153 | /* | ||
154 | * Reset the write pointer of the BTS/PEBS buffer. | ||
155 | * | ||
156 | * Returns 0 on success; -Eerrno on error | ||
157 | * | ||
158 | * task: the task to access; | ||
159 | * NULL to access the current cpu | ||
160 | */ | ||
161 | extern int ds_reset_bts(struct task_struct *task); | ||
162 | extern int ds_reset_pebs(struct task_struct *task); | ||
163 | |||
164 | /* | ||
165 | * Clear the BTS/PEBS buffer and reset the write pointer. | ||
166 | * The entire buffer will be zeroed out. | ||
167 | * | ||
168 | * Returns 0 on success; -Eerrno on error | ||
169 | * | ||
170 | * task: the task to access; | ||
171 | * NULL to access the current cpu | ||
172 | */ | ||
173 | extern int ds_clear_bts(struct task_struct *task); | ||
174 | extern int ds_clear_pebs(struct task_struct *task); | ||
175 | |||
176 | /* | ||
177 | * Provide the PEBS counter reset value. | ||
178 | * | ||
179 | * Returns 0 on success; -Eerrno on error | ||
180 | * | ||
181 | * task: the task to access; | ||
182 | * NULL to access the current cpu | ||
183 | * value (out): the counter reset value | ||
184 | */ | ||
185 | extern int ds_get_pebs_reset(struct task_struct *task, u64 *value); | ||
186 | |||
187 | /* | ||
188 | * Set the PEBS counter reset value. | ||
189 | * | ||
190 | * Returns 0 on success; -Eerrno on error | ||
191 | * | ||
192 | * task: the task to access; | ||
193 | * NULL to access the current cpu | ||
194 | * value: the new counter reset value | ||
195 | */ | ||
196 | extern int ds_set_pebs_reset(struct task_struct *task, u64 value); | ||
197 | |||
198 | /* | ||
199 | * Initialization | ||
200 | */ | ||
201 | struct cpuinfo_x86; | ||
202 | extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | ||
203 | |||
204 | |||
40 | 205 | ||
41 | struct bts_struct { | 206 | /* |
42 | u64 qualifier; | 207 | * The DS context - part of struct thread_struct. |
43 | union { | 208 | */ |
44 | /* BTS_BRANCH */ | 209 | struct ds_context { |
45 | struct { | 210 | /* pointer to the DS configuration; goes into MSR_IA32_DS_AREA */ |
46 | u64 from_ip; | 211 | unsigned char *ds; |
47 | u64 to_ip; | 212 | /* the owner of the BTS and PEBS configuration, respectively */ |
48 | } lbr; | 213 | struct task_struct *owner[2]; |
49 | /* BTS_TASK_ARRIVES or | 214 | /* buffer overflow notification function for BTS and PEBS */ |
50 | BTS_TASK_DEPARTS */ | 215 | ds_ovfl_callback_t callback[2]; |
51 | u64 jiffies; | 216 | /* the original buffer address */ |
52 | } variant; | 217 | void *buffer[2]; |
218 | /* the number of allocated pages for on-request allocated buffers */ | ||
219 | unsigned int pages[2]; | ||
220 | /* use count */ | ||
221 | unsigned long count; | ||
222 | /* a pointer to the context location inside the thread_struct | ||
223 | * or the per_cpu context array */ | ||
224 | struct ds_context **this; | ||
225 | /* a pointer to the task owning this context, or NULL, if the | ||
226 | * context is owned by a cpu */ | ||
227 | struct task_struct *task; | ||
53 | }; | 228 | }; |
54 | 229 | ||
55 | /* Overflow handling mechanisms */ | 230 | /* called by exit_thread() to free leftover contexts */ |
56 | #define DS_O_SIGNAL 1 /* send overflow signal */ | 231 | extern void ds_free(struct ds_context *context); |
57 | #define DS_O_WRAP 2 /* wrap around */ | 232 | |
58 | 233 | #else /* CONFIG_X86_DS */ | |
59 | extern int ds_allocate(void **, size_t); | 234 | |
60 | extern int ds_free(void **); | 235 | #define ds_init_intel(config) do {} while (0) |
61 | extern int ds_get_bts_size(void *); | ||
62 | extern int ds_get_bts_end(void *); | ||
63 | extern int ds_get_bts_index(void *); | ||
64 | extern int ds_set_overflow(void *, int); | ||
65 | extern int ds_get_overflow(void *); | ||
66 | extern int ds_clear(void *); | ||
67 | extern int ds_read_bts(void *, int, struct bts_struct *); | ||
68 | extern int ds_write_bts(void *, const struct bts_struct *); | ||
69 | extern unsigned long ds_debugctl_mask(void); | ||
70 | extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *c); | ||
71 | 236 | ||
237 | #endif /* CONFIG_X86_DS */ | ||
72 | #endif /* _ASM_X86_DS_H */ | 238 | #endif /* _ASM_X86_DS_H */ |
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h index 559105220a47..beaccb71628f 100644 --- a/include/asm-x86/processor.h +++ b/include/asm-x86/processor.h | |||
@@ -20,6 +20,7 @@ struct mm_struct; | |||
20 | #include <asm/msr.h> | 20 | #include <asm/msr.h> |
21 | #include <asm/desc_defs.h> | 21 | #include <asm/desc_defs.h> |
22 | #include <asm/nops.h> | 22 | #include <asm/nops.h> |
23 | #include <asm/ds.h> | ||
23 | 24 | ||
24 | #include <linux/personality.h> | 25 | #include <linux/personality.h> |
25 | #include <linux/cpumask.h> | 26 | #include <linux/cpumask.h> |
@@ -415,9 +416,14 @@ struct thread_struct { | |||
415 | unsigned io_bitmap_max; | 416 | unsigned io_bitmap_max; |
416 | /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ | 417 | /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ |
417 | unsigned long debugctlmsr; | 418 | unsigned long debugctlmsr; |
418 | /* Debug Store - if not 0 points to a DS Save Area configuration; | 419 | #ifdef CONFIG_X86_DS |
419 | * goes into MSR_IA32_DS_AREA */ | 420 | /* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */ |
420 | unsigned long ds_area_msr; | 421 | struct ds_context *ds_ctx; |
422 | #endif /* CONFIG_X86_DS */ | ||
423 | #ifdef CONFIG_X86_PTRACE_BTS | ||
424 | /* the signal to send on a bts buffer overflow */ | ||
425 | unsigned int bts_ovfl_signal; | ||
426 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
421 | }; | 427 | }; |
422 | 428 | ||
423 | static inline unsigned long native_get_debugreg(int regno) | 429 | static inline unsigned long native_get_debugreg(int regno) |
diff --git a/include/asm-x86/ptrace-abi.h b/include/asm-x86/ptrace-abi.h index f224eb3c3157..9bcaa75cbcaf 100644 --- a/include/asm-x86/ptrace-abi.h +++ b/include/asm-x86/ptrace-abi.h | |||
@@ -80,8 +80,9 @@ | |||
80 | 80 | ||
81 | #define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */ | 81 | #define PTRACE_SINGLEBLOCK 33 /* resume execution until next branch */ |
82 | 82 | ||
83 | #ifndef __ASSEMBLY__ | 83 | #ifdef CONFIG_X86_PTRACE_BTS |
84 | 84 | ||
85 | #ifndef __ASSEMBLY__ | ||
85 | #include <asm/types.h> | 86 | #include <asm/types.h> |
86 | 87 | ||
87 | /* configuration/status structure used in PTRACE_BTS_CONFIG and | 88 | /* configuration/status structure used in PTRACE_BTS_CONFIG and |
@@ -97,20 +98,20 @@ struct ptrace_bts_config { | |||
97 | /* actual size of bts_struct in bytes */ | 98 | /* actual size of bts_struct in bytes */ |
98 | __u32 bts_size; | 99 | __u32 bts_size; |
99 | }; | 100 | }; |
100 | #endif | 101 | #endif /* __ASSEMBLY__ */ |
101 | 102 | ||
102 | #define PTRACE_BTS_O_TRACE 0x1 /* branch trace */ | 103 | #define PTRACE_BTS_O_TRACE 0x1 /* branch trace */ |
103 | #define PTRACE_BTS_O_SCHED 0x2 /* scheduling events w/ jiffies */ | 104 | #define PTRACE_BTS_O_SCHED 0x2 /* scheduling events w/ jiffies */ |
104 | #define PTRACE_BTS_O_SIGNAL 0x4 /* send SIG<signal> on buffer overflow | 105 | #define PTRACE_BTS_O_SIGNAL 0x4 /* send SIG<signal> on buffer overflow |
105 | instead of wrapping around */ | 106 | instead of wrapping around */ |
106 | #define PTRACE_BTS_O_CUT_SIZE 0x8 /* cut requested size to max available | 107 | #define PTRACE_BTS_O_ALLOC 0x8 /* (re)allocate buffer */ |
107 | instead of failing */ | ||
108 | 108 | ||
109 | #define PTRACE_BTS_CONFIG 40 | 109 | #define PTRACE_BTS_CONFIG 40 |
110 | /* Configure branch trace recording. | 110 | /* Configure branch trace recording. |
111 | ADDR points to a struct ptrace_bts_config. | 111 | ADDR points to a struct ptrace_bts_config. |
112 | DATA gives the size of that buffer. | 112 | DATA gives the size of that buffer. |
113 | A new buffer is allocated, iff the size changes. | 113 | A new buffer is allocated, if requested in the flags. |
114 | An overflow signal may only be requested for new buffers. | ||
114 | Returns the number of bytes read. | 115 | Returns the number of bytes read. |
115 | */ | 116 | */ |
116 | #define PTRACE_BTS_STATUS 41 | 117 | #define PTRACE_BTS_STATUS 41 |
@@ -119,7 +120,7 @@ struct ptrace_bts_config { | |||
119 | Returns the number of bytes written. | 120 | Returns the number of bytes written. |
120 | */ | 121 | */ |
121 | #define PTRACE_BTS_SIZE 42 | 122 | #define PTRACE_BTS_SIZE 42 |
122 | /* Return the number of available BTS records. | 123 | /* Return the number of available BTS records for draining. |
123 | DATA and ADDR are ignored. | 124 | DATA and ADDR are ignored. |
124 | */ | 125 | */ |
125 | #define PTRACE_BTS_GET 43 | 126 | #define PTRACE_BTS_GET 43 |
@@ -139,5 +140,6 @@ struct ptrace_bts_config { | |||
139 | BTS records are read from oldest to newest. | 140 | BTS records are read from oldest to newest. |
140 | Returns number of BTS records drained. | 141 | Returns number of BTS records drained. |
141 | */ | 142 | */ |
143 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
142 | 144 | ||
143 | #endif | 145 | #endif |
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h index 9f922b0b95d6..6303701d18e3 100644 --- a/include/asm-x86/ptrace.h +++ b/include/asm-x86/ptrace.h | |||
@@ -125,14 +125,48 @@ struct pt_regs { | |||
125 | #endif /* __KERNEL__ */ | 125 | #endif /* __KERNEL__ */ |
126 | #endif /* !__i386__ */ | 126 | #endif /* !__i386__ */ |
127 | 127 | ||
128 | |||
129 | #ifdef CONFIG_X86_PTRACE_BTS | ||
130 | /* a branch trace record entry | ||
131 | * | ||
132 | * In order to unify the interface between various processor versions, | ||
133 | * we use the below data structure for all processors. | ||
134 | */ | ||
135 | enum bts_qualifier { | ||
136 | BTS_INVALID = 0, | ||
137 | BTS_BRANCH, | ||
138 | BTS_TASK_ARRIVES, | ||
139 | BTS_TASK_DEPARTS | ||
140 | }; | ||
141 | |||
142 | struct bts_struct { | ||
143 | __u64 qualifier; | ||
144 | union { | ||
145 | /* BTS_BRANCH */ | ||
146 | struct { | ||
147 | __u64 from_ip; | ||
148 | __u64 to_ip; | ||
149 | } lbr; | ||
150 | /* BTS_TASK_ARRIVES or | ||
151 | BTS_TASK_DEPARTS */ | ||
152 | __u64 jiffies; | ||
153 | } variant; | ||
154 | }; | ||
155 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
156 | |||
128 | #ifdef __KERNEL__ | 157 | #ifdef __KERNEL__ |
129 | 158 | ||
130 | /* the DS BTS struct is used for ptrace as well */ | 159 | #include <linux/init.h> |
131 | #include <asm/ds.h> | ||
132 | 160 | ||
161 | struct cpuinfo_x86; | ||
133 | struct task_struct; | 162 | struct task_struct; |
134 | 163 | ||
164 | #ifdef CONFIG_X86_PTRACE_BTS | ||
165 | extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *); | ||
135 | extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier); | 166 | extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier); |
167 | #else | ||
168 | #define ptrace_bts_init_intel(config) do {} while (0) | ||
169 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
136 | 170 | ||
137 | extern unsigned long profile_pc(struct pt_regs *regs); | 171 | extern unsigned long profile_pc(struct pt_regs *regs); |
138 | 172 | ||