diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-06 10:17:23 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-06 10:17:23 -0400 |
commit | 19268ed7449c561694d048a34601a30e2d1aaf79 (patch) | |
tree | 6f3f28ddac5d2b1cecd0f18ccf283f076839532a /include/asm-x86 | |
parent | b8cd9d056bbc5f2630ab1787dbf76f83bbb517c0 (diff) | |
parent | 493cd9122af5bd0b219974a48f0e31da0c29ff7e (diff) |
Merge branch 'x86/pebs' into x86-v28-for-linus-phase1
Conflicts:
include/asm-x86/ds.h
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'include/asm-x86')
-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 6b27c686fa10..c3c953a45b21 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 24cc5261af0c..51297d7f99c9 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> |
@@ -411,9 +412,14 @@ struct thread_struct { | |||
411 | unsigned io_bitmap_max; | 412 | unsigned io_bitmap_max; |
412 | /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ | 413 | /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ |
413 | unsigned long debugctlmsr; | 414 | unsigned long debugctlmsr; |
414 | /* Debug Store - if not 0 points to a DS Save Area configuration; | 415 | #ifdef CONFIG_X86_DS |
415 | * goes into MSR_IA32_DS_AREA */ | 416 | /* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */ |
416 | unsigned long ds_area_msr; | 417 | struct ds_context *ds_ctx; |
418 | #endif /* CONFIG_X86_DS */ | ||
419 | #ifdef CONFIG_X86_PTRACE_BTS | ||
420 | /* the signal to send on a bts buffer overflow */ | ||
421 | unsigned int bts_ovfl_signal; | ||
422 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
417 | }; | 423 | }; |
418 | 424 | ||
419 | static inline unsigned long native_get_debugreg(int regno) | 425 | 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 d0cf3344a586..4298b8882a78 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 /* ASM_X86__PTRACE_ABI_H */ | 145 | #endif /* ASM_X86__PTRACE_ABI_H */ |
diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h index d464f252edc3..45c75238cd08 100644 --- a/include/asm-x86/ptrace.h +++ b/include/asm-x86/ptrace.h | |||
@@ -127,14 +127,48 @@ struct pt_regs { | |||
127 | #endif /* __KERNEL__ */ | 127 | #endif /* __KERNEL__ */ |
128 | #endif /* !__i386__ */ | 128 | #endif /* !__i386__ */ |
129 | 129 | ||
130 | |||
131 | #ifdef CONFIG_X86_PTRACE_BTS | ||
132 | /* a branch trace record entry | ||
133 | * | ||
134 | * In order to unify the interface between various processor versions, | ||
135 | * we use the below data structure for all processors. | ||
136 | */ | ||
137 | enum bts_qualifier { | ||
138 | BTS_INVALID = 0, | ||
139 | BTS_BRANCH, | ||
140 | BTS_TASK_ARRIVES, | ||
141 | BTS_TASK_DEPARTS | ||
142 | }; | ||
143 | |||
144 | struct bts_struct { | ||
145 | __u64 qualifier; | ||
146 | union { | ||
147 | /* BTS_BRANCH */ | ||
148 | struct { | ||
149 | __u64 from_ip; | ||
150 | __u64 to_ip; | ||
151 | } lbr; | ||
152 | /* BTS_TASK_ARRIVES or | ||
153 | BTS_TASK_DEPARTS */ | ||
154 | __u64 jiffies; | ||
155 | } variant; | ||
156 | }; | ||
157 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
158 | |||
130 | #ifdef __KERNEL__ | 159 | #ifdef __KERNEL__ |
131 | 160 | ||
132 | /* the DS BTS struct is used for ptrace as well */ | 161 | #include <linux/init.h> |
133 | #include <asm/ds.h> | ||
134 | 162 | ||
163 | struct cpuinfo_x86; | ||
135 | struct task_struct; | 164 | struct task_struct; |
136 | 165 | ||
166 | #ifdef CONFIG_X86_PTRACE_BTS | ||
167 | extern void __cpuinit ptrace_bts_init_intel(struct cpuinfo_x86 *); | ||
137 | extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier); | 168 | extern void ptrace_bts_take_timestamp(struct task_struct *, enum bts_qualifier); |
169 | #else | ||
170 | #define ptrace_bts_init_intel(config) do {} while (0) | ||
171 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
138 | 172 | ||
139 | extern unsigned long profile_pc(struct pt_regs *regs); | 173 | extern unsigned long profile_pc(struct pt_regs *regs); |
140 | 174 | ||