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