diff options
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_ds.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 32e9ed81cd00..c1760ff3c757 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #define BTS_BUFFER_SIZE (PAGE_SIZE << 4) | 13 | #define BTS_BUFFER_SIZE (PAGE_SIZE << 4) |
14 | #define PEBS_BUFFER_SIZE PAGE_SIZE | 14 | #define PEBS_BUFFER_SIZE PAGE_SIZE |
15 | #define PEBS_FIXUP_SIZE PAGE_SIZE | ||
15 | 16 | ||
16 | /* | 17 | /* |
17 | * pebs_record_32 for p4 and core not supported | 18 | * pebs_record_32 for p4 and core not supported |
@@ -228,12 +229,14 @@ void fini_debug_store_on_cpu(int cpu) | |||
228 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); | 229 | wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0); |
229 | } | 230 | } |
230 | 231 | ||
232 | static DEFINE_PER_CPU(void *, insn_buffer); | ||
233 | |||
231 | static int alloc_pebs_buffer(int cpu) | 234 | static int alloc_pebs_buffer(int cpu) |
232 | { | 235 | { |
233 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; | 236 | struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds; |
234 | int node = cpu_to_node(cpu); | 237 | int node = cpu_to_node(cpu); |
235 | int max, thresh = 1; /* always use a single PEBS record */ | 238 | int max, thresh = 1; /* always use a single PEBS record */ |
236 | void *buffer; | 239 | void *buffer, *ibuffer; |
237 | 240 | ||
238 | if (!x86_pmu.pebs) | 241 | if (!x86_pmu.pebs) |
239 | return 0; | 242 | return 0; |
@@ -242,6 +245,19 @@ static int alloc_pebs_buffer(int cpu) | |||
242 | if (unlikely(!buffer)) | 245 | if (unlikely(!buffer)) |
243 | return -ENOMEM; | 246 | return -ENOMEM; |
244 | 247 | ||
248 | /* | ||
249 | * HSW+ already provides us the eventing ip; no need to allocate this | ||
250 | * buffer then. | ||
251 | */ | ||
252 | if (x86_pmu.intel_cap.pebs_format < 2) { | ||
253 | ibuffer = kzalloc_node(PEBS_FIXUP_SIZE, GFP_KERNEL, node); | ||
254 | if (!ibuffer) { | ||
255 | kfree(buffer); | ||
256 | return -ENOMEM; | ||
257 | } | ||
258 | per_cpu(insn_buffer, cpu) = ibuffer; | ||
259 | } | ||
260 | |||
245 | max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size; | 261 | max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size; |
246 | 262 | ||
247 | ds->pebs_buffer_base = (u64)(unsigned long)buffer; | 263 | ds->pebs_buffer_base = (u64)(unsigned long)buffer; |
@@ -262,6 +278,9 @@ static void release_pebs_buffer(int cpu) | |||
262 | if (!ds || !x86_pmu.pebs) | 278 | if (!ds || !x86_pmu.pebs) |
263 | return; | 279 | return; |
264 | 280 | ||
281 | kfree(per_cpu(insn_buffer, cpu)); | ||
282 | per_cpu(insn_buffer, cpu) = NULL; | ||
283 | |||
265 | kfree((void *)(unsigned long)ds->pebs_buffer_base); | 284 | kfree((void *)(unsigned long)ds->pebs_buffer_base); |
266 | ds->pebs_buffer_base = 0; | 285 | ds->pebs_buffer_base = 0; |
267 | } | 286 | } |
@@ -729,6 +748,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) | |||
729 | unsigned long old_to, to = cpuc->lbr_entries[0].to; | 748 | unsigned long old_to, to = cpuc->lbr_entries[0].to; |
730 | unsigned long ip = regs->ip; | 749 | unsigned long ip = regs->ip; |
731 | int is_64bit = 0; | 750 | int is_64bit = 0; |
751 | void *kaddr; | ||
732 | 752 | ||
733 | /* | 753 | /* |
734 | * We don't need to fixup if the PEBS assist is fault like | 754 | * We don't need to fixup if the PEBS assist is fault like |
@@ -752,7 +772,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) | |||
752 | * unsigned math, either ip is before the start (impossible) or | 772 | * unsigned math, either ip is before the start (impossible) or |
753 | * the basic block is larger than 1 page (sanity) | 773 | * the basic block is larger than 1 page (sanity) |
754 | */ | 774 | */ |
755 | if ((ip - to) > PAGE_SIZE) | 775 | if ((ip - to) > PEBS_FIXUP_SIZE) |
756 | return 0; | 776 | return 0; |
757 | 777 | ||
758 | /* | 778 | /* |
@@ -763,29 +783,33 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) | |||
763 | return 1; | 783 | return 1; |
764 | } | 784 | } |
765 | 785 | ||
786 | if (!kernel_ip(ip)) { | ||
787 | int size, bytes; | ||
788 | u8 *buf = this_cpu_read(insn_buffer); | ||
789 | |||
790 | size = ip - to; /* Must fit our buffer, see above */ | ||
791 | bytes = copy_from_user_nmi(buf, (void __user *)to, size); | ||
792 | if (bytes != size) | ||
793 | return 0; | ||
794 | |||
795 | kaddr = buf; | ||
796 | } else { | ||
797 | kaddr = (void *)to; | ||
798 | } | ||
799 | |||
766 | do { | 800 | do { |
767 | struct insn insn; | 801 | struct insn insn; |
768 | u8 buf[MAX_INSN_SIZE]; | ||
769 | void *kaddr; | ||
770 | 802 | ||
771 | old_to = to; | 803 | old_to = to; |
772 | if (!kernel_ip(ip)) { | ||
773 | int bytes, size = MAX_INSN_SIZE; | ||
774 | |||
775 | bytes = copy_from_user_nmi(buf, (void __user *)to, size); | ||
776 | if (bytes != size) | ||
777 | return 0; | ||
778 | |||
779 | kaddr = buf; | ||
780 | } else | ||
781 | kaddr = (void *)to; | ||
782 | 804 | ||
783 | #ifdef CONFIG_X86_64 | 805 | #ifdef CONFIG_X86_64 |
784 | is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); | 806 | is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); |
785 | #endif | 807 | #endif |
786 | insn_init(&insn, kaddr, is_64bit); | 808 | insn_init(&insn, kaddr, is_64bit); |
787 | insn_get_length(&insn); | 809 | insn_get_length(&insn); |
810 | |||
788 | to += insn.length; | 811 | to += insn.length; |
812 | kaddr += insn.length; | ||
789 | } while (to < ip); | 813 | } while (to < ip); |
790 | 814 | ||
791 | if (to == ip) { | 815 | if (to == ip) { |