diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-06-17 02:59:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-17 02:59:10 -0400 |
commit | cc4949e1fdade5d063e9f8783cf0e2cc92041ce5 (patch) | |
tree | 4023bd641bfe464efbde518fb504d6865c9df014 /arch/blackfin/kernel/ftrace-entry.S | |
parent | 28b4868820a56de661f54742ff91b78e12f1e582 (diff) | |
parent | 300df7dc89cc276377fc020704e34875d5c473b6 (diff) |
Merge branch 'linus' into x86/urgent
Merge reason: pull in latest to fix a bug in it.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/blackfin/kernel/ftrace-entry.S')
-rw-r--r-- | arch/blackfin/kernel/ftrace-entry.S | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S new file mode 100644 index 000000000000..6980b7a0615d --- /dev/null +++ b/arch/blackfin/kernel/ftrace-entry.S | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * mcount and friends -- ftrace stuff | ||
3 | * | ||
4 | * Copyright (C) 2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #include <linux/linkage.h> | ||
9 | #include <asm/ftrace.h> | ||
10 | |||
11 | .text | ||
12 | |||
13 | /* GCC will have called us before setting up the function prologue, so we | ||
14 | * can clobber the normal scratch registers, but we need to make sure to | ||
15 | * save/restore the registers used for argument passing (R0-R2) in case | ||
16 | * the profiled function is using them. With data registers, R3 is the | ||
17 | * only one we can blow away. With pointer registers, we have P0-P2. | ||
18 | * | ||
19 | * Upon entry, the RETS will point to the top of the current profiled | ||
20 | * function. And since GCC setup the frame for us, the previous function | ||
21 | * will be waiting there. mmmm pie. | ||
22 | */ | ||
23 | ENTRY(__mcount) | ||
24 | /* save third function arg early so we can do testing below */ | ||
25 | [--sp] = r2; | ||
26 | |||
27 | /* load the function pointer to the tracer */ | ||
28 | p0.l = _ftrace_trace_function; | ||
29 | p0.h = _ftrace_trace_function; | ||
30 | r3 = [p0]; | ||
31 | |||
32 | /* optional micro optimization: don't call the stub tracer */ | ||
33 | r2.l = _ftrace_stub; | ||
34 | r2.h = _ftrace_stub; | ||
35 | cc = r2 == r3; | ||
36 | if ! cc jump .Ldo_trace; | ||
37 | |||
38 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
39 | /* if the ftrace_graph_return function pointer is not set to | ||
40 | * the ftrace_stub entry, call prepare_ftrace_return(). | ||
41 | */ | ||
42 | p0.l = _ftrace_graph_return; | ||
43 | p0.h = _ftrace_graph_return; | ||
44 | r3 = [p0]; | ||
45 | cc = r2 == r3; | ||
46 | if ! cc jump _ftrace_graph_caller; | ||
47 | |||
48 | /* similarly, if the ftrace_graph_entry function pointer is not | ||
49 | * set to the ftrace_graph_entry_stub entry, ... | ||
50 | */ | ||
51 | p0.l = _ftrace_graph_entry; | ||
52 | p0.h = _ftrace_graph_entry; | ||
53 | r2.l = _ftrace_graph_entry_stub; | ||
54 | r2.h = _ftrace_graph_entry_stub; | ||
55 | r3 = [p0]; | ||
56 | cc = r2 == r3; | ||
57 | if ! cc jump _ftrace_graph_caller; | ||
58 | #endif | ||
59 | |||
60 | r2 = [sp++]; | ||
61 | rts; | ||
62 | |||
63 | .Ldo_trace: | ||
64 | |||
65 | /* save first/second function arg and the return register */ | ||
66 | [--sp] = r0; | ||
67 | [--sp] = r1; | ||
68 | [--sp] = rets; | ||
69 | |||
70 | /* setup the tracer function */ | ||
71 | p0 = r3; | ||
72 | |||
73 | /* tracer(ulong frompc, ulong selfpc): | ||
74 | * frompc: the pc that did the call to ... | ||
75 | * selfpc: ... this location | ||
76 | * the selfpc itself will need adjusting for the mcount call | ||
77 | */ | ||
78 | r1 = rets; | ||
79 | r0 = [fp + 4]; | ||
80 | r1 += -MCOUNT_INSN_SIZE; | ||
81 | |||
82 | /* call the tracer */ | ||
83 | call (p0); | ||
84 | |||
85 | /* restore state and get out of dodge */ | ||
86 | .Lfinish_trace: | ||
87 | rets = [sp++]; | ||
88 | r1 = [sp++]; | ||
89 | r0 = [sp++]; | ||
90 | r2 = [sp++]; | ||
91 | |||
92 | .globl _ftrace_stub | ||
93 | _ftrace_stub: | ||
94 | rts; | ||
95 | ENDPROC(__mcount) | ||
96 | |||
97 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
98 | /* The prepare_ftrace_return() function is similar to the trace function | ||
99 | * except it takes a pointer to the location of the frompc. This is so | ||
100 | * the prepare_ftrace_return() can hijack it temporarily for probing | ||
101 | * purposes. | ||
102 | */ | ||
103 | ENTRY(_ftrace_graph_caller) | ||
104 | /* save first/second function arg and the return register */ | ||
105 | [--sp] = r0; | ||
106 | [--sp] = r1; | ||
107 | [--sp] = rets; | ||
108 | |||
109 | r0 = fp; | ||
110 | r1 = rets; | ||
111 | r0 += 4; | ||
112 | r1 += -MCOUNT_INSN_SIZE; | ||
113 | call _prepare_ftrace_return; | ||
114 | |||
115 | jump .Lfinish_trace; | ||
116 | ENDPROC(_ftrace_graph_caller) | ||
117 | |||
118 | /* Undo the rewrite caused by ftrace_graph_caller(). The common function | ||
119 | * ftrace_return_to_handler() will return the original rets so we can | ||
120 | * restore it and be on our way. | ||
121 | */ | ||
122 | ENTRY(_return_to_handler) | ||
123 | /* make sure original return values are saved */ | ||
124 | [--sp] = p0; | ||
125 | [--sp] = r0; | ||
126 | [--sp] = r1; | ||
127 | |||
128 | /* get original return address */ | ||
129 | call _ftrace_return_to_handler; | ||
130 | rets = r0; | ||
131 | |||
132 | /* anomaly 05000371 - make sure we have at least three instructions | ||
133 | * between rets setting and the return | ||
134 | */ | ||
135 | r1 = [sp++]; | ||
136 | r0 = [sp++]; | ||
137 | p0 = [sp++]; | ||
138 | rts; | ||
139 | ENDPROC(_return_to_handler) | ||
140 | #endif | ||