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