2 * mcount and friends -- ftrace stuff
4 * Copyright (C) 2009-2010 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
8 #include <linux/linkage.h>
9 #include <asm/ftrace.h>
13 #ifdef CONFIG_DYNAMIC_FTRACE
15 /* Simple stub so we can boot the kernel until runtime patching has
16 * disabled all calls to this. Then it'll be unused.
25 /* GCC will have called us before setting up the function prologue, so we
26 * can clobber the normal scratch registers, but we need to make sure to
27 * save/restore the registers used for argument passing (R0-R2) in case
28 * the profiled function is using them. With data registers, R3 is the
29 * only one we can blow away. With pointer registers, we have P0-P2.
31 * Upon entry, the RETS will point to the top of the current profiled
32 * function. And since GCC pushed the previous RETS for us, the previous
33 * function will be waiting there. mmmm pie.
36 # ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
37 /* optional micro optimization: return if stopped */
38 p1.l = _function_trace_stop;
39 p1.h = _function_trace_stop;
42 if ! cc jump _ftrace_stub (bp);
45 /* save first/second/third function arg and the return register */
51 /* function_trace_call(unsigned long ip, unsigned long parent_ip):
52 * ip: this point was called by ...
53 * parent_ip: ... this function
54 * the ip itself will need adjusting for the mcount call
57 r1 = [sp + 16]; /* skip the 4 local regs on stack */
58 r0 += -MCOUNT_INSN_SIZE;
64 # ifdef CONFIG_FUNCTION_GRAPH_TRACER
65 .globl _ftrace_graph_call
67 nop; /* jump _ftrace_graph_caller; */
70 /* restore state and get out of dodge */
80 ENDPROC(_ftrace_caller)
84 /* See documentation for _ftrace_caller */
86 # ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
87 /* optional micro optimization: return if stopped */
88 p1.l = _function_trace_stop;
89 p1.h = _function_trace_stop;
92 if ! cc jump _ftrace_stub (bp);
95 /* save third function arg early so we can do testing below */
98 /* load the function pointer to the tracer */
99 p0.l = _ftrace_trace_function;
100 p0.h = _ftrace_trace_function;
103 /* optional micro optimization: don't call the stub tracer */
107 if ! cc jump .Ldo_trace;
109 # ifdef CONFIG_FUNCTION_GRAPH_TRACER
110 /* if the ftrace_graph_return function pointer is not set to
111 * the ftrace_stub entry, call prepare_ftrace_return().
113 p0.l = _ftrace_graph_return;
114 p0.h = _ftrace_graph_return;
117 if ! cc jump _ftrace_graph_caller;
119 /* similarly, if the ftrace_graph_entry function pointer is not
120 * set to the ftrace_graph_entry_stub entry, ...
122 p0.l = _ftrace_graph_entry;
123 p0.h = _ftrace_graph_entry;
124 r2.l = _ftrace_graph_entry_stub;
125 r2.h = _ftrace_graph_entry_stub;
128 if ! cc jump _ftrace_graph_caller;
136 /* save first/second function arg and the return register */
141 /* setup the tracer function */
144 /* function_trace_call(unsigned long ip, unsigned long parent_ip):
145 * ip: this point was called by ...
146 * parent_ip: ... this function
147 * the ip itself will need adjusting for the mcount call
150 r1 = [sp + 16]; /* skip the 4 local regs on stack */
151 r0 += -MCOUNT_INSN_SIZE;
153 /* call the tracer */
156 /* restore state and get out of dodge */
170 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
171 /* The prepare_ftrace_return() function is similar to the trace function
172 * except it takes a pointer to the location of the frompc. This is so
173 * the prepare_ftrace_return() can hijack it temporarily for probing
176 ENTRY(_ftrace_graph_caller)
177 # ifndef CONFIG_DYNAMIC_FTRACE
178 /* save first/second function arg and the return register */
183 /* prepare_ftrace_return(parent, self_addr, frame_pointer) */
184 r0 = sp; /* unsigned long *parent */
185 r1 = rets; /* unsigned long self_addr */
187 r0 = sp; /* unsigned long *parent */
188 r1 = [sp]; /* unsigned long self_addr */
190 # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
191 r2 = fp; /* unsigned long frame_pointer */
193 r0 += 16; /* skip the 4 local regs on stack */
194 r1 += -MCOUNT_INSN_SIZE;
195 call _prepare_ftrace_return;
198 ENDPROC(_ftrace_graph_caller)
200 /* Undo the rewrite caused by ftrace_graph_caller(). The common function
201 * ftrace_return_to_handler() will return the original rets so we can
202 * restore it and be on our way.
204 ENTRY(_return_to_handler)
205 /* make sure original return values are saved */
210 /* get original return address */
211 # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
212 r0 = fp; /* Blackfin is sane, so omit this */
214 call _ftrace_return_to_handler;
217 /* anomaly 05000371 - make sure we have at least three instructions
218 * between rets setting and the return
224 ENDPROC(_return_to_handler)