diff options
34 files changed, 9 insertions, 3269 deletions
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index a19829374e6a..918fbb1855cc 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu | |||
@@ -502,23 +502,3 @@ config CPU_SUP_UMC_32 | |||
502 | CPU might render the kernel unbootable. | 502 | CPU might render the kernel unbootable. |
503 | 503 | ||
504 | If unsure, say N. | 504 | If unsure, say N. |
505 | |||
506 | config X86_DS | ||
507 | def_bool X86_PTRACE_BTS | ||
508 | depends on X86_DEBUGCTLMSR | ||
509 | select HAVE_HW_BRANCH_TRACER | ||
510 | |||
511 | config X86_PTRACE_BTS | ||
512 | bool "Branch Trace Store" | ||
513 | default y | ||
514 | depends on X86_DEBUGCTLMSR | ||
515 | depends on BROKEN | ||
516 | ---help--- | ||
517 | This adds a ptrace interface to the hardware's branch trace store. | ||
518 | |||
519 | Debuggers may use it to collect an execution trace of the debugged | ||
520 | application in order to answer the question 'how did I get here?'. | ||
521 | Debuggers may trace user mode as well as kernel mode. | ||
522 | |||
523 | Say Y unless there is no application development on this machine | ||
524 | and you want to save a small amount of code size. | ||
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index bc01e3ebfeb2..bd58c8abbfbd 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
@@ -174,15 +174,6 @@ config IOMMU_LEAK | |||
174 | Add a simple leak tracer to the IOMMU code. This is useful when you | 174 | Add a simple leak tracer to the IOMMU code. This is useful when you |
175 | are debugging a buggy device driver that leaks IOMMU mappings. | 175 | are debugging a buggy device driver that leaks IOMMU mappings. |
176 | 176 | ||
177 | config X86_DS_SELFTEST | ||
178 | bool "DS selftest" | ||
179 | default y | ||
180 | depends on DEBUG_KERNEL | ||
181 | depends on X86_DS | ||
182 | ---help--- | ||
183 | Perform Debug Store selftests at boot time. | ||
184 | If in doubt, say "N". | ||
185 | |||
186 | config HAVE_MMIOTRACE_SUPPORT | 177 | config HAVE_MMIOTRACE_SUPPORT |
187 | def_bool y | 178 | def_bool y |
188 | 179 | ||
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h deleted file mode 100644 index 70dac199b093..000000000000 --- a/arch/x86/include/asm/ds.h +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | /* | ||
2 | * Debug Store (DS) support | ||
3 | * | ||
4 | * This provides a low-level interface to the hardware's Debug Store | ||
5 | * feature that is used for branch trace store (BTS) and | ||
6 | * precise-event based sampling (PEBS). | ||
7 | * | ||
8 | * It manages: | ||
9 | * - DS and BTS hardware configuration | ||
10 | * - buffer overflow handling (to be done) | ||
11 | * - buffer access | ||
12 | * | ||
13 | * It does not do: | ||
14 | * - security checking (is the caller allowed to trace the task) | ||
15 | * - buffer allocation (memory accounting) | ||
16 | * | ||
17 | * | ||
18 | * Copyright (C) 2007-2009 Intel Corporation. | ||
19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 | ||
20 | */ | ||
21 | |||
22 | #ifndef _ASM_X86_DS_H | ||
23 | #define _ASM_X86_DS_H | ||
24 | |||
25 | |||
26 | #include <linux/types.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/err.h> | ||
29 | |||
30 | |||
31 | #ifdef CONFIG_X86_DS | ||
32 | |||
33 | struct task_struct; | ||
34 | struct ds_context; | ||
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 *); | ||
41 | |||
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 | |||
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. | ||
79 | * | ||
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. | ||
85 | * | ||
86 | * The function might sleep. | ||
87 | * | ||
88 | * task: the task to request recording for | ||
89 | * cpu: the cpu to request recording for | ||
90 | * base: the base pointer for the (non-pageable) buffer; | ||
91 | * size: the size of the provided buffer in bytes | ||
92 | * ovfl: pointer to a function to be called on buffer overflow; | ||
93 | * NULL if cyclic buffer requested | ||
94 | * th: the interrupt threshold in records from the end of the buffer; | ||
95 | * -1 if no interrupt threshold is requested. | ||
96 | * flags: a bit-mask of the above flags | ||
97 | */ | ||
98 | extern struct bts_tracer *ds_request_bts_task(struct task_struct *task, | ||
99 | void *base, size_t size, | ||
100 | bts_ovfl_callback_t ovfl, | ||
101 | size_t th, unsigned int flags); | ||
102 | extern struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size, | ||
103 | bts_ovfl_callback_t ovfl, | ||
104 | size_t th, unsigned int flags); | ||
105 | extern struct pebs_tracer *ds_request_pebs_task(struct task_struct *task, | ||
106 | void *base, size_t size, | ||
107 | pebs_ovfl_callback_t ovfl, | ||
108 | size_t th, unsigned int flags); | ||
109 | extern struct pebs_tracer *ds_request_pebs_cpu(int cpu, | ||
110 | void *base, size_t size, | ||
111 | pebs_ovfl_callback_t ovfl, | ||
112 | size_t th, unsigned int flags); | ||
113 | |||
114 | /* | ||
115 | * Release BTS or PEBS resources | ||
116 | * Suspend and resume BTS or PEBS tracing | ||
117 | * | ||
118 | * Must be called with irq's enabled. | ||
119 | * | ||
120 | * tracer: the tracer handle returned from ds_request_~() | ||
121 | */ | ||
122 | extern void ds_release_bts(struct bts_tracer *tracer); | ||
123 | extern void ds_suspend_bts(struct bts_tracer *tracer); | ||
124 | extern void ds_resume_bts(struct bts_tracer *tracer); | ||
125 | extern void ds_release_pebs(struct pebs_tracer *tracer); | ||
126 | extern void ds_suspend_pebs(struct pebs_tracer *tracer); | ||
127 | extern void ds_resume_pebs(struct pebs_tracer *tracer); | ||
128 | |||
129 | /* | ||
130 | * Release BTS or PEBS resources | ||
131 | * Suspend and resume BTS or PEBS tracing | ||
132 | * | ||
133 | * Cpu tracers must call this on the traced cpu. | ||
134 | * Task tracers must call ds_release_~_noirq() for themselves. | ||
135 | * | ||
136 | * May be called with irq's disabled. | ||
137 | * | ||
138 | * Returns 0 if successful; | ||
139 | * -EPERM if the cpu tracer does not trace the current cpu. | ||
140 | * -EPERM if the task tracer does not trace itself. | ||
141 | * | ||
142 | * tracer: the tracer handle returned from ds_request_~() | ||
143 | */ | ||
144 | extern int ds_release_bts_noirq(struct bts_tracer *tracer); | ||
145 | extern int ds_suspend_bts_noirq(struct bts_tracer *tracer); | ||
146 | extern int ds_resume_bts_noirq(struct bts_tracer *tracer); | ||
147 | extern int ds_release_pebs_noirq(struct pebs_tracer *tracer); | ||
148 | extern int ds_suspend_pebs_noirq(struct pebs_tracer *tracer); | ||
149 | extern int ds_resume_pebs_noirq(struct pebs_tracer *tracer); | ||
150 | |||
151 | |||
152 | /* | ||
153 | * The raw DS buffer state as it is used for BTS and PEBS recording. | ||
154 | * | ||
155 | * This is the low-level, arch-dependent interface for working | ||
156 | * directly on the raw trace data. | ||
157 | */ | ||
158 | struct ds_trace { | ||
159 | /* the number of bts/pebs records */ | ||
160 | size_t n; | ||
161 | /* the size of a bts/pebs record in bytes */ | ||
162 | size_t size; | ||
163 | /* pointers into the raw buffer: | ||
164 | - to the first entry */ | ||
165 | void *begin; | ||
166 | /* - one beyond the last entry */ | ||
167 | void *end; | ||
168 | /* - one beyond the newest entry */ | ||
169 | void *top; | ||
170 | /* - the interrupt threshold */ | ||
171 | void *ith; | ||
172 | /* flags given on ds_request() */ | ||
173 | unsigned int flags; | ||
174 | }; | ||
175 | |||
176 | /* | ||
177 | * An arch-independent view on branch trace data. | ||
178 | */ | ||
179 | enum bts_qualifier { | ||
180 | bts_invalid, | ||
181 | #define BTS_INVALID bts_invalid | ||
182 | |||
183 | bts_branch, | ||
184 | #define BTS_BRANCH bts_branch | ||
185 | |||
186 | bts_task_arrives, | ||
187 | #define BTS_TASK_ARRIVES bts_task_arrives | ||
188 | |||
189 | bts_task_departs, | ||
190 | #define BTS_TASK_DEPARTS bts_task_departs | ||
191 | |||
192 | bts_qual_bit_size = 4, | ||
193 | bts_qual_max = (1 << bts_qual_bit_size), | ||
194 | }; | ||
195 | |||
196 | struct bts_struct { | ||
197 | __u64 qualifier; | ||
198 | union { | ||
199 | /* BTS_BRANCH */ | ||
200 | struct { | ||
201 | __u64 from; | ||
202 | __u64 to; | ||
203 | } lbr; | ||
204 | /* BTS_TASK_ARRIVES or BTS_TASK_DEPARTS */ | ||
205 | struct { | ||
206 | __u64 clock; | ||
207 | pid_t pid; | ||
208 | } event; | ||
209 | } variant; | ||
210 | }; | ||
211 | |||
212 | |||
213 | /* | ||
214 | * The BTS state. | ||
215 | * | ||
216 | * This gives access to the raw DS state and adds functions to provide | ||
217 | * an arch-independent view of the BTS data. | ||
218 | */ | ||
219 | struct bts_trace { | ||
220 | struct ds_trace ds; | ||
221 | |||
222 | int (*read)(struct bts_tracer *tracer, const void *at, | ||
223 | struct bts_struct *out); | ||
224 | int (*write)(struct bts_tracer *tracer, const struct bts_struct *in); | ||
225 | }; | ||
226 | |||
227 | |||
228 | /* | ||
229 | * The PEBS state. | ||
230 | * | ||
231 | * This gives access to the raw DS state and the PEBS-specific counter | ||
232 | * reset value. | ||
233 | */ | ||
234 | struct pebs_trace { | ||
235 | struct ds_trace ds; | ||
236 | |||
237 | /* the number of valid counters in the below array */ | ||
238 | unsigned int counters; | ||
239 | |||
240 | #define MAX_PEBS_COUNTERS 4 | ||
241 | /* the counter reset value */ | ||
242 | unsigned long long counter_reset[MAX_PEBS_COUNTERS]; | ||
243 | }; | ||
244 | |||
245 | |||
246 | /* | ||
247 | * Read the BTS or PEBS trace. | ||
248 | * | ||
249 | * Returns a view on the trace collected for the parameter tracer. | ||
250 | * | ||
251 | * The view remains valid as long as the traced task is not running or | ||
252 | * the tracer is suspended. | ||
253 | * Writes into the trace buffer are not reflected. | ||
254 | * | ||
255 | * tracer: the tracer handle returned from ds_request_~() | ||
256 | */ | ||
257 | extern const struct bts_trace *ds_read_bts(struct bts_tracer *tracer); | ||
258 | extern const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer); | ||
259 | |||
260 | |||
261 | /* | ||
262 | * Reset the write pointer of the BTS/PEBS buffer. | ||
263 | * | ||
264 | * Returns 0 on success; -Eerrno on error | ||
265 | * | ||
266 | * tracer: the tracer handle returned from ds_request_~() | ||
267 | */ | ||
268 | extern int ds_reset_bts(struct bts_tracer *tracer); | ||
269 | extern int ds_reset_pebs(struct pebs_tracer *tracer); | ||
270 | |||
271 | /* | ||
272 | * Set the PEBS counter reset value. | ||
273 | * | ||
274 | * Returns 0 on success; -Eerrno on error | ||
275 | * | ||
276 | * tracer: the tracer handle returned from ds_request_pebs() | ||
277 | * counter: the index of the counter | ||
278 | * value: the new counter reset value | ||
279 | */ | ||
280 | extern int ds_set_pebs_reset(struct pebs_tracer *tracer, | ||
281 | unsigned int counter, u64 value); | ||
282 | |||
283 | /* | ||
284 | * Initialization | ||
285 | */ | ||
286 | struct cpuinfo_x86; | ||
287 | extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *); | ||
288 | |||
289 | /* | ||
290 | * Context switch work | ||
291 | */ | ||
292 | extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); | ||
293 | |||
294 | #else /* CONFIG_X86_DS */ | ||
295 | |||
296 | struct cpuinfo_x86; | ||
297 | static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} | ||
298 | static inline void ds_switch_to(struct task_struct *prev, | ||
299 | struct task_struct *next) {} | ||
300 | |||
301 | #endif /* CONFIG_X86_DS */ | ||
302 | #endif /* _ASM_X86_DS_H */ | ||
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index b753ea59703a..5bec21a66dc5 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -21,7 +21,6 @@ struct mm_struct; | |||
21 | #include <asm/msr.h> | 21 | #include <asm/msr.h> |
22 | #include <asm/desc_defs.h> | 22 | #include <asm/desc_defs.h> |
23 | #include <asm/nops.h> | 23 | #include <asm/nops.h> |
24 | #include <asm/ds.h> | ||
25 | 24 | ||
26 | #include <linux/personality.h> | 25 | #include <linux/personality.h> |
27 | #include <linux/cpumask.h> | 26 | #include <linux/cpumask.h> |
@@ -29,6 +28,7 @@ struct mm_struct; | |||
29 | #include <linux/threads.h> | 28 | #include <linux/threads.h> |
30 | #include <linux/math64.h> | 29 | #include <linux/math64.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/err.h> | ||
32 | 32 | ||
33 | #define HBP_NUM 4 | 33 | #define HBP_NUM 4 |
34 | /* | 34 | /* |
@@ -473,10 +473,6 @@ struct thread_struct { | |||
473 | unsigned long iopl; | 473 | unsigned long iopl; |
474 | /* Max allowed port in the bitmap, in bytes: */ | 474 | /* Max allowed port in the bitmap, in bytes: */ |
475 | unsigned io_bitmap_max; | 475 | unsigned io_bitmap_max; |
476 | /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set. */ | ||
477 | unsigned long debugctlmsr; | ||
478 | /* Debug Store context; see asm/ds.h */ | ||
479 | struct ds_context *ds_ctx; | ||
480 | }; | 476 | }; |
481 | 477 | ||
482 | static inline unsigned long native_get_debugreg(int regno) | 478 | static inline unsigned long native_get_debugreg(int regno) |
@@ -814,21 +810,6 @@ static inline unsigned long get_debugctlmsr(void) | |||
814 | return debugctlmsr; | 810 | return debugctlmsr; |
815 | } | 811 | } |
816 | 812 | ||
817 | static inline unsigned long get_debugctlmsr_on_cpu(int cpu) | ||
818 | { | ||
819 | u64 debugctlmsr = 0; | ||
820 | u32 val1, val2; | ||
821 | |||
822 | #ifndef CONFIG_X86_DEBUGCTLMSR | ||
823 | if (boot_cpu_data.x86 < 6) | ||
824 | return 0; | ||
825 | #endif | ||
826 | rdmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, &val1, &val2); | ||
827 | debugctlmsr = val1 | ((u64)val2 << 32); | ||
828 | |||
829 | return debugctlmsr; | ||
830 | } | ||
831 | |||
832 | static inline void update_debugctlmsr(unsigned long debugctlmsr) | 813 | static inline void update_debugctlmsr(unsigned long debugctlmsr) |
833 | { | 814 | { |
834 | #ifndef CONFIG_X86_DEBUGCTLMSR | 815 | #ifndef CONFIG_X86_DEBUGCTLMSR |
@@ -838,18 +819,6 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) | |||
838 | wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); | 819 | wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); |
839 | } | 820 | } |
840 | 821 | ||
841 | static inline void update_debugctlmsr_on_cpu(int cpu, | ||
842 | unsigned long debugctlmsr) | ||
843 | { | ||
844 | #ifndef CONFIG_X86_DEBUGCTLMSR | ||
845 | if (boot_cpu_data.x86 < 6) | ||
846 | return; | ||
847 | #endif | ||
848 | wrmsr_on_cpu(cpu, MSR_IA32_DEBUGCTLMSR, | ||
849 | (u32)((u64)debugctlmsr), | ||
850 | (u32)((u64)debugctlmsr >> 32)); | ||
851 | } | ||
852 | |||
853 | /* | 822 | /* |
854 | * from system description table in BIOS. Mostly for MCA use, but | 823 | * from system description table in BIOS. Mostly for MCA use, but |
855 | * others may find it useful: | 824 | * others may find it useful: |
diff --git a/arch/x86/include/asm/ptrace-abi.h b/arch/x86/include/asm/ptrace-abi.h index 86723035a515..52b098a6eebb 100644 --- a/arch/x86/include/asm/ptrace-abi.h +++ b/arch/x86/include/asm/ptrace-abi.h | |||
@@ -82,61 +82,6 @@ | |||
82 | 82 | ||
83 | #ifndef __ASSEMBLY__ | 83 | #ifndef __ASSEMBLY__ |
84 | #include <linux/types.h> | 84 | #include <linux/types.h> |
85 | 85 | #endif | |
86 | /* configuration/status structure used in PTRACE_BTS_CONFIG and | ||
87 | PTRACE_BTS_STATUS commands. | ||
88 | */ | ||
89 | struct ptrace_bts_config { | ||
90 | /* requested or actual size of BTS buffer in bytes */ | ||
91 | __u32 size; | ||
92 | /* bitmask of below flags */ | ||
93 | __u32 flags; | ||
94 | /* buffer overflow signal */ | ||
95 | __u32 signal; | ||
96 | /* actual size of bts_struct in bytes */ | ||
97 | __u32 bts_size; | ||
98 | }; | ||
99 | #endif /* __ASSEMBLY__ */ | ||
100 | |||
101 | #define PTRACE_BTS_O_TRACE 0x1 /* branch trace */ | ||
102 | #define PTRACE_BTS_O_SCHED 0x2 /* scheduling events w/ jiffies */ | ||
103 | #define PTRACE_BTS_O_SIGNAL 0x4 /* send SIG<signal> on buffer overflow | ||
104 | instead of wrapping around */ | ||
105 | #define PTRACE_BTS_O_ALLOC 0x8 /* (re)allocate buffer */ | ||
106 | |||
107 | #define PTRACE_BTS_CONFIG 40 | ||
108 | /* Configure branch trace recording. | ||
109 | ADDR points to a struct ptrace_bts_config. | ||
110 | DATA gives the size of that buffer. | ||
111 | A new buffer is allocated, if requested in the flags. | ||
112 | An overflow signal may only be requested for new buffers. | ||
113 | Returns the number of bytes read. | ||
114 | */ | ||
115 | #define PTRACE_BTS_STATUS 41 | ||
116 | /* Return the current configuration in a struct ptrace_bts_config | ||
117 | pointed to by ADDR; DATA gives the size of that buffer. | ||
118 | Returns the number of bytes written. | ||
119 | */ | ||
120 | #define PTRACE_BTS_SIZE 42 | ||
121 | /* Return the number of available BTS records for draining. | ||
122 | DATA and ADDR are ignored. | ||
123 | */ | ||
124 | #define PTRACE_BTS_GET 43 | ||
125 | /* Get a single BTS record. | ||
126 | DATA defines the index into the BTS array, where 0 is the newest | ||
127 | entry, and higher indices refer to older entries. | ||
128 | ADDR is pointing to struct bts_struct (see asm/ds.h). | ||
129 | */ | ||
130 | #define PTRACE_BTS_CLEAR 44 | ||
131 | /* Clear the BTS buffer. | ||
132 | DATA and ADDR are ignored. | ||
133 | */ | ||
134 | #define PTRACE_BTS_DRAIN 45 | ||
135 | /* Read all available BTS records and clear the buffer. | ||
136 | ADDR points to an array of struct bts_struct. | ||
137 | DATA gives the size of that buffer. | ||
138 | BTS records are read from oldest to newest. | ||
139 | Returns number of BTS records drained. | ||
140 | */ | ||
141 | 86 | ||
142 | #endif /* _ASM_X86_PTRACE_ABI_H */ | 87 | #endif /* _ASM_X86_PTRACE_ABI_H */ |
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 69a686a7dff0..78cd1ea94500 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h | |||
@@ -289,12 +289,6 @@ extern int do_get_thread_area(struct task_struct *p, int idx, | |||
289 | extern int do_set_thread_area(struct task_struct *p, int idx, | 289 | extern int do_set_thread_area(struct task_struct *p, int idx, |
290 | struct user_desc __user *info, int can_allocate); | 290 | struct user_desc __user *info, int can_allocate); |
291 | 291 | ||
292 | #ifdef CONFIG_X86_PTRACE_BTS | ||
293 | extern void ptrace_bts_untrace(struct task_struct *tsk); | ||
294 | |||
295 | #define arch_ptrace_untrace(tsk) ptrace_bts_untrace(tsk) | ||
296 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
297 | |||
298 | #endif /* __KERNEL__ */ | 292 | #endif /* __KERNEL__ */ |
299 | 293 | ||
300 | #endif /* !__ASSEMBLY__ */ | 294 | #endif /* !__ASSEMBLY__ */ |
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index e0d28901e969..dc85e12d1405 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h | |||
@@ -92,8 +92,6 @@ struct thread_info { | |||
92 | #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ | 92 | #define TIF_IO_BITMAP 22 /* uses I/O bitmap */ |
93 | #define TIF_FREEZE 23 /* is freezing for suspend */ | 93 | #define TIF_FREEZE 23 /* is freezing for suspend */ |
94 | #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ | 94 | #define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ |
95 | #define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ | ||
96 | #define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ | ||
97 | #define TIF_LAZY_MMU_UPDATES 27 /* task is updating the mmu lazily */ | 95 | #define TIF_LAZY_MMU_UPDATES 27 /* task is updating the mmu lazily */ |
98 | #define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ | 96 | #define TIF_SYSCALL_TRACEPOINT 28 /* syscall tracepoint instrumentation */ |
99 | 97 | ||
@@ -115,8 +113,6 @@ struct thread_info { | |||
115 | #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) | 113 | #define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) |
116 | #define _TIF_FREEZE (1 << TIF_FREEZE) | 114 | #define _TIF_FREEZE (1 << TIF_FREEZE) |
117 | #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) | 115 | #define _TIF_FORCED_TF (1 << TIF_FORCED_TF) |
118 | #define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) | ||
119 | #define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) | ||
120 | #define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES) | 116 | #define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES) |
121 | #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) | 117 | #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) |
122 | 118 | ||
@@ -147,7 +143,7 @@ struct thread_info { | |||
147 | 143 | ||
148 | /* flags to check in __switch_to() */ | 144 | /* flags to check in __switch_to() */ |
149 | #define _TIF_WORK_CTXSW \ | 145 | #define _TIF_WORK_CTXSW \ |
150 | (_TIF_IO_BITMAP|_TIF_DEBUGCTLMSR|_TIF_DS_AREA_MSR|_TIF_NOTSC) | 146 | (_TIF_IO_BITMAP|_TIF_NOTSC) |
151 | 147 | ||
152 | #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) | 148 | #define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY) |
153 | #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) | 149 | #define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG) |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 4c58352209e0..e77b22083721 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -47,8 +47,6 @@ obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o | |||
47 | obj-y += process.o | 47 | obj-y += process.o |
48 | obj-y += i387.o xsave.o | 48 | obj-y += i387.o xsave.o |
49 | obj-y += ptrace.o | 49 | obj-y += ptrace.o |
50 | obj-$(CONFIG_X86_DS) += ds.o | ||
51 | obj-$(CONFIG_X86_DS_SELFTEST) += ds_selftest.o | ||
52 | obj-$(CONFIG_X86_32) += tls.o | 50 | obj-$(CONFIG_X86_32) += tls.o |
53 | obj-$(CONFIG_IA32_EMULATION) += tls.o | 51 | obj-$(CONFIG_IA32_EMULATION) += tls.o |
54 | obj-y += step.o | 52 | obj-y += step.o |
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 7e1cca13af35..d72377c41c76 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
14 | #include <asm/msr.h> | 14 | #include <asm/msr.h> |
15 | #include <asm/ds.h> | ||
16 | #include <asm/bugs.h> | 15 | #include <asm/bugs.h> |
17 | #include <asm/cpu.h> | 16 | #include <asm/cpu.h> |
18 | 17 | ||
@@ -367,7 +366,6 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c) | |||
367 | set_cpu_cap(c, X86_FEATURE_BTS); | 366 | set_cpu_cap(c, X86_FEATURE_BTS); |
368 | if (!(l1 & (1<<12))) | 367 | if (!(l1 & (1<<12))) |
369 | set_cpu_cap(c, X86_FEATURE_PEBS); | 368 | set_cpu_cap(c, X86_FEATURE_PEBS); |
370 | ds_init_intel(c); | ||
371 | } | 369 | } |
372 | 370 | ||
373 | if (c->x86 == 6 && c->x86_model == 29 && cpu_has_clflush) | 371 | if (c->x86 == 6 && c->x86_model == 29 && cpu_has_clflush) |
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c deleted file mode 100644 index 1c47390dd0e5..000000000000 --- a/arch/x86/kernel/ds.c +++ /dev/null | |||
@@ -1,1437 +0,0 @@ | |||
1 | /* | ||
2 | * Debug Store support | ||
3 | * | ||
4 | * This provides a low-level interface to the hardware's Debug Store | ||
5 | * feature that is used for branch trace store (BTS) and | ||
6 | * precise-event based sampling (PEBS). | ||
7 | * | ||
8 | * It manages: | ||
9 | * - DS and BTS hardware configuration | ||
10 | * - buffer overflow handling (to be done) | ||
11 | * - buffer access | ||
12 | * | ||
13 | * It does not do: | ||
14 | * - security checking (is the caller allowed to trace the task) | ||
15 | * - buffer allocation (memory accounting) | ||
16 | * | ||
17 | * | ||
18 | * Copyright (C) 2007-2009 Intel Corporation. | ||
19 | * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009 | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/trace_clock.h> | ||
29 | |||
30 | #include <asm/ds.h> | ||
31 | |||
32 | #include "ds_selftest.h" | ||
33 | |||
34 | /* | ||
35 | * The configuration for a particular DS hardware implementation: | ||
36 | */ | ||
37 | struct ds_configuration { | ||
38 | /* The name of the configuration: */ | ||
39 | const char *name; | ||
40 | |||
41 | /* The size of pointer-typed fields in DS, BTS, and PEBS: */ | ||
42 | unsigned char sizeof_ptr_field; | ||
43 | |||
44 | /* The size of a BTS/PEBS record in bytes: */ | ||
45 | unsigned char sizeof_rec[2]; | ||
46 | |||
47 | /* The number of pebs counter reset values in the DS structure. */ | ||
48 | unsigned char nr_counter_reset; | ||
49 | |||
50 | /* Control bit-masks indexed by enum ds_feature: */ | ||
51 | unsigned long ctl[dsf_ctl_max]; | ||
52 | }; | ||
53 | static struct ds_configuration ds_cfg __read_mostly; | ||
54 | |||
55 | |||
56 | /* Maximal size of a DS configuration: */ | ||
57 | #define MAX_SIZEOF_DS 0x80 | ||
58 | |||
59 | /* Maximal size of a BTS record: */ | ||
60 | #define MAX_SIZEOF_BTS (3 * 8) | ||
61 | |||
62 | /* BTS and PEBS buffer alignment: */ | ||
63 | #define DS_ALIGNMENT (1 << 3) | ||
64 | |||
65 | /* Number of buffer pointers in DS: */ | ||
66 | #define NUM_DS_PTR_FIELDS 8 | ||
67 | |||
68 | /* Size of a pebs reset value in DS: */ | ||
69 | #define PEBS_RESET_FIELD_SIZE 8 | ||
70 | |||
71 | /* Mask of control bits in the DS MSR register: */ | ||
72 | #define BTS_CONTROL \ | ||
73 | ( ds_cfg.ctl[dsf_bts] | \ | ||
74 | ds_cfg.ctl[dsf_bts_kernel] | \ | ||
75 | ds_cfg.ctl[dsf_bts_user] | \ | ||
76 | ds_cfg.ctl[dsf_bts_overflow] ) | ||
77 | |||
78 | /* | ||
79 | * A BTS or PEBS tracer. | ||
80 | * | ||
81 | * This holds the configuration of the tracer and serves as a handle | ||
82 | * to identify tracers. | ||
83 | */ | ||
84 | struct ds_tracer { | ||
85 | /* The DS context (partially) owned by this tracer. */ | ||
86 | struct ds_context *context; | ||
87 | /* The buffer provided on ds_request() and its size in bytes. */ | ||
88 | void *buffer; | ||
89 | size_t size; | ||
90 | }; | ||
91 | |||
92 | struct bts_tracer { | ||
93 | /* The common DS part: */ | ||
94 | struct ds_tracer ds; | ||
95 | |||
96 | /* The trace including the DS configuration: */ | ||
97 | struct bts_trace trace; | ||
98 | |||
99 | /* Buffer overflow notification function: */ | ||
100 | bts_ovfl_callback_t ovfl; | ||
101 | |||
102 | /* Active flags affecting trace collection. */ | ||
103 | unsigned int flags; | ||
104 | }; | ||
105 | |||
106 | struct pebs_tracer { | ||
107 | /* The common DS part: */ | ||
108 | struct ds_tracer ds; | ||
109 | |||
110 | /* The trace including the DS configuration: */ | ||
111 | struct pebs_trace trace; | ||
112 | |||
113 | /* Buffer overflow notification function: */ | ||
114 | pebs_ovfl_callback_t ovfl; | ||
115 | }; | ||
116 | |||
117 | /* | ||
118 | * Debug Store (DS) save area configuration (see Intel64 and IA32 | ||
119 | * Architectures Software Developer's Manual, section 18.5) | ||
120 | * | ||
121 | * The DS configuration consists of the following fields; different | ||
122 | * architetures vary in the size of those fields. | ||
123 | * | ||
124 | * - double-word aligned base linear address of the BTS buffer | ||
125 | * - write pointer into the BTS buffer | ||
126 | * - end linear address of the BTS buffer (one byte beyond the end of | ||
127 | * the buffer) | ||
128 | * - interrupt pointer into BTS buffer | ||
129 | * (interrupt occurs when write pointer passes interrupt pointer) | ||
130 | * - double-word aligned base linear address of the PEBS buffer | ||
131 | * - write pointer into the PEBS buffer | ||
132 | * - end linear address of the PEBS buffer (one byte beyond the end of | ||
133 | * the buffer) | ||
134 | * - interrupt pointer into PEBS buffer | ||
135 | * (interrupt occurs when write pointer passes interrupt pointer) | ||
136 | * - value to which counter is reset following counter overflow | ||
137 | * | ||
138 | * Later architectures use 64bit pointers throughout, whereas earlier | ||
139 | * architectures use 32bit pointers in 32bit mode. | ||
140 | * | ||
141 | * | ||
142 | * We compute the base address for the first 8 fields based on: | ||
143 | * - the field size stored in the DS configuration | ||
144 | * - the relative field position | ||
145 | * - an offset giving the start of the respective region | ||
146 | * | ||
147 | * This offset is further used to index various arrays holding | ||
148 | * information for BTS and PEBS at the respective index. | ||
149 | * | ||
150 | * On later 32bit processors, we only access the lower 32bit of the | ||
151 | * 64bit pointer fields. The upper halves will be zeroed out. | ||
152 | */ | ||
153 | |||
154 | enum ds_field { | ||
155 | ds_buffer_base = 0, | ||
156 | ds_index, | ||
157 | ds_absolute_maximum, | ||
158 | ds_interrupt_threshold, | ||
159 | }; | ||
160 | |||
161 | enum ds_qualifier { | ||
162 | ds_bts = 0, | ||
163 | ds_pebs | ||
164 | }; | ||
165 | |||
166 | static inline unsigned long | ||
167 | ds_get(const unsigned char *base, enum ds_qualifier qual, enum ds_field field) | ||
168 | { | ||
169 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); | ||
170 | return *(unsigned long *)base; | ||
171 | } | ||
172 | |||
173 | static inline void | ||
174 | ds_set(unsigned char *base, enum ds_qualifier qual, enum ds_field field, | ||
175 | unsigned long value) | ||
176 | { | ||
177 | base += (ds_cfg.sizeof_ptr_field * (field + (4 * qual))); | ||
178 | (*(unsigned long *)base) = value; | ||
179 | } | ||
180 | |||
181 | |||
182 | /* | ||
183 | * Locking is done only for allocating BTS or PEBS resources. | ||
184 | */ | ||
185 | static DEFINE_SPINLOCK(ds_lock); | ||
186 | |||
187 | /* | ||
188 | * We either support (system-wide) per-cpu or per-thread allocation. | ||
189 | * We distinguish the two based on the task_struct pointer, where a | ||
190 | * NULL pointer indicates per-cpu allocation for the current cpu. | ||
191 | * | ||
192 | * Allocations are use-counted. As soon as resources are allocated, | ||
193 | * further allocations must be of the same type (per-cpu or | ||
194 | * per-thread). We model this by counting allocations (i.e. the number | ||
195 | * of tracers of a certain type) for one type negatively: | ||
196 | * =0 no tracers | ||
197 | * >0 number of per-thread tracers | ||
198 | * <0 number of per-cpu tracers | ||
199 | * | ||
200 | * Tracers essentially gives the number of ds contexts for a certain | ||
201 | * type of allocation. | ||
202 | */ | ||
203 | static atomic_t tracers = ATOMIC_INIT(0); | ||
204 | |||
205 | static inline int get_tracer(struct task_struct *task) | ||
206 | { | ||
207 | int error; | ||
208 | |||
209 | spin_lock_irq(&ds_lock); | ||
210 | |||
211 | if (task) { | ||
212 | error = -EPERM; | ||
213 | if (atomic_read(&tracers) < 0) | ||
214 | goto out; | ||
215 | atomic_inc(&tracers); | ||
216 | } else { | ||
217 | error = -EPERM; | ||
218 | if (atomic_read(&tracers) > 0) | ||
219 | goto out; | ||
220 | atomic_dec(&tracers); | ||
221 | } | ||
222 | |||
223 | error = 0; | ||
224 | out: | ||
225 | spin_unlock_irq(&ds_lock); | ||
226 | return error; | ||
227 | } | ||
228 | |||
229 | static inline void put_tracer(struct task_struct *task) | ||
230 | { | ||
231 | if (task) | ||
232 | atomic_dec(&tracers); | ||
233 | else | ||
234 | atomic_inc(&tracers); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * The DS context is either attached to a thread or to a cpu: | ||
239 | * - in the former case, the thread_struct contains a pointer to the | ||
240 | * attached context. | ||
241 | * - in the latter case, we use a static array of per-cpu context | ||
242 | * pointers. | ||
243 | * | ||
244 | * Contexts are use-counted. They are allocated on first access and | ||
245 | * deallocated when the last user puts the context. | ||
246 | */ | ||
247 | struct ds_context { | ||
248 | /* The DS configuration; goes into MSR_IA32_DS_AREA: */ | ||
249 | unsigned char ds[MAX_SIZEOF_DS]; | ||
250 | |||
251 | /* The owner of the BTS and PEBS configuration, respectively: */ | ||
252 | struct bts_tracer *bts_master; | ||
253 | struct pebs_tracer *pebs_master; | ||
254 | |||
255 | /* Use count: */ | ||
256 | unsigned long count; | ||
257 | |||
258 | /* Pointer to the context pointer field: */ | ||
259 | struct ds_context **this; | ||
260 | |||
261 | /* The traced task; NULL for cpu tracing: */ | ||
262 | struct task_struct *task; | ||
263 | |||
264 | /* The traced cpu; only valid if task is NULL: */ | ||
265 | int cpu; | ||
266 | }; | ||
267 | |||
268 | static DEFINE_PER_CPU(struct ds_context *, cpu_ds_context); | ||
269 | |||
270 | |||
271 | static struct ds_context *ds_get_context(struct task_struct *task, int cpu) | ||
272 | { | ||
273 | struct ds_context **p_context = | ||
274 | (task ? &task->thread.ds_ctx : &per_cpu(cpu_ds_context, cpu)); | ||
275 | struct ds_context *context = NULL; | ||
276 | struct ds_context *new_context = NULL; | ||
277 | |||
278 | /* Chances are small that we already have a context. */ | ||
279 | new_context = kzalloc(sizeof(*new_context), GFP_KERNEL); | ||
280 | if (!new_context) | ||
281 | return NULL; | ||
282 | |||
283 | spin_lock_irq(&ds_lock); | ||
284 | |||
285 | context = *p_context; | ||
286 | if (likely(!context)) { | ||
287 | context = new_context; | ||
288 | |||
289 | context->this = p_context; | ||
290 | context->task = task; | ||
291 | context->cpu = cpu; | ||
292 | context->count = 0; | ||
293 | |||
294 | *p_context = context; | ||
295 | } | ||
296 | |||
297 | context->count++; | ||
298 | |||
299 | spin_unlock_irq(&ds_lock); | ||
300 | |||
301 | if (context != new_context) | ||
302 | kfree(new_context); | ||
303 | |||
304 | return context; | ||
305 | } | ||
306 | |||
307 | static void ds_put_context(struct ds_context *context) | ||
308 | { | ||
309 | struct task_struct *task; | ||
310 | unsigned long irq; | ||
311 | |||
312 | if (!context) | ||
313 | return; | ||
314 | |||
315 | spin_lock_irqsave(&ds_lock, irq); | ||
316 | |||
317 | if (--context->count) { | ||
318 | spin_unlock_irqrestore(&ds_lock, irq); | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | *(context->this) = NULL; | ||
323 | |||
324 | task = context->task; | ||
325 | |||
326 | if (task) | ||
327 | clear_tsk_thread_flag(task, TIF_DS_AREA_MSR); | ||
328 | |||
329 | /* | ||
330 | * We leave the (now dangling) pointer to the DS configuration in | ||
331 | * the DS_AREA msr. This is as good or as bad as replacing it with | ||
332 | * NULL - the hardware would crash if we enabled tracing. | ||
333 | * | ||
334 | * This saves us some problems with having to write an msr on a | ||
335 | * different cpu while preventing others from doing the same for the | ||
336 | * next context for that same cpu. | ||
337 | */ | ||
338 | |||
339 | spin_unlock_irqrestore(&ds_lock, irq); | ||
340 | |||
341 | /* The context might still be in use for context switching. */ | ||
342 | if (task && (task != current)) | ||
343 | wait_task_context_switch(task); | ||
344 | |||
345 | kfree(context); | ||
346 | } | ||
347 | |||
348 | static void ds_install_ds_area(struct ds_context *context) | ||
349 | { | ||
350 | unsigned long ds; | ||
351 | |||
352 | ds = (unsigned long)context->ds; | ||
353 | |||
354 | /* | ||
355 | * There is a race between the bts master and the pebs master. | ||
356 | * | ||
357 | * The thread/cpu access is synchronized via get/put_cpu() for | ||
358 | * task tracing and via wrmsr_on_cpu for cpu tracing. | ||
359 | * | ||
360 | * If bts and pebs are collected for the same task or same cpu, | ||
361 | * the same confiuration is written twice. | ||
362 | */ | ||
363 | if (context->task) { | ||
364 | get_cpu(); | ||
365 | if (context->task == current) | ||
366 | wrmsrl(MSR_IA32_DS_AREA, ds); | ||
367 | set_tsk_thread_flag(context->task, TIF_DS_AREA_MSR); | ||
368 | put_cpu(); | ||
369 | } else | ||
370 | wrmsr_on_cpu(context->cpu, MSR_IA32_DS_AREA, | ||
371 | (u32)((u64)ds), (u32)((u64)ds >> 32)); | ||
372 | } | ||
373 | |||
374 | /* | ||
375 | * Call the tracer's callback on a buffer overflow. | ||
376 | * | ||
377 | * context: the ds context | ||
378 | * qual: the buffer type | ||
379 | */ | ||
380 | static void ds_overflow(struct ds_context *context, enum ds_qualifier qual) | ||
381 | { | ||
382 | switch (qual) { | ||
383 | case ds_bts: | ||
384 | if (context->bts_master && | ||
385 | context->bts_master->ovfl) | ||
386 | context->bts_master->ovfl(context->bts_master); | ||
387 | break; | ||
388 | case ds_pebs: | ||
389 | if (context->pebs_master && | ||
390 | context->pebs_master->ovfl) | ||
391 | context->pebs_master->ovfl(context->pebs_master); | ||
392 | break; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | |||
397 | /* | ||
398 | * Write raw data into the BTS or PEBS buffer. | ||
399 | * | ||
400 | * The remainder of any partially written record is zeroed out. | ||
401 | * | ||
402 | * context: the DS context | ||
403 | * qual: the buffer type | ||
404 | * record: the data to write | ||
405 | * size: the size of the data | ||
406 | */ | ||
407 | static int ds_write(struct ds_context *context, enum ds_qualifier qual, | ||
408 | const void *record, size_t size) | ||
409 | { | ||
410 | int bytes_written = 0; | ||
411 | |||
412 | if (!record) | ||
413 | return -EINVAL; | ||
414 | |||
415 | while (size) { | ||
416 | unsigned long base, index, end, write_end, int_th; | ||
417 | unsigned long write_size, adj_write_size; | ||
418 | |||
419 | /* | ||
420 | * Write as much as possible without producing an | ||
421 | * overflow interrupt. | ||
422 | * | ||
423 | * Interrupt_threshold must either be | ||
424 | * - bigger than absolute_maximum or | ||
425 | * - point to a record between buffer_base and absolute_maximum | ||
426 | * | ||
427 | * Index points to a valid record. | ||
428 | */ | ||
429 | base = ds_get(context->ds, qual, ds_buffer_base); | ||
430 | index = ds_get(context->ds, qual, ds_index); | ||
431 | end = ds_get(context->ds, qual, ds_absolute_maximum); | ||
432 | int_th = ds_get(context->ds, qual, ds_interrupt_threshold); | ||
433 | |||
434 | write_end = min(end, int_th); | ||
435 | |||
436 | /* | ||
437 | * If we are already beyond the interrupt threshold, | ||
438 | * we fill the entire buffer. | ||
439 | */ | ||
440 | if (write_end <= index) | ||
441 | write_end = end; | ||
442 | |||
443 | if (write_end <= index) | ||
444 | break; | ||
445 | |||
446 | write_size = min((unsigned long) size, write_end - index); | ||
447 | memcpy((void *)index, record, write_size); | ||
448 | |||
449 | record = (const char *)record + write_size; | ||
450 | size -= write_size; | ||
451 | bytes_written += write_size; | ||
452 | |||
453 | adj_write_size = write_size / ds_cfg.sizeof_rec[qual]; | ||
454 | adj_write_size *= ds_cfg.sizeof_rec[qual]; | ||
455 | |||
456 | /* Zero out trailing bytes. */ | ||
457 | memset((char *)index + write_size, 0, | ||
458 | adj_write_size - write_size); | ||
459 | index += adj_write_size; | ||
460 | |||
461 | if (index >= end) | ||
462 | index = base; | ||
463 | ds_set(context->ds, qual, ds_index, index); | ||
464 | |||
465 | if (index >= int_th) | ||
466 | ds_overflow(context, qual); | ||
467 | } | ||
468 | |||
469 | return bytes_written; | ||
470 | } | ||
471 | |||
472 | |||
473 | /* | ||
474 | * Branch Trace Store (BTS) uses the following format. Different | ||
475 | * architectures vary in the size of those fields. | ||
476 | * - source linear address | ||
477 | * - destination linear address | ||
478 | * - flags | ||
479 | * | ||
480 | * Later architectures use 64bit pointers throughout, whereas earlier | ||
481 | * architectures use 32bit pointers in 32bit mode. | ||
482 | * | ||
483 | * We compute the base address for the fields based on: | ||
484 | * - the field size stored in the DS configuration | ||
485 | * - the relative field position | ||
486 | * | ||
487 | * In order to store additional information in the BTS buffer, we use | ||
488 | * a special source address to indicate that the record requires | ||
489 | * special interpretation. | ||
490 | * | ||
491 | * Netburst indicated via a bit in the flags field whether the branch | ||
492 | * was predicted; this is ignored. | ||
493 | * | ||
494 | * We use two levels of abstraction: | ||
495 | * - the raw data level defined here | ||
496 | * - an arch-independent level defined in ds.h | ||
497 | */ | ||
498 | |||
499 | enum bts_field { | ||
500 | bts_from, | ||
501 | bts_to, | ||
502 | bts_flags, | ||
503 | |||
504 | bts_qual = bts_from, | ||
505 | bts_clock = bts_to, | ||
506 | bts_pid = bts_flags, | ||
507 | |||
508 | bts_qual_mask = (bts_qual_max - 1), | ||
509 | bts_escape = ((unsigned long)-1 & ~bts_qual_mask) | ||
510 | }; | ||
511 | |||
512 | static inline unsigned long bts_get(const char *base, unsigned long field) | ||
513 | { | ||
514 | base += (ds_cfg.sizeof_ptr_field * field); | ||
515 | return *(unsigned long *)base; | ||
516 | } | ||
517 | |||
518 | static inline void bts_set(char *base, unsigned long field, unsigned long val) | ||
519 | { | ||
520 | base += (ds_cfg.sizeof_ptr_field * field); | ||
521 | (*(unsigned long *)base) = val; | ||
522 | } | ||
523 | |||
524 | |||
525 | /* | ||
526 | * The raw BTS data is architecture dependent. | ||
527 | * | ||
528 | * For higher-level users, we give an arch-independent view. | ||
529 | * - ds.h defines struct bts_struct | ||
530 | * - bts_read translates one raw bts record into a bts_struct | ||
531 | * - bts_write translates one bts_struct into the raw format and | ||
532 | * writes it into the top of the parameter tracer's buffer. | ||
533 | * | ||
534 | * return: bytes read/written on success; -Eerrno, otherwise | ||
535 | */ | ||
536 | static int | ||
537 | bts_read(struct bts_tracer *tracer, const void *at, struct bts_struct *out) | ||
538 | { | ||
539 | if (!tracer) | ||
540 | return -EINVAL; | ||
541 | |||
542 | if (at < tracer->trace.ds.begin) | ||
543 | return -EINVAL; | ||
544 | |||
545 | if (tracer->trace.ds.end < (at + tracer->trace.ds.size)) | ||
546 | return -EINVAL; | ||
547 | |||
548 | memset(out, 0, sizeof(*out)); | ||
549 | if ((bts_get(at, bts_qual) & ~bts_qual_mask) == bts_escape) { | ||
550 | out->qualifier = (bts_get(at, bts_qual) & bts_qual_mask); | ||
551 | out->variant.event.clock = bts_get(at, bts_clock); | ||
552 | out->variant.event.pid = bts_get(at, bts_pid); | ||
553 | } else { | ||
554 | out->qualifier = bts_branch; | ||
555 | out->variant.lbr.from = bts_get(at, bts_from); | ||
556 | out->variant.lbr.to = bts_get(at, bts_to); | ||
557 | |||
558 | if (!out->variant.lbr.from && !out->variant.lbr.to) | ||
559 | out->qualifier = bts_invalid; | ||
560 | } | ||
561 | |||
562 | return ds_cfg.sizeof_rec[ds_bts]; | ||
563 | } | ||
564 | |||
565 | static int bts_write(struct bts_tracer *tracer, const struct bts_struct *in) | ||
566 | { | ||
567 | unsigned char raw[MAX_SIZEOF_BTS]; | ||
568 | |||
569 | if (!tracer) | ||
570 | return -EINVAL; | ||
571 | |||
572 | if (MAX_SIZEOF_BTS < ds_cfg.sizeof_rec[ds_bts]) | ||
573 | return -EOVERFLOW; | ||
574 | |||
575 | switch (in->qualifier) { | ||
576 | case bts_invalid: | ||
577 | bts_set(raw, bts_from, 0); | ||
578 | bts_set(raw, bts_to, 0); | ||
579 | bts_set(raw, bts_flags, 0); | ||
580 | break; | ||
581 | case bts_branch: | ||
582 | bts_set(raw, bts_from, in->variant.lbr.from); | ||
583 | bts_set(raw, bts_to, in->variant.lbr.to); | ||
584 | bts_set(raw, bts_flags, 0); | ||
585 | break; | ||
586 | case bts_task_arrives: | ||
587 | case bts_task_departs: | ||
588 | bts_set(raw, bts_qual, (bts_escape | in->qualifier)); | ||
589 | bts_set(raw, bts_clock, in->variant.event.clock); | ||
590 | bts_set(raw, bts_pid, in->variant.event.pid); | ||
591 | break; | ||
592 | default: | ||
593 | return -EINVAL; | ||
594 | } | ||
595 | |||
596 | return ds_write(tracer->ds.context, ds_bts, raw, | ||
597 | ds_cfg.sizeof_rec[ds_bts]); | ||
598 | } | ||
599 | |||
600 | |||
601 | static void ds_write_config(struct ds_context *context, | ||
602 | struct ds_trace *cfg, enum ds_qualifier qual) | ||
603 | { | ||
604 | unsigned char *ds = context->ds; | ||
605 | |||
606 | ds_set(ds, qual, ds_buffer_base, (unsigned long)cfg->begin); | ||
607 | ds_set(ds, qual, ds_index, (unsigned long)cfg->top); | ||
608 | ds_set(ds, qual, ds_absolute_maximum, (unsigned long)cfg->end); | ||
609 | ds_set(ds, qual, ds_interrupt_threshold, (unsigned long)cfg->ith); | ||
610 | } | ||
611 | |||
612 | static void ds_read_config(struct ds_context *context, | ||
613 | struct ds_trace *cfg, enum ds_qualifier qual) | ||
614 | { | ||
615 | unsigned char *ds = context->ds; | ||
616 | |||
617 | cfg->begin = (void *)ds_get(ds, qual, ds_buffer_base); | ||
618 | cfg->top = (void *)ds_get(ds, qual, ds_index); | ||
619 | cfg->end = (void *)ds_get(ds, qual, ds_absolute_maximum); | ||
620 | cfg->ith = (void *)ds_get(ds, qual, ds_interrupt_threshold); | ||
621 | } | ||
622 | |||
623 | static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual, | ||
624 | void *base, size_t size, size_t ith, | ||
625 | unsigned int flags) { | ||
626 | unsigned long buffer, adj; | ||
627 | |||
628 | /* | ||
629 | * Adjust the buffer address and size to meet alignment | ||
630 | * constraints: | ||
631 | * - buffer is double-word aligned | ||
632 | * - size is multiple of record size | ||
633 | * | ||
634 | * We checked the size at the very beginning; we have enough | ||
635 | * space to do the adjustment. | ||
636 | */ | ||
637 | buffer = (unsigned long)base; | ||
638 | |||
639 | adj = ALIGN(buffer, DS_ALIGNMENT) - buffer; | ||
640 | buffer += adj; | ||
641 | size -= adj; | ||
642 | |||
643 | trace->n = size / ds_cfg.sizeof_rec[qual]; | ||
644 | trace->size = ds_cfg.sizeof_rec[qual]; | ||
645 | |||
646 | size = (trace->n * trace->size); | ||
647 | |||
648 | trace->begin = (void *)buffer; | ||
649 | trace->top = trace->begin; | ||
650 | trace->end = (void *)(buffer + size); | ||
651 | /* | ||
652 | * The value for 'no threshold' is -1, which will set the | ||
653 | * threshold outside of the buffer, just like we want it. | ||
654 | */ | ||
655 | ith *= ds_cfg.sizeof_rec[qual]; | ||
656 | trace->ith = (void *)(buffer + size - ith); | ||
657 | |||
658 | trace->flags = flags; | ||
659 | } | ||
660 | |||
661 | |||
662 | static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, | ||
663 | enum ds_qualifier qual, struct task_struct *task, | ||
664 | int cpu, void *base, size_t size, size_t th) | ||
665 | { | ||
666 | struct ds_context *context; | ||
667 | int error; | ||
668 | size_t req_size; | ||
669 | |||
670 | error = -EOPNOTSUPP; | ||
671 | if (!ds_cfg.sizeof_rec[qual]) | ||
672 | goto out; | ||
673 | |||
674 | error = -EINVAL; | ||
675 | if (!base) | ||
676 | goto out; | ||
677 | |||
678 | req_size = ds_cfg.sizeof_rec[qual]; | ||
679 | /* We might need space for alignment adjustments. */ | ||
680 | if (!IS_ALIGNED((unsigned long)base, DS_ALIGNMENT)) | ||
681 | req_size += DS_ALIGNMENT; | ||
682 | |||
683 | error = -EINVAL; | ||
684 | if (size < req_size) | ||
685 | goto out; | ||
686 | |||
687 | if (th != (size_t)-1) { | ||
688 | th *= ds_cfg.sizeof_rec[qual]; | ||
689 | |||
690 | error = -EINVAL; | ||
691 | if (size <= th) | ||
692 | goto out; | ||
693 | } | ||
694 | |||
695 | tracer->buffer = base; | ||
696 | tracer->size = size; | ||
697 | |||
698 | error = -ENOMEM; | ||
699 | context = ds_get_context(task, cpu); | ||
700 | if (!context) | ||
701 | goto out; | ||
702 | tracer->context = context; | ||
703 | |||
704 | /* | ||
705 | * Defer any tracer-specific initialization work for the context until | ||
706 | * context ownership has been clarified. | ||
707 | */ | ||
708 | |||
709 | error = 0; | ||
710 | out: | ||
711 | return error; | ||
712 | } | ||
713 | |||
714 | static struct bts_tracer *ds_request_bts(struct task_struct *task, int cpu, | ||
715 | void *base, size_t size, | ||
716 | bts_ovfl_callback_t ovfl, size_t th, | ||
717 | unsigned int flags) | ||
718 | { | ||
719 | struct bts_tracer *tracer; | ||
720 | int error; | ||
721 | |||
722 | /* Buffer overflow notification is not yet implemented. */ | ||
723 | error = -EOPNOTSUPP; | ||
724 | if (ovfl) | ||
725 | goto out; | ||
726 | |||
727 | error = get_tracer(task); | ||
728 | if (error < 0) | ||
729 | goto out; | ||
730 | |||
731 | error = -ENOMEM; | ||
732 | tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); | ||
733 | if (!tracer) | ||
734 | goto out_put_tracer; | ||
735 | tracer->ovfl = ovfl; | ||
736 | |||
737 | /* Do some more error checking and acquire a tracing context. */ | ||
738 | error = ds_request(&tracer->ds, &tracer->trace.ds, | ||
739 | ds_bts, task, cpu, base, size, th); | ||
740 | if (error < 0) | ||
741 | goto out_tracer; | ||
742 | |||
743 | /* Claim the bts part of the tracing context we acquired above. */ | ||
744 | spin_lock_irq(&ds_lock); | ||
745 | |||
746 | error = -EPERM; | ||
747 | if (tracer->ds.context->bts_master) | ||
748 | goto out_unlock; | ||
749 | tracer->ds.context->bts_master = tracer; | ||
750 | |||
751 | spin_unlock_irq(&ds_lock); | ||
752 | |||
753 | /* | ||
754 | * Now that we own the bts part of the context, let's complete the | ||
755 | * initialization for that part. | ||
756 | */ | ||
757 | ds_init_ds_trace(&tracer->trace.ds, ds_bts, base, size, th, flags); | ||
758 | ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); | ||
759 | ds_install_ds_area(tracer->ds.context); | ||
760 | |||
761 | tracer->trace.read = bts_read; | ||
762 | tracer->trace.write = bts_write; | ||
763 | |||
764 | /* Start tracing. */ | ||
765 | ds_resume_bts(tracer); | ||
766 | |||
767 | return tracer; | ||
768 | |||
769 | out_unlock: | ||
770 | spin_unlock_irq(&ds_lock); | ||
771 | ds_put_context(tracer->ds.context); | ||
772 | out_tracer: | ||
773 | kfree(tracer); | ||
774 | out_put_tracer: | ||
775 | put_tracer(task); | ||
776 | out: | ||
777 | return ERR_PTR(error); | ||
778 | } | ||
779 | |||
780 | struct bts_tracer *ds_request_bts_task(struct task_struct *task, | ||
781 | void *base, size_t size, | ||
782 | bts_ovfl_callback_t ovfl, | ||
783 | size_t th, unsigned int flags) | ||
784 | { | ||
785 | return ds_request_bts(task, 0, base, size, ovfl, th, flags); | ||
786 | } | ||
787 | |||
788 | struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size, | ||
789 | bts_ovfl_callback_t ovfl, | ||
790 | size_t th, unsigned int flags) | ||
791 | { | ||
792 | return ds_request_bts(NULL, cpu, base, size, ovfl, th, flags); | ||
793 | } | ||
794 | |||
795 | static struct pebs_tracer *ds_request_pebs(struct task_struct *task, int cpu, | ||
796 | void *base, size_t size, | ||
797 | pebs_ovfl_callback_t ovfl, size_t th, | ||
798 | unsigned int flags) | ||
799 | { | ||
800 | struct pebs_tracer *tracer; | ||
801 | int error; | ||
802 | |||
803 | /* Buffer overflow notification is not yet implemented. */ | ||
804 | error = -EOPNOTSUPP; | ||
805 | if (ovfl) | ||
806 | goto out; | ||
807 | |||
808 | error = get_tracer(task); | ||
809 | if (error < 0) | ||
810 | goto out; | ||
811 | |||
812 | error = -ENOMEM; | ||
813 | tracer = kzalloc(sizeof(*tracer), GFP_KERNEL); | ||
814 | if (!tracer) | ||
815 | goto out_put_tracer; | ||
816 | tracer->ovfl = ovfl; | ||
817 | |||
818 | /* Do some more error checking and acquire a tracing context. */ | ||
819 | error = ds_request(&tracer->ds, &tracer->trace.ds, | ||
820 | ds_pebs, task, cpu, base, size, th); | ||
821 | if (error < 0) | ||
822 | goto out_tracer; | ||
823 | |||
824 | /* Claim the pebs part of the tracing context we acquired above. */ | ||
825 | spin_lock_irq(&ds_lock); | ||
826 | |||
827 | error = -EPERM; | ||
828 | if (tracer->ds.context->pebs_master) | ||
829 | goto out_unlock; | ||
830 | tracer->ds.context->pebs_master = tracer; | ||
831 | |||
832 | spin_unlock_irq(&ds_lock); | ||
833 | |||
834 | /* | ||
835 | * Now that we own the pebs part of the context, let's complete the | ||
836 | * initialization for that part. | ||
837 | */ | ||
838 | ds_init_ds_trace(&tracer->trace.ds, ds_pebs, base, size, th, flags); | ||
839 | ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); | ||
840 | ds_install_ds_area(tracer->ds.context); | ||
841 | |||
842 | /* Start tracing. */ | ||
843 | ds_resume_pebs(tracer); | ||
844 | |||
845 | return tracer; | ||
846 | |||
847 | out_unlock: | ||
848 | spin_unlock_irq(&ds_lock); | ||
849 | ds_put_context(tracer->ds.context); | ||
850 | out_tracer: | ||
851 | kfree(tracer); | ||
852 | out_put_tracer: | ||
853 | put_tracer(task); | ||
854 | out: | ||
855 | return ERR_PTR(error); | ||
856 | } | ||
857 | |||
858 | struct pebs_tracer *ds_request_pebs_task(struct task_struct *task, | ||
859 | void *base, size_t size, | ||
860 | pebs_ovfl_callback_t ovfl, | ||
861 | size_t th, unsigned int flags) | ||
862 | { | ||
863 | return ds_request_pebs(task, 0, base, size, ovfl, th, flags); | ||
864 | } | ||
865 | |||
866 | struct pebs_tracer *ds_request_pebs_cpu(int cpu, void *base, size_t size, | ||
867 | pebs_ovfl_callback_t ovfl, | ||
868 | size_t th, unsigned int flags) | ||
869 | { | ||
870 | return ds_request_pebs(NULL, cpu, base, size, ovfl, th, flags); | ||
871 | } | ||
872 | |||
873 | static void ds_free_bts(struct bts_tracer *tracer) | ||
874 | { | ||
875 | struct task_struct *task; | ||
876 | |||
877 | task = tracer->ds.context->task; | ||
878 | |||
879 | WARN_ON_ONCE(tracer->ds.context->bts_master != tracer); | ||
880 | tracer->ds.context->bts_master = NULL; | ||
881 | |||
882 | /* Make sure tracing stopped and the tracer is not in use. */ | ||
883 | if (task && (task != current)) | ||
884 | wait_task_context_switch(task); | ||
885 | |||
886 | ds_put_context(tracer->ds.context); | ||
887 | put_tracer(task); | ||
888 | |||
889 | kfree(tracer); | ||
890 | } | ||
891 | |||
892 | void ds_release_bts(struct bts_tracer *tracer) | ||
893 | { | ||
894 | might_sleep(); | ||
895 | |||
896 | if (!tracer) | ||
897 | return; | ||
898 | |||
899 | ds_suspend_bts(tracer); | ||
900 | ds_free_bts(tracer); | ||
901 | } | ||
902 | |||
903 | int ds_release_bts_noirq(struct bts_tracer *tracer) | ||
904 | { | ||
905 | struct task_struct *task; | ||
906 | unsigned long irq; | ||
907 | int error; | ||
908 | |||
909 | if (!tracer) | ||
910 | return 0; | ||
911 | |||
912 | task = tracer->ds.context->task; | ||
913 | |||
914 | local_irq_save(irq); | ||
915 | |||
916 | error = -EPERM; | ||
917 | if (!task && | ||
918 | (tracer->ds.context->cpu != smp_processor_id())) | ||
919 | goto out; | ||
920 | |||
921 | error = -EPERM; | ||
922 | if (task && (task != current)) | ||
923 | goto out; | ||
924 | |||
925 | ds_suspend_bts_noirq(tracer); | ||
926 | ds_free_bts(tracer); | ||
927 | |||
928 | error = 0; | ||
929 | out: | ||
930 | local_irq_restore(irq); | ||
931 | return error; | ||
932 | } | ||
933 | |||
934 | static void update_task_debugctlmsr(struct task_struct *task, | ||
935 | unsigned long debugctlmsr) | ||
936 | { | ||
937 | task->thread.debugctlmsr = debugctlmsr; | ||
938 | |||
939 | get_cpu(); | ||
940 | if (task == current) | ||
941 | update_debugctlmsr(debugctlmsr); | ||
942 | put_cpu(); | ||
943 | } | ||
944 | |||
945 | void ds_suspend_bts(struct bts_tracer *tracer) | ||
946 | { | ||
947 | struct task_struct *task; | ||
948 | unsigned long debugctlmsr; | ||
949 | int cpu; | ||
950 | |||
951 | if (!tracer) | ||
952 | return; | ||
953 | |||
954 | tracer->flags = 0; | ||
955 | |||
956 | task = tracer->ds.context->task; | ||
957 | cpu = tracer->ds.context->cpu; | ||
958 | |||
959 | WARN_ON(!task && irqs_disabled()); | ||
960 | |||
961 | debugctlmsr = (task ? | ||
962 | task->thread.debugctlmsr : | ||
963 | get_debugctlmsr_on_cpu(cpu)); | ||
964 | debugctlmsr &= ~BTS_CONTROL; | ||
965 | |||
966 | if (task) | ||
967 | update_task_debugctlmsr(task, debugctlmsr); | ||
968 | else | ||
969 | update_debugctlmsr_on_cpu(cpu, debugctlmsr); | ||
970 | } | ||
971 | |||
972 | int ds_suspend_bts_noirq(struct bts_tracer *tracer) | ||
973 | { | ||
974 | struct task_struct *task; | ||
975 | unsigned long debugctlmsr, irq; | ||
976 | int cpu, error = 0; | ||
977 | |||
978 | if (!tracer) | ||
979 | return 0; | ||
980 | |||
981 | tracer->flags = 0; | ||
982 | |||
983 | task = tracer->ds.context->task; | ||
984 | cpu = tracer->ds.context->cpu; | ||
985 | |||
986 | local_irq_save(irq); | ||
987 | |||
988 | error = -EPERM; | ||
989 | if (!task && (cpu != smp_processor_id())) | ||
990 | goto out; | ||
991 | |||
992 | debugctlmsr = (task ? | ||
993 | task->thread.debugctlmsr : | ||
994 | get_debugctlmsr()); | ||
995 | debugctlmsr &= ~BTS_CONTROL; | ||
996 | |||
997 | if (task) | ||
998 | update_task_debugctlmsr(task, debugctlmsr); | ||
999 | else | ||
1000 | update_debugctlmsr(debugctlmsr); | ||
1001 | |||
1002 | error = 0; | ||
1003 | out: | ||
1004 | local_irq_restore(irq); | ||
1005 | return error; | ||
1006 | } | ||
1007 | |||
1008 | static unsigned long ds_bts_control(struct bts_tracer *tracer) | ||
1009 | { | ||
1010 | unsigned long control; | ||
1011 | |||
1012 | control = ds_cfg.ctl[dsf_bts]; | ||
1013 | if (!(tracer->trace.ds.flags & BTS_KERNEL)) | ||
1014 | control |= ds_cfg.ctl[dsf_bts_kernel]; | ||
1015 | if (!(tracer->trace.ds.flags & BTS_USER)) | ||
1016 | control |= ds_cfg.ctl[dsf_bts_user]; | ||
1017 | |||
1018 | return control; | ||
1019 | } | ||
1020 | |||
1021 | void ds_resume_bts(struct bts_tracer *tracer) | ||
1022 | { | ||
1023 | struct task_struct *task; | ||
1024 | unsigned long debugctlmsr; | ||
1025 | int cpu; | ||
1026 | |||
1027 | if (!tracer) | ||
1028 | return; | ||
1029 | |||
1030 | tracer->flags = tracer->trace.ds.flags; | ||
1031 | |||
1032 | task = tracer->ds.context->task; | ||
1033 | cpu = tracer->ds.context->cpu; | ||
1034 | |||
1035 | WARN_ON(!task && irqs_disabled()); | ||
1036 | |||
1037 | debugctlmsr = (task ? | ||
1038 | task->thread.debugctlmsr : | ||
1039 | get_debugctlmsr_on_cpu(cpu)); | ||
1040 | debugctlmsr |= ds_bts_control(tracer); | ||
1041 | |||
1042 | if (task) | ||
1043 | update_task_debugctlmsr(task, debugctlmsr); | ||
1044 | else | ||
1045 | update_debugctlmsr_on_cpu(cpu, debugctlmsr); | ||
1046 | } | ||
1047 | |||
1048 | int ds_resume_bts_noirq(struct bts_tracer *tracer) | ||
1049 | { | ||
1050 | struct task_struct *task; | ||
1051 | unsigned long debugctlmsr, irq; | ||
1052 | int cpu, error = 0; | ||
1053 | |||
1054 | if (!tracer) | ||
1055 | return 0; | ||
1056 | |||
1057 | tracer->flags = tracer->trace.ds.flags; | ||
1058 | |||
1059 | task = tracer->ds.context->task; | ||
1060 | cpu = tracer->ds.context->cpu; | ||
1061 | |||
1062 | local_irq_save(irq); | ||
1063 | |||
1064 | error = -EPERM; | ||
1065 | if (!task && (cpu != smp_processor_id())) | ||
1066 | goto out; | ||
1067 | |||
1068 | debugctlmsr = (task ? | ||
1069 | task->thread.debugctlmsr : | ||
1070 | get_debugctlmsr()); | ||
1071 | debugctlmsr |= ds_bts_control(tracer); | ||
1072 | |||
1073 | if (task) | ||
1074 | update_task_debugctlmsr(task, debugctlmsr); | ||
1075 | else | ||
1076 | update_debugctlmsr(debugctlmsr); | ||
1077 | |||
1078 | error = 0; | ||
1079 | out: | ||
1080 | local_irq_restore(irq); | ||
1081 | return error; | ||
1082 | } | ||
1083 | |||
1084 | static void ds_free_pebs(struct pebs_tracer *tracer) | ||
1085 | { | ||
1086 | struct task_struct *task; | ||
1087 | |||
1088 | task = tracer->ds.context->task; | ||
1089 | |||
1090 | WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer); | ||
1091 | tracer->ds.context->pebs_master = NULL; | ||
1092 | |||
1093 | ds_put_context(tracer->ds.context); | ||
1094 | put_tracer(task); | ||
1095 | |||
1096 | kfree(tracer); | ||
1097 | } | ||
1098 | |||
1099 | void ds_release_pebs(struct pebs_tracer *tracer) | ||
1100 | { | ||
1101 | might_sleep(); | ||
1102 | |||
1103 | if (!tracer) | ||
1104 | return; | ||
1105 | |||
1106 | ds_suspend_pebs(tracer); | ||
1107 | ds_free_pebs(tracer); | ||
1108 | } | ||
1109 | |||
1110 | int ds_release_pebs_noirq(struct pebs_tracer *tracer) | ||
1111 | { | ||
1112 | struct task_struct *task; | ||
1113 | unsigned long irq; | ||
1114 | int error; | ||
1115 | |||
1116 | if (!tracer) | ||
1117 | return 0; | ||
1118 | |||
1119 | task = tracer->ds.context->task; | ||
1120 | |||
1121 | local_irq_save(irq); | ||
1122 | |||
1123 | error = -EPERM; | ||
1124 | if (!task && | ||
1125 | (tracer->ds.context->cpu != smp_processor_id())) | ||
1126 | goto out; | ||
1127 | |||
1128 | error = -EPERM; | ||
1129 | if (task && (task != current)) | ||
1130 | goto out; | ||
1131 | |||
1132 | ds_suspend_pebs_noirq(tracer); | ||
1133 | ds_free_pebs(tracer); | ||
1134 | |||
1135 | error = 0; | ||
1136 | out: | ||
1137 | local_irq_restore(irq); | ||
1138 | return error; | ||
1139 | } | ||
1140 | |||
1141 | void ds_suspend_pebs(struct pebs_tracer *tracer) | ||
1142 | { | ||
1143 | |||
1144 | } | ||
1145 | |||
1146 | int ds_suspend_pebs_noirq(struct pebs_tracer *tracer) | ||
1147 | { | ||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | void ds_resume_pebs(struct pebs_tracer *tracer) | ||
1152 | { | ||
1153 | |||
1154 | } | ||
1155 | |||
1156 | int ds_resume_pebs_noirq(struct pebs_tracer *tracer) | ||
1157 | { | ||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | const struct bts_trace *ds_read_bts(struct bts_tracer *tracer) | ||
1162 | { | ||
1163 | if (!tracer) | ||
1164 | return NULL; | ||
1165 | |||
1166 | ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_bts); | ||
1167 | return &tracer->trace; | ||
1168 | } | ||
1169 | |||
1170 | const struct pebs_trace *ds_read_pebs(struct pebs_tracer *tracer) | ||
1171 | { | ||
1172 | if (!tracer) | ||
1173 | return NULL; | ||
1174 | |||
1175 | ds_read_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); | ||
1176 | |||
1177 | tracer->trace.counters = ds_cfg.nr_counter_reset; | ||
1178 | memcpy(tracer->trace.counter_reset, | ||
1179 | tracer->ds.context->ds + | ||
1180 | (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field), | ||
1181 | ds_cfg.nr_counter_reset * PEBS_RESET_FIELD_SIZE); | ||
1182 | |||
1183 | return &tracer->trace; | ||
1184 | } | ||
1185 | |||
1186 | int ds_reset_bts(struct bts_tracer *tracer) | ||
1187 | { | ||
1188 | if (!tracer) | ||
1189 | return -EINVAL; | ||
1190 | |||
1191 | tracer->trace.ds.top = tracer->trace.ds.begin; | ||
1192 | |||
1193 | ds_set(tracer->ds.context->ds, ds_bts, ds_index, | ||
1194 | (unsigned long)tracer->trace.ds.top); | ||
1195 | |||
1196 | return 0; | ||
1197 | } | ||
1198 | |||
1199 | int ds_reset_pebs(struct pebs_tracer *tracer) | ||
1200 | { | ||
1201 | if (!tracer) | ||
1202 | return -EINVAL; | ||
1203 | |||
1204 | tracer->trace.ds.top = tracer->trace.ds.begin; | ||
1205 | |||
1206 | ds_set(tracer->ds.context->ds, ds_pebs, ds_index, | ||
1207 | (unsigned long)tracer->trace.ds.top); | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | int ds_set_pebs_reset(struct pebs_tracer *tracer, | ||
1213 | unsigned int counter, u64 value) | ||
1214 | { | ||
1215 | if (!tracer) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | if (ds_cfg.nr_counter_reset < counter) | ||
1219 | return -EINVAL; | ||
1220 | |||
1221 | *(u64 *)(tracer->ds.context->ds + | ||
1222 | (NUM_DS_PTR_FIELDS * ds_cfg.sizeof_ptr_field) + | ||
1223 | (counter * PEBS_RESET_FIELD_SIZE)) = value; | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | static const struct ds_configuration ds_cfg_netburst = { | ||
1229 | .name = "Netburst", | ||
1230 | .ctl[dsf_bts] = (1 << 2) | (1 << 3), | ||
1231 | .ctl[dsf_bts_kernel] = (1 << 5), | ||
1232 | .ctl[dsf_bts_user] = (1 << 6), | ||
1233 | .nr_counter_reset = 1, | ||
1234 | }; | ||
1235 | static const struct ds_configuration ds_cfg_pentium_m = { | ||
1236 | .name = "Pentium M", | ||
1237 | .ctl[dsf_bts] = (1 << 6) | (1 << 7), | ||
1238 | .nr_counter_reset = 1, | ||
1239 | }; | ||
1240 | static const struct ds_configuration ds_cfg_core2_atom = { | ||
1241 | .name = "Core 2/Atom", | ||
1242 | .ctl[dsf_bts] = (1 << 6) | (1 << 7), | ||
1243 | .ctl[dsf_bts_kernel] = (1 << 9), | ||
1244 | .ctl[dsf_bts_user] = (1 << 10), | ||
1245 | .nr_counter_reset = 1, | ||
1246 | }; | ||
1247 | static const struct ds_configuration ds_cfg_core_i7 = { | ||
1248 | .name = "Core i7", | ||
1249 | .ctl[dsf_bts] = (1 << 6) | (1 << 7), | ||
1250 | .ctl[dsf_bts_kernel] = (1 << 9), | ||
1251 | .ctl[dsf_bts_user] = (1 << 10), | ||
1252 | .nr_counter_reset = 4, | ||
1253 | }; | ||
1254 | |||
1255 | static void | ||
1256 | ds_configure(const struct ds_configuration *cfg, | ||
1257 | struct cpuinfo_x86 *cpu) | ||
1258 | { | ||
1259 | unsigned long nr_pebs_fields = 0; | ||
1260 | |||
1261 | printk(KERN_INFO "[ds] using %s configuration\n", cfg->name); | ||
1262 | |||
1263 | #ifdef __i386__ | ||
1264 | nr_pebs_fields = 10; | ||
1265 | #else | ||
1266 | nr_pebs_fields = 18; | ||
1267 | #endif | ||
1268 | |||
1269 | /* | ||
1270 | * Starting with version 2, architectural performance | ||
1271 | * monitoring supports a format specifier. | ||
1272 | */ | ||
1273 | if ((cpuid_eax(0xa) & 0xff) > 1) { | ||
1274 | unsigned long perf_capabilities, format; | ||
1275 | |||
1276 | rdmsrl(MSR_IA32_PERF_CAPABILITIES, perf_capabilities); | ||
1277 | |||
1278 | format = (perf_capabilities >> 8) & 0xf; | ||
1279 | |||
1280 | switch (format) { | ||
1281 | case 0: | ||
1282 | nr_pebs_fields = 18; | ||
1283 | break; | ||
1284 | case 1: | ||
1285 | nr_pebs_fields = 22; | ||
1286 | break; | ||
1287 | default: | ||
1288 | printk(KERN_INFO | ||
1289 | "[ds] unknown PEBS format: %lu\n", format); | ||
1290 | nr_pebs_fields = 0; | ||
1291 | break; | ||
1292 | } | ||
1293 | } | ||
1294 | |||
1295 | memset(&ds_cfg, 0, sizeof(ds_cfg)); | ||
1296 | ds_cfg = *cfg; | ||
1297 | |||
1298 | ds_cfg.sizeof_ptr_field = | ||
1299 | (cpu_has(cpu, X86_FEATURE_DTES64) ? 8 : 4); | ||
1300 | |||
1301 | ds_cfg.sizeof_rec[ds_bts] = ds_cfg.sizeof_ptr_field * 3; | ||
1302 | ds_cfg.sizeof_rec[ds_pebs] = ds_cfg.sizeof_ptr_field * nr_pebs_fields; | ||
1303 | |||
1304 | if (!cpu_has(cpu, X86_FEATURE_BTS)) { | ||
1305 | ds_cfg.sizeof_rec[ds_bts] = 0; | ||
1306 | printk(KERN_INFO "[ds] bts not available\n"); | ||
1307 | } | ||
1308 | if (!cpu_has(cpu, X86_FEATURE_PEBS)) { | ||
1309 | ds_cfg.sizeof_rec[ds_pebs] = 0; | ||
1310 | printk(KERN_INFO "[ds] pebs not available\n"); | ||
1311 | } | ||
1312 | |||
1313 | printk(KERN_INFO "[ds] sizes: address: %u bit, ", | ||
1314 | 8 * ds_cfg.sizeof_ptr_field); | ||
1315 | printk("bts/pebs record: %u/%u bytes\n", | ||
1316 | ds_cfg.sizeof_rec[ds_bts], ds_cfg.sizeof_rec[ds_pebs]); | ||
1317 | |||
1318 | WARN_ON_ONCE(MAX_PEBS_COUNTERS < ds_cfg.nr_counter_reset); | ||
1319 | } | ||
1320 | |||
1321 | void __cpuinit ds_init_intel(struct cpuinfo_x86 *c) | ||
1322 | { | ||
1323 | /* Only configure the first cpu. Others are identical. */ | ||
1324 | if (ds_cfg.name) | ||
1325 | return; | ||
1326 | |||
1327 | switch (c->x86) { | ||
1328 | case 0x6: | ||
1329 | switch (c->x86_model) { | ||
1330 | case 0x9: | ||
1331 | case 0xd: /* Pentium M */ | ||
1332 | ds_configure(&ds_cfg_pentium_m, c); | ||
1333 | break; | ||
1334 | case 0xf: | ||
1335 | case 0x17: /* Core2 */ | ||
1336 | case 0x1c: /* Atom */ | ||
1337 | ds_configure(&ds_cfg_core2_atom, c); | ||
1338 | break; | ||
1339 | case 0x1a: /* Core i7 */ | ||
1340 | ds_configure(&ds_cfg_core_i7, c); | ||
1341 | break; | ||
1342 | default: | ||
1343 | /* Sorry, don't know about them. */ | ||
1344 | break; | ||
1345 | } | ||
1346 | break; | ||
1347 | case 0xf: | ||
1348 | switch (c->x86_model) { | ||
1349 | case 0x0: | ||
1350 | case 0x1: | ||
1351 | case 0x2: /* Netburst */ | ||
1352 | ds_configure(&ds_cfg_netburst, c); | ||
1353 | break; | ||
1354 | default: | ||
1355 | /* Sorry, don't know about them. */ | ||
1356 | break; | ||
1357 | } | ||
1358 | break; | ||
1359 | default: | ||
1360 | /* Sorry, don't know about them. */ | ||
1361 | break; | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1365 | static inline void ds_take_timestamp(struct ds_context *context, | ||
1366 | enum bts_qualifier qualifier, | ||
1367 | struct task_struct *task) | ||
1368 | { | ||
1369 | struct bts_tracer *tracer = context->bts_master; | ||
1370 | struct bts_struct ts; | ||
1371 | |||
1372 | /* Prevent compilers from reading the tracer pointer twice. */ | ||
1373 | barrier(); | ||
1374 | |||
1375 | if (!tracer || !(tracer->flags & BTS_TIMESTAMPS)) | ||
1376 | return; | ||
1377 | |||
1378 | memset(&ts, 0, sizeof(ts)); | ||
1379 | ts.qualifier = qualifier; | ||
1380 | ts.variant.event.clock = trace_clock_global(); | ||
1381 | ts.variant.event.pid = task->pid; | ||
1382 | |||
1383 | bts_write(tracer, &ts); | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * Change the DS configuration from tracing prev to tracing next. | ||
1388 | */ | ||
1389 | void ds_switch_to(struct task_struct *prev, struct task_struct *next) | ||
1390 | { | ||
1391 | struct ds_context *prev_ctx = prev->thread.ds_ctx; | ||
1392 | struct ds_context *next_ctx = next->thread.ds_ctx; | ||
1393 | unsigned long debugctlmsr = next->thread.debugctlmsr; | ||
1394 | |||
1395 | /* Make sure all data is read before we start. */ | ||
1396 | barrier(); | ||
1397 | |||
1398 | if (prev_ctx) { | ||
1399 | update_debugctlmsr(0); | ||
1400 | |||
1401 | ds_take_timestamp(prev_ctx, bts_task_departs, prev); | ||
1402 | } | ||
1403 | |||
1404 | if (next_ctx) { | ||
1405 | ds_take_timestamp(next_ctx, bts_task_arrives, next); | ||
1406 | |||
1407 | wrmsrl(MSR_IA32_DS_AREA, (unsigned long)next_ctx->ds); | ||
1408 | } | ||
1409 | |||
1410 | update_debugctlmsr(debugctlmsr); | ||
1411 | } | ||
1412 | |||
1413 | static __init int ds_selftest(void) | ||
1414 | { | ||
1415 | if (ds_cfg.sizeof_rec[ds_bts]) { | ||
1416 | int error; | ||
1417 | |||
1418 | error = ds_selftest_bts(); | ||
1419 | if (error) { | ||
1420 | WARN(1, "[ds] selftest failed. disabling bts.\n"); | ||
1421 | ds_cfg.sizeof_rec[ds_bts] = 0; | ||
1422 | } | ||
1423 | } | ||
1424 | |||
1425 | if (ds_cfg.sizeof_rec[ds_pebs]) { | ||
1426 | int error; | ||
1427 | |||
1428 | error = ds_selftest_pebs(); | ||
1429 | if (error) { | ||
1430 | WARN(1, "[ds] selftest failed. disabling pebs.\n"); | ||
1431 | ds_cfg.sizeof_rec[ds_pebs] = 0; | ||
1432 | } | ||
1433 | } | ||
1434 | |||
1435 | return 0; | ||
1436 | } | ||
1437 | device_initcall(ds_selftest); | ||
diff --git a/arch/x86/kernel/ds_selftest.c b/arch/x86/kernel/ds_selftest.c deleted file mode 100644 index 6bc7c199ab99..000000000000 --- a/arch/x86/kernel/ds_selftest.c +++ /dev/null | |||
@@ -1,408 +0,0 @@ | |||
1 | /* | ||
2 | * Debug Store support - selftest | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. | ||
6 | * Markus Metzger <markus.t.metzger@intel.com>, 2009 | ||
7 | */ | ||
8 | |||
9 | #include "ds_selftest.h" | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/smp.h> | ||
14 | #include <linux/cpu.h> | ||
15 | |||
16 | #include <asm/ds.h> | ||
17 | |||
18 | |||
19 | #define BUFFER_SIZE 521 /* Intentionally chose an odd size. */ | ||
20 | #define SMALL_BUFFER_SIZE 24 /* A single bts entry. */ | ||
21 | |||
22 | struct ds_selftest_bts_conf { | ||
23 | struct bts_tracer *tracer; | ||
24 | int error; | ||
25 | int (*suspend)(struct bts_tracer *); | ||
26 | int (*resume)(struct bts_tracer *); | ||
27 | }; | ||
28 | |||
29 | static int ds_selftest_bts_consistency(const struct bts_trace *trace) | ||
30 | { | ||
31 | int error = 0; | ||
32 | |||
33 | if (!trace) { | ||
34 | printk(KERN_CONT "failed to access trace..."); | ||
35 | /* Bail out. Other tests are pointless. */ | ||
36 | return -1; | ||
37 | } | ||
38 | |||
39 | if (!trace->read) { | ||
40 | printk(KERN_CONT "bts read not available..."); | ||
41 | error = -1; | ||
42 | } | ||
43 | |||
44 | /* Do some sanity checks on the trace configuration. */ | ||
45 | if (!trace->ds.n) { | ||
46 | printk(KERN_CONT "empty bts buffer..."); | ||
47 | error = -1; | ||
48 | } | ||
49 | if (!trace->ds.size) { | ||
50 | printk(KERN_CONT "bad bts trace setup..."); | ||
51 | error = -1; | ||
52 | } | ||
53 | if (trace->ds.end != | ||
54 | (char *)trace->ds.begin + (trace->ds.n * trace->ds.size)) { | ||
55 | printk(KERN_CONT "bad bts buffer setup..."); | ||
56 | error = -1; | ||
57 | } | ||
58 | /* | ||
59 | * We allow top in [begin; end], since its not clear when the | ||
60 | * overflow adjustment happens: after the increment or before the | ||
61 | * write. | ||
62 | */ | ||
63 | if ((trace->ds.top < trace->ds.begin) || | ||
64 | (trace->ds.end < trace->ds.top)) { | ||
65 | printk(KERN_CONT "bts top out of bounds..."); | ||
66 | error = -1; | ||
67 | } | ||
68 | |||
69 | return error; | ||
70 | } | ||
71 | |||
72 | static int ds_selftest_bts_read(struct bts_tracer *tracer, | ||
73 | const struct bts_trace *trace, | ||
74 | const void *from, const void *to) | ||
75 | { | ||
76 | const unsigned char *at; | ||
77 | |||
78 | /* | ||
79 | * Check a few things which do not belong to this test. | ||
80 | * They should be covered by other tests. | ||
81 | */ | ||
82 | if (!trace) | ||
83 | return -1; | ||
84 | |||
85 | if (!trace->read) | ||
86 | return -1; | ||
87 | |||
88 | if (to < from) | ||
89 | return -1; | ||
90 | |||
91 | if (from < trace->ds.begin) | ||
92 | return -1; | ||
93 | |||
94 | if (trace->ds.end < to) | ||
95 | return -1; | ||
96 | |||
97 | if (!trace->ds.size) | ||
98 | return -1; | ||
99 | |||
100 | /* Now to the test itself. */ | ||
101 | for (at = from; (void *)at < to; at += trace->ds.size) { | ||
102 | struct bts_struct bts; | ||
103 | unsigned long index; | ||
104 | int error; | ||
105 | |||
106 | if (((void *)at - trace->ds.begin) % trace->ds.size) { | ||
107 | printk(KERN_CONT | ||
108 | "read from non-integer index..."); | ||
109 | return -1; | ||
110 | } | ||
111 | index = ((void *)at - trace->ds.begin) / trace->ds.size; | ||
112 | |||
113 | memset(&bts, 0, sizeof(bts)); | ||
114 | error = trace->read(tracer, at, &bts); | ||
115 | if (error < 0) { | ||
116 | printk(KERN_CONT | ||
117 | "error reading bts trace at [%lu] (0x%p)...", | ||
118 | index, at); | ||
119 | return error; | ||
120 | } | ||
121 | |||
122 | switch (bts.qualifier) { | ||
123 | case BTS_BRANCH: | ||
124 | break; | ||
125 | default: | ||
126 | printk(KERN_CONT | ||
127 | "unexpected bts entry %llu at [%lu] (0x%p)...", | ||
128 | bts.qualifier, index, at); | ||
129 | return -1; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static void ds_selftest_bts_cpu(void *arg) | ||
137 | { | ||
138 | struct ds_selftest_bts_conf *conf = arg; | ||
139 | const struct bts_trace *trace; | ||
140 | void *top; | ||
141 | |||
142 | if (IS_ERR(conf->tracer)) { | ||
143 | conf->error = PTR_ERR(conf->tracer); | ||
144 | conf->tracer = NULL; | ||
145 | |||
146 | printk(KERN_CONT | ||
147 | "initialization failed (err: %d)...", conf->error); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | /* We should meanwhile have enough trace. */ | ||
152 | conf->error = conf->suspend(conf->tracer); | ||
153 | if (conf->error < 0) | ||
154 | return; | ||
155 | |||
156 | /* Let's see if we can access the trace. */ | ||
157 | trace = ds_read_bts(conf->tracer); | ||
158 | |||
159 | conf->error = ds_selftest_bts_consistency(trace); | ||
160 | if (conf->error < 0) | ||
161 | return; | ||
162 | |||
163 | /* If everything went well, we should have a few trace entries. */ | ||
164 | if (trace->ds.top == trace->ds.begin) { | ||
165 | /* | ||
166 | * It is possible but highly unlikely that we got a | ||
167 | * buffer overflow and end up at exactly the same | ||
168 | * position we started from. | ||
169 | * Let's issue a warning, but continue. | ||
170 | */ | ||
171 | printk(KERN_CONT "no trace/overflow..."); | ||
172 | } | ||
173 | |||
174 | /* Let's try to read the trace we collected. */ | ||
175 | conf->error = | ||
176 | ds_selftest_bts_read(conf->tracer, trace, | ||
177 | trace->ds.begin, trace->ds.top); | ||
178 | if (conf->error < 0) | ||
179 | return; | ||
180 | |||
181 | /* | ||
182 | * Let's read the trace again. | ||
183 | * Since we suspended tracing, we should get the same result. | ||
184 | */ | ||
185 | top = trace->ds.top; | ||
186 | |||
187 | trace = ds_read_bts(conf->tracer); | ||
188 | conf->error = ds_selftest_bts_consistency(trace); | ||
189 | if (conf->error < 0) | ||
190 | return; | ||
191 | |||
192 | if (top != trace->ds.top) { | ||
193 | printk(KERN_CONT "suspend not working..."); | ||
194 | conf->error = -1; | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | /* Let's collect some more trace - see if resume is working. */ | ||
199 | conf->error = conf->resume(conf->tracer); | ||
200 | if (conf->error < 0) | ||
201 | return; | ||
202 | |||
203 | conf->error = conf->suspend(conf->tracer); | ||
204 | if (conf->error < 0) | ||
205 | return; | ||
206 | |||
207 | trace = ds_read_bts(conf->tracer); | ||
208 | |||
209 | conf->error = ds_selftest_bts_consistency(trace); | ||
210 | if (conf->error < 0) | ||
211 | return; | ||
212 | |||
213 | if (trace->ds.top == top) { | ||
214 | /* | ||
215 | * It is possible but highly unlikely that we got a | ||
216 | * buffer overflow and end up at exactly the same | ||
217 | * position we started from. | ||
218 | * Let's issue a warning and check the full trace. | ||
219 | */ | ||
220 | printk(KERN_CONT | ||
221 | "no resume progress/overflow..."); | ||
222 | |||
223 | conf->error = | ||
224 | ds_selftest_bts_read(conf->tracer, trace, | ||
225 | trace->ds.begin, trace->ds.end); | ||
226 | } else if (trace->ds.top < top) { | ||
227 | /* | ||
228 | * We had a buffer overflow - the entire buffer should | ||
229 | * contain trace records. | ||
230 | */ | ||
231 | conf->error = | ||
232 | ds_selftest_bts_read(conf->tracer, trace, | ||
233 | trace->ds.begin, trace->ds.end); | ||
234 | } else { | ||
235 | /* | ||
236 | * It is quite likely that the buffer did not overflow. | ||
237 | * Let's just check the delta trace. | ||
238 | */ | ||
239 | conf->error = | ||
240 | ds_selftest_bts_read(conf->tracer, trace, top, | ||
241 | trace->ds.top); | ||
242 | } | ||
243 | if (conf->error < 0) | ||
244 | return; | ||
245 | |||
246 | conf->error = 0; | ||
247 | } | ||
248 | |||
249 | static int ds_suspend_bts_wrap(struct bts_tracer *tracer) | ||
250 | { | ||
251 | ds_suspend_bts(tracer); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int ds_resume_bts_wrap(struct bts_tracer *tracer) | ||
256 | { | ||
257 | ds_resume_bts(tracer); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static void ds_release_bts_noirq_wrap(void *tracer) | ||
262 | { | ||
263 | (void)ds_release_bts_noirq(tracer); | ||
264 | } | ||
265 | |||
266 | static int ds_selftest_bts_bad_release_noirq(int cpu, | ||
267 | struct bts_tracer *tracer) | ||
268 | { | ||
269 | int error = -EPERM; | ||
270 | |||
271 | /* Try to release the tracer on the wrong cpu. */ | ||
272 | get_cpu(); | ||
273 | if (cpu != smp_processor_id()) { | ||
274 | error = ds_release_bts_noirq(tracer); | ||
275 | if (error != -EPERM) | ||
276 | printk(KERN_CONT "release on wrong cpu..."); | ||
277 | } | ||
278 | put_cpu(); | ||
279 | |||
280 | return error ? 0 : -1; | ||
281 | } | ||
282 | |||
283 | static int ds_selftest_bts_bad_request_cpu(int cpu, void *buffer) | ||
284 | { | ||
285 | struct bts_tracer *tracer; | ||
286 | int error; | ||
287 | |||
288 | /* Try to request cpu tracing while task tracing is active. */ | ||
289 | tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL, | ||
290 | (size_t)-1, BTS_KERNEL); | ||
291 | error = PTR_ERR(tracer); | ||
292 | if (!IS_ERR(tracer)) { | ||
293 | ds_release_bts(tracer); | ||
294 | error = 0; | ||
295 | } | ||
296 | |||
297 | if (error != -EPERM) | ||
298 | printk(KERN_CONT "cpu/task tracing overlap..."); | ||
299 | |||
300 | return error ? 0 : -1; | ||
301 | } | ||
302 | |||
303 | static int ds_selftest_bts_bad_request_task(void *buffer) | ||
304 | { | ||
305 | struct bts_tracer *tracer; | ||
306 | int error; | ||
307 | |||
308 | /* Try to request cpu tracing while task tracing is active. */ | ||
309 | tracer = ds_request_bts_task(current, buffer, BUFFER_SIZE, NULL, | ||
310 | (size_t)-1, BTS_KERNEL); | ||
311 | error = PTR_ERR(tracer); | ||
312 | if (!IS_ERR(tracer)) { | ||
313 | error = 0; | ||
314 | ds_release_bts(tracer); | ||
315 | } | ||
316 | |||
317 | if (error != -EPERM) | ||
318 | printk(KERN_CONT "task/cpu tracing overlap..."); | ||
319 | |||
320 | return error ? 0 : -1; | ||
321 | } | ||
322 | |||
323 | int ds_selftest_bts(void) | ||
324 | { | ||
325 | struct ds_selftest_bts_conf conf; | ||
326 | unsigned char buffer[BUFFER_SIZE], *small_buffer; | ||
327 | unsigned long irq; | ||
328 | int cpu; | ||
329 | |||
330 | printk(KERN_INFO "[ds] bts selftest..."); | ||
331 | conf.error = 0; | ||
332 | |||
333 | small_buffer = (unsigned char *)ALIGN((unsigned long)buffer, 8) + 8; | ||
334 | |||
335 | get_online_cpus(); | ||
336 | for_each_online_cpu(cpu) { | ||
337 | conf.suspend = ds_suspend_bts_wrap; | ||
338 | conf.resume = ds_resume_bts_wrap; | ||
339 | conf.tracer = | ||
340 | ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, | ||
341 | NULL, (size_t)-1, BTS_KERNEL); | ||
342 | ds_selftest_bts_cpu(&conf); | ||
343 | if (conf.error >= 0) | ||
344 | conf.error = ds_selftest_bts_bad_request_task(buffer); | ||
345 | ds_release_bts(conf.tracer); | ||
346 | if (conf.error < 0) | ||
347 | goto out; | ||
348 | |||
349 | conf.suspend = ds_suspend_bts_noirq; | ||
350 | conf.resume = ds_resume_bts_noirq; | ||
351 | conf.tracer = | ||
352 | ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, | ||
353 | NULL, (size_t)-1, BTS_KERNEL); | ||
354 | smp_call_function_single(cpu, ds_selftest_bts_cpu, &conf, 1); | ||
355 | if (conf.error >= 0) { | ||
356 | conf.error = | ||
357 | ds_selftest_bts_bad_release_noirq(cpu, | ||
358 | conf.tracer); | ||
359 | /* We must not release the tracer twice. */ | ||
360 | if (conf.error < 0) | ||
361 | conf.tracer = NULL; | ||
362 | } | ||
363 | if (conf.error >= 0) | ||
364 | conf.error = ds_selftest_bts_bad_request_task(buffer); | ||
365 | smp_call_function_single(cpu, ds_release_bts_noirq_wrap, | ||
366 | conf.tracer, 1); | ||
367 | if (conf.error < 0) | ||
368 | goto out; | ||
369 | } | ||
370 | |||
371 | conf.suspend = ds_suspend_bts_wrap; | ||
372 | conf.resume = ds_resume_bts_wrap; | ||
373 | conf.tracer = | ||
374 | ds_request_bts_task(current, buffer, BUFFER_SIZE, | ||
375 | NULL, (size_t)-1, BTS_KERNEL); | ||
376 | ds_selftest_bts_cpu(&conf); | ||
377 | if (conf.error >= 0) | ||
378 | conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); | ||
379 | ds_release_bts(conf.tracer); | ||
380 | if (conf.error < 0) | ||
381 | goto out; | ||
382 | |||
383 | conf.suspend = ds_suspend_bts_noirq; | ||
384 | conf.resume = ds_resume_bts_noirq; | ||
385 | conf.tracer = | ||
386 | ds_request_bts_task(current, small_buffer, SMALL_BUFFER_SIZE, | ||
387 | NULL, (size_t)-1, BTS_KERNEL); | ||
388 | local_irq_save(irq); | ||
389 | ds_selftest_bts_cpu(&conf); | ||
390 | if (conf.error >= 0) | ||
391 | conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); | ||
392 | ds_release_bts_noirq(conf.tracer); | ||
393 | local_irq_restore(irq); | ||
394 | if (conf.error < 0) | ||
395 | goto out; | ||
396 | |||
397 | conf.error = 0; | ||
398 | out: | ||
399 | put_online_cpus(); | ||
400 | printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed")); | ||
401 | |||
402 | return conf.error; | ||
403 | } | ||
404 | |||
405 | int ds_selftest_pebs(void) | ||
406 | { | ||
407 | return 0; | ||
408 | } | ||
diff --git a/arch/x86/kernel/ds_selftest.h b/arch/x86/kernel/ds_selftest.h deleted file mode 100644 index 2ba8745c6663..000000000000 --- a/arch/x86/kernel/ds_selftest.h +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | /* | ||
2 | * Debug Store support - selftest | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2009 Intel Corporation. | ||
6 | * Markus Metzger <markus.t.metzger@intel.com>, 2009 | ||
7 | */ | ||
8 | |||
9 | #ifdef CONFIG_X86_DS_SELFTEST | ||
10 | extern int ds_selftest_bts(void); | ||
11 | extern int ds_selftest_pebs(void); | ||
12 | #else | ||
13 | static inline int ds_selftest_bts(void) { return 0; } | ||
14 | static inline int ds_selftest_pebs(void) { return 0; } | ||
15 | #endif | ||
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 6d817554780a..c89a386930b7 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -224,11 +224,6 @@ unsigned __kprobes long oops_begin(void) | |||
224 | int cpu; | 224 | int cpu; |
225 | unsigned long flags; | 225 | unsigned long flags; |
226 | 226 | ||
227 | /* notify the hw-branch tracer so it may disable tracing and | ||
228 | add the last trace to the trace buffer - | ||
229 | the earlier this happens, the more useful the trace. */ | ||
230 | trace_hw_branch_oops(); | ||
231 | |||
232 | oops_enter(); | 227 | oops_enter(); |
233 | 228 | ||
234 | /* racy, but better than risking deadlock. */ | 229 | /* racy, but better than risking deadlock. */ |
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index b43bbaebe2c0..7a880ad3a208 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -422,14 +422,12 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | |||
422 | 422 | ||
423 | static void __kprobes clear_btf(void) | 423 | static void __kprobes clear_btf(void) |
424 | { | 424 | { |
425 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | 425 | /* XXX */ |
426 | update_debugctlmsr(0); | ||
427 | } | 426 | } |
428 | 427 | ||
429 | static void __kprobes restore_btf(void) | 428 | static void __kprobes restore_btf(void) |
430 | { | 429 | { |
431 | if (test_thread_flag(TIF_DEBUGCTLMSR)) | 430 | /* XXX */ |
432 | update_debugctlmsr(current->thread.debugctlmsr); | ||
433 | } | 431 | } |
434 | 432 | ||
435 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 433 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, |
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index ad9540676fcc..1a60beb32ede 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <asm/idle.h> | 20 | #include <asm/idle.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | #include <asm/i387.h> | 22 | #include <asm/i387.h> |
23 | #include <asm/ds.h> | ||
24 | #include <asm/debugreg.h> | 23 | #include <asm/debugreg.h> |
25 | 24 | ||
26 | unsigned long idle_halt; | 25 | unsigned long idle_halt; |
@@ -50,8 +49,6 @@ void free_thread_xstate(struct task_struct *tsk) | |||
50 | kmem_cache_free(task_xstate_cachep, tsk->thread.xstate); | 49 | kmem_cache_free(task_xstate_cachep, tsk->thread.xstate); |
51 | tsk->thread.xstate = NULL; | 50 | tsk->thread.xstate = NULL; |
52 | } | 51 | } |
53 | |||
54 | WARN(tsk->thread.ds_ctx, "leaking DS context\n"); | ||
55 | } | 52 | } |
56 | 53 | ||
57 | void free_thread_info(struct thread_info *ti) | 54 | void free_thread_info(struct thread_info *ti) |
@@ -198,12 +195,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | |||
198 | prev = &prev_p->thread; | 195 | prev = &prev_p->thread; |
199 | next = &next_p->thread; | 196 | next = &next_p->thread; |
200 | 197 | ||
201 | if (test_tsk_thread_flag(next_p, TIF_DS_AREA_MSR) || | ||
202 | test_tsk_thread_flag(prev_p, TIF_DS_AREA_MSR)) | ||
203 | ds_switch_to(prev_p, next_p); | ||
204 | else if (next->debugctlmsr != prev->debugctlmsr) | ||
205 | update_debugctlmsr(next->debugctlmsr); | ||
206 | |||
207 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ | 198 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ |
208 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { | 199 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { |
209 | /* prev and next are different */ | 200 | /* prev and next are different */ |
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index f6c62667e30c..75090c589b7a 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #include <asm/cpu.h> | 55 | #include <asm/cpu.h> |
56 | #include <asm/idle.h> | 56 | #include <asm/idle.h> |
57 | #include <asm/syscalls.h> | 57 | #include <asm/syscalls.h> |
58 | #include <asm/ds.h> | ||
59 | #include <asm/debugreg.h> | 58 | #include <asm/debugreg.h> |
60 | 59 | ||
61 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | 60 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); |
@@ -238,13 +237,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
238 | kfree(p->thread.io_bitmap_ptr); | 237 | kfree(p->thread.io_bitmap_ptr); |
239 | p->thread.io_bitmap_max = 0; | 238 | p->thread.io_bitmap_max = 0; |
240 | } | 239 | } |
241 | |||
242 | clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); | ||
243 | p->thread.ds_ctx = NULL; | ||
244 | |||
245 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
246 | p->thread.debugctlmsr = 0; | ||
247 | |||
248 | return err; | 240 | return err; |
249 | } | 241 | } |
250 | 242 | ||
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index dc9690b4c4cc..cc4258f2beb5 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #include <asm/ia32.h> | 49 | #include <asm/ia32.h> |
50 | #include <asm/idle.h> | 50 | #include <asm/idle.h> |
51 | #include <asm/syscalls.h> | 51 | #include <asm/syscalls.h> |
52 | #include <asm/ds.h> | ||
53 | #include <asm/debugreg.h> | 52 | #include <asm/debugreg.h> |
54 | 53 | ||
55 | asmlinkage extern void ret_from_fork(void); | 54 | asmlinkage extern void ret_from_fork(void); |
@@ -313,13 +312,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
313 | if (err) | 312 | if (err) |
314 | goto out; | 313 | goto out; |
315 | } | 314 | } |
316 | |||
317 | clear_tsk_thread_flag(p, TIF_DS_AREA_MSR); | ||
318 | p->thread.ds_ctx = NULL; | ||
319 | |||
320 | clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR); | ||
321 | p->thread.debugctlmsr = 0; | ||
322 | |||
323 | err = 0; | 315 | err = 0; |
324 | out: | 316 | out: |
325 | if (err && p->thread.io_bitmap_ptr) { | 317 | if (err && p->thread.io_bitmap_ptr) { |
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index a503b1fd04e5..f2fd3b80e565 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -2,9 +2,6 @@ | |||
2 | /* | 2 | /* |
3 | * Pentium III FXSR, SSE support | 3 | * Pentium III FXSR, SSE support |
4 | * Gareth Hughes <gareth@valinux.com>, May 2000 | 4 | * Gareth Hughes <gareth@valinux.com>, May 2000 |
5 | * | ||
6 | * BTS tracing | ||
7 | * Markus Metzger <markus.t.metzger@intel.com>, Dec 2007 | ||
8 | */ | 5 | */ |
9 | 6 | ||
10 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
@@ -21,7 +18,6 @@ | |||
21 | #include <linux/audit.h> | 18 | #include <linux/audit.h> |
22 | #include <linux/seccomp.h> | 19 | #include <linux/seccomp.h> |
23 | #include <linux/signal.h> | 20 | #include <linux/signal.h> |
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/perf_event.h> | 21 | #include <linux/perf_event.h> |
26 | #include <linux/hw_breakpoint.h> | 22 | #include <linux/hw_breakpoint.h> |
27 | 23 | ||
@@ -35,7 +31,6 @@ | |||
35 | #include <asm/desc.h> | 31 | #include <asm/desc.h> |
36 | #include <asm/prctl.h> | 32 | #include <asm/prctl.h> |
37 | #include <asm/proto.h> | 33 | #include <asm/proto.h> |
38 | #include <asm/ds.h> | ||
39 | #include <asm/hw_breakpoint.h> | 34 | #include <asm/hw_breakpoint.h> |
40 | 35 | ||
41 | #include "tls.h" | 36 | #include "tls.h" |
@@ -788,342 +783,6 @@ static int ioperm_get(struct task_struct *target, | |||
788 | 0, IO_BITMAP_BYTES); | 783 | 0, IO_BITMAP_BYTES); |
789 | } | 784 | } |
790 | 785 | ||
791 | #ifdef CONFIG_X86_PTRACE_BTS | ||
792 | /* | ||
793 | * A branch trace store context. | ||
794 | * | ||
795 | * Contexts may only be installed by ptrace_bts_config() and only for | ||
796 | * ptraced tasks. | ||
797 | * | ||
798 | * Contexts are destroyed when the tracee is detached from the tracer. | ||
799 | * The actual destruction work requires interrupts enabled, so the | ||
800 | * work is deferred and will be scheduled during __ptrace_unlink(). | ||
801 | * | ||
802 | * Contexts hold an additional task_struct reference on the traced | ||
803 | * task, as well as a reference on the tracer's mm. | ||
804 | * | ||
805 | * Ptrace already holds a task_struct for the duration of ptrace operations, | ||
806 | * but since destruction is deferred, it may be executed after both | ||
807 | * tracer and tracee exited. | ||
808 | */ | ||
809 | struct bts_context { | ||
810 | /* The branch trace handle. */ | ||
811 | struct bts_tracer *tracer; | ||
812 | |||
813 | /* The buffer used to store the branch trace and its size. */ | ||
814 | void *buffer; | ||
815 | unsigned int size; | ||
816 | |||
817 | /* The mm that paid for the above buffer. */ | ||
818 | struct mm_struct *mm; | ||
819 | |||
820 | /* The task this context belongs to. */ | ||
821 | struct task_struct *task; | ||
822 | |||
823 | /* The signal to send on a bts buffer overflow. */ | ||
824 | unsigned int bts_ovfl_signal; | ||
825 | |||
826 | /* The work struct to destroy a context. */ | ||
827 | struct work_struct work; | ||
828 | }; | ||
829 | |||
830 | static int alloc_bts_buffer(struct bts_context *context, unsigned int size) | ||
831 | { | ||
832 | void *buffer = NULL; | ||
833 | int err = -ENOMEM; | ||
834 | |||
835 | err = account_locked_memory(current->mm, current->signal->rlim, size); | ||
836 | if (err < 0) | ||
837 | return err; | ||
838 | |||
839 | buffer = kzalloc(size, GFP_KERNEL); | ||
840 | if (!buffer) | ||
841 | goto out_refund; | ||
842 | |||
843 | context->buffer = buffer; | ||
844 | context->size = size; | ||
845 | context->mm = get_task_mm(current); | ||
846 | |||
847 | return 0; | ||
848 | |||
849 | out_refund: | ||
850 | refund_locked_memory(current->mm, size); | ||
851 | return err; | ||
852 | } | ||
853 | |||
854 | static inline void free_bts_buffer(struct bts_context *context) | ||
855 | { | ||
856 | if (!context->buffer) | ||
857 | return; | ||
858 | |||
859 | kfree(context->buffer); | ||
860 | context->buffer = NULL; | ||
861 | |||
862 | refund_locked_memory(context->mm, context->size); | ||
863 | context->size = 0; | ||
864 | |||
865 | mmput(context->mm); | ||
866 | context->mm = NULL; | ||
867 | } | ||
868 | |||
869 | static void free_bts_context_work(struct work_struct *w) | ||
870 | { | ||
871 | struct bts_context *context; | ||
872 | |||
873 | context = container_of(w, struct bts_context, work); | ||
874 | |||
875 | ds_release_bts(context->tracer); | ||
876 | put_task_struct(context->task); | ||
877 | free_bts_buffer(context); | ||
878 | kfree(context); | ||
879 | } | ||
880 | |||
881 | static inline void free_bts_context(struct bts_context *context) | ||
882 | { | ||
883 | INIT_WORK(&context->work, free_bts_context_work); | ||
884 | schedule_work(&context->work); | ||
885 | } | ||
886 | |||
887 | static inline struct bts_context *alloc_bts_context(struct task_struct *task) | ||
888 | { | ||
889 | struct bts_context *context = kzalloc(sizeof(*context), GFP_KERNEL); | ||
890 | if (context) { | ||
891 | context->task = task; | ||
892 | task->bts = context; | ||
893 | |||
894 | get_task_struct(task); | ||
895 | } | ||
896 | |||
897 | return context; | ||
898 | } | ||
899 | |||
900 | static int ptrace_bts_read_record(struct task_struct *child, size_t index, | ||
901 | struct bts_struct __user *out) | ||
902 | { | ||
903 | struct bts_context *context; | ||
904 | const struct bts_trace *trace; | ||
905 | struct bts_struct bts; | ||
906 | const unsigned char *at; | ||
907 | int error; | ||
908 | |||
909 | context = child->bts; | ||
910 | if (!context) | ||
911 | return -ESRCH; | ||
912 | |||
913 | trace = ds_read_bts(context->tracer); | ||
914 | if (!trace) | ||
915 | return -ESRCH; | ||
916 | |||
917 | at = trace->ds.top - ((index + 1) * trace->ds.size); | ||
918 | if ((void *)at < trace->ds.begin) | ||
919 | at += (trace->ds.n * trace->ds.size); | ||
920 | |||
921 | if (!trace->read) | ||
922 | return -EOPNOTSUPP; | ||
923 | |||
924 | error = trace->read(context->tracer, at, &bts); | ||
925 | if (error < 0) | ||
926 | return error; | ||
927 | |||
928 | if (copy_to_user(out, &bts, sizeof(bts))) | ||
929 | return -EFAULT; | ||
930 | |||
931 | return sizeof(bts); | ||
932 | } | ||
933 | |||
934 | static int ptrace_bts_drain(struct task_struct *child, | ||
935 | long size, | ||
936 | struct bts_struct __user *out) | ||
937 | { | ||
938 | struct bts_context *context; | ||
939 | const struct bts_trace *trace; | ||
940 | const unsigned char *at; | ||
941 | int error, drained = 0; | ||
942 | |||
943 | context = child->bts; | ||
944 | if (!context) | ||
945 | return -ESRCH; | ||
946 | |||
947 | trace = ds_read_bts(context->tracer); | ||
948 | if (!trace) | ||
949 | return -ESRCH; | ||
950 | |||
951 | if (!trace->read) | ||
952 | return -EOPNOTSUPP; | ||
953 | |||
954 | if (size < (trace->ds.top - trace->ds.begin)) | ||
955 | return -EIO; | ||
956 | |||
957 | for (at = trace->ds.begin; (void *)at < trace->ds.top; | ||
958 | out++, drained++, at += trace->ds.size) { | ||
959 | struct bts_struct bts; | ||
960 | |||
961 | error = trace->read(context->tracer, at, &bts); | ||
962 | if (error < 0) | ||
963 | return error; | ||
964 | |||
965 | if (copy_to_user(out, &bts, sizeof(bts))) | ||
966 | return -EFAULT; | ||
967 | } | ||
968 | |||
969 | memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); | ||
970 | |||
971 | error = ds_reset_bts(context->tracer); | ||
972 | if (error < 0) | ||
973 | return error; | ||
974 | |||
975 | return drained; | ||
976 | } | ||
977 | |||
978 | static int ptrace_bts_config(struct task_struct *child, | ||
979 | long cfg_size, | ||
980 | const struct ptrace_bts_config __user *ucfg) | ||
981 | { | ||
982 | struct bts_context *context; | ||
983 | struct ptrace_bts_config cfg; | ||
984 | unsigned int flags = 0; | ||
985 | |||
986 | if (cfg_size < sizeof(cfg)) | ||
987 | return -EIO; | ||
988 | |||
989 | if (copy_from_user(&cfg, ucfg, sizeof(cfg))) | ||
990 | return -EFAULT; | ||
991 | |||
992 | context = child->bts; | ||
993 | if (!context) | ||
994 | context = alloc_bts_context(child); | ||
995 | if (!context) | ||
996 | return -ENOMEM; | ||
997 | |||
998 | if (cfg.flags & PTRACE_BTS_O_SIGNAL) { | ||
999 | if (!cfg.signal) | ||
1000 | return -EINVAL; | ||
1001 | |||
1002 | return -EOPNOTSUPP; | ||
1003 | context->bts_ovfl_signal = cfg.signal; | ||
1004 | } | ||
1005 | |||
1006 | ds_release_bts(context->tracer); | ||
1007 | context->tracer = NULL; | ||
1008 | |||
1009 | if ((cfg.flags & PTRACE_BTS_O_ALLOC) && (cfg.size != context->size)) { | ||
1010 | int err; | ||
1011 | |||
1012 | free_bts_buffer(context); | ||
1013 | if (!cfg.size) | ||
1014 | return 0; | ||
1015 | |||
1016 | err = alloc_bts_buffer(context, cfg.size); | ||
1017 | if (err < 0) | ||
1018 | return err; | ||
1019 | } | ||
1020 | |||
1021 | if (cfg.flags & PTRACE_BTS_O_TRACE) | ||
1022 | flags |= BTS_USER; | ||
1023 | |||
1024 | if (cfg.flags & PTRACE_BTS_O_SCHED) | ||
1025 | flags |= BTS_TIMESTAMPS; | ||
1026 | |||
1027 | context->tracer = | ||
1028 | ds_request_bts_task(child, context->buffer, context->size, | ||
1029 | NULL, (size_t)-1, flags); | ||
1030 | if (unlikely(IS_ERR(context->tracer))) { | ||
1031 | int error = PTR_ERR(context->tracer); | ||
1032 | |||
1033 | free_bts_buffer(context); | ||
1034 | context->tracer = NULL; | ||
1035 | return error; | ||
1036 | } | ||
1037 | |||
1038 | return sizeof(cfg); | ||
1039 | } | ||
1040 | |||
1041 | static int ptrace_bts_status(struct task_struct *child, | ||
1042 | long cfg_size, | ||
1043 | struct ptrace_bts_config __user *ucfg) | ||
1044 | { | ||
1045 | struct bts_context *context; | ||
1046 | const struct bts_trace *trace; | ||
1047 | struct ptrace_bts_config cfg; | ||
1048 | |||
1049 | context = child->bts; | ||
1050 | if (!context) | ||
1051 | return -ESRCH; | ||
1052 | |||
1053 | if (cfg_size < sizeof(cfg)) | ||
1054 | return -EIO; | ||
1055 | |||
1056 | trace = ds_read_bts(context->tracer); | ||
1057 | if (!trace) | ||
1058 | return -ESRCH; | ||
1059 | |||
1060 | memset(&cfg, 0, sizeof(cfg)); | ||
1061 | cfg.size = trace->ds.end - trace->ds.begin; | ||
1062 | cfg.signal = context->bts_ovfl_signal; | ||
1063 | cfg.bts_size = sizeof(struct bts_struct); | ||
1064 | |||
1065 | if (cfg.signal) | ||
1066 | cfg.flags |= PTRACE_BTS_O_SIGNAL; | ||
1067 | |||
1068 | if (trace->ds.flags & BTS_USER) | ||
1069 | cfg.flags |= PTRACE_BTS_O_TRACE; | ||
1070 | |||
1071 | if (trace->ds.flags & BTS_TIMESTAMPS) | ||
1072 | cfg.flags |= PTRACE_BTS_O_SCHED; | ||
1073 | |||
1074 | if (copy_to_user(ucfg, &cfg, sizeof(cfg))) | ||
1075 | return -EFAULT; | ||
1076 | |||
1077 | return sizeof(cfg); | ||
1078 | } | ||
1079 | |||
1080 | static int ptrace_bts_clear(struct task_struct *child) | ||
1081 | { | ||
1082 | struct bts_context *context; | ||
1083 | const struct bts_trace *trace; | ||
1084 | |||
1085 | context = child->bts; | ||
1086 | if (!context) | ||
1087 | return -ESRCH; | ||
1088 | |||
1089 | trace = ds_read_bts(context->tracer); | ||
1090 | if (!trace) | ||
1091 | return -ESRCH; | ||
1092 | |||
1093 | memset(trace->ds.begin, 0, trace->ds.n * trace->ds.size); | ||
1094 | |||
1095 | return ds_reset_bts(context->tracer); | ||
1096 | } | ||
1097 | |||
1098 | static int ptrace_bts_size(struct task_struct *child) | ||
1099 | { | ||
1100 | struct bts_context *context; | ||
1101 | const struct bts_trace *trace; | ||
1102 | |||
1103 | context = child->bts; | ||
1104 | if (!context) | ||
1105 | return -ESRCH; | ||
1106 | |||
1107 | trace = ds_read_bts(context->tracer); | ||
1108 | if (!trace) | ||
1109 | return -ESRCH; | ||
1110 | |||
1111 | return (trace->ds.top - trace->ds.begin) / trace->ds.size; | ||
1112 | } | ||
1113 | |||
1114 | /* | ||
1115 | * Called from __ptrace_unlink() after the child has been moved back | ||
1116 | * to its original parent. | ||
1117 | */ | ||
1118 | void ptrace_bts_untrace(struct task_struct *child) | ||
1119 | { | ||
1120 | if (unlikely(child->bts)) { | ||
1121 | free_bts_context(child->bts); | ||
1122 | child->bts = NULL; | ||
1123 | } | ||
1124 | } | ||
1125 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
1126 | |||
1127 | /* | 786 | /* |
1128 | * Called by kernel/ptrace.c when detaching.. | 787 | * Called by kernel/ptrace.c when detaching.. |
1129 | * | 788 | * |
@@ -1251,39 +910,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
1251 | break; | 910 | break; |
1252 | #endif | 911 | #endif |
1253 | 912 | ||
1254 | /* | ||
1255 | * These bits need more cooking - not enabled yet: | ||
1256 | */ | ||
1257 | #ifdef CONFIG_X86_PTRACE_BTS | ||
1258 | case PTRACE_BTS_CONFIG: | ||
1259 | ret = ptrace_bts_config | ||
1260 | (child, data, (struct ptrace_bts_config __user *)addr); | ||
1261 | break; | ||
1262 | |||
1263 | case PTRACE_BTS_STATUS: | ||
1264 | ret = ptrace_bts_status | ||
1265 | (child, data, (struct ptrace_bts_config __user *)addr); | ||
1266 | break; | ||
1267 | |||
1268 | case PTRACE_BTS_SIZE: | ||
1269 | ret = ptrace_bts_size(child); | ||
1270 | break; | ||
1271 | |||
1272 | case PTRACE_BTS_GET: | ||
1273 | ret = ptrace_bts_read_record | ||
1274 | (child, data, (struct bts_struct __user *) addr); | ||
1275 | break; | ||
1276 | |||
1277 | case PTRACE_BTS_CLEAR: | ||
1278 | ret = ptrace_bts_clear(child); | ||
1279 | break; | ||
1280 | |||
1281 | case PTRACE_BTS_DRAIN: | ||
1282 | ret = ptrace_bts_drain | ||
1283 | (child, data, (struct bts_struct __user *) addr); | ||
1284 | break; | ||
1285 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
1286 | |||
1287 | default: | 913 | default: |
1288 | ret = ptrace_request(child, request, addr, data); | 914 | ret = ptrace_request(child, request, addr, data); |
1289 | break; | 915 | break; |
@@ -1543,14 +1169,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
1543 | 1169 | ||
1544 | case PTRACE_GET_THREAD_AREA: | 1170 | case PTRACE_GET_THREAD_AREA: |
1545 | case PTRACE_SET_THREAD_AREA: | 1171 | case PTRACE_SET_THREAD_AREA: |
1546 | #ifdef CONFIG_X86_PTRACE_BTS | ||
1547 | case PTRACE_BTS_CONFIG: | ||
1548 | case PTRACE_BTS_STATUS: | ||
1549 | case PTRACE_BTS_SIZE: | ||
1550 | case PTRACE_BTS_GET: | ||
1551 | case PTRACE_BTS_CLEAR: | ||
1552 | case PTRACE_BTS_DRAIN: | ||
1553 | #endif /* CONFIG_X86_PTRACE_BTS */ | ||
1554 | return arch_ptrace(child, request, addr, data); | 1172 | return arch_ptrace(child, request, addr, data); |
1555 | 1173 | ||
1556 | default: | 1174 | default: |
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index 3149032ff107..7beba0769a8c 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c | |||
@@ -158,22 +158,6 @@ static int enable_single_step(struct task_struct *child) | |||
158 | } | 158 | } |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * Install this value in MSR_IA32_DEBUGCTLMSR whenever child is running. | ||
162 | */ | ||
163 | static void write_debugctlmsr(struct task_struct *child, unsigned long val) | ||
164 | { | ||
165 | if (child->thread.debugctlmsr == val) | ||
166 | return; | ||
167 | |||
168 | child->thread.debugctlmsr = val; | ||
169 | |||
170 | if (child != current) | ||
171 | return; | ||
172 | |||
173 | update_debugctlmsr(val); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Enable single or block step. | 161 | * Enable single or block step. |
178 | */ | 162 | */ |
179 | static void enable_step(struct task_struct *child, bool block) | 163 | static void enable_step(struct task_struct *child, bool block) |
@@ -185,17 +169,9 @@ static void enable_step(struct task_struct *child, bool block) | |||
185 | * So noone should try to use debugger block stepping in a program | 169 | * So noone should try to use debugger block stepping in a program |
186 | * that uses user-mode single stepping itself. | 170 | * that uses user-mode single stepping itself. |
187 | */ | 171 | */ |
188 | if (enable_single_step(child) && block) { | 172 | if (!enable_single_step(child)) |
189 | set_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | 173 | return; |
190 | write_debugctlmsr(child, | 174 | /* XXX */ |
191 | child->thread.debugctlmsr | DEBUGCTLMSR_BTF); | ||
192 | } else { | ||
193 | write_debugctlmsr(child, | ||
194 | child->thread.debugctlmsr & ~DEBUGCTLMSR_BTF); | ||
195 | |||
196 | if (!child->thread.debugctlmsr) | ||
197 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | ||
198 | } | ||
199 | } | 175 | } |
200 | 176 | ||
201 | void user_enable_single_step(struct task_struct *child) | 177 | void user_enable_single_step(struct task_struct *child) |
@@ -213,11 +189,7 @@ void user_disable_single_step(struct task_struct *child) | |||
213 | /* | 189 | /* |
214 | * Make sure block stepping (BTF) is disabled. | 190 | * Make sure block stepping (BTF) is disabled. |
215 | */ | 191 | */ |
216 | write_debugctlmsr(child, | 192 | /* XXX */ |
217 | child->thread.debugctlmsr & ~DEBUGCTLMSR_BTF); | ||
218 | |||
219 | if (!child->thread.debugctlmsr) | ||
220 | clear_tsk_thread_flag(child, TIF_DEBUGCTLMSR); | ||
221 | 193 | ||
222 | /* Always clear TIF_SINGLESTEP... */ | 194 | /* Always clear TIF_SINGLESTEP... */ |
223 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); | 195 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 1168e4454188..e3da5d726a37 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -543,11 +543,6 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
543 | 543 | ||
544 | /* DR6 may or may not be cleared by the CPU */ | 544 | /* DR6 may or may not be cleared by the CPU */ |
545 | set_debugreg(0, 6); | 545 | set_debugreg(0, 6); |
546 | /* | ||
547 | * The processor cleared BTF, so don't mark that we need it set. | ||
548 | */ | ||
549 | clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR); | ||
550 | tsk->thread.debugctlmsr = 0; | ||
551 | 546 | ||
552 | /* Store the virtualized DR6 value */ | 547 | /* Store the virtualized DR6 value */ |
553 | tsk->thread.debugreg6 = dr6; | 548 | tsk->thread.debugreg6 = dr6; |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 01e6adea07ec..cc12b3c556b3 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -504,18 +504,6 @@ extern int ftrace_dump_on_oops; | |||
504 | #define INIT_TRACE_RECURSION | 504 | #define INIT_TRACE_RECURSION |
505 | #endif | 505 | #endif |
506 | 506 | ||
507 | #ifdef CONFIG_HW_BRANCH_TRACER | ||
508 | |||
509 | void trace_hw_branch(u64 from, u64 to); | ||
510 | void trace_hw_branch_oops(void); | ||
511 | |||
512 | #else /* CONFIG_HW_BRANCH_TRACER */ | ||
513 | |||
514 | static inline void trace_hw_branch(u64 from, u64 to) {} | ||
515 | static inline void trace_hw_branch_oops(void) {} | ||
516 | |||
517 | #endif /* CONFIG_HW_BRANCH_TRACER */ | ||
518 | |||
519 | #ifdef CONFIG_FTRACE_SYSCALLS | 507 | #ifdef CONFIG_FTRACE_SYSCALLS |
520 | 508 | ||
521 | unsigned long arch_syscall_addr(int nr); | 509 | unsigned long arch_syscall_addr(int nr); |
diff --git a/include/linux/mm.h b/include/linux/mm.h index e70f21beb4b4..c8442b655111 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -19,7 +19,6 @@ struct anon_vma; | |||
19 | struct file_ra_state; | 19 | struct file_ra_state; |
20 | struct user_struct; | 20 | struct user_struct; |
21 | struct writeback_control; | 21 | struct writeback_control; |
22 | struct rlimit; | ||
23 | 22 | ||
24 | #ifndef CONFIG_DISCONTIGMEM /* Don't use mapnrs, do it properly */ | 23 | #ifndef CONFIG_DISCONTIGMEM /* Don't use mapnrs, do it properly */ |
25 | extern unsigned long max_mapnr; | 24 | extern unsigned long max_mapnr; |
@@ -1449,9 +1448,6 @@ int vmemmap_populate_basepages(struct page *start_page, | |||
1449 | int vmemmap_populate(struct page *start_page, unsigned long pages, int node); | 1448 | int vmemmap_populate(struct page *start_page, unsigned long pages, int node); |
1450 | void vmemmap_populate_print_last(void); | 1449 | void vmemmap_populate_print_last(void); |
1451 | 1450 | ||
1452 | extern int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim, | ||
1453 | size_t size); | ||
1454 | extern void refund_locked_memory(struct mm_struct *mm, size_t size); | ||
1455 | 1451 | ||
1456 | enum mf_flags { | 1452 | enum mf_flags { |
1457 | MF_COUNT_INCREASED = 1 << 0, | 1453 | MF_COUNT_INCREASED = 1 << 0, |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index e1fb60729979..4272521e29e9 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -345,18 +345,6 @@ static inline void user_single_step_siginfo(struct task_struct *tsk, | |||
345 | #define arch_ptrace_stop(code, info) do { } while (0) | 345 | #define arch_ptrace_stop(code, info) do { } while (0) |
346 | #endif | 346 | #endif |
347 | 347 | ||
348 | #ifndef arch_ptrace_untrace | ||
349 | /* | ||
350 | * Do machine-specific work before untracing child. | ||
351 | * | ||
352 | * This is called for a normal detach as well as from ptrace_exit() | ||
353 | * when the tracing task dies. | ||
354 | * | ||
355 | * Called with write_lock(&tasklist_lock) held. | ||
356 | */ | ||
357 | #define arch_ptrace_untrace(task) do { } while (0) | ||
358 | #endif | ||
359 | |||
360 | extern int task_current_syscall(struct task_struct *target, long *callno, | 348 | extern int task_current_syscall(struct task_struct *target, long *callno, |
361 | unsigned long args[6], unsigned int maxargs, | 349 | unsigned long args[6], unsigned int maxargs, |
362 | unsigned long *sp, unsigned long *pc); | 350 | unsigned long *sp, unsigned long *pc); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index dad7f668ebf7..e0447c64af6a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -99,7 +99,6 @@ struct futex_pi_state; | |||
99 | struct robust_list_head; | 99 | struct robust_list_head; |
100 | struct bio_list; | 100 | struct bio_list; |
101 | struct fs_struct; | 101 | struct fs_struct; |
102 | struct bts_context; | ||
103 | struct perf_event_context; | 102 | struct perf_event_context; |
104 | 103 | ||
105 | /* | 104 | /* |
@@ -1272,12 +1271,6 @@ struct task_struct { | |||
1272 | struct list_head ptraced; | 1271 | struct list_head ptraced; |
1273 | struct list_head ptrace_entry; | 1272 | struct list_head ptrace_entry; |
1274 | 1273 | ||
1275 | /* | ||
1276 | * This is the tracer handle for the ptrace BTS extension. | ||
1277 | * This field actually belongs to the ptracer task. | ||
1278 | */ | ||
1279 | struct bts_context *bts; | ||
1280 | |||
1281 | /* PID/PID hash table linkage. */ | 1274 | /* PID/PID hash table linkage. */ |
1282 | struct pid_link pids[PIDTYPE_MAX]; | 1275 | struct pid_link pids[PIDTYPE_MAX]; |
1283 | struct list_head thread_group; | 1276 | struct list_head thread_group; |
@@ -2123,10 +2116,8 @@ extern void set_task_comm(struct task_struct *tsk, char *from); | |||
2123 | extern char *get_task_comm(char *to, struct task_struct *tsk); | 2116 | extern char *get_task_comm(char *to, struct task_struct *tsk); |
2124 | 2117 | ||
2125 | #ifdef CONFIG_SMP | 2118 | #ifdef CONFIG_SMP |
2126 | extern void wait_task_context_switch(struct task_struct *p); | ||
2127 | extern unsigned long wait_task_inactive(struct task_struct *, long match_state); | 2119 | extern unsigned long wait_task_inactive(struct task_struct *, long match_state); |
2128 | #else | 2120 | #else |
2129 | static inline void wait_task_context_switch(struct task_struct *p) {} | ||
2130 | static inline unsigned long wait_task_inactive(struct task_struct *p, | 2121 | static inline unsigned long wait_task_inactive(struct task_struct *p, |
2131 | long match_state) | 2122 | long match_state) |
2132 | { | 2123 | { |
diff --git a/kernel/fork.c b/kernel/fork.c index 4799c5f0e6d0..d67f1dbfbe03 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1108,9 +1108,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1108 | p->memcg_batch.do_batch = 0; | 1108 | p->memcg_batch.do_batch = 0; |
1109 | p->memcg_batch.memcg = NULL; | 1109 | p->memcg_batch.memcg = NULL; |
1110 | #endif | 1110 | #endif |
1111 | |||
1112 | p->bts = NULL; | ||
1113 | |||
1114 | p->stack_start = stack_start; | 1111 | p->stack_start = stack_start; |
1115 | 1112 | ||
1116 | /* Perform scheduler related setup. Assign this task to a CPU. */ | 1113 | /* Perform scheduler related setup. Assign this task to a CPU. */ |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 42ad8ae729a0..9fb51237b18c 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -76,7 +76,6 @@ void __ptrace_unlink(struct task_struct *child) | |||
76 | child->parent = child->real_parent; | 76 | child->parent = child->real_parent; |
77 | list_del_init(&child->ptrace_entry); | 77 | list_del_init(&child->ptrace_entry); |
78 | 78 | ||
79 | arch_ptrace_untrace(child); | ||
80 | if (task_is_traced(child)) | 79 | if (task_is_traced(child)) |
81 | ptrace_untrace(child); | 80 | ptrace_untrace(child); |
82 | } | 81 | } |
diff --git a/kernel/sched.c b/kernel/sched.c index 9ab3cd7858d3..117b7cad31b3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -2077,49 +2077,6 @@ migrate_task(struct task_struct *p, int dest_cpu, struct migration_req *req) | |||
2077 | } | 2077 | } |
2078 | 2078 | ||
2079 | /* | 2079 | /* |
2080 | * wait_task_context_switch - wait for a thread to complete at least one | ||
2081 | * context switch. | ||
2082 | * | ||
2083 | * @p must not be current. | ||
2084 | */ | ||
2085 | void wait_task_context_switch(struct task_struct *p) | ||
2086 | { | ||
2087 | unsigned long nvcsw, nivcsw, flags; | ||
2088 | int running; | ||
2089 | struct rq *rq; | ||
2090 | |||
2091 | nvcsw = p->nvcsw; | ||
2092 | nivcsw = p->nivcsw; | ||
2093 | for (;;) { | ||
2094 | /* | ||
2095 | * The runqueue is assigned before the actual context | ||
2096 | * switch. We need to take the runqueue lock. | ||
2097 | * | ||
2098 | * We could check initially without the lock but it is | ||
2099 | * very likely that we need to take the lock in every | ||
2100 | * iteration. | ||
2101 | */ | ||
2102 | rq = task_rq_lock(p, &flags); | ||
2103 | running = task_running(rq, p); | ||
2104 | task_rq_unlock(rq, &flags); | ||
2105 | |||
2106 | if (likely(!running)) | ||
2107 | break; | ||
2108 | /* | ||
2109 | * The switch count is incremented before the actual | ||
2110 | * context switch. We thus wait for two switches to be | ||
2111 | * sure at least one completed. | ||
2112 | */ | ||
2113 | if ((p->nvcsw - nvcsw) > 1) | ||
2114 | break; | ||
2115 | if ((p->nivcsw - nivcsw) > 1) | ||
2116 | break; | ||
2117 | |||
2118 | cpu_relax(); | ||
2119 | } | ||
2120 | } | ||
2121 | |||
2122 | /* | ||
2123 | * wait_task_inactive - wait for a thread to unschedule. | 2080 | * wait_task_inactive - wait for a thread to unschedule. |
2124 | * | 2081 | * |
2125 | * If @match_state is nonzero, it's the @p->state value just checked and | 2082 | * If @match_state is nonzero, it's the @p->state value just checked and |
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 13e13d428cd3..8b1797c4545b 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
@@ -44,9 +44,6 @@ config HAVE_FTRACE_MCOUNT_RECORD | |||
44 | help | 44 | help |
45 | See Documentation/trace/ftrace-design.txt | 45 | See Documentation/trace/ftrace-design.txt |
46 | 46 | ||
47 | config HAVE_HW_BRANCH_TRACER | ||
48 | bool | ||
49 | |||
50 | config HAVE_SYSCALL_TRACEPOINTS | 47 | config HAVE_SYSCALL_TRACEPOINTS |
51 | bool | 48 | bool |
52 | help | 49 | help |
@@ -374,14 +371,6 @@ config STACK_TRACER | |||
374 | 371 | ||
375 | Say N if unsure. | 372 | Say N if unsure. |
376 | 373 | ||
377 | config HW_BRANCH_TRACER | ||
378 | depends on HAVE_HW_BRANCH_TRACER | ||
379 | bool "Trace hw branches" | ||
380 | select GENERIC_TRACER | ||
381 | help | ||
382 | This tracer records all branches on the system in a circular | ||
383 | buffer, giving access to the last N branches for each cpu. | ||
384 | |||
385 | config KMEMTRACE | 374 | config KMEMTRACE |
386 | bool "Trace SLAB allocations" | 375 | bool "Trace SLAB allocations" |
387 | select GENERIC_TRACER | 376 | select GENERIC_TRACER |
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 78edc6490038..ffb1a5b0550e 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile | |||
@@ -41,7 +41,6 @@ obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o | |||
41 | obj-$(CONFIG_BOOT_TRACER) += trace_boot.o | 41 | obj-$(CONFIG_BOOT_TRACER) += trace_boot.o |
42 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o | 42 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o |
43 | obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o | 43 | obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o |
44 | obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o | ||
45 | obj-$(CONFIG_KMEMTRACE) += kmemtrace.o | 44 | obj-$(CONFIG_KMEMTRACE) += kmemtrace.o |
46 | obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o | 45 | obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o |
47 | obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o | 46 | obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 2825ef2c0b15..bec2c973ff0c 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -34,7 +34,6 @@ enum trace_type { | |||
34 | TRACE_GRAPH_RET, | 34 | TRACE_GRAPH_RET, |
35 | TRACE_GRAPH_ENT, | 35 | TRACE_GRAPH_ENT, |
36 | TRACE_USER_STACK, | 36 | TRACE_USER_STACK, |
37 | TRACE_HW_BRANCHES, | ||
38 | TRACE_KMEM_ALLOC, | 37 | TRACE_KMEM_ALLOC, |
39 | TRACE_KMEM_FREE, | 38 | TRACE_KMEM_FREE, |
40 | TRACE_BLK, | 39 | TRACE_BLK, |
@@ -229,7 +228,6 @@ extern void __ftrace_bad_type(void); | |||
229 | TRACE_GRAPH_ENT); \ | 228 | TRACE_GRAPH_ENT); \ |
230 | IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ | 229 | IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ |
231 | TRACE_GRAPH_RET); \ | 230 | TRACE_GRAPH_RET); \ |
232 | IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\ | ||
233 | IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ | 231 | IF_ASSIGN(var, ent, struct kmemtrace_alloc_entry, \ |
234 | TRACE_KMEM_ALLOC); \ | 232 | TRACE_KMEM_ALLOC); \ |
235 | IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ | 233 | IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ |
@@ -467,8 +465,6 @@ extern int trace_selftest_startup_sysprof(struct tracer *trace, | |||
467 | struct trace_array *tr); | 465 | struct trace_array *tr); |
468 | extern int trace_selftest_startup_branch(struct tracer *trace, | 466 | extern int trace_selftest_startup_branch(struct tracer *trace, |
469 | struct trace_array *tr); | 467 | struct trace_array *tr); |
470 | extern int trace_selftest_startup_hw_branches(struct tracer *trace, | ||
471 | struct trace_array *tr); | ||
472 | extern int trace_selftest_startup_ksym(struct tracer *trace, | 468 | extern int trace_selftest_startup_ksym(struct tracer *trace, |
473 | struct trace_array *tr); | 469 | struct trace_array *tr); |
474 | #endif /* CONFIG_FTRACE_STARTUP_TEST */ | 470 | #endif /* CONFIG_FTRACE_STARTUP_TEST */ |
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h index c16a08f399df..dc008c1240da 100644 --- a/kernel/trace/trace_entries.h +++ b/kernel/trace/trace_entries.h | |||
@@ -318,18 +318,6 @@ FTRACE_ENTRY(branch, trace_branch, | |||
318 | __entry->func, __entry->file, __entry->correct) | 318 | __entry->func, __entry->file, __entry->correct) |
319 | ); | 319 | ); |
320 | 320 | ||
321 | FTRACE_ENTRY(hw_branch, hw_branch_entry, | ||
322 | |||
323 | TRACE_HW_BRANCHES, | ||
324 | |||
325 | F_STRUCT( | ||
326 | __field( u64, from ) | ||
327 | __field( u64, to ) | ||
328 | ), | ||
329 | |||
330 | F_printk("from: %llx to: %llx", __entry->from, __entry->to) | ||
331 | ); | ||
332 | |||
333 | FTRACE_ENTRY(kmem_alloc, kmemtrace_alloc_entry, | 321 | FTRACE_ENTRY(kmem_alloc, kmemtrace_alloc_entry, |
334 | 322 | ||
335 | TRACE_KMEM_ALLOC, | 323 | TRACE_KMEM_ALLOC, |
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c deleted file mode 100644 index 7b97000745f5..000000000000 --- a/kernel/trace/trace_hw_branches.c +++ /dev/null | |||
@@ -1,312 +0,0 @@ | |||
1 | /* | ||
2 | * h/w branch tracer for x86 based on BTS | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 Intel Corporation. | ||
5 | * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009 | ||
6 | */ | ||
7 | #include <linux/kallsyms.h> | ||
8 | #include <linux/debugfs.h> | ||
9 | #include <linux/ftrace.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/cpu.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/fs.h> | ||
14 | |||
15 | #include <asm/ds.h> | ||
16 | |||
17 | #include "trace_output.h" | ||
18 | #include "trace.h" | ||
19 | |||
20 | |||
21 | #define BTS_BUFFER_SIZE (1 << 13) | ||
22 | |||
23 | static DEFINE_PER_CPU(struct bts_tracer *, hwb_tracer); | ||
24 | static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], hwb_buffer); | ||
25 | |||
26 | #define this_tracer per_cpu(hwb_tracer, smp_processor_id()) | ||
27 | |||
28 | static int trace_hw_branches_enabled __read_mostly; | ||
29 | static int trace_hw_branches_suspended __read_mostly; | ||
30 | static struct trace_array *hw_branch_trace __read_mostly; | ||
31 | |||
32 | |||
33 | static void bts_trace_init_cpu(int cpu) | ||
34 | { | ||
35 | per_cpu(hwb_tracer, cpu) = | ||
36 | ds_request_bts_cpu(cpu, per_cpu(hwb_buffer, cpu), | ||
37 | BTS_BUFFER_SIZE, NULL, (size_t)-1, | ||
38 | BTS_KERNEL); | ||
39 | |||
40 | if (IS_ERR(per_cpu(hwb_tracer, cpu))) | ||
41 | per_cpu(hwb_tracer, cpu) = NULL; | ||
42 | } | ||
43 | |||
44 | static int bts_trace_init(struct trace_array *tr) | ||
45 | { | ||
46 | int cpu; | ||
47 | |||
48 | hw_branch_trace = tr; | ||
49 | trace_hw_branches_enabled = 0; | ||
50 | |||
51 | get_online_cpus(); | ||
52 | for_each_online_cpu(cpu) { | ||
53 | bts_trace_init_cpu(cpu); | ||
54 | |||
55 | if (likely(per_cpu(hwb_tracer, cpu))) | ||
56 | trace_hw_branches_enabled = 1; | ||
57 | } | ||
58 | trace_hw_branches_suspended = 0; | ||
59 | put_online_cpus(); | ||
60 | |||
61 | /* If we could not enable tracing on a single cpu, we fail. */ | ||
62 | return trace_hw_branches_enabled ? 0 : -EOPNOTSUPP; | ||
63 | } | ||
64 | |||
65 | static void bts_trace_reset(struct trace_array *tr) | ||
66 | { | ||
67 | int cpu; | ||
68 | |||
69 | get_online_cpus(); | ||
70 | for_each_online_cpu(cpu) { | ||
71 | if (likely(per_cpu(hwb_tracer, cpu))) { | ||
72 | ds_release_bts(per_cpu(hwb_tracer, cpu)); | ||
73 | per_cpu(hwb_tracer, cpu) = NULL; | ||
74 | } | ||
75 | } | ||
76 | trace_hw_branches_enabled = 0; | ||
77 | trace_hw_branches_suspended = 0; | ||
78 | put_online_cpus(); | ||
79 | } | ||
80 | |||
81 | static void bts_trace_start(struct trace_array *tr) | ||
82 | { | ||
83 | int cpu; | ||
84 | |||
85 | get_online_cpus(); | ||
86 | for_each_online_cpu(cpu) | ||
87 | if (likely(per_cpu(hwb_tracer, cpu))) | ||
88 | ds_resume_bts(per_cpu(hwb_tracer, cpu)); | ||
89 | trace_hw_branches_suspended = 0; | ||
90 | put_online_cpus(); | ||
91 | } | ||
92 | |||
93 | static void bts_trace_stop(struct trace_array *tr) | ||
94 | { | ||
95 | int cpu; | ||
96 | |||
97 | get_online_cpus(); | ||
98 | for_each_online_cpu(cpu) | ||
99 | if (likely(per_cpu(hwb_tracer, cpu))) | ||
100 | ds_suspend_bts(per_cpu(hwb_tracer, cpu)); | ||
101 | trace_hw_branches_suspended = 1; | ||
102 | put_online_cpus(); | ||
103 | } | ||
104 | |||
105 | static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb, | ||
106 | unsigned long action, void *hcpu) | ||
107 | { | ||
108 | int cpu = (long)hcpu; | ||
109 | |||
110 | switch (action) { | ||
111 | case CPU_ONLINE: | ||
112 | case CPU_DOWN_FAILED: | ||
113 | /* The notification is sent with interrupts enabled. */ | ||
114 | if (trace_hw_branches_enabled) { | ||
115 | bts_trace_init_cpu(cpu); | ||
116 | |||
117 | if (trace_hw_branches_suspended && | ||
118 | likely(per_cpu(hwb_tracer, cpu))) | ||
119 | ds_suspend_bts(per_cpu(hwb_tracer, cpu)); | ||
120 | } | ||
121 | break; | ||
122 | |||
123 | case CPU_DOWN_PREPARE: | ||
124 | /* The notification is sent with interrupts enabled. */ | ||
125 | if (likely(per_cpu(hwb_tracer, cpu))) { | ||
126 | ds_release_bts(per_cpu(hwb_tracer, cpu)); | ||
127 | per_cpu(hwb_tracer, cpu) = NULL; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | return NOTIFY_DONE; | ||
132 | } | ||
133 | |||
134 | static struct notifier_block bts_hotcpu_notifier __cpuinitdata = { | ||
135 | .notifier_call = bts_hotcpu_handler | ||
136 | }; | ||
137 | |||
138 | static void bts_trace_print_header(struct seq_file *m) | ||
139 | { | ||
140 | seq_puts(m, "# CPU# TO <- FROM\n"); | ||
141 | } | ||
142 | |||
143 | static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) | ||
144 | { | ||
145 | unsigned long symflags = TRACE_ITER_SYM_OFFSET; | ||
146 | struct trace_entry *entry = iter->ent; | ||
147 | struct trace_seq *seq = &iter->seq; | ||
148 | struct hw_branch_entry *it; | ||
149 | |||
150 | trace_assign_type(it, entry); | ||
151 | |||
152 | if (entry->type == TRACE_HW_BRANCHES) { | ||
153 | if (trace_seq_printf(seq, "%4d ", iter->cpu) && | ||
154 | seq_print_ip_sym(seq, it->to, symflags) && | ||
155 | trace_seq_printf(seq, "\t <- ") && | ||
156 | seq_print_ip_sym(seq, it->from, symflags) && | ||
157 | trace_seq_printf(seq, "\n")) | ||
158 | return TRACE_TYPE_HANDLED; | ||
159 | return TRACE_TYPE_PARTIAL_LINE; | ||
160 | } | ||
161 | return TRACE_TYPE_UNHANDLED; | ||
162 | } | ||
163 | |||
164 | void trace_hw_branch(u64 from, u64 to) | ||
165 | { | ||
166 | struct ftrace_event_call *call = &event_hw_branch; | ||
167 | struct trace_array *tr = hw_branch_trace; | ||
168 | struct ring_buffer_event *event; | ||
169 | struct ring_buffer *buf; | ||
170 | struct hw_branch_entry *entry; | ||
171 | unsigned long irq1; | ||
172 | int cpu; | ||
173 | |||
174 | if (unlikely(!tr)) | ||
175 | return; | ||
176 | |||
177 | if (unlikely(!trace_hw_branches_enabled)) | ||
178 | return; | ||
179 | |||
180 | local_irq_save(irq1); | ||
181 | cpu = raw_smp_processor_id(); | ||
182 | if (atomic_inc_return(&tr->data[cpu]->disabled) != 1) | ||
183 | goto out; | ||
184 | |||
185 | buf = tr->buffer; | ||
186 | event = trace_buffer_lock_reserve(buf, TRACE_HW_BRANCHES, | ||
187 | sizeof(*entry), 0, 0); | ||
188 | if (!event) | ||
189 | goto out; | ||
190 | entry = ring_buffer_event_data(event); | ||
191 | tracing_generic_entry_update(&entry->ent, 0, from); | ||
192 | entry->ent.type = TRACE_HW_BRANCHES; | ||
193 | entry->from = from; | ||
194 | entry->to = to; | ||
195 | if (!filter_check_discard(call, entry, buf, event)) | ||
196 | trace_buffer_unlock_commit(buf, event, 0, 0); | ||
197 | |||
198 | out: | ||
199 | atomic_dec(&tr->data[cpu]->disabled); | ||
200 | local_irq_restore(irq1); | ||
201 | } | ||
202 | |||
203 | static void trace_bts_at(const struct bts_trace *trace, void *at) | ||
204 | { | ||
205 | struct bts_struct bts; | ||
206 | int err = 0; | ||
207 | |||
208 | WARN_ON_ONCE(!trace->read); | ||
209 | if (!trace->read) | ||
210 | return; | ||
211 | |||
212 | err = trace->read(this_tracer, at, &bts); | ||
213 | if (err < 0) | ||
214 | return; | ||
215 | |||
216 | switch (bts.qualifier) { | ||
217 | case BTS_BRANCH: | ||
218 | trace_hw_branch(bts.variant.lbr.from, bts.variant.lbr.to); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * Collect the trace on the current cpu and write it into the ftrace buffer. | ||
225 | * | ||
226 | * pre: tracing must be suspended on the current cpu | ||
227 | */ | ||
228 | static void trace_bts_cpu(void *arg) | ||
229 | { | ||
230 | struct trace_array *tr = (struct trace_array *)arg; | ||
231 | const struct bts_trace *trace; | ||
232 | unsigned char *at; | ||
233 | |||
234 | if (unlikely(!tr)) | ||
235 | return; | ||
236 | |||
237 | if (unlikely(atomic_read(&tr->data[raw_smp_processor_id()]->disabled))) | ||
238 | return; | ||
239 | |||
240 | if (unlikely(!this_tracer)) | ||
241 | return; | ||
242 | |||
243 | trace = ds_read_bts(this_tracer); | ||
244 | if (!trace) | ||
245 | return; | ||
246 | |||
247 | for (at = trace->ds.top; (void *)at < trace->ds.end; | ||
248 | at += trace->ds.size) | ||
249 | trace_bts_at(trace, at); | ||
250 | |||
251 | for (at = trace->ds.begin; (void *)at < trace->ds.top; | ||
252 | at += trace->ds.size) | ||
253 | trace_bts_at(trace, at); | ||
254 | } | ||
255 | |||
256 | static void trace_bts_prepare(struct trace_iterator *iter) | ||
257 | { | ||
258 | int cpu; | ||
259 | |||
260 | get_online_cpus(); | ||
261 | for_each_online_cpu(cpu) | ||
262 | if (likely(per_cpu(hwb_tracer, cpu))) | ||
263 | ds_suspend_bts(per_cpu(hwb_tracer, cpu)); | ||
264 | /* | ||
265 | * We need to collect the trace on the respective cpu since ftrace | ||
266 | * implicitly adds the record for the current cpu. | ||
267 | * Once that is more flexible, we could collect the data from any cpu. | ||
268 | */ | ||
269 | on_each_cpu(trace_bts_cpu, iter->tr, 1); | ||
270 | |||
271 | for_each_online_cpu(cpu) | ||
272 | if (likely(per_cpu(hwb_tracer, cpu))) | ||
273 | ds_resume_bts(per_cpu(hwb_tracer, cpu)); | ||
274 | put_online_cpus(); | ||
275 | } | ||
276 | |||
277 | static void trace_bts_close(struct trace_iterator *iter) | ||
278 | { | ||
279 | tracing_reset_online_cpus(iter->tr); | ||
280 | } | ||
281 | |||
282 | void trace_hw_branch_oops(void) | ||
283 | { | ||
284 | if (this_tracer) { | ||
285 | ds_suspend_bts_noirq(this_tracer); | ||
286 | trace_bts_cpu(hw_branch_trace); | ||
287 | ds_resume_bts_noirq(this_tracer); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | struct tracer bts_tracer __read_mostly = | ||
292 | { | ||
293 | .name = "hw-branch-tracer", | ||
294 | .init = bts_trace_init, | ||
295 | .reset = bts_trace_reset, | ||
296 | .print_header = bts_trace_print_header, | ||
297 | .print_line = bts_trace_print_line, | ||
298 | .start = bts_trace_start, | ||
299 | .stop = bts_trace_stop, | ||
300 | .open = trace_bts_prepare, | ||
301 | .close = trace_bts_close, | ||
302 | #ifdef CONFIG_FTRACE_SELFTEST | ||
303 | .selftest = trace_selftest_startup_hw_branches, | ||
304 | #endif /* CONFIG_FTRACE_SELFTEST */ | ||
305 | }; | ||
306 | |||
307 | __init static int init_bts_trace(void) | ||
308 | { | ||
309 | register_hotcpu_notifier(&bts_hotcpu_notifier); | ||
310 | return register_tracer(&bts_tracer); | ||
311 | } | ||
312 | device_initcall(init_bts_trace); | ||
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 280fea470d67..a7084e7c0427 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -16,7 +16,6 @@ static inline int trace_valid_entry(struct trace_entry *entry) | |||
16 | case TRACE_BRANCH: | 16 | case TRACE_BRANCH: |
17 | case TRACE_GRAPH_ENT: | 17 | case TRACE_GRAPH_ENT: |
18 | case TRACE_GRAPH_RET: | 18 | case TRACE_GRAPH_RET: |
19 | case TRACE_HW_BRANCHES: | ||
20 | case TRACE_KSYM: | 19 | case TRACE_KSYM: |
21 | return 1; | 20 | return 1; |
22 | } | 21 | } |
@@ -754,62 +753,6 @@ trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr) | |||
754 | } | 753 | } |
755 | #endif /* CONFIG_BRANCH_TRACER */ | 754 | #endif /* CONFIG_BRANCH_TRACER */ |
756 | 755 | ||
757 | #ifdef CONFIG_HW_BRANCH_TRACER | ||
758 | int | ||
759 | trace_selftest_startup_hw_branches(struct tracer *trace, | ||
760 | struct trace_array *tr) | ||
761 | { | ||
762 | struct trace_iterator *iter; | ||
763 | struct tracer tracer; | ||
764 | unsigned long count; | ||
765 | int ret; | ||
766 | |||
767 | if (!trace->open) { | ||
768 | printk(KERN_CONT "missing open function..."); | ||
769 | return -1; | ||
770 | } | ||
771 | |||
772 | ret = tracer_init(trace, tr); | ||
773 | if (ret) { | ||
774 | warn_failed_init_tracer(trace, ret); | ||
775 | return ret; | ||
776 | } | ||
777 | |||
778 | /* | ||
779 | * The hw-branch tracer needs to collect the trace from the various | ||
780 | * cpu trace buffers - before tracing is stopped. | ||
781 | */ | ||
782 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); | ||
783 | if (!iter) | ||
784 | return -ENOMEM; | ||
785 | |||
786 | memcpy(&tracer, trace, sizeof(tracer)); | ||
787 | |||
788 | iter->trace = &tracer; | ||
789 | iter->tr = tr; | ||
790 | iter->pos = -1; | ||
791 | mutex_init(&iter->mutex); | ||
792 | |||
793 | trace->open(iter); | ||
794 | |||
795 | mutex_destroy(&iter->mutex); | ||
796 | kfree(iter); | ||
797 | |||
798 | tracing_stop(); | ||
799 | |||
800 | ret = trace_test_buffer(tr, &count); | ||
801 | trace->reset(tr); | ||
802 | tracing_start(); | ||
803 | |||
804 | if (!ret && !count) { | ||
805 | printk(KERN_CONT "no entries found.."); | ||
806 | ret = -1; | ||
807 | } | ||
808 | |||
809 | return ret; | ||
810 | } | ||
811 | #endif /* CONFIG_HW_BRANCH_TRACER */ | ||
812 | |||
813 | #ifdef CONFIG_KSYM_TRACER | 756 | #ifdef CONFIG_KSYM_TRACER |
814 | static int ksym_selftest_dummy; | 757 | static int ksym_selftest_dummy; |
815 | 758 | ||
diff --git a/mm/mlock.c b/mm/mlock.c index 8f4e2dfceec1..3f82720e0515 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -607,44 +607,3 @@ void user_shm_unlock(size_t size, struct user_struct *user) | |||
607 | spin_unlock(&shmlock_user_lock); | 607 | spin_unlock(&shmlock_user_lock); |
608 | free_uid(user); | 608 | free_uid(user); |
609 | } | 609 | } |
610 | |||
611 | int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim, | ||
612 | size_t size) | ||
613 | { | ||
614 | unsigned long lim, vm, pgsz; | ||
615 | int error = -ENOMEM; | ||
616 | |||
617 | pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
618 | |||
619 | down_write(&mm->mmap_sem); | ||
620 | |||
621 | lim = ACCESS_ONCE(rlim[RLIMIT_AS].rlim_cur) >> PAGE_SHIFT; | ||
622 | vm = mm->total_vm + pgsz; | ||
623 | if (lim < vm) | ||
624 | goto out; | ||
625 | |||
626 | lim = ACCESS_ONCE(rlim[RLIMIT_MEMLOCK].rlim_cur) >> PAGE_SHIFT; | ||
627 | vm = mm->locked_vm + pgsz; | ||
628 | if (lim < vm) | ||
629 | goto out; | ||
630 | |||
631 | mm->total_vm += pgsz; | ||
632 | mm->locked_vm += pgsz; | ||
633 | |||
634 | error = 0; | ||
635 | out: | ||
636 | up_write(&mm->mmap_sem); | ||
637 | return error; | ||
638 | } | ||
639 | |||
640 | void refund_locked_memory(struct mm_struct *mm, size_t size) | ||
641 | { | ||
642 | unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT; | ||
643 | |||
644 | down_write(&mm->mmap_sem); | ||
645 | |||
646 | mm->total_vm -= pgsz; | ||
647 | mm->locked_vm -= pgsz; | ||
648 | |||
649 | up_write(&mm->mmap_sem); | ||
650 | } | ||