xref: /openbmc/linux/arch/arm/kernel/entry-ftrace.S (revision d3c61619)
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 *
18d3c61619SStefan Agner * Newer GCCs (4.4+) solve this problem by using a version of mcount with call
19d3c61619SStefan Agner * sites like:
2082112379SRussell King *
2182112379SRussell King *	push	{lr}
2282112379SRussell King *	bl	__gnu_mcount_nc
2382112379SRussell King *
2482112379SRussell King * With these compilers, frame pointers are not necessary.
2582112379SRussell King *
2682112379SRussell King * mcount can be thought of as a function called in the middle of a subroutine
2782112379SRussell King * call.  As such, it needs to be transparent for both the caller and the
2882112379SRussell King * callee: the original lr needs to be restored when leaving mcount, and no
2982112379SRussell King * registers should be clobbered.  (In the __gnu_mcount_nc implementation, we
3082112379SRussell King * clobber the ip register.  This is OK because the ARM calling convention
3182112379SRussell King * allows it to be clobbered in subroutines and doesn't use it to hold
3282112379SRussell King * parameters.)
3382112379SRussell King *
34d3c61619SStefan Agner * When using dynamic ftrace, we patch out the mcount call by a "pop {lr}"
35d3c61619SStefan Agner * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
3682112379SRussell King */
3782112379SRussell King
3882112379SRussell King.macro mcount_adjust_addr rd, rn
3982112379SRussell King	bic	\rd, \rn, #1		@ clear the Thumb bit if present
4082112379SRussell King	sub	\rd, \rd, #MCOUNT_INSN_SIZE
4182112379SRussell King.endm
4282112379SRussell King
4382112379SRussell King.macro __mcount suffix
4482112379SRussell King	mcount_enter
4582112379SRussell King	ldr	r0, =ftrace_trace_function
4682112379SRussell King	ldr	r2, [r0]
4782112379SRussell King	adr	r0, .Lftrace_stub
4882112379SRussell King	cmp	r0, r2
4982112379SRussell King	bne	1f
5082112379SRussell King
5182112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
5282112379SRussell King	ldr     r1, =ftrace_graph_return
5382112379SRussell King	ldr     r2, [r1]
5482112379SRussell King	cmp     r0, r2
5582112379SRussell King	bne     ftrace_graph_caller\suffix
5682112379SRussell King
5782112379SRussell King	ldr     r1, =ftrace_graph_entry
5882112379SRussell King	ldr     r2, [r1]
5982112379SRussell King	ldr     r0, =ftrace_graph_entry_stub
6082112379SRussell King	cmp     r0, r2
6182112379SRussell King	bne     ftrace_graph_caller\suffix
6282112379SRussell King#endif
6382112379SRussell King
6482112379SRussell King	mcount_exit
6582112379SRussell King
6682112379SRussell King1: 	mcount_get_lr	r1			@ lr of instrumented func
6782112379SRussell King	mcount_adjust_addr	r0, lr		@ instrumented function
6814327c66SRussell King	badr	lr, 2f
6982112379SRussell King	mov	pc, r2
7082112379SRussell King2:	mcount_exit
7182112379SRussell King.endm
7282112379SRussell King
73620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
74620176f3SAbel Vesa
75620176f3SAbel Vesa.macro __ftrace_regs_caller
76620176f3SAbel Vesa
77620176f3SAbel Vesa	sub	sp, sp, #8	@ space for PC and CPSR OLD_R0,
78620176f3SAbel Vesa				@ OLD_R0 will overwrite previous LR
79620176f3SAbel Vesa
80620176f3SAbel Vesa	add 	ip, sp, #12	@ move in IP the value of SP as it was
81620176f3SAbel Vesa				@ before the push {lr} of the mcount mechanism
82620176f3SAbel Vesa
83620176f3SAbel Vesa	str     lr, [sp, #0]    @ store LR instead of PC
84620176f3SAbel Vesa
85620176f3SAbel Vesa	ldr     lr, [sp, #8]    @ get previous LR
86620176f3SAbel Vesa
87620176f3SAbel Vesa	str	r0, [sp, #8]	@ write r0 as OLD_R0 over previous LR
88620176f3SAbel Vesa
89620176f3SAbel Vesa	stmdb   sp!, {ip, lr}
90620176f3SAbel Vesa	stmdb   sp!, {r0-r11, lr}
91620176f3SAbel Vesa
92620176f3SAbel Vesa	@ stack content at this point:
93620176f3SAbel Vesa	@ 0  4          48   52       56            60   64    68       72
94620176f3SAbel Vesa	@ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 |
95620176f3SAbel Vesa
96620176f3SAbel Vesa	mov r3, sp				@ struct pt_regs*
97620176f3SAbel Vesa
98620176f3SAbel Vesa	ldr r2, =function_trace_op
99620176f3SAbel Vesa	ldr r2, [r2]				@ pointer to the current
100620176f3SAbel Vesa						@ function tracing op
101620176f3SAbel Vesa
102620176f3SAbel Vesa	ldr	r1, [sp, #S_LR]			@ lr of instrumented func
103620176f3SAbel Vesa
104620176f3SAbel Vesa	ldr	lr, [sp, #S_PC]			@ get LR
105620176f3SAbel Vesa
106620176f3SAbel Vesa	mcount_adjust_addr	r0, lr		@ instrumented function
107620176f3SAbel Vesa
108620176f3SAbel Vesa	.globl ftrace_regs_call
109620176f3SAbel Vesaftrace_regs_call:
110620176f3SAbel Vesa	bl	ftrace_stub
111620176f3SAbel Vesa
112620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER
113620176f3SAbel Vesa	.globl ftrace_graph_regs_call
114620176f3SAbel Vesaftrace_graph_regs_call:
115620176f3SAbel Vesa	mov	r0, r0
116620176f3SAbel Vesa#endif
117620176f3SAbel Vesa
118620176f3SAbel Vesa	@ pop saved regs
119620176f3SAbel Vesa	ldmia   sp!, {r0-r12}			@ restore r0 through r12
120620176f3SAbel Vesa	ldr	ip, [sp, #8]			@ restore PC
121620176f3SAbel Vesa	ldr	lr, [sp, #4]			@ restore LR
122620176f3SAbel Vesa	ldr	sp, [sp, #0]			@ restore SP
123620176f3SAbel Vesa	mov	pc, ip				@ return
124620176f3SAbel Vesa.endm
125620176f3SAbel Vesa
126620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER
127620176f3SAbel Vesa.macro __ftrace_graph_regs_caller
128620176f3SAbel Vesa
129620176f3SAbel Vesa	sub     r0, fp, #4              @ lr of instrumented routine (parent)
130620176f3SAbel Vesa
131620176f3SAbel Vesa	@ called from __ftrace_regs_caller
132620176f3SAbel Vesa	ldr     r1, [sp, #S_PC]		@ instrumented routine (func)
133620176f3SAbel Vesa	mcount_adjust_addr	r1, r1
134620176f3SAbel Vesa
135620176f3SAbel Vesa	mov	r2, fp			@ frame pointer
136620176f3SAbel Vesa	bl	prepare_ftrace_return
137620176f3SAbel Vesa
138620176f3SAbel Vesa	@ pop registers saved in ftrace_regs_caller
139620176f3SAbel Vesa	ldmia   sp!, {r0-r12}			@ restore r0 through r12
140620176f3SAbel Vesa	ldr	ip, [sp, #8]			@ restore PC
141620176f3SAbel Vesa	ldr	lr, [sp, #4]			@ restore LR
142620176f3SAbel Vesa	ldr	sp, [sp, #0]			@ restore SP
143620176f3SAbel Vesa	mov	pc, ip				@ return
144620176f3SAbel Vesa
145620176f3SAbel Vesa.endm
146620176f3SAbel Vesa#endif
147620176f3SAbel Vesa#endif
148620176f3SAbel Vesa
14982112379SRussell King.macro __ftrace_caller suffix
15082112379SRussell King	mcount_enter
15182112379SRussell King
15282112379SRussell King	mcount_get_lr	r1			@ lr of instrumented func
15382112379SRussell King	mcount_adjust_addr	r0, lr		@ instrumented function
15482112379SRussell King
155620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
156620176f3SAbel Vesa	ldr r2, =function_trace_op
157620176f3SAbel Vesa	ldr r2, [r2]				@ pointer to the current
158620176f3SAbel Vesa						@ function tracing op
159620176f3SAbel Vesa	mov r3, #0				@ regs is NULL
160620176f3SAbel Vesa#endif
161620176f3SAbel Vesa
16282112379SRussell King	.globl ftrace_call\suffix
16382112379SRussell Kingftrace_call\suffix:
16482112379SRussell King	bl	ftrace_stub
16582112379SRussell King
16682112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
16782112379SRussell King	.globl ftrace_graph_call\suffix
16882112379SRussell Kingftrace_graph_call\suffix:
16982112379SRussell King	mov	r0, r0
17082112379SRussell King#endif
17182112379SRussell King
17282112379SRussell King	mcount_exit
17382112379SRussell King.endm
17482112379SRussell King
17582112379SRussell King.macro __ftrace_graph_caller
17682112379SRussell King	sub	r0, fp, #4		@ &lr of instrumented routine (&parent)
17782112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
17882112379SRussell King	@ called from __ftrace_caller, saved in mcount_enter
17982112379SRussell King	ldr	r1, [sp, #16]		@ instrumented routine (func)
18082112379SRussell King	mcount_adjust_addr	r1, r1
18182112379SRussell King#else
18282112379SRussell King	@ called from __mcount, untouched in lr
18382112379SRussell King	mcount_adjust_addr	r1, lr	@ instrumented routine (func)
18482112379SRussell King#endif
18582112379SRussell King	mov	r2, fp			@ frame pointer
18682112379SRussell King	bl	prepare_ftrace_return
18782112379SRussell King	mcount_exit
18882112379SRussell King.endm
18982112379SRussell King
19082112379SRussell King/*
19182112379SRussell King * __gnu_mcount_nc
19282112379SRussell King */
19382112379SRussell King
19482112379SRussell King.macro mcount_enter
19582112379SRussell King/*
19682112379SRussell King * This pad compensates for the push {lr} at the call site.  Note that we are
19782112379SRussell King * unable to unwind through a function which does not otherwise save its lr.
19882112379SRussell King */
19982112379SRussell King UNWIND(.pad	#4)
20082112379SRussell King	stmdb	sp!, {r0-r3, lr}
20182112379SRussell King UNWIND(.save	{r0-r3, lr})
20282112379SRussell King.endm
20382112379SRussell King
20482112379SRussell King.macro mcount_get_lr reg
20582112379SRussell King	ldr	\reg, [sp, #20]
20682112379SRussell King.endm
20782112379SRussell King
20882112379SRussell King.macro mcount_exit
20982112379SRussell King	ldmia	sp!, {r0-r3, ip, lr}
21082112379SRussell King	ret	ip
21182112379SRussell King.endm
21282112379SRussell King
21382112379SRussell KingENTRY(__gnu_mcount_nc)
21482112379SRussell KingUNWIND(.fnstart)
21582112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
21682112379SRussell King	mov	ip, lr
21782112379SRussell King	ldmia	sp!, {lr}
21882112379SRussell King	ret	ip
21982112379SRussell King#else
22082112379SRussell King	__mcount
22182112379SRussell King#endif
22282112379SRussell KingUNWIND(.fnend)
22382112379SRussell KingENDPROC(__gnu_mcount_nc)
22482112379SRussell King
22582112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE
22682112379SRussell KingENTRY(ftrace_caller)
22782112379SRussell KingUNWIND(.fnstart)
22882112379SRussell King	__ftrace_caller
22982112379SRussell KingUNWIND(.fnend)
23082112379SRussell KingENDPROC(ftrace_caller)
231620176f3SAbel Vesa
232620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
233620176f3SAbel VesaENTRY(ftrace_regs_caller)
234620176f3SAbel VesaUNWIND(.fnstart)
235620176f3SAbel Vesa	__ftrace_regs_caller
236620176f3SAbel VesaUNWIND(.fnend)
237620176f3SAbel VesaENDPROC(ftrace_regs_caller)
238620176f3SAbel Vesa#endif
239620176f3SAbel Vesa
24082112379SRussell King#endif
24182112379SRussell King
24282112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
24382112379SRussell KingENTRY(ftrace_graph_caller)
24482112379SRussell KingUNWIND(.fnstart)
24582112379SRussell King	__ftrace_graph_caller
24682112379SRussell KingUNWIND(.fnend)
24782112379SRussell KingENDPROC(ftrace_graph_caller)
248620176f3SAbel Vesa
249620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
250620176f3SAbel VesaENTRY(ftrace_graph_regs_caller)
251620176f3SAbel VesaUNWIND(.fnstart)
252620176f3SAbel Vesa	__ftrace_graph_regs_caller
253620176f3SAbel VesaUNWIND(.fnend)
254620176f3SAbel VesaENDPROC(ftrace_graph_regs_caller)
255620176f3SAbel Vesa#endif
25682112379SRussell King#endif
25782112379SRussell King
25882112379SRussell King.purgem mcount_enter
25982112379SRussell King.purgem mcount_get_lr
26082112379SRussell King.purgem mcount_exit
26182112379SRussell King
26282112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER
26382112379SRussell King	.globl return_to_handler
26482112379SRussell Kingreturn_to_handler:
26582112379SRussell King	stmdb	sp!, {r0-r3}
26682112379SRussell King	mov	r0, fp			@ frame pointer
26782112379SRussell King	bl	ftrace_return_to_handler
26882112379SRussell King	mov	lr, r0			@ r0 has real ret addr
26982112379SRussell King	ldmia	sp!, {r0-r3}
27082112379SRussell King	ret	lr
27182112379SRussell King#endif
27282112379SRussell King
27382112379SRussell KingENTRY(ftrace_stub)
27482112379SRussell King.Lftrace_stub:
27582112379SRussell King	ret	lr
27682112379SRussell KingENDPROC(ftrace_stub)
277