aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/perf/callchain.c
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2012-02-20 12:02:09 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-02-22 18:50:04 -0500
commitf2699491e06584a2ebb0939f108ad29f3b151456 (patch)
tree62c68617c28ac901bddb54b1d1ec108d2809a282 /arch/powerpc/perf/callchain.c
parent12d9299241241200e4f34f3b02f206fa8384a923 (diff)
powerpc/perf: Move perf core & PMU code into a subdirectory
The perf code has grown a lot since it started, and is big enough to warrant its own subdirectory. For reference it's ~60% bigger than the oprofile code. It declutters the kernel directory, makes it simpler to grep for "just perf stuff", and allows us to shorten some filenames. While we're at it, make it more obvious that we have two implementations of the core perf logic. One for (roughly) Book3S CPUs, which was the original implementation, and the other for Freescale embedded CPUs. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/perf/callchain.c')
-rw-r--r--arch/powerpc/perf/callchain.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c
new file mode 100644
index 00000000000..e8a18d1cc7c
--- /dev/null
+++ b/arch/powerpc/perf/callchain.c
@@ -0,0 +1,492 @@
1/*
2 * Performance counter callchain support - powerpc architecture code
3 *
4 * Copyright © 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/perf_event.h>
14#include <linux/percpu.h>
15#include <linux/uaccess.h>
16#include <linux/mm.h>
17#include <asm/ptrace.h>
18#include <asm/pgtable.h>
19#include <asm/sigcontext.h>
20#include <asm/ucontext.h>
21#include <asm/vdso.h>
22#ifdef CONFIG_PPC64
23#include "../kernel/ppc32.h"
24#endif
25
26
27/*
28 * Is sp valid as the address of the next kernel stack frame after prev_sp?
29 * The next frame may be in a different stack area but should not go
30 * back down in the same stack area.
31 */
32static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
33{
34 if (sp & 0xf)
35 return 0; /* must be 16-byte aligned */
36 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
37 return 0;
38 if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
39 return 1;
40 /*
41 * sp could decrease when we jump off an interrupt stack
42 * back to the regular process stack.
43 */
44 if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
45 return 1;
46 return 0;
47}
48
49void
50perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
51{
52 unsigned long sp, next_sp;
53 unsigned long next_ip;
54 unsigned long lr;
55 long level = 0;
56 unsigned long *fp;
57
58 lr = regs->link;
59 sp = regs->gpr[1];
60 perf_callchain_store(entry, regs->nip);
61
62 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
63 return;
64
65 for (;;) {
66 fp = (unsigned long *) sp;
67 next_sp = fp[0];
68
69 if (next_sp == sp + STACK_INT_FRAME_SIZE &&
70 fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
71 /*
72 * This looks like an interrupt frame for an
73 * interrupt that occurred in the kernel
74 */
75 regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
76 next_ip = regs->nip;
77 lr = regs->link;
78 level = 0;
79 perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
80
81 } else {
82 if (level == 0)
83 next_ip = lr;
84 else
85 next_ip = fp[STACK_FRAME_LR_SAVE];
86
87 /*
88 * We can't tell which of the first two addresses
89 * we get are valid, but we can filter out the
90 * obviously bogus ones here. We replace them
91 * with 0 rather than removing them entirely so
92 * that userspace can tell which is which.
93 */
94 if ((level == 1 && next_ip == lr) ||
95 (level <= 1 && !kernel_text_address(next_ip)))
96 next_ip = 0;
97
98 ++level;
99 }
100
101 perf_callchain_store(entry, next_ip);
102 if (!valid_next_sp(next_sp, sp))
103 return;
104 sp = next_sp;
105 }
106}
107
108#ifdef CONFIG_PPC64
109/*
110 * On 64-bit we don't want to invoke hash_page on user addresses from
111 * interrupt context, so if the access faults, we read the page tables
112 * to find which page (if any) is mapped and access it directly.
113 */
114static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
115{
116 pgd_t *pgdir;
117 pte_t *ptep, pte;
118 unsigned shift;
119 unsigned long addr = (unsigned long) ptr;
120 unsigned long offset;
121 unsigned long pfn;
122 void *kaddr;
123
124 pgdir = current->mm->pgd;
125 if (!pgdir)
126 return -EFAULT;
127
128 ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
129 if (!shift)
130 shift = PAGE_SHIFT;
131
132 /* align address to page boundary */
133 offset = addr & ((1UL << shift) - 1);
134 addr -= offset;
135
136 if (ptep == NULL)
137 return -EFAULT;
138 pte = *ptep;
139 if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
140 return -EFAULT;
141 pfn = pte_pfn(pte);
142 if (!page_is_ram(pfn))
143 return -EFAULT;
144
145 /* no highmem to worry about here */
146 kaddr = pfn_to_kaddr(pfn);
147 memcpy(ret, kaddr + offset, nb);
148 return 0;
149}
150
151static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
152{
153 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
154 ((unsigned long)ptr & 7))
155 return -EFAULT;
156
157 pagefault_disable();
158 if (!__get_user_inatomic(*ret, ptr)) {
159 pagefault_enable();
160 return 0;
161 }
162 pagefault_enable();
163
164 return read_user_stack_slow(ptr, ret, 8);
165}
166
167static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
168{
169 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
170 ((unsigned long)ptr & 3))
171 return -EFAULT;
172
173 pagefault_disable();
174 if (!__get_user_inatomic(*ret, ptr)) {
175 pagefault_enable();
176 return 0;
177 }
178 pagefault_enable();
179
180 return read_user_stack_slow(ptr, ret, 4);
181}
182
183static inline int valid_user_sp(unsigned long sp, int is_64)
184{
185 if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
186 return 0;
187 return 1;
188}
189
190/*
191 * 64-bit user processes use the same stack frame for RT and non-RT signals.
192 */
193struct signal_frame_64 {
194 char dummy[__SIGNAL_FRAMESIZE];
195 struct ucontext uc;
196 unsigned long unused[2];
197 unsigned int tramp[6];
198 struct siginfo *pinfo;
199 void *puc;
200 struct siginfo info;
201 char abigap[288];
202};
203
204static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
205{
206 if (nip == fp + offsetof(struct signal_frame_64, tramp))
207 return 1;
208 if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
209 nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
210 return 1;
211 return 0;
212}
213
214/*
215 * Do some sanity checking on the signal frame pointed to by sp.
216 * We check the pinfo and puc pointers in the frame.
217 */
218static int sane_signal_64_frame(unsigned long sp)
219{
220 struct signal_frame_64 __user *sf;
221 unsigned long pinfo, puc;
222
223 sf = (struct signal_frame_64 __user *) sp;
224 if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
225 read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
226 return 0;
227 return pinfo == (unsigned long) &sf->info &&
228 puc == (unsigned long) &sf->uc;
229}
230
231static void perf_callchain_user_64(struct perf_callchain_entry *entry,
232 struct pt_regs *regs)
233{
234 unsigned long sp, next_sp;
235 unsigned long next_ip;
236 unsigned long lr;
237 long level = 0;
238 struct signal_frame_64 __user *sigframe;
239 unsigned long __user *fp, *uregs;
240
241 next_ip = regs->nip;
242 lr = regs->link;
243 sp = regs->gpr[1];
244 perf_callchain_store(entry, next_ip);
245
246 for (;;) {
247 fp = (unsigned long __user *) sp;
248 if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
249 return;
250 if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
251 return;
252
253 /*
254 * Note: the next_sp - sp >= signal frame size check
255 * is true when next_sp < sp, which can happen when
256 * transitioning from an alternate signal stack to the
257 * normal stack.
258 */
259 if (next_sp - sp >= sizeof(struct signal_frame_64) &&
260 (is_sigreturn_64_address(next_ip, sp) ||
261 (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
262 sane_signal_64_frame(sp)) {
263 /*
264 * This looks like an signal frame
265 */
266 sigframe = (struct signal_frame_64 __user *) sp;
267 uregs = sigframe->uc.uc_mcontext.gp_regs;
268 if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
269 read_user_stack_64(&uregs[PT_LNK], &lr) ||
270 read_user_stack_64(&uregs[PT_R1], &sp))
271 return;
272 level = 0;
273 perf_callchain_store(entry, PERF_CONTEXT_USER);
274 perf_callchain_store(entry, next_ip);
275 continue;
276 }
277
278 if (level == 0)
279 next_ip = lr;
280 perf_callchain_store(entry, next_ip);
281 ++level;
282 sp = next_sp;
283 }
284}
285
286static inline int current_is_64bit(void)
287{
288 /*
289 * We can't use test_thread_flag() here because we may be on an
290 * interrupt stack, and the thread flags don't get copied over
291 * from the thread_info on the main stack to the interrupt stack.
292 */
293 return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
294}
295
296#else /* CONFIG_PPC64 */
297/*
298 * On 32-bit we just access the address and let hash_page create a
299 * HPTE if necessary, so there is no need to fall back to reading
300 * the page tables. Since this is called at interrupt level,
301 * do_page_fault() won't treat a DSI as a page fault.
302 */
303static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
304{
305 int rc;
306
307 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
308 ((unsigned long)ptr & 3))
309 return -EFAULT;
310
311 pagefault_disable();
312 rc = __get_user_inatomic(*ret, ptr);
313 pagefault_enable();
314
315 return rc;
316}
317
318static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
319 struct pt_regs *regs)
320{
321}
322
323static inline int current_is_64bit(void)
324{
325 return 0;
326}
327
328static inline int valid_user_sp(unsigned long sp, int is_64)
329{
330 if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
331 return 0;
332 return 1;
333}
334
335#define __SIGNAL_FRAMESIZE32 __SIGNAL_FRAMESIZE
336#define sigcontext32 sigcontext
337#define mcontext32 mcontext
338#define ucontext32 ucontext
339#define compat_siginfo_t struct siginfo
340
341#endif /* CONFIG_PPC64 */
342
343/*
344 * Layout for non-RT signal frames
345 */
346struct signal_frame_32 {
347 char dummy[__SIGNAL_FRAMESIZE32];
348 struct sigcontext32 sctx;
349 struct mcontext32 mctx;
350 int abigap[56];
351};
352
353/*
354 * Layout for RT signal frames
355 */
356struct rt_signal_frame_32 {
357 char dummy[__SIGNAL_FRAMESIZE32 + 16];
358 compat_siginfo_t info;
359 struct ucontext32 uc;
360 int abigap[56];
361};
362
363static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
364{
365 if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
366 return 1;
367 if (vdso32_sigtramp && current->mm->context.vdso_base &&
368 nip == current->mm->context.vdso_base + vdso32_sigtramp)
369 return 1;
370 return 0;
371}
372
373static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
374{
375 if (nip == fp + offsetof(struct rt_signal_frame_32,
376 uc.uc_mcontext.mc_pad))
377 return 1;
378 if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
379 nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
380 return 1;
381 return 0;
382}
383
384static int sane_signal_32_frame(unsigned int sp)
385{
386 struct signal_frame_32 __user *sf;
387 unsigned int regs;
388
389 sf = (struct signal_frame_32 __user *) (unsigned long) sp;
390 if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
391 return 0;
392 return regs == (unsigned long) &sf->mctx;
393}
394
395static int sane_rt_signal_32_frame(unsigned int sp)
396{
397 struct rt_signal_frame_32 __user *sf;
398 unsigned int regs;
399
400 sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
401 if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
402 return 0;
403 return regs == (unsigned long) &sf->uc.uc_mcontext;
404}
405
406static unsigned int __user *signal_frame_32_regs(unsigned int sp,
407 unsigned int next_sp, unsigned int next_ip)
408{
409 struct mcontext32 __user *mctx = NULL;
410 struct signal_frame_32 __user *sf;
411 struct rt_signal_frame_32 __user *rt_sf;
412
413 /*
414 * Note: the next_sp - sp >= signal frame size check
415 * is true when next_sp < sp, for example, when
416 * transitioning from an alternate signal stack to the
417 * normal stack.
418 */
419 if (next_sp - sp >= sizeof(struct signal_frame_32) &&
420 is_sigreturn_32_address(next_ip, sp) &&
421 sane_signal_32_frame(sp)) {
422 sf = (struct signal_frame_32 __user *) (unsigned long) sp;
423 mctx = &sf->mctx;
424 }
425
426 if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
427 is_rt_sigreturn_32_address(next_ip, sp) &&
428 sane_rt_signal_32_frame(sp)) {
429 rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
430 mctx = &rt_sf->uc.uc_mcontext;
431 }
432
433 if (!mctx)
434 return NULL;
435 return mctx->mc_gregs;
436}
437
438static void perf_callchain_user_32(struct perf_callchain_entry *entry,
439 struct pt_regs *regs)
440{
441 unsigned int sp, next_sp;
442 unsigned int next_ip;
443 unsigned int lr;
444 long level = 0;
445 unsigned int __user *fp, *uregs;
446
447 next_ip = regs->nip;
448 lr = regs->link;
449 sp = regs->gpr[1];
450 perf_callchain_store(entry, next_ip);
451
452 while (entry->nr < PERF_MAX_STACK_DEPTH) {
453 fp = (unsigned int __user *) (unsigned long) sp;
454 if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
455 return;
456 if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
457 return;
458
459 uregs = signal_frame_32_regs(sp, next_sp, next_ip);
460 if (!uregs && level <= 1)
461 uregs = signal_frame_32_regs(sp, next_sp, lr);
462 if (uregs) {
463 /*
464 * This looks like an signal frame, so restart
465 * the stack trace with the values in it.
466 */
467 if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
468 read_user_stack_32(&uregs[PT_LNK], &lr) ||
469 read_user_stack_32(&uregs[PT_R1], &sp))
470 return;
471 level = 0;
472 perf_callchain_store(entry, PERF_CONTEXT_USER);
473 perf_callchain_store(entry, next_ip);
474 continue;
475 }
476
477 if (level == 0)
478 next_ip = lr;
479 perf_callchain_store(entry, next_ip);
480 ++level;
481 sp = next_sp;
482 }
483}
484
485void
486perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
487{
488 if (current_is_64bit())
489 perf_callchain_user_64(entry, regs);
490 else
491 perf_callchain_user_32(entry, regs);
492}