diff options
Diffstat (limited to 'arch/sh/lib/mcount.S')
-rw-r--r-- | arch/sh/lib/mcount.S | 228 |
1 files changed, 224 insertions, 4 deletions
diff --git a/arch/sh/lib/mcount.S b/arch/sh/lib/mcount.S index 110fbfe1831f..84a57761f17e 100644 --- a/arch/sh/lib/mcount.S +++ b/arch/sh/lib/mcount.S | |||
@@ -1,14 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * arch/sh/lib/mcount.S | 2 | * arch/sh/lib/mcount.S |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Paul Mundt | 4 | * Copyright (C) 2008, 2009 Paul Mundt |
5 | * Copyright (C) 2008 Matt Fleming | 5 | * Copyright (C) 2008, 2009 Matt Fleming |
6 | * | 6 | * |
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License. See the file "COPYING" in the main directory of this archive | 8 | * License. See the file "COPYING" in the main directory of this archive |
9 | * for more details. | 9 | * for more details. |
10 | */ | 10 | */ |
11 | #include <asm/ftrace.h> | 11 | #include <asm/ftrace.h> |
12 | #include <asm/thread_info.h> | ||
13 | #include <asm/asm-offsets.h> | ||
12 | 14 | ||
13 | #define MCOUNT_ENTER() \ | 15 | #define MCOUNT_ENTER() \ |
14 | mov.l r4, @-r15; \ | 16 | mov.l r4, @-r15; \ |
@@ -28,6 +30,55 @@ | |||
28 | rts; \ | 30 | rts; \ |
29 | mov.l @r15+, r4 | 31 | mov.l @r15+, r4 |
30 | 32 | ||
33 | #ifdef CONFIG_STACK_DEBUG | ||
34 | /* | ||
35 | * Perform diagnostic checks on the state of the kernel stack. | ||
36 | * | ||
37 | * Check for stack overflow. If there is less than 1KB free | ||
38 | * then it has overflowed. | ||
39 | * | ||
40 | * Make sure the stack pointer contains a valid address. Valid | ||
41 | * addresses for kernel stacks are anywhere after the bss | ||
42 | * (after _ebss) and anywhere in init_thread_union (init_stack). | ||
43 | */ | ||
44 | #define STACK_CHECK() \ | ||
45 | mov #(THREAD_SIZE >> 10), r0; \ | ||
46 | shll8 r0; \ | ||
47 | shll2 r0; \ | ||
48 | \ | ||
49 | /* r1 = sp & (THREAD_SIZE - 1) */ \ | ||
50 | mov #-1, r1; \ | ||
51 | add r0, r1; \ | ||
52 | and r15, r1; \ | ||
53 | \ | ||
54 | mov #TI_SIZE, r3; \ | ||
55 | mov #(STACK_WARN >> 8), r2; \ | ||
56 | shll8 r2; \ | ||
57 | add r3, r2; \ | ||
58 | \ | ||
59 | /* Is the stack overflowing? */ \ | ||
60 | cmp/hi r2, r1; \ | ||
61 | bf stack_panic; \ | ||
62 | \ | ||
63 | /* If sp > _ebss then we're OK. */ \ | ||
64 | mov.l .L_ebss, r1; \ | ||
65 | cmp/hi r1, r15; \ | ||
66 | bt 1f; \ | ||
67 | \ | ||
68 | /* If sp < init_stack, we're not OK. */ \ | ||
69 | mov.l .L_init_thread_union, r1; \ | ||
70 | cmp/hs r1, r15; \ | ||
71 | bf stack_panic; \ | ||
72 | \ | ||
73 | /* If sp > init_stack && sp < _ebss, not OK. */ \ | ||
74 | add r0, r1; \ | ||
75 | cmp/hs r1, r15; \ | ||
76 | bt stack_panic; \ | ||
77 | 1: | ||
78 | #else | ||
79 | #define STACK_CHECK() | ||
80 | #endif /* CONFIG_STACK_DEBUG */ | ||
81 | |||
31 | .align 2 | 82 | .align 2 |
32 | .globl _mcount | 83 | .globl _mcount |
33 | .type _mcount,@function | 84 | .type _mcount,@function |
@@ -35,6 +86,19 @@ | |||
35 | .type mcount,@function | 86 | .type mcount,@function |
36 | _mcount: | 87 | _mcount: |
37 | mcount: | 88 | mcount: |
89 | STACK_CHECK() | ||
90 | |||
91 | #ifndef CONFIG_FUNCTION_TRACER | ||
92 | rts | ||
93 | nop | ||
94 | #else | ||
95 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
96 | mov.l .Lfunction_trace_stop, r0 | ||
97 | mov.l @r0, r0 | ||
98 | tst r0, r0 | ||
99 | bf ftrace_stub | ||
100 | #endif | ||
101 | |||
38 | MCOUNT_ENTER() | 102 | MCOUNT_ENTER() |
39 | 103 | ||
40 | #ifdef CONFIG_DYNAMIC_FTRACE | 104 | #ifdef CONFIG_DYNAMIC_FTRACE |
@@ -52,16 +116,69 @@ mcount_call: | |||
52 | jsr @r6 | 116 | jsr @r6 |
53 | nop | 117 | nop |
54 | 118 | ||
119 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
120 | mov.l .Lftrace_graph_return, r6 | ||
121 | mov.l .Lftrace_stub, r7 | ||
122 | cmp/eq r6, r7 | ||
123 | bt 1f | ||
124 | |||
125 | mov.l .Lftrace_graph_caller, r0 | ||
126 | jmp @r0 | ||
127 | nop | ||
128 | |||
129 | 1: | ||
130 | mov.l .Lftrace_graph_entry, r6 | ||
131 | mov.l .Lftrace_graph_entry_stub, r7 | ||
132 | cmp/eq r6, r7 | ||
133 | bt skip_trace | ||
134 | |||
135 | mov.l .Lftrace_graph_caller, r0 | ||
136 | jmp @r0 | ||
137 | nop | ||
138 | |||
139 | .align 2 | ||
140 | .Lftrace_graph_return: | ||
141 | .long ftrace_graph_return | ||
142 | .Lftrace_graph_entry: | ||
143 | .long ftrace_graph_entry | ||
144 | .Lftrace_graph_entry_stub: | ||
145 | .long ftrace_graph_entry_stub | ||
146 | .Lftrace_graph_caller: | ||
147 | .long ftrace_graph_caller | ||
148 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
149 | |||
150 | .globl skip_trace | ||
55 | skip_trace: | 151 | skip_trace: |
56 | MCOUNT_LEAVE() | 152 | MCOUNT_LEAVE() |
57 | 153 | ||
58 | .align 2 | 154 | .align 2 |
59 | .Lftrace_trace_function: | 155 | .Lftrace_trace_function: |
60 | .long ftrace_trace_function | 156 | .long ftrace_trace_function |
61 | 157 | ||
62 | #ifdef CONFIG_DYNAMIC_FTRACE | 158 | #ifdef CONFIG_DYNAMIC_FTRACE |
159 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
160 | /* | ||
161 | * NOTE: Do not move either ftrace_graph_call or ftrace_caller | ||
162 | * as this will affect the calculation of GRAPH_INSN_OFFSET. | ||
163 | */ | ||
164 | .globl ftrace_graph_call | ||
165 | ftrace_graph_call: | ||
166 | mov.l .Lskip_trace, r0 | ||
167 | jmp @r0 | ||
168 | nop | ||
169 | |||
170 | .align 2 | ||
171 | .Lskip_trace: | ||
172 | .long skip_trace | ||
173 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
174 | |||
63 | .globl ftrace_caller | 175 | .globl ftrace_caller |
64 | ftrace_caller: | 176 | ftrace_caller: |
177 | mov.l .Lfunction_trace_stop, r0 | ||
178 | mov.l @r0, r0 | ||
179 | tst r0, r0 | ||
180 | bf ftrace_stub | ||
181 | |||
65 | MCOUNT_ENTER() | 182 | MCOUNT_ENTER() |
66 | 183 | ||
67 | .globl ftrace_call | 184 | .globl ftrace_call |
@@ -70,9 +187,18 @@ ftrace_call: | |||
70 | jsr @r6 | 187 | jsr @r6 |
71 | nop | 188 | nop |
72 | 189 | ||
190 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
191 | bra ftrace_graph_call | ||
192 | nop | ||
193 | #else | ||
73 | MCOUNT_LEAVE() | 194 | MCOUNT_LEAVE() |
195 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
74 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 196 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
75 | 197 | ||
198 | .align 2 | ||
199 | .Lfunction_trace_stop: | ||
200 | .long function_trace_stop | ||
201 | |||
76 | /* | 202 | /* |
77 | * NOTE: From here on the locations of the .Lftrace_stub label and | 203 | * NOTE: From here on the locations of the .Lftrace_stub label and |
78 | * ftrace_stub itself are fixed. Adding additional data here will skew | 204 | * ftrace_stub itself are fixed. Adding additional data here will skew |
@@ -80,7 +206,6 @@ ftrace_call: | |||
80 | * Place new labels either after the ftrace_stub body, or before | 206 | * Place new labels either after the ftrace_stub body, or before |
81 | * ftrace_caller. You have been warned. | 207 | * ftrace_caller. You have been warned. |
82 | */ | 208 | */ |
83 | .align 2 | ||
84 | .Lftrace_stub: | 209 | .Lftrace_stub: |
85 | .long ftrace_stub | 210 | .long ftrace_stub |
86 | 211 | ||
@@ -88,3 +213,98 @@ ftrace_call: | |||
88 | ftrace_stub: | 213 | ftrace_stub: |
89 | rts | 214 | rts |
90 | nop | 215 | nop |
216 | |||
217 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
218 | .globl ftrace_graph_caller | ||
219 | ftrace_graph_caller: | ||
220 | mov.l 2f, r0 | ||
221 | mov.l @r0, r0 | ||
222 | tst r0, r0 | ||
223 | bt 1f | ||
224 | |||
225 | mov.l 3f, r1 | ||
226 | jmp @r1 | ||
227 | nop | ||
228 | 1: | ||
229 | /* | ||
230 | * MCOUNT_ENTER() pushed 5 registers onto the stack, so | ||
231 | * the stack address containing our return address is | ||
232 | * r15 + 20. | ||
233 | */ | ||
234 | mov #20, r0 | ||
235 | add r15, r0 | ||
236 | mov r0, r4 | ||
237 | |||
238 | mov.l .Lprepare_ftrace_return, r0 | ||
239 | jsr @r0 | ||
240 | nop | ||
241 | |||
242 | MCOUNT_LEAVE() | ||
243 | |||
244 | .align 2 | ||
245 | 2: .long function_trace_stop | ||
246 | 3: .long skip_trace | ||
247 | .Lprepare_ftrace_return: | ||
248 | .long prepare_ftrace_return | ||
249 | |||
250 | .globl return_to_handler | ||
251 | return_to_handler: | ||
252 | /* | ||
253 | * Save the return values. | ||
254 | */ | ||
255 | mov.l r0, @-r15 | ||
256 | mov.l r1, @-r15 | ||
257 | |||
258 | mov #0, r4 | ||
259 | |||
260 | mov.l .Lftrace_return_to_handler, r0 | ||
261 | jsr @r0 | ||
262 | nop | ||
263 | |||
264 | /* | ||
265 | * The return value from ftrace_return_handler has the real | ||
266 | * address that we should return to. | ||
267 | */ | ||
268 | lds r0, pr | ||
269 | mov.l @r15+, r1 | ||
270 | rts | ||
271 | mov.l @r15+, r0 | ||
272 | |||
273 | |||
274 | .align 2 | ||
275 | .Lftrace_return_to_handler: | ||
276 | .long ftrace_return_to_handler | ||
277 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
278 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
279 | |||
280 | #ifdef CONFIG_STACK_DEBUG | ||
281 | .globl stack_panic | ||
282 | stack_panic: | ||
283 | mov.l .Ldump_stack, r0 | ||
284 | jsr @r0 | ||
285 | nop | ||
286 | |||
287 | mov.l .Lpanic, r0 | ||
288 | jsr @r0 | ||
289 | mov.l .Lpanic_s, r4 | ||
290 | |||
291 | rts | ||
292 | nop | ||
293 | |||
294 | .align 2 | ||
295 | .L_ebss: | ||
296 | .long _ebss | ||
297 | .L_init_thread_union: | ||
298 | .long init_thread_union | ||
299 | .Lpanic: | ||
300 | .long panic | ||
301 | .Lpanic_s: | ||
302 | .long .Lpanic_str | ||
303 | .Ldump_stack: | ||
304 | .long dump_stack | ||
305 | |||
306 | .section .rodata | ||
307 | .align 2 | ||
308 | .Lpanic_str: | ||
309 | .string "Stack error" | ||
310 | #endif /* CONFIG_STACK_DEBUG */ | ||