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;				\
741:
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:
85mcount:
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
96mcount_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
1191:
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
141skip_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
155ftrace_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
166ftrace_caller:
167	MCOUNT_ENTER()
168
169	.globl ftrace_call
170ftrace_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
196ftrace_stub:
197	rts
198	 nop
199
200#ifdef CONFIG_FUNCTION_GRAPH_TRACER
201	.globl	ftrace_graph_caller
202ftrace_graph_caller:
203	mov.l	2f, r1
204	jmp	@r1
205	 nop
2061:
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
2232:	.long	skip_trace
224.Lprepare_ftrace_return:
225	.long	prepare_ftrace_return
226
227	.globl	return_to_handler
228return_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
259stack_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