sh: Provide diagnostic kernel stack checks
[safe/jmp/linux-2.6] / arch / sh / lib / mcount.S
1 /*
2  * arch/sh/lib/mcount.S
3  *
4  *  Copyright (C) 2008  Paul Mundt
5  *  Copyright (C) 2008, 2009  Matt Fleming
6  *
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
9  * for more details.
10  */
11 #include <asm/ftrace.h>
12 #include <asm/thread_info.h>
13 #include <asm/asm-offsets.h>
14
15 #define MCOUNT_ENTER()          \
16         mov.l   r4, @-r15;      \
17         mov.l   r5, @-r15;      \
18         mov.l   r6, @-r15;      \
19         mov.l   r7, @-r15;      \
20         sts.l   pr, @-r15;      \
21                                 \
22         mov.l   @(20,r15),r4;   \
23         sts     pr, r5
24
25 #define MCOUNT_LEAVE()          \
26         lds.l   @r15+, pr;      \
27         mov.l   @r15+, r7;      \
28         mov.l   @r15+, r6;      \
29         mov.l   @r15+, r5;      \
30         rts;                    \
31          mov.l  @r15+, r4
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
82         .align 2
83         .globl  _mcount
84         .type   _mcount,@function
85         .globl  mcount
86         .type   mcount,@function
87 _mcount:
88 mcount:
89 #ifndef CONFIG_DYNAMIC_FTRACE
90         mov.l   .Lfunction_trace_stop, r0
91         mov.l   @r0, r0
92         tst     r0, r0
93         bf      ftrace_stub
94 #endif
95         STACK_CHECK()
96
97         MCOUNT_ENTER()
98
99 #ifdef CONFIG_DYNAMIC_FTRACE
100         .globl  mcount_call
101 mcount_call:
102         mov.l   .Lftrace_stub, r6
103 #else
104         mov.l   .Lftrace_trace_function, r6
105         mov.l   ftrace_stub, r7
106         cmp/eq  r6, r7
107         bt      skip_trace
108         mov.l   @r6, r6
109 #endif
110
111         jsr     @r6
112          nop
113
114 skip_trace:
115         MCOUNT_LEAVE()
116
117         .align 2
118 .Lftrace_trace_function:
119         .long   ftrace_trace_function
120
121 #ifdef CONFIG_DYNAMIC_FTRACE
122         .globl ftrace_caller
123 ftrace_caller:
124         mov.l   .Lfunction_trace_stop, r0
125         mov.l   @r0, r0
126         tst     r0, r0
127         bf      ftrace_stub
128
129         STACK_CHECK()
130
131         MCOUNT_ENTER()
132
133         .globl ftrace_call
134 ftrace_call:
135         mov.l   .Lftrace_stub, r6
136         jsr     @r6
137          nop
138
139         MCOUNT_LEAVE()
140 #endif /* CONFIG_DYNAMIC_FTRACE */
141
142 /*
143  * NOTE: From here on the locations of the .Lftrace_stub label and
144  * ftrace_stub itself are fixed. Adding additional data here will skew
145  * the displacement for the memory table and break the block replacement.
146  * Place new labels either after the ftrace_stub body, or before
147  * ftrace_caller. You have been warned.
148  */
149         .align 2
150 .Lftrace_stub:
151         .long   ftrace_stub
152
153         .globl  ftrace_stub
154 ftrace_stub:
155         rts
156          nop
157
158 #ifdef CONFIG_STACK_DEBUG
159         .globl  stack_panic
160 stack_panic:
161         mov.l   .Ldump_stack, r0
162         jsr     @r0
163          nop
164
165         mov.l   .Lpanic, r0
166         jsr     @r0
167          mov.l  .Lpanic_s, r4
168
169         rts
170          nop
171
172         .align 2
173 .Lfunction_trace_stop:
174         .long   function_trace_stop
175 .L_ebss:
176         .long   _ebss
177 .L_init_thread_union:
178         .long   init_thread_union
179 .Lpanic:
180         .long   panic
181 .Lpanic_s:
182         .long   .Lpanic_str
183 .Ldump_stack:
184         .long   dump_stack
185
186         .section        .rodata
187         .align 2
188 .Lpanic_str:
189         .string "Stack error"
190 #endif /* CONFIG_STACK_DEBUG */