~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/trace/ftrace_entry.S

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-or-later */
  2 /*
  3  * Split from ftrace_64.S
  4  */
  5 
  6 #include <linux/export.h>
  7 #include <linux/magic.h>
  8 #include <asm/ppc_asm.h>
  9 #include <asm/asm-offsets.h>
 10 #include <asm/ftrace.h>
 11 #include <asm/ppc-opcode.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 .macro  ftrace_regs_entry allregs
 36         /* Create a minimal stack frame for representing B */
 37         PPC_STLU        r1, -STACK_FRAME_MIN_SIZE(r1)
 38 
 39         /* Create our stack frame + pt_regs */
 40         PPC_STLU        r1,-SWITCH_FRAME_SIZE(r1)
 41 
 42         /* Save all gprs to pt_regs */
 43         SAVE_GPR(0, r1)
 44         SAVE_GPRS(3, 10, r1)
 45 
 46 #ifdef CONFIG_PPC64
 47         /* Save the original return address in A's stack frame */
 48         std     r0, LRSAVE+SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE(r1)
 49         /* Ok to continue? */
 50         lbz     r3, PACA_FTRACE_ENABLED(r13)
 51         cmpdi   r3, 0
 52         beq     ftrace_no_trace
 53 #endif
 54 
 55         .if \allregs == 1
 56         SAVE_GPR(2, r1)
 57         SAVE_GPRS(11, 31, r1)
 58         .else
 59 #ifdef CONFIG_LIVEPATCH_64
 60         SAVE_GPR(14, r1)
 61 #endif
 62         .endif
 63 
 64         /* Save previous stack pointer (r1) */
 65         addi    r8, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
 66         PPC_STL r8, GPR1(r1)
 67 
 68         .if \allregs == 1
 69         /* Load special regs for save below */
 70         mfmsr   r8
 71         mfctr   r9
 72         mfxer   r10
 73         mfcr    r11
 74         .else
 75         /* Clear MSR to flag as ftrace_caller versus frace_regs_caller */
 76         li      r8, 0
 77         .endif
 78 
 79         /* Get the _mcount() call site out of LR */
 80         mflr    r7
 81         /* Save it as pt_regs->nip */
 82         PPC_STL r7, _NIP(r1)
 83         /* Also save it in B's stackframe header for proper unwind */
 84         PPC_STL r7, LRSAVE+SWITCH_FRAME_SIZE(r1)
 85         /* Save the read LR in pt_regs->link */
 86         PPC_STL r0, _LINK(r1)
 87 
 88 #ifdef CONFIG_PPC64
 89         /* Save callee's TOC in the ABI compliant location */
 90         std     r2, STK_GOT(r1)
 91         LOAD_PACA_TOC()         /* get kernel TOC in r2 */
 92         LOAD_REG_ADDR(r3, function_trace_op)
 93         ld      r5,0(r3)
 94 #else
 95         lis     r3,function_trace_op@ha
 96         lwz     r5,function_trace_op@l(r3)
 97 #endif
 98 
 99 #ifdef CONFIG_LIVEPATCH_64
100         mr      r14, r7         /* remember old NIP */
101 #endif
102 
103         /* Calculate ip from nip-4 into r3 for call below */
104         subi    r3, r7, MCOUNT_INSN_SIZE
105 
106         /* Put the original return address in r4 as parent_ip */
107         mr      r4, r0
108 
109         /* Save special regs */
110         PPC_STL r8, _MSR(r1)
111         .if \allregs == 1
112         PPC_STL r9, _CTR(r1)
113         PPC_STL r10, _XER(r1)
114         PPC_STL r11, _CCR(r1)
115         .endif
116 
117         /* Load &pt_regs in r6 for call below */
118         addi    r6, r1, STACK_INT_FRAME_REGS
119 .endm
120 
121 .macro  ftrace_regs_exit allregs
122         /* Load ctr with the possibly modified NIP */
123         PPC_LL  r3, _NIP(r1)
124         mtctr   r3
125 
126 #ifdef CONFIG_LIVEPATCH_64
127         cmpd    r14, r3         /* has NIP been altered? */
128 #endif
129 
130         /* Restore gprs */
131         .if \allregs == 1
132         REST_GPRS(2, 31, r1)
133         .else
134         REST_GPRS(3, 10, r1)
135 #ifdef CONFIG_LIVEPATCH_64
136         REST_GPR(14, r1)
137 #endif
138         .endif
139 
140         /* Restore possibly modified LR */
141         PPC_LL  r0, _LINK(r1)
142         mtlr    r0
143 
144 #ifdef CONFIG_PPC64
145         /* Restore callee's TOC */
146         ld      r2, STK_GOT(r1)
147 #endif
148 
149         /* Pop our stack frame */
150         addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
151 
152 #ifdef CONFIG_LIVEPATCH_64
153         /* Based on the cmpd above, if the NIP was altered handle livepatch */
154         bne-    livepatch_handler
155 #endif
156         bctr                    /* jump after _mcount site */
157 .endm
158 
159 _GLOBAL(ftrace_regs_caller)
160         ftrace_regs_entry 1
161         /* ftrace_call(r3, r4, r5, r6) */
162 .globl ftrace_regs_call
163 ftrace_regs_call:
164         bl      ftrace_stub
165         ftrace_regs_exit 1
166 
167 _GLOBAL(ftrace_caller)
168         ftrace_regs_entry 0
169         /* ftrace_call(r3, r4, r5, r6) */
170 .globl ftrace_call
171 ftrace_call:
172         bl      ftrace_stub
173         ftrace_regs_exit 0
174 
175 _GLOBAL(ftrace_stub)
176         blr
177 
178 #ifdef CONFIG_PPC64
179 ftrace_no_trace:
180         mflr    r3
181         mtctr   r3
182         REST_GPR(3, r1)
183         addi    r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE
184         mtlr    r0
185         bctr
186 #endif
187 
188 #ifdef CONFIG_LIVEPATCH_64
189         /*
190          * This function runs in the mcount context, between two functions. As
191          * such it can only clobber registers which are volatile and used in
192          * function linkage.
193          *
194          * We get here when a function A, calls another function B, but B has
195          * been live patched with a new function C.
196          *
197          * On entry:
198          *  - we have no stack frame and can not allocate one
199          *  - LR points back to the original caller (in A)
200          *  - CTR holds the new NIP in C
201          *  - r0, r11 & r12 are free
202          */
203 livepatch_handler:
204         ld      r12, PACA_THREAD_INFO(r13)
205 
206         /* Allocate 3 x 8 bytes */
207         ld      r11, TI_livepatch_sp(r12)
208         addi    r11, r11, 24
209         std     r11, TI_livepatch_sp(r12)
210 
211         /* Save toc & real LR on livepatch stack */
212         std     r2,  -24(r11)
213         mflr    r12
214         std     r12, -16(r11)
215 
216         /* Store stack end marker */
217         lis     r12, STACK_END_MAGIC@h
218         ori     r12, r12, STACK_END_MAGIC@l
219         std     r12, -8(r11)
220 
221         /* Put ctr in r12 for global entry and branch there */
222         mfctr   r12
223         bctrl
224 
225         /*
226          * Now we are returning from the patched function to the original
227          * caller A. We are free to use r11, r12 and we can use r2 until we
228          * restore it.
229          */
230 
231         ld      r12, PACA_THREAD_INFO(r13)
232 
233         ld      r11, TI_livepatch_sp(r12)
234 
235         /* Check stack marker hasn't been trashed */
236         lis     r2,  STACK_END_MAGIC@h
237         ori     r2,  r2, STACK_END_MAGIC@l
238         ld      r12, -8(r11)
239 1:      tdne    r12, r2
240         EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
241 
242         /* Restore LR & toc from livepatch stack */
243         ld      r12, -16(r11)
244         mtlr    r12
245         ld      r2,  -24(r11)
246 
247         /* Pop livepatch stack frame */
248         ld      r12, PACA_THREAD_INFO(r13)
249         subi    r11, r11, 24
250         std     r11, TI_livepatch_sp(r12)
251 
252         /* Return to original caller of live patched function */
253         blr
254 #endif /* CONFIG_LIVEPATCH */
255 
256 #ifndef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY
257 _GLOBAL(mcount)
258 _GLOBAL(_mcount)
259 EXPORT_SYMBOL(_mcount)
260         mflr    r12
261         mtctr   r12
262         mtlr    r0
263         bctr
264 #endif
265 
266 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
267 _GLOBAL(return_to_handler)
268         /* need to save return values */
269 #ifdef CONFIG_PPC64
270         std     r4,  -32(r1)
271         std     r3,  -24(r1)
272         /* save TOC */
273         std     r2,  -16(r1)
274         std     r31, -8(r1)
275         mr      r31, r1
276         stdu    r1, -112(r1)
277 
278         /*
279          * We might be called from a module.
280          * Switch to our TOC to run inside the core kernel.
281          */
282         LOAD_PACA_TOC()
283 #else
284         stwu    r1, -16(r1)
285         stw     r3, 8(r1)
286         stw     r4, 12(r1)
287 #endif
288 
289         bl      ftrace_return_to_handler
290         nop
291 
292         /* return value has real return address */
293         mtlr    r3
294 
295 #ifdef CONFIG_PPC64
296         ld      r1, 0(r1)
297         ld      r4,  -32(r1)
298         ld      r3,  -24(r1)
299         ld      r2,  -16(r1)
300         ld      r31, -8(r1)
301 #else
302         lwz     r3, 8(r1)
303         lwz     r4, 12(r1)
304         addi    r1, r1, 16
305 #endif
306 
307         /* Jump back to real return address */
308         blr
309 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
310 
311 .pushsection ".tramp.ftrace.text","aw",@progbits;
312 .globl ftrace_tramp_text
313 ftrace_tramp_text:
314         .space 32
315 .popsection
316 
317 .pushsection ".tramp.ftrace.init","aw",@progbits;
318 .globl ftrace_tramp_init
319 ftrace_tramp_init:
320         .space 32
321 .popsection

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php