Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / arch / blackfin / kernel / ftrace-entry.S
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