xref: /openbmc/linux/arch/arm/kernel/entry-ftrace.S (revision 620176f3)
182112379SRussell King/*
282112379SRussell King * This program is free software; you can redistribute it and/or modify
382112379SRussell King * it under the terms of the GNU General Public License version 2 as
482112379SRussell King * published by the Free Software Foundation.
582112379SRussell King */
682112379SRussell King
782112379SRussell King#include <asm/assembler.h>
882112379SRussell King#include <asm/ftrace.h>
982112379SRussell King#include <asm/unwind.h>
1082112379SRussell King
1182112379SRussell King#include "entry-header.S"
1282112379SRussell King
1382112379SRussell King/*
1482112379SRussell King * When compiling with -pg, gcc inserts a call to the mcount routine at the
1582112379SRussell King * start of every function.  In mcount, apart from the function's address (in
1682112379SRussell King * lr), we need to get hold of the function's caller's address.
1782112379SRussell King *
1882112379SRussell King * Older GCCs (pre-4.4) inserted a call to a routine called mcount like this:
1982112379SRussell King *
2082112379SRussell King *	bl	mcount
2182112379SRussell King *
2282112379SRussell King * These versions have the limitation that in order for the mcount routine to
2382112379SRussell King * be able to determine the function's caller's address, an APCS-style frame
2482112379SRussell King * pointer (which is set up with something like the code below) is required.
2582112379SRussell King *
2682112379SRussell King *	mov     ip, sp
2782112379SRussell King *	push    {fp, ip, lr, pc}
2882112379SRussell King *	sub     fp, ip, #4
2982112379SRussell King *
3082112379SRussell King * With EABI, these frame pointers are not available unless -mapcs-frame is
3182112379SRussell King * specified, and if building as Thumb-2, not even then.
3282112379SRussell King *
3382112379SRussell King * Newer GCCs (4.4+) solve this problem by introducing a new version of mcount,
3482112379SRussell King * with call sites like:
3582112379SRussell King *
3682112379SRussell King *	push	{lr}
3782112379SRussell King *	bl	__gnu_mcount_nc
3882112379SRussell King *
3982112379SRussell King * With these compilers, frame pointers are not necessary.
4082112379SRussell King *
4182112379SRussell King * mcount can be thought of as a function called in the middle of a subroutine
4282112379SRussell King * call.  As such, it needs to be transparent for both the caller and the
4382112379SRussell King * callee: the original lr needs to be restored when leaving mcount, and no
4482112379SRussell King * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
4582112379SRussell King * clobber the ip register.  This is OK because the ARM calling convention
4682112379SRussell King * allows it to be clobbered in subroutines and doesn't use it to hold
4782112379SRussell King * parameters.)
4882112379SRussell King *
4982112379SRussell King * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0"
5082112379SRussell King * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see
5182112379SRussell King * arch/arm/kernel/ftrace.c).
5282112379SRussell King */
5382112379SRussell King
5482112379SRussell King#ifndef CONFIG_OLD_MCOUNT
5582112379SRussell King#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
5682112379SRussell King#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
5782112379SRussell King#endif
5882112379SRussell King#endif
5982112379SRussell King
6082112379SRussell King.macro mcount_adjust_addr rd, rn
6182112379SRussell King	bic	\rd, \rn, #1		@ clear the Thumb bit if present
6282112379SRussell King	sub	\rd, \rd, #MCOUNT_INSN_SIZE
6382112379SRussell King.endm
6482112379SRussell King
6582112379SRussell King.macro __mcount suffix
6682112379SRussell King	mcount_enter
6782112379SRussell King	ldr	r0, =ftrace_trace_function
6882112379SRussell King	ldr	r2, [r0]
6982112379SRussell King	adr	r0, .Lftrace_stub
7082112379SRussell King	cmp	r0, r2
7182112379SRussell King	bne	1f
7282112379SRussell King
7382112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
7482112379SRussell King	ldr     r1, =ftrace_graph_return
7582112379SRussell King	ldr     r2, [r1]
7682112379SRussell King	cmp     r0, r2
7782112379SRussell King	bne     ftrace_graph_caller\suffix
7882112379SRussell King
7982112379SRussell King	ldr     r1, =ftrace_graph_entry
8082112379SRussell King	ldr     r2, [r1]
8182112379SRussell King	ldr     r0, =ftrace_graph_entry_stub
8282112379SRussell King	cmp     r0, r2
8382112379SRussell King	bne     ftrace_graph_caller\suffix
8482112379SRussell King#endif
8582112379SRussell King
8682112379SRussell King	mcount_exit
8782112379SRussell King
8882112379SRussell King1: 	mcount_get_lr	r1			@ lr of instrumented func
8982112379SRussell King	mcount_adjust_addr	r0, lr		@ instrumented function
9014327c66SRussell King	badr	lr, 2f
9182112379SRussell King	mov	pc, r2
9282112379SRussell King2:	mcount_exit
9382112379SRussell King.endm
9482112379SRussell King
95620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
96620176f3SAbel Vesa
97620176f3SAbel Vesa.macro __ftrace_regs_caller
98620176f3SAbel Vesa
99620176f3SAbel Vesa	sub	sp, sp, #8	@ space for PC and CPSR OLD_R0,
100620176f3SAbel Vesa				@ OLD_R0 will overwrite previous LR
101620176f3SAbel Vesa
102620176f3SAbel Vesa	add 	ip, sp, #12	@ move in IP the value of SP as it was
103620176f3SAbel Vesa				@ before the push {lr} of the mcount mechanism
104620176f3SAbel Vesa
105620176f3SAbel Vesa	str     lr, [sp, #0]    @ store LR instead of PC
106620176f3SAbel Vesa
107620176f3SAbel Vesa	ldr     lr, [sp, #8]    @ get previous LR
108620176f3SAbel Vesa
109620176f3SAbel Vesa	str	r0, [sp, #8]	@ write r0 as OLD_R0 over previous LR
110620176f3SAbel Vesa
111620176f3SAbel Vesa	stmdb   sp!, {ip, lr}
112620176f3SAbel Vesa	stmdb   sp!, {r0-r11, lr}
113620176f3SAbel Vesa
114620176f3SAbel Vesa	@ stack content at this point:
115620176f3SAbel Vesa	@ 0  4          48   52       56            60   64    68       72
116620176f3SAbel Vesa	@ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
117620176f3SAbel Vesa
118620176f3SAbel Vesa	mov r3, sp				@ struct pt_regs*
119620176f3SAbel Vesa
120620176f3SAbel Vesa	ldr r2, =function_trace_op
121620176f3SAbel Vesa	ldr r2, [r2]				@ pointer to the current
122620176f3SAbel Vesa						@ function tracing op
123620176f3SAbel Vesa
124620176f3SAbel Vesa	ldr	r1, [sp, #S_LR]			@ lr of instrumented func
125620176f3SAbel Vesa
126620176f3SAbel Vesa	ldr	lr, [sp, #S_PC]			@ get LR
127620176f3SAbel Vesa
128620176f3SAbel Vesa	mcount_adjust_addr	r0, lr		@ instrumented function
129620176f3SAbel Vesa
130620176f3SAbel Vesa	.globl ftrace_regs_call
131620176f3SAbel Vesaftrace_regs_call:
132620176f3SAbel Vesa	bl	ftrace_stub
133620176f3SAbel Vesa
134620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER
135620176f3SAbel Vesa	.globl ftrace_graph_regs_call
136620176f3SAbel Vesaftrace_graph_regs_call:
137620176f3SAbel Vesa	mov	r0, r0
138620176f3SAbel Vesa#endif
139620176f3SAbel Vesa
140620176f3SAbel Vesa	@ pop saved regs
141620176f3SAbel Vesa	ldmia   sp!, {r0-r12}			@ restore r0 through r12
142620176f3SAbel Vesa	ldr	ip, [sp, #8]			@ restore PC
143620176f3SAbel Vesa	ldr	lr, [sp, #4]			@ restore LR
144620176f3SAbel Vesa	ldr	sp, [sp, #0]			@ restore SP
145620176f3SAbel Vesa	mov	pc, ip				@ return
146620176f3SAbel Vesa.endm
147620176f3SAbel Vesa
148620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER
149620176f3SAbel Vesa.macro __ftrace_graph_regs_caller
150620176f3SAbel Vesa
151620176f3SAbel Vesa	sub     r0, fp, #4              @ lr of instrumented routine (parent)
152620176f3SAbel Vesa
153620176f3SAbel Vesa	@ called from __ftrace_regs_caller
154620176f3SAbel Vesa	ldr     r1, [sp, #S_PC]		@ instrumented routine (func)
155620176f3SAbel Vesa	mcount_adjust_addr	r1, r1
156620176f3SAbel Vesa
157620176f3SAbel Vesa	mov	r2, fp			@ frame pointer
158620176f3SAbel Vesa	bl	prepare_ftrace_return
159620176f3SAbel Vesa
160620176f3SAbel Vesa	@ pop registers saved in ftrace_regs_caller
161620176f3SAbel Vesa	ldmia   sp!, {r0-r12}			@ restore r0 through r12
162620176f3SAbel Vesa	ldr	ip, [sp, #8]			@ restore PC
163620176f3SAbel Vesa	ldr	lr, [sp, #4]			@ restore LR
164620176f3SAbel Vesa	ldr	sp, [sp, #0]			@ restore SP
165620176f3SAbel Vesa	mov	pc, ip				@ return
166620176f3SAbel Vesa
167620176f3SAbel Vesa.endm
168620176f3SAbel Vesa#endif
169620176f3SAbel Vesa#endif
170620176f3SAbel Vesa
17182112379SRussell King.macro __ftrace_caller suffix
17282112379SRussell King	mcount_enter
17382112379SRussell King
17482112379SRussell King	mcount_get_lr	r1			@ lr of instrumented func
17582112379SRussell King	mcount_adjust_addr	r0, lr		@ instrumented function
17682112379SRussell King
177620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
178620176f3SAbel Vesa	ldr r2, =function_trace_op
179620176f3SAbel Vesa	ldr r2, [r2]				@ pointer to the current
180620176f3SAbel Vesa						@ function tracing op
181620176f3SAbel Vesa	mov r3, #0				@ regs is NULL
182620176f3SAbel Vesa#endif
183620176f3SAbel Vesa
18482112379SRussell King	.globl ftrace_call\suffix
18582112379SRussell Kingftrace_call\suffix:
18682112379SRussell King	bl	ftrace_stub
18782112379SRussell King
18882112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
18982112379SRussell King	.globl ftrace_graph_call\suffix
19082112379SRussell Kingftrace_graph_call\suffix:
19182112379SRussell King	mov	r0, r0
19282112379SRussell King#endif
19382112379SRussell King
19482112379SRussell King	mcount_exit
19582112379SRussell King.endm
19682112379SRussell King
19782112379SRussell King.macro __ftrace_graph_caller
19882112379SRussell King	sub	r0, fp, #4		@ &lr of instrumented routine (&parent)
19982112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
20082112379SRussell King	@ called from __ftrace_caller, saved in mcount_enter
20182112379SRussell King	ldr	r1, [sp, #16]		@ instrumented routine (func)
20282112379SRussell King	mcount_adjust_addr	r1, r1
20382112379SRussell King#else
20482112379SRussell King	@ called from __mcount, untouched in lr
20582112379SRussell King	mcount_adjust_addr	r1, lr	@ instrumented routine (func)
20682112379SRussell King#endif
20782112379SRussell King	mov	r2, fp			@ frame pointer
20882112379SRussell King	bl	prepare_ftrace_return
20982112379SRussell King	mcount_exit
21082112379SRussell King.endm
21182112379SRussell King
21282112379SRussell King#ifdef CONFIG_OLD_MCOUNT
21382112379SRussell King/*
21482112379SRussell King * mcount
21582112379SRussell King */
21682112379SRussell King
21782112379SRussell King.macro mcount_enter
21882112379SRussell King	stmdb	sp!, {r0-r3, lr}
21982112379SRussell King.endm
22082112379SRussell King
22182112379SRussell King.macro mcount_get_lr reg
22282112379SRussell King	ldr	\reg, [fp, #-4]
22382112379SRussell King.endm
22482112379SRussell King
22582112379SRussell King.macro mcount_exit
22682112379SRussell King	ldr	lr, [fp, #-4]
22782112379SRussell King	ldmia	sp!, {r0-r3, pc}
22882112379SRussell King.endm
22982112379SRussell King
23082112379SRussell KingENTRY(mcount)
23182112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
23282112379SRussell King	stmdb	sp!, {lr}
23382112379SRussell King	ldr	lr, [fp, #-4]
23482112379SRussell King	ldmia	sp!, {pc}
23582112379SRussell King#else
23682112379SRussell King	__mcount _old
23782112379SRussell King#endif
23882112379SRussell KingENDPROC(mcount)
23982112379SRussell King
24082112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
24182112379SRussell KingENTRY(ftrace_caller_old)
24282112379SRussell King	__ftrace_caller _old
24382112379SRussell KingENDPROC(ftrace_caller_old)
24482112379SRussell King#endif
24582112379SRussell King
24682112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
24782112379SRussell KingENTRY(ftrace_graph_caller_old)
24882112379SRussell King	__ftrace_graph_caller
24982112379SRussell KingENDPROC(ftrace_graph_caller_old)
25082112379SRussell King#endif
25182112379SRussell King
25282112379SRussell King.purgem mcount_enter
25382112379SRussell King.purgem mcount_get_lr
25482112379SRussell King.purgem mcount_exit
25582112379SRussell King#endif
25682112379SRussell King
25782112379SRussell King/*
25882112379SRussell King * __gnu_mcount_nc
25982112379SRussell King */
26082112379SRussell King
26182112379SRussell King.macro mcount_enter
26282112379SRussell King/*
26382112379SRussell King * This pad compensates for the push {lr} at the call site.  Note that we are
26482112379SRussell King * unable to unwind through a function which does not otherwise save its lr.
26582112379SRussell King */
26682112379SRussell King UNWIND(.pad	#4)
26782112379SRussell King	stmdb	sp!, {r0-r3, lr}
26882112379SRussell King UNWIND(.save	{r0-r3, lr})
26982112379SRussell King.endm
27082112379SRussell King
27182112379SRussell King.macro mcount_get_lr reg
27282112379SRussell King	ldr	\reg, [sp, #20]
27382112379SRussell King.endm
27482112379SRussell King
27582112379SRussell King.macro mcount_exit
27682112379SRussell King	ldmia	sp!, {r0-r3, ip, lr}
27782112379SRussell King	ret	ip
27882112379SRussell King.endm
27982112379SRussell King
28082112379SRussell KingENTRY(__gnu_mcount_nc)
28182112379SRussell KingUNWIND(.fnstart)
28282112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
28382112379SRussell King	mov	ip, lr
28482112379SRussell King	ldmia	sp!, {lr}
28582112379SRussell King	ret	ip
28682112379SRussell King#else
28782112379SRussell King	__mcount
28882112379SRussell King#endif
28982112379SRussell KingUNWIND(.fnend)
29082112379SRussell KingENDPROC(__gnu_mcount_nc)
29182112379SRussell King
29282112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
29382112379SRussell KingENTRY(ftrace_caller)
29482112379SRussell KingUNWIND(.fnstart)
29582112379SRussell King	__ftrace_caller
29682112379SRussell KingUNWIND(.fnend)
29782112379SRussell KingENDPROC(ftrace_caller)
298620176f3SAbel Vesa
299620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
300620176f3SAbel VesaENTRY(ftrace_regs_caller)
301620176f3SAbel VesaUNWIND(.fnstart)
302620176f3SAbel Vesa	__ftrace_regs_caller
303620176f3SAbel VesaUNWIND(.fnend)
304620176f3SAbel VesaENDPROC(ftrace_regs_caller)
305620176f3SAbel Vesa#endif
306620176f3SAbel Vesa
30782112379SRussell King#endif
30882112379SRussell King
30982112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
31082112379SRussell KingENTRY(ftrace_graph_caller)
31182112379SRussell KingUNWIND(.fnstart)
31282112379SRussell King	__ftrace_graph_caller
31382112379SRussell KingUNWIND(.fnend)
31482112379SRussell KingENDPROC(ftrace_graph_caller)
315620176f3SAbel Vesa
316620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
317620176f3SAbel VesaENTRY(ftrace_graph_regs_caller)
318620176f3SAbel VesaUNWIND(.fnstart)
319620176f3SAbel Vesa	__ftrace_graph_regs_caller
320620176f3SAbel VesaUNWIND(.fnend)
321620176f3SAbel VesaENDPROC(ftrace_graph_regs_caller)
322620176f3SAbel Vesa#endif
32382112379SRussell King#endif
32482112379SRussell King
32582112379SRussell King.purgem mcount_enter
32682112379SRussell King.purgem mcount_get_lr
32782112379SRussell King.purgem mcount_exit
32882112379SRussell King
32982112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
33082112379SRussell King	.globl return_to_handler
33182112379SRussell Kingreturn_to_handler:
33282112379SRussell King	stmdb	sp!, {r0-r3}
33382112379SRussell King	mov	r0, fp			@ frame pointer
33482112379SRussell King	bl	ftrace_return_to_handler
33582112379SRussell King	mov	lr, r0			@ r0 has real ret addr
33682112379SRussell King	ldmia	sp!, {r0-r3}
33782112379SRussell King	ret	lr
33882112379SRussell King#endif
33982112379SRussell King
34082112379SRussell KingENTRY(ftrace_stub)
34182112379SRussell King.Lftrace_stub:
34282112379SRussell King	ret	lr
34382112379SRussell KingENDPROC(ftrace_stub)
344