summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/mcount.S
blob: 0a9cfdb271dd2c2c92f0cb8f31930f84d73c6127 (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
/*
 * 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
 * Author: Wu Zhangjin <wuzj@lemote.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
#ifdef CONFIG_64BIT
	PTR_ADDIU	sp, PT_SIZE
#else
	PTR_ADDIU	sp, (PT_SIZE + 8)
#endif
.endm

	.macro RETURN_BACK
	jr ra
	 move ra, AT
	.endm

#ifdef CONFIG_DYNAMIC_FTRACE

NESTED(ftrace_caller, PT_SIZE, ra)
	.globl _mcount
_mcount:
	b	ftrace_stub
	 nop
	lw	t1, function_trace_stop
	bnez	t1, ftrace_stub
	 nop

	MCOUNT_SAVE_REGS
#ifdef KBUILD_MCOUNT_RA_ADDRESS
	PTR_S	t0, PT_R12(sp)	/* t0 saved the location of the return address(at) by -mmcount-ra-address */
#endif

	move	a0, ra		/* arg1: next ip, selfaddr */
	.globl ftrace_call
ftrace_call:
	nop	/* a placeholder for the call to a real tracing function */
	 move	a1, AT		/* arg2: the caller's next ip, parent */

#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)
	lw	t1, function_trace_stop
	bnez	t1, ftrace_stub
	 nop
	PTR_LA	t1, ftrace_stub
	PTR_L	t2, ftrace_trace_function /* Prepare t2 for (1) */
	bne	t1, t2, static_trace
	 nop

#ifdef	CONFIG_FUNCTION_GRAPH_TRACER
	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
	b	ftrace_stub
	 nop

static_trace:
	MCOUNT_SAVE_REGS

	move	a0, ra		/* arg1: next ip, selfaddr */
	jalr	t2		/* (1) call *ftrace_trace_function */
	 move	a1, AT		/* arg2: the caller's next ip, parent */

	MCOUNT_RESTORE_REGS
	.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)
#ifdef CONFIG_DYNAMIC_FTRACE
	PTR_L	a1, PT_R31(sp)	/* load the original ra from the stack */
#ifdef KBUILD_MCOUNT_RA_ADDRESS
	PTR_L	t0, PT_R12(sp)	/* load the original t0 from the stack */
#endif
#else
	MCOUNT_SAVE_REGS
	move	a1, ra		/* arg2: next ip, selfaddr */
#endif

#ifdef KBUILD_MCOUNT_RA_ADDRESS
	bnez	t0, 1f		/* non-leaf func: t0 saved the location of the return address */
	 nop
	PTR_LA	t0, PT_R1(sp)	/* leaf func: get the location of at(old ra) from our own stack */
1:	move	a0, t0		/* arg1: the location of the return address */
#else
	PTR_LA	a0, PT_R1(sp)	/* arg1: &AT -> a0 */
#endif
	jal	prepare_ftrace_return
#ifdef CONFIG_FRAME_POINTER
	 move	a2, fp		/* arg3: frame pointer */
#else
#ifdef CONFIG_64BIT
	 PTR_LA	a2, PT_SIZE(sp)
#else
	 PTR_LA	a2, (PT_SIZE+8)(sp)
#endif
#endif

	MCOUNT_RESTORE_REGS
	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