xref: /openbmc/linux/arch/arm64/kernel/entry-ftrace.S (revision 36469703)
1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
2819e50e2SAKASHI Takahiro/*
3819e50e2SAKASHI Takahiro * arch/arm64/kernel/entry-ftrace.S
4819e50e2SAKASHI Takahiro *
5819e50e2SAKASHI Takahiro * Copyright (C) 2013 Linaro Limited
6819e50e2SAKASHI Takahiro * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
7819e50e2SAKASHI Takahiro */
8819e50e2SAKASHI Takahiro
9819e50e2SAKASHI Takahiro#include <linux/linkage.h>
10883bbbffSPeter Zijlstra#include <linux/cfi_types.h>
113b23e499STorsten Duwe#include <asm/asm-offsets.h>
12f705d954SArnd Bergmann#include <asm/assembler.h>
13819e50e2SAKASHI Takahiro#include <asm/ftrace.h>
14819e50e2SAKASHI Takahiro#include <asm/insn.h>
15819e50e2SAKASHI Takahiro
1626299b3fSMark Rutland#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
173b23e499STorsten Duwe/*
183b23e499STorsten Duwe * Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before
193b23e499STorsten Duwe * the regular function prologue. For an enabled callsite, ftrace_init_nop() and
203b23e499STorsten Duwe * ftrace_make_call() have patched those NOPs to:
213b23e499STorsten Duwe *
223b23e499STorsten Duwe * 	MOV	X9, LR
2326299b3fSMark Rutland * 	BL	ftrace_caller
243b23e499STorsten Duwe *
25258c3d62SWill Deacon * Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are
26258c3d62SWill Deacon * live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to
27258c3d62SWill Deacon * clobber.
283b23e499STorsten Duwe *
2926299b3fSMark Rutland * We save the callsite's context into a struct ftrace_regs before invoking any
3026299b3fSMark Rutland * ftrace callbacks. So that we can get a sensible backtrace, we create frame
3126299b3fSMark Rutland * records for the callsite and the ftrace entry assembly. This is not
3226299b3fSMark Rutland * sufficient for reliable stacktrace: until we create the callsite stack
3326299b3fSMark Rutland * record, its caller is missing from the LR and existing chain of frame
3426299b3fSMark Rutland * records.
353b23e499STorsten Duwe */
36e434b08bSMark BrownSYM_CODE_START(ftrace_caller)
37742a15b1SMark Brown	bti	c
383b23e499STorsten Duwe
392aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
402aa6ac03SFlorent Revest	/*
412aa6ac03SFlorent Revest	 * The literal pointer to the ops is at an 8-byte aligned boundary
422aa6ac03SFlorent Revest	 * which is either 12 or 16 bytes before the BL instruction in the call
432aa6ac03SFlorent Revest	 * site. See ftrace_call_adjust() for details.
442aa6ac03SFlorent Revest	 *
452aa6ac03SFlorent Revest	 * Therefore here the LR points at `literal + 16` or `literal + 20`,
462aa6ac03SFlorent Revest	 * and we can find the address of the literal in either case by
472aa6ac03SFlorent Revest	 * aligning to an 8-byte boundary and subtracting 16. We do the
482aa6ac03SFlorent Revest	 * alignment first as this allows us to fold the subtraction into the
492aa6ac03SFlorent Revest	 * LDR.
502aa6ac03SFlorent Revest	 */
512aa6ac03SFlorent Revest	bic	x11, x30, 0x7
522aa6ac03SFlorent Revest	ldr	x11, [x11, #-(4 * AARCH64_INSN_SIZE)]		// op
532aa6ac03SFlorent Revest
542aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
552aa6ac03SFlorent Revest	/*
562aa6ac03SFlorent Revest	 * If the op has a direct call, handle it immediately without
572aa6ac03SFlorent Revest	 * saving/restoring registers.
582aa6ac03SFlorent Revest	 */
592aa6ac03SFlorent Revest	ldr	x17, [x11, #FTRACE_OPS_DIRECT_CALL]		// op->direct_call
602aa6ac03SFlorent Revest	cbnz	x17, ftrace_caller_direct
612aa6ac03SFlorent Revest#endif
622aa6ac03SFlorent Revest#endif
632aa6ac03SFlorent Revest
6426299b3fSMark Rutland	/* Save original SP */
6526299b3fSMark Rutland	mov	x10, sp
6626299b3fSMark Rutland
6726299b3fSMark Rutland	/* Make room for ftrace regs, plus two frame records */
6826299b3fSMark Rutland	sub	sp, sp, #(FREGS_SIZE + 32)
6926299b3fSMark Rutland
7026299b3fSMark Rutland	/* Save function arguments */
7126299b3fSMark Rutland	stp	x0, x1, [sp, #FREGS_X0]
7226299b3fSMark Rutland	stp	x2, x3, [sp, #FREGS_X2]
7326299b3fSMark Rutland	stp	x4, x5, [sp, #FREGS_X4]
7426299b3fSMark Rutland	stp	x6, x7, [sp, #FREGS_X6]
7526299b3fSMark Rutland	str	x8,     [sp, #FREGS_X8]
7626299b3fSMark Rutland
772aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
782aa6ac03SFlorent Revest	str	xzr, [sp, #FREGS_DIRECT_TRAMP]
792aa6ac03SFlorent Revest#endif
802aa6ac03SFlorent Revest
8126299b3fSMark Rutland	/* Save the callsite's FP, LR, SP */
8226299b3fSMark Rutland	str	x29, [sp, #FREGS_FP]
8326299b3fSMark Rutland	str	x9,  [sp, #FREGS_LR]
8426299b3fSMark Rutland	str	x10, [sp, #FREGS_SP]
8526299b3fSMark Rutland
8626299b3fSMark Rutland	/* Save the PC after the ftrace callsite */
8726299b3fSMark Rutland	str	x30, [sp, #FREGS_PC]
8826299b3fSMark Rutland
8926299b3fSMark Rutland	/* Create a frame record for the callsite above the ftrace regs */
9026299b3fSMark Rutland	stp	x29, x9, [sp, #FREGS_SIZE + 16]
9126299b3fSMark Rutland	add	x29, sp, #FREGS_SIZE + 16
9226299b3fSMark Rutland
9326299b3fSMark Rutland	/* Create our frame record above the ftrace regs */
9426299b3fSMark Rutland	stp	x29, x30, [sp, #FREGS_SIZE]
9526299b3fSMark Rutland	add	x29, sp, #FREGS_SIZE
9626299b3fSMark Rutland
97baaf553dSMark Rutland	/* Prepare arguments for the the tracer func */
983b23e499STorsten Duwe	sub	x0, x30, #AARCH64_INSN_SIZE		// ip (callsite's BL insn)
993b23e499STorsten Duwe	mov	x1, x9					// parent_ip (callsite's LR)
1003b23e499STorsten Duwe	mov	x3, sp					// regs
1013b23e499STorsten Duwe
102baaf553dSMark Rutland#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
1032aa6ac03SFlorent Revest	mov	x2, x11					// op
104baaf553dSMark Rutland	ldr	x4, [x2, #FTRACE_OPS_FUNC]		// op->func
105baaf553dSMark Rutland	blr	x4					// op->func(ip, parent_ip, op, regs)
106baaf553dSMark Rutland
107baaf553dSMark Rutland#else
108baaf553dSMark Rutland	ldr_l   x2, function_trace_op			// op
109baaf553dSMark Rutland
110e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
111baaf553dSMark Rutland	bl      ftrace_stub				// func(ip, parent_ip, op, regs)
112baaf553dSMark Rutland#endif
1133b23e499STorsten Duwe
1143b23e499STorsten Duwe/*
1153b23e499STorsten Duwe * At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved
1163b23e499STorsten Duwe * x19-x29 per the AAPCS, and we created frame records upon entry, so we need
1173b23e499STorsten Duwe * to restore x0-x8, x29, and x30.
1183b23e499STorsten Duwe */
1193b23e499STorsten Duwe	/* Restore function arguments */
12026299b3fSMark Rutland	ldp	x0, x1, [sp, #FREGS_X0]
12126299b3fSMark Rutland	ldp	x2, x3, [sp, #FREGS_X2]
12226299b3fSMark Rutland	ldp	x4, x5, [sp, #FREGS_X4]
12326299b3fSMark Rutland	ldp	x6, x7, [sp, #FREGS_X6]
12426299b3fSMark Rutland	ldr	x8,     [sp, #FREGS_X8]
1253b23e499STorsten Duwe
1262aa6ac03SFlorent Revest	/* Restore the callsite's FP */
12726299b3fSMark Rutland	ldr	x29, [sp, #FREGS_FP]
1282aa6ac03SFlorent Revest
1292aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
1302aa6ac03SFlorent Revest	ldr	x17, [sp, #FREGS_DIRECT_TRAMP]
1312aa6ac03SFlorent Revest	cbnz	x17, ftrace_caller_direct_late
1322aa6ac03SFlorent Revest#endif
1332aa6ac03SFlorent Revest
1342aa6ac03SFlorent Revest	/* Restore the callsite's LR and PC */
13526299b3fSMark Rutland	ldr	x30, [sp, #FREGS_LR]
13626299b3fSMark Rutland	ldr	x9,  [sp, #FREGS_PC]
1373b23e499STorsten Duwe
1383b23e499STorsten Duwe	/* Restore the callsite's SP */
13926299b3fSMark Rutland	add	sp, sp, #FREGS_SIZE + 32
1403b23e499STorsten Duwe
1413b23e499STorsten Duwe	ret	x9
1422aa6ac03SFlorent Revest
1432aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
1442aa6ac03SFlorent RevestSYM_INNER_LABEL(ftrace_caller_direct_late, SYM_L_LOCAL)
1452aa6ac03SFlorent Revest	/*
1462aa6ac03SFlorent Revest	 * Head to a direct trampoline in x17 after having run other tracers.
1472aa6ac03SFlorent Revest	 * The ftrace_regs are live, and x0-x8 and FP have been restored. The
1482aa6ac03SFlorent Revest	 * LR, PC, and SP have not been restored.
1492aa6ac03SFlorent Revest	 */
1502aa6ac03SFlorent Revest
1512aa6ac03SFlorent Revest	/*
1522aa6ac03SFlorent Revest	 * Restore the callsite's LR and PC matching the trampoline calling
1532aa6ac03SFlorent Revest	 * convention.
1542aa6ac03SFlorent Revest	 */
1552aa6ac03SFlorent Revest	ldr	x9,  [sp, #FREGS_LR]
1562aa6ac03SFlorent Revest	ldr	x30, [sp, #FREGS_PC]
1572aa6ac03SFlorent Revest
1582aa6ac03SFlorent Revest	/* Restore the callsite's SP */
1592aa6ac03SFlorent Revest	add	sp, sp, #FREGS_SIZE + 32
1602aa6ac03SFlorent Revest
1612aa6ac03SFlorent RevestSYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL)
1622aa6ac03SFlorent Revest	/*
1632aa6ac03SFlorent Revest	 * Head to a direct trampoline in x17.
1642aa6ac03SFlorent Revest	 *
1652aa6ac03SFlorent Revest	 * We use `BR X17` as this can safely land on a `BTI C` or `PACIASP` in
1662aa6ac03SFlorent Revest	 * the trampoline, and will not unbalance any return stack.
1672aa6ac03SFlorent Revest	 */
1682aa6ac03SFlorent Revest	br	x17
1692aa6ac03SFlorent Revest#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
17026299b3fSMark RutlandSYM_CODE_END(ftrace_caller)
1713b23e499STorsten Duwe
1722aa6ac03SFlorent Revest#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
1732aa6ac03SFlorent RevestSYM_CODE_START(ftrace_stub_direct_tramp)
1742aa6ac03SFlorent Revest	bti	c
1752aa6ac03SFlorent Revest	mov	x10, x30
1762aa6ac03SFlorent Revest	mov	x30, x9
1772aa6ac03SFlorent Revest	ret	x10
1782aa6ac03SFlorent RevestSYM_CODE_END(ftrace_stub_direct_tramp)
1792aa6ac03SFlorent Revest#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
1802aa6ac03SFlorent Revest
18126299b3fSMark Rutland#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
1823b23e499STorsten Duwe
183819e50e2SAKASHI Takahiro/*
184819e50e2SAKASHI Takahiro * Gcc with -pg will put the following code in the beginning of each function:
185819e50e2SAKASHI Takahiro *      mov x0, x30
186819e50e2SAKASHI Takahiro *      bl _mcount
187819e50e2SAKASHI Takahiro *	[function's body ...]
188819e50e2SAKASHI Takahiro * "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic
189819e50e2SAKASHI Takahiro * ftrace is enabled.
190819e50e2SAKASHI Takahiro *
191819e50e2SAKASHI Takahiro * Please note that x0 as an argument will not be used here because we can
192819e50e2SAKASHI Takahiro * get lr(x30) of instrumented function at any time by winding up call stack
193819e50e2SAKASHI Takahiro * as long as the kernel is compiled without -fomit-frame-pointer.
194819e50e2SAKASHI Takahiro * (or CONFIG_FRAME_POINTER, this is forced on arm64)
195819e50e2SAKASHI Takahiro *
196819e50e2SAKASHI Takahiro * stack layout after mcount_enter in _mcount():
197819e50e2SAKASHI Takahiro *
198819e50e2SAKASHI Takahiro * current sp/fp =>  0:+-----+
199819e50e2SAKASHI Takahiro * in _mcount()        | x29 | -> instrumented function's fp
200819e50e2SAKASHI Takahiro *                     +-----+
201819e50e2SAKASHI Takahiro *                     | x30 | -> _mcount()'s lr (= instrumented function's pc)
202819e50e2SAKASHI Takahiro * old sp       => +16:+-----+
203819e50e2SAKASHI Takahiro * when instrumented   |     |
204819e50e2SAKASHI Takahiro * function calls      | ... |
205819e50e2SAKASHI Takahiro * _mcount()           |     |
206819e50e2SAKASHI Takahiro *                     |     |
207819e50e2SAKASHI Takahiro * instrumented => +xx:+-----+
208819e50e2SAKASHI Takahiro * function's fp       | x29 | -> parent's fp
209819e50e2SAKASHI Takahiro *                     +-----+
210819e50e2SAKASHI Takahiro *                     | x30 | -> instrumented function's lr (= parent's pc)
211819e50e2SAKASHI Takahiro *                     +-----+
212819e50e2SAKASHI Takahiro *                     | ... |
213819e50e2SAKASHI Takahiro */
214819e50e2SAKASHI Takahiro
215819e50e2SAKASHI Takahiro	.macro mcount_enter
216819e50e2SAKASHI Takahiro	stp	x29, x30, [sp, #-16]!
217819e50e2SAKASHI Takahiro	mov	x29, sp
218819e50e2SAKASHI Takahiro	.endm
219819e50e2SAKASHI Takahiro
220819e50e2SAKASHI Takahiro	.macro mcount_exit
221819e50e2SAKASHI Takahiro	ldp	x29, x30, [sp], #16
222819e50e2SAKASHI Takahiro	ret
223819e50e2SAKASHI Takahiro	.endm
224819e50e2SAKASHI Takahiro
225819e50e2SAKASHI Takahiro	.macro mcount_adjust_addr rd, rn
226819e50e2SAKASHI Takahiro	sub	\rd, \rn, #AARCH64_INSN_SIZE
227819e50e2SAKASHI Takahiro	.endm
228819e50e2SAKASHI Takahiro
229819e50e2SAKASHI Takahiro	/* for instrumented function's parent */
230819e50e2SAKASHI Takahiro	.macro mcount_get_parent_fp reg
231819e50e2SAKASHI Takahiro	ldr	\reg, [x29]
232819e50e2SAKASHI Takahiro	ldr	\reg, [\reg]
233819e50e2SAKASHI Takahiro	.endm
234819e50e2SAKASHI Takahiro
235819e50e2SAKASHI Takahiro	/* for instrumented function */
236819e50e2SAKASHI Takahiro	.macro mcount_get_pc0 reg
237819e50e2SAKASHI Takahiro	mcount_adjust_addr	\reg, x30
238819e50e2SAKASHI Takahiro	.endm
239819e50e2SAKASHI Takahiro
240819e50e2SAKASHI Takahiro	.macro mcount_get_pc reg
241819e50e2SAKASHI Takahiro	ldr	\reg, [x29, #8]
242819e50e2SAKASHI Takahiro	mcount_adjust_addr	\reg, \reg
243819e50e2SAKASHI Takahiro	.endm
244819e50e2SAKASHI Takahiro
245819e50e2SAKASHI Takahiro	.macro mcount_get_lr reg
246819e50e2SAKASHI Takahiro	ldr	\reg, [x29]
247819e50e2SAKASHI Takahiro	ldr	\reg, [\reg, #8]
248819e50e2SAKASHI Takahiro	.endm
249819e50e2SAKASHI Takahiro
250819e50e2SAKASHI Takahiro	.macro mcount_get_lr_addr reg
251819e50e2SAKASHI Takahiro	ldr	\reg, [x29]
252819e50e2SAKASHI Takahiro	add	\reg, \reg, #8
253819e50e2SAKASHI Takahiro	.endm
254819e50e2SAKASHI Takahiro
255bd7d38dbSAKASHI Takahiro/*
256bd7d38dbSAKASHI Takahiro * _mcount() is used to build the kernel with -pg option, but all the branch
257bd7d38dbSAKASHI Takahiro * instructions to _mcount() are replaced to NOP initially at kernel start up,
258bd7d38dbSAKASHI Takahiro * and later on, NOP to branch to ftrace_caller() when enabled or branch to
259bd7d38dbSAKASHI Takahiro * NOP when disabled per-function base.
260bd7d38dbSAKASHI Takahiro */
261e2d591d2SMark BrownSYM_FUNC_START(_mcount)
262bd7d38dbSAKASHI Takahiro	ret
263e2d591d2SMark BrownSYM_FUNC_END(_mcount)
264dbd31962SMark RutlandEXPORT_SYMBOL(_mcount)
265dbd31962SMark RutlandNOKPROBE(_mcount)
266bd7d38dbSAKASHI Takahiro
267bd7d38dbSAKASHI Takahiro/*
268bd7d38dbSAKASHI Takahiro * void ftrace_caller(unsigned long return_address)
269bd7d38dbSAKASHI Takahiro * @return_address: return address to instrumented function
270bd7d38dbSAKASHI Takahiro *
271bd7d38dbSAKASHI Takahiro * This function is a counterpart of _mcount() in 'static' ftrace, and
272bd7d38dbSAKASHI Takahiro * makes calls to:
273bd7d38dbSAKASHI Takahiro *     - tracer function to probe instrumented function's entry,
274bd7d38dbSAKASHI Takahiro *     - ftrace_graph_caller to set up an exit hook
275bd7d38dbSAKASHI Takahiro */
276e2d591d2SMark BrownSYM_FUNC_START(ftrace_caller)
277bd7d38dbSAKASHI Takahiro	mcount_enter
278bd7d38dbSAKASHI Takahiro
279bd7d38dbSAKASHI Takahiro	mcount_get_pc0	x0		//     function's pc
280bd7d38dbSAKASHI Takahiro	mcount_get_lr	x1		//     function's lr
281bd7d38dbSAKASHI Takahiro
282e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)	// tracer(pc, lr);
283bd7d38dbSAKASHI Takahiro	nop				// This will be replaced with "bl xxx"
284bd7d38dbSAKASHI Takahiro					// where xxx can be any kind of tracer.
285bd7d38dbSAKASHI Takahiro
286bd7d38dbSAKASHI Takahiro#ifdef CONFIG_FUNCTION_GRAPH_TRACER
28769d113b5SKunihiko HayashiSYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();
288bd7d38dbSAKASHI Takahiro	nop				// If enabled, this will be replaced
289bd7d38dbSAKASHI Takahiro					// "b ftrace_graph_caller"
290bd7d38dbSAKASHI Takahiro#endif
291bd7d38dbSAKASHI Takahiro
292bd7d38dbSAKASHI Takahiro	mcount_exit
293e2d591d2SMark BrownSYM_FUNC_END(ftrace_caller)
294819e50e2SAKASHI Takahiro
295819e50e2SAKASHI Takahiro#ifdef CONFIG_FUNCTION_GRAPH_TRACER
296819e50e2SAKASHI Takahiro/*
297819e50e2SAKASHI Takahiro * void ftrace_graph_caller(void)
298819e50e2SAKASHI Takahiro *
299819e50e2SAKASHI Takahiro * Called from _mcount() or ftrace_caller() when function_graph tracer is
300819e50e2SAKASHI Takahiro * selected.
301819e50e2SAKASHI Takahiro * This function w/ prepare_ftrace_return() fakes link register's value on
302819e50e2SAKASHI Takahiro * the call stack in order to intercept instrumented function's return path
303819e50e2SAKASHI Takahiro * and run return_to_handler() later on its exit.
304819e50e2SAKASHI Takahiro */
305e2d591d2SMark BrownSYM_FUNC_START(ftrace_graph_caller)
3067dc48bf9SMark Rutland	mcount_get_pc		  x0	//     function's pc
3077dc48bf9SMark Rutland	mcount_get_lr_addr	  x1	//     pointer to function's saved lr
308819e50e2SAKASHI Takahiro	mcount_get_parent_fp	  x2	//     parent's fp
3097dc48bf9SMark Rutland	bl	prepare_ftrace_return	// prepare_ftrace_return(pc, &lr, fp)
310819e50e2SAKASHI Takahiro
311819e50e2SAKASHI Takahiro	mcount_exit
312e2d591d2SMark BrownSYM_FUNC_END(ftrace_graph_caller)
3133b23e499STorsten Duwe#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
31426299b3fSMark Rutland#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
315819e50e2SAKASHI Takahiro
316883bbbffSPeter ZijlstraSYM_TYPED_FUNC_START(ftrace_stub)
3173b23e499STorsten Duwe	ret
318e2d591d2SMark BrownSYM_FUNC_END(ftrace_stub)
3193b23e499STorsten Duwe
3202598ac6eSSami Tolvanen#ifdef CONFIG_FUNCTION_GRAPH_TRACER
321883bbbffSPeter ZijlstraSYM_TYPED_FUNC_START(ftrace_stub_graph)
322883bbbffSPeter Zijlstra	ret
323883bbbffSPeter ZijlstraSYM_FUNC_END(ftrace_stub_graph)
324883bbbffSPeter Zijlstra
325819e50e2SAKASHI Takahiro/*
326819e50e2SAKASHI Takahiro * void return_to_handler(void)
327819e50e2SAKASHI Takahiro *
328819e50e2SAKASHI Takahiro * Run ftrace_return_to_handler() before going back to parent.
3295c176affSMark Rutland * @fp is checked against the value passed by ftrace_graph_caller().
330819e50e2SAKASHI Takahiro */
3311e4729edSMark BrownSYM_CODE_START(return_to_handler)
33249e258e0SMark Rutland	/* save return value regs */
333*36469703SDonglin Peng	sub sp, sp, #FGRET_REGS_SIZE
334*36469703SDonglin Peng	stp x0, x1, [sp, #FGRET_REGS_X0]
335*36469703SDonglin Peng	stp x2, x3, [sp, #FGRET_REGS_X2]
336*36469703SDonglin Peng	stp x4, x5, [sp, #FGRET_REGS_X4]
337*36469703SDonglin Peng	stp x6, x7, [sp, #FGRET_REGS_X6]
338*36469703SDonglin Peng	str x29,    [sp, #FGRET_REGS_FP]	// parent's fp
33949e258e0SMark Rutland
340*36469703SDonglin Peng	mov	x0, sp
341*36469703SDonglin Peng	bl	ftrace_return_to_handler	// addr = ftrace_return_to_hander(regs);
342819e50e2SAKASHI Takahiro	mov	x30, x0				// restore the original return address
34349e258e0SMark Rutland
34449e258e0SMark Rutland	/* restore return value regs */
345*36469703SDonglin Peng	ldp x0, x1, [sp, #FGRET_REGS_X0]
346*36469703SDonglin Peng	ldp x2, x3, [sp, #FGRET_REGS_X2]
347*36469703SDonglin Peng	ldp x4, x5, [sp, #FGRET_REGS_X4]
348*36469703SDonglin Peng	ldp x6, x7, [sp, #FGRET_REGS_X6]
349*36469703SDonglin Peng	add sp, sp, #FGRET_REGS_SIZE
35049e258e0SMark Rutland
351819e50e2SAKASHI Takahiro	ret
3521e4729edSMark BrownSYM_CODE_END(return_to_handler)
353819e50e2SAKASHI Takahiro#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
354