summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/mcount.S
blob: 0df911e772ae0f55f0f46c964b1d1d699566b05b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * MIPS specific _mcount support
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive for
 * more details.
 *
 * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
 * Copyright (C) 2010 DSLab, Lanzhou University, China
 * Author: Wu Zhangjin <wuzhangjin@gmail.com>
 */

#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ftrace.h>

	.text
	.set noreorder
	.set noat

	.macro MCOUNT_SAVE_REGS
	PTR_SUBU	sp, PT_SIZE
	PTR_S	ra, PT_R31(sp)
	PTR_S	AT, PT_R1(sp)
	PTR_S	a0, PT_R4(sp)
	PTR_S	a1, PT_R5(sp)
	PTR_S	a2, PT_R6(sp)
	PTR_S	a3, PT_R7(sp)
#ifdef CONFIG_64BIT
	PTR_S	a4, PT_R8(sp)
	PTR_S	a5, PT_R9(sp)
	PTR_S	a6, PT_R10(sp)
	PTR_S	a7, PT_R11(sp)
#endif
	.endm

	.macro MCOUNT_RESTORE_REGS
	PTR_L	ra, PT_R31(sp)
	PTR_L	AT, PT_R1(sp)
	PTR_L	a0, PT_R4(sp)
	PTR_L	a1, PT_R5(sp)
	PTR_L	a2, PT_R6(sp)
	PTR_L	a3, PT_R7(sp)
#ifdef CONFIG_64BIT
	PTR_L	a4, PT_R8(sp)
	PTR_L	a5, PT_R9(sp)
	PTR_L	a6, PT_R10(sp)
	PTR_L	a7, PT_R11(sp)
#endif
	PTR_ADDIU	sp, PT_SIZE
	.endm

	.macro RETURN_BACK
	jr ra
	 move ra, AT
	.endm

/*
 * The -mmcount-ra-address option of gcc 4.5 uses register $12 to pass
 * the location of the parent's return address.
 */
#define MCOUNT_RA_ADDRESS_REG	$12

#ifdef CONFIG_DYNAMIC_FTRACE

NESTED(ftrace_caller, PT_SIZE, ra)
	.globl _mcount
_mcount:
	b	ftrace_stub
#ifdef CONFIG_32BIT
	 addiu sp,sp,8
#else
	 nop
#endif

	/* When tracing is activated, it calls ftrace_caller+8 (aka here) */
	MCOUNT_SAVE_REGS
#ifdef KBUILD_MCOUNT_RA_ADDRESS
	PTR_S	MCOUNT_RA_ADDRESS_REG, PT_R12(sp)
#endif

	PTR_SUBU a0, ra, 8	/* arg1: self address */
	PTR_LA   t1, _stext
	sltu     t2, a0, t1	/* t2 = (a0 < _stext) */
	PTR_LA   t1, _etext
	sltu     t3, t1, a0	/* t3 = (a0 > _etext) */
	or       t1, t2, t3
	beqz     t1, ftrace_call
	 nop
#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
	PTR_SUBU a0, a0, 16	/* arg1: adjust to module's recorded callsite */
#else
	PTR_SUBU a0, a0, 12
#endif

	.globl ftrace_call
ftrace_call:
	nop	/* a placeholder for the call to a real tracing function */
	 move	a1, AT		/* arg2: parent's return address */

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	.globl ftrace_graph_call
ftrace_graph_call:
	nop
	 nop
#endif

	MCOUNT_RESTORE_REGS
	.globl ftrace_stub
ftrace_stub:
	RETURN_BACK
	END(ftrace_caller)

#else	/* ! CONFIG_DYNAMIC_FTRACE */

NESTED(_mcount, PT_SIZE, ra)
	PTR_LA	t1, ftrace_stub
	PTR_L	t2, ftrace_trace_function /* Prepare t2 for (1) */
	beq	t1, t2, fgraph_trace
	 nop

	MCOUNT_SAVE_REGS

	move	a0, ra		/* arg1: self return address */
	jalr	t2		/* (1) call *ftrace_trace_function */
	 move	a1, AT		/* arg2: parent's return address */

	MCOUNT_RESTORE_REGS

fgraph_trace:
#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
	PTR_LA	t1, ftrace_stub
	PTR_L	t3, ftrace_graph_return
	bne	t1, t3, ftrace_graph_caller
	 nop
	PTR_LA	t1, ftrace_graph_entry_stub
	PTR_L	t3, ftrace_graph_entry
	bne	t1, t3, ftrace_graph_caller
	 nop
#endif

#ifdef CONFIG_32BIT
	addiu sp, sp, 8
#endif

	.globl ftrace_stub
ftrace_stub:
	RETURN_BACK
	END(_mcount)

#endif	/* ! CONFIG_DYNAMIC_FTRACE */

#ifdef CONFIG_FUNCTION_GRAPH_TRACER

NESTED(ftrace_graph_caller, PT_SIZE, ra)
#ifndef CONFIG_DYNAMIC_FTRACE
	MCOUNT_SAVE_REGS
#endif

	/* arg1: Get the location of the parent's return address */
#ifdef KBUILD_MCOUNT_RA_ADDRESS
#ifdef CONFIG_DYNAMIC_FTRACE
	PTR_L	a0, PT_R12(sp)
#else
	move	a0, MCOUNT_RA_ADDRESS_REG
#endif
	bnez	a0, 1f	/* non-leaf func: stored in MCOUNT_RA_ADDRESS_REG */
	 nop
#endif
	PTR_LA	a0, PT_R1(sp)	/* leaf func: the location in current stack */
1:

	/* arg2: Get self return address */
#ifdef CONFIG_DYNAMIC_FTRACE
	PTR_L	a1, PT_R31(sp)
#else
	move	a1, ra
#endif

	/* arg3: Get frame pointer of current stack */
#ifdef CONFIG_64BIT
	PTR_LA	a2, PT_SIZE(sp)
#else
	PTR_LA	a2, (PT_SIZE+8)(sp)
#endif

	jal	prepare_ftrace_return
	 nop
	MCOUNT_RESTORE_REGS
#ifndef CONFIG_DYNAMIC_FTRACE
#ifdef CONFIG_32BIT
	addiu sp, sp, 8
#endif
#endif
	RETURN_BACK
	END(ftrace_graph_caller)

	.align	2
	.globl	return_to_handler
return_to_handler:
	PTR_SUBU	sp, PT_SIZE
	PTR_S	v0, PT_R2(sp)

	jal	ftrace_return_to_handler
	 PTR_S	v1, PT_R3(sp)

	/* restore the real parent address: v0 -> ra */
	move	ra, v0

	PTR_L	v0, PT_R2(sp)
	PTR_L	v1, PT_R3(sp)
	jr	ra
	 PTR_ADDIU	sp, PT_SIZE
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

	.set at
	.set reorder