• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Split from ftrace_64.S
4 */
5
6#include <linux/magic.h>
7#include <asm/ppc_asm.h>
8#include <asm/asm-offsets.h>
9#include <asm/ftrace.h>
10#include <asm/ppc-opcode.h>
11#include <asm/export.h>
12#include <asm/thread_info.h>
13#include <asm/bug.h>
14#include <asm/ptrace.h>
15
16/*
17 *
18 * ftrace_caller()/ftrace_regs_caller() is the function that replaces _mcount()
19 * when ftrace is active.
20 *
21 * We arrive here after a function A calls function B, and we are the trace
22 * function for B. When we enter r1 points to A's stack frame, B has not yet
23 * had a chance to allocate one yet.
24 *
25 * Additionally r2 may point either to the TOC for A, or B, depending on
26 * whether B did a TOC setup sequence before calling us.
27 *
28 * On entry the LR points back to the _mcount() call site, and r0 holds the
29 * saved LR as it was on entry to B, ie. the original return address at the
30 * call site in A.
31 *
32 * Our job is to save the register state into a struct pt_regs (on the stack)
33 * and then arrange for the ftrace function to be called.
34 */
35_GLOBAL(ftrace_regs_caller)
36	/* Save the original return address in A's stack frame */
37	std	r0,LRSAVE(r1)
38
39	/* Create a minimal stack frame for representing B */
40	stdu	r1, -STACK_FRAME_MIN_SIZE(r1)
41
42	/* Create our stack frame + pt_regs */
43	stdu	r1,-SWITCH_FRAME_SIZE(r1)
44
45	/* Save all gprs to pt_regs */
46	SAVE_GPR(0, r1)
47	SAVE_10GPRS(2, r1)
48
49	/* Ok to continue? */
50	lbz	r3, PACA_FTRACE_ENABLED(r13)
51	cmpdi	r3, 0
52	beq	ftrace_no_trace
53
54	SAVE_10GPRS(12, r1)
55	SAVE_10GPRS(22, r1)
56
57	/* Save previous stack pointer (r1) */
58	addi	r8, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
59	std	r8, GPR1(r1)
60
61	/* Load special regs for save below */
62	mfmsr   r8
63	mfctr   r9
64	mfxer   r10
65	mfcr	r11
66
67	/* Get the _mcount() call site out of LR */
68	mflr	r7
69	/* Save it as pt_regs->nip */
70	std     r7, _NIP(r1)
71	/* Also save it in B's stackframe header for proper unwind */
72	std	r7, LRSAVE+SWITCH_FRAME_SIZE(r1)
73	/* Save the read LR in pt_regs->link */
74	std     r0, _LINK(r1)
75
76	/* Save callee's TOC in the ABI compliant location */
77	std	r2, 24(r1)
78	ld	r2,PACATOC(r13)	/* get kernel TOC in r2 */
79
80	addis	r3,r2,function_trace_op@toc@ha
81	addi	r3,r3,function_trace_op@toc@l
82	ld	r5,0(r3)
83
84#ifdef CONFIG_LIVEPATCH
85	mr	r14,r7		/* remember old NIP */
86#endif
87	/* Calculate ip from nip-4 into r3 for call below */
88	subi    r3, r7, MCOUNT_INSN_SIZE
89
90	/* Put the original return address in r4 as parent_ip */
91	mr	r4, r0
92
93	/* Save special regs */
94	std     r8, _MSR(r1)
95	std     r9, _CTR(r1)
96	std     r10, _XER(r1)
97	std     r11, _CCR(r1)
98
99	/* Load &pt_regs in r6 for call below */
100	addi    r6, r1 ,STACK_FRAME_OVERHEAD
101
102	/* ftrace_call(r3, r4, r5, r6) */
103.globl ftrace_regs_call
104ftrace_regs_call:
105	bl	ftrace_stub
106	nop
107
108	/* Load ctr with the possibly modified NIP */
109	ld	r3, _NIP(r1)
110	mtctr	r3
111#ifdef CONFIG_LIVEPATCH
112	cmpd	r14, r3		/* has NIP been altered? */
113#endif
114
115	/* Restore gprs */
116	REST_GPR(0,r1)
117	REST_10GPRS(2,r1)
118	REST_10GPRS(12,r1)
119	REST_10GPRS(22,r1)
120
121	/* Restore possibly modified LR */
122	ld	r0, _LINK(r1)
123	mtlr	r0
124
125	/* Restore callee's TOC */
126	ld	r2, 24(r1)
127
128	/* Pop our stack frame */
129	addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
130
131#ifdef CONFIG_LIVEPATCH
132        /* Based on the cmpd above, if the NIP was altered handle livepatch */
133	bne-	livepatch_handler
134#endif
135
136ftrace_caller_common:
137#ifdef CONFIG_FUNCTION_GRAPH_TRACER
138.globl ftrace_graph_call
139ftrace_graph_call:
140	b	ftrace_graph_stub
141_GLOBAL(ftrace_graph_stub)
142#endif
143
144	bctr			/* jump after _mcount site */
145
146_GLOBAL(ftrace_stub)
147	blr
148
149ftrace_no_trace:
150	mflr	r3
151	mtctr	r3
152	REST_GPR(3, r1)
153	addi	r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
154	mtlr	r0
155	bctr
156
157_GLOBAL(ftrace_caller)
158	/* Save the original return address in A's stack frame */
159	std	r0, LRSAVE(r1)
160
161	/* Create a minimal stack frame for representing B */
162	stdu	r1, -STACK_FRAME_MIN_SIZE(r1)
163
164	/* Create our stack frame + pt_regs */
165	stdu	r1, -SWITCH_FRAME_SIZE(r1)
166
167	/* Save all gprs to pt_regs */
168	SAVE_8GPRS(3, r1)
169
170	lbz	r3, PACA_FTRACE_ENABLED(r13)
171	cmpdi	r3, 0
172	beq	ftrace_no_trace
173
174	/* Get the _mcount() call site out of LR */
175	mflr	r7
176	std     r7, _NIP(r1)
177	std	r7, LRSAVE+SWITCH_FRAME_SIZE(r1)
178
179	/* Save callee's TOC in the ABI compliant location */
180	std	r2, 24(r1)
181	ld	r2, PACATOC(r13)	/* get kernel TOC in r2 */
182
183	addis	r3, r2, function_trace_op@toc@ha
184	addi	r3, r3, function_trace_op@toc@l
185	ld	r5, 0(r3)
186
187	/* Calculate ip from nip-4 into r3 for call below */
188	subi    r3, r7, MCOUNT_INSN_SIZE
189
190	/* Put the original return address in r4 as parent_ip */
191	mr	r4, r0
192
193	/* Set pt_regs to NULL */
194	li	r6, 0
195
196	/* ftrace_call(r3, r4, r5, r6) */
197.globl ftrace_call
198ftrace_call:
199	bl	ftrace_stub
200	nop
201
202	ld	r3, _NIP(r1)
203	mtctr	r3
204
205	/* Restore gprs */
206	REST_8GPRS(3,r1)
207
208	/* Restore callee's TOC */
209	ld	r2, 24(r1)
210
211	/* Pop our stack frame */
212	addi	r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
213
214	/* Reload original LR */
215	ld	r0, LRSAVE(r1)
216	mtlr	r0
217
218	/* Handle function_graph or go back */
219	b	ftrace_caller_common
220
221#ifdef CONFIG_LIVEPATCH
222	/*
223	 * This function runs in the mcount context, between two functions. As
224	 * such it can only clobber registers which are volatile and used in
225	 * function linkage.
226	 *
227	 * We get here when a function A, calls another function B, but B has
228	 * been live patched with a new function C.
229	 *
230	 * On entry:
231	 *  - we have no stack frame and can not allocate one
232	 *  - LR points back to the original caller (in A)
233	 *  - CTR holds the new NIP in C
234	 *  - r0, r11 & r12 are free
235	 */
236livepatch_handler:
237	ld	r12, PACA_THREAD_INFO(r13)
238
239	/* Allocate 3 x 8 bytes */
240	ld	r11, TI_livepatch_sp(r12)
241	addi	r11, r11, 24
242	std	r11, TI_livepatch_sp(r12)
243
244	/* Save toc & real LR on livepatch stack */
245	std	r2,  -24(r11)
246	mflr	r12
247	std	r12, -16(r11)
248
249	/* Store stack end marker */
250	lis     r12, STACK_END_MAGIC@h
251	ori     r12, r12, STACK_END_MAGIC@l
252	std	r12, -8(r11)
253
254	/* Put ctr in r12 for global entry and branch there */
255	mfctr	r12
256	bctrl
257
258	/*
259	 * Now we are returning from the patched function to the original
260	 * caller A. We are free to use r11, r12 and we can use r2 until we
261	 * restore it.
262	 */
263
264	ld	r12, PACA_THREAD_INFO(r13)
265
266	ld	r11, TI_livepatch_sp(r12)
267
268	/* Check stack marker hasn't been trashed */
269	lis     r2,  STACK_END_MAGIC@h
270	ori     r2,  r2, STACK_END_MAGIC@l
271	ld	r12, -8(r11)
2721:	tdne	r12, r2
273	EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
274
275	/* Restore LR & toc from livepatch stack */
276	ld	r12, -16(r11)
277	mtlr	r12
278	ld	r2,  -24(r11)
279
280	/* Pop livepatch stack frame */
281	ld	r12, PACA_THREAD_INFO(r13)
282	subi	r11, r11, 24
283	std	r11, TI_livepatch_sp(r12)
284
285	/* Return to original caller of live patched function */
286	blr
287#endif /* CONFIG_LIVEPATCH */
288
289#ifdef CONFIG_FUNCTION_GRAPH_TRACER
290_GLOBAL(ftrace_graph_caller)
291	stdu	r1, -112(r1)
292	/* with -mprofile-kernel, parameter regs are still alive at _mcount */
293	std	r10, 104(r1)
294	std	r9, 96(r1)
295	std	r8, 88(r1)
296	std	r7, 80(r1)
297	std	r6, 72(r1)
298	std	r5, 64(r1)
299	std	r4, 56(r1)
300	std	r3, 48(r1)
301
302	/* Save callee's TOC in the ABI compliant location */
303	std	r2, 24(r1)
304	ld	r2, PACATOC(r13)	/* get kernel TOC in r2 */
305
306	addi	r5, r1, 112
307	mfctr	r4		/* ftrace_caller has moved local addr here */
308	std	r4, 40(r1)
309	mflr	r3		/* ftrace_caller has restored LR from stack */
310	subi	r4, r4, MCOUNT_INSN_SIZE
311
312	bl	prepare_ftrace_return
313	nop
314
315	/*
316	 * prepare_ftrace_return gives us the address we divert to.
317	 * Change the LR to this.
318	 */
319	mtlr	r3
320
321	ld	r0, 40(r1)
322	mtctr	r0
323	ld	r10, 104(r1)
324	ld	r9, 96(r1)
325	ld	r8, 88(r1)
326	ld	r7, 80(r1)
327	ld	r6, 72(r1)
328	ld	r5, 64(r1)
329	ld	r4, 56(r1)
330	ld	r3, 48(r1)
331
332	/* Restore callee's TOC */
333	ld	r2, 24(r1)
334
335	addi	r1, r1, 112
336	mflr	r0
337	std	r0, LRSAVE(r1)
338	bctr
339#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
340