Blame view

arch/arm/oprofile/common.c 2.67 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /**
   * @file common.c
   *
   * @remark Copyright 2004 Oprofile Authors
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
5
   * @remark Copyright 2010 ARM Ltd.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
   * @remark Read the file COPYING
   *
   * @author Zwane Mwaikambo
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
9
   * @author Will Deacon [move to perf]
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
11
  #include <linux/cpumask.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/init.h>
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
13
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/oprofile.h>
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
15
  #include <linux/perf_event.h>
d1e86d64b   Will Deacon   ARM: 6074/1: opro...
16
  #include <linux/platform_device.h>
ae92dc9f7   Russell King   [ARM] Oprofile: d...
17
  #include <linux/slab.h>
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
18
19
20
21
22
  #include <asm/stacktrace.h>
  #include <linux/uaccess.h>
  
  #include <asm/perf_event.h>
  #include <asm/ptrace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
24
  #ifdef CONFIG_HW_PERF_EVENTS
56946331b   Matt Fleming   oprofile: Make op...
25
  char *op_name_from_perf_id(void)
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
26
  {
56946331b   Matt Fleming   oprofile: Make op...
27
  	enum arm_perf_pmu_ids id = armpmu_get_pmu_id();
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  	switch (id) {
  	case ARM_PERF_PMU_ID_XSCALE1:
  		return "arm/xscale1";
  	case ARM_PERF_PMU_ID_XSCALE2:
  		return "arm/xscale2";
  	case ARM_PERF_PMU_ID_V6:
  		return "arm/armv6";
  	case ARM_PERF_PMU_ID_V6MP:
  		return "arm/mpcore";
  	case ARM_PERF_PMU_ID_CA8:
  		return "arm/armv7";
  	case ARM_PERF_PMU_ID_CA9:
  		return "arm/armv7-ca9";
  	default:
  		return NULL;
  	}
  }
d14dd7e20   Ari Kauppi   ARM: oprofile: Fi...
45
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
47
  static int report_trace(struct stackframe *frame, void *d)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  {
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
49
  	unsigned int *depth = d;
c6b9dafce   Russell King   [ARM] 4/4 Combine...
50

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
51
52
53
54
  	if (*depth) {
  		oprofile_add_trace(frame->pc);
  		(*depth)--;
  	}
1b7b56982   Richard Purdie   [ARM] 4237/2: opr...
55

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
56
57
  	return *depth == 0;
  }
c6b9dafce   Russell King   [ARM] 4/4 Combine...
58

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
59
60
61
62
63
64
65
66
67
68
69
  /*
   * The registers we're interested in are at the end of the variable
   * length saved register structure. The fp points at the end of this
   * structure so the address of this struct is:
   * (struct frame_tail *)(xxx->fp)-1
   */
  struct frame_tail {
  	struct frame_tail *fp;
  	unsigned long sp;
  	unsigned long lr;
  } __attribute__((packed));
2d9e1ae06   Russell King   [ARM] oprofile: a...
70

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
71
72
73
  static struct frame_tail* user_backtrace(struct frame_tail *tail)
  {
  	struct frame_tail buftail[2];
10c03f696   Russell King   [ARM] oprofile: a...
74

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
75
76
77
78
79
  	/* Also check accessibility of one struct frame_tail beyond */
  	if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
  		return NULL;
  	if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail)))
  		return NULL;
d7ac4e28c   Jean PIHET   [ARM] 5195/1: ARM...
80

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
81
  	oprofile_add_trace(buftail[0].lr);
c6b9dafce   Russell King   [ARM] 4/4 Combine...
82

8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
83
84
  	/* frame pointers should strictly progress back up the stack
  	 * (towards higher addresses) */
cb06199b1   Rabin Vincent   ARM: 6654/1: perf...
85
  	if (tail + 1 >= buftail[0].fp)
8c1fc96f6   Will Deacon   ARM: 6072/1: opro...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  		return NULL;
  
  	return buftail[0].fp-1;
  }
  
  static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
  {
  	struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
  
  	if (!user_mode(regs)) {
  		struct stackframe frame;
  		frame.fp = regs->ARM_fp;
  		frame.sp = regs->ARM_sp;
  		frame.lr = regs->ARM_lr;
  		frame.pc = regs->ARM_pc;
  		walk_stackframe(&frame, report_trace, &depth);
  		return;
  	}
  
  	while (depth-- && tail && !((unsigned long) tail & 3))
  		tail = user_backtrace(tail);
  }
58850e210   Matt Fleming   ARM: oprofile: Mo...
108
109
  int __init oprofile_arch_init(struct oprofile_operations *ops)
  {
d14dd7e20   Ari Kauppi   ARM: oprofile: Fi...
110
  	/* provide backtrace support also in timer mode: */
58850e210   Matt Fleming   ARM: oprofile: Mo...
111
112
113
114
  	ops->backtrace		= arm_backtrace;
  
  	return oprofile_perf_init(ops);
  }
55205c916   Vladimir Zapolskiy   oprofile, arm/sh:...
115
  void oprofile_arch_exit(void)
58850e210   Matt Fleming   ARM: oprofile: Mo...
116
117
118
  {
  	oprofile_perf_exit();
  }