xref: /OK3568_Linux_fs/kernel/arch/microblaze/kernel/mcount.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/*
2*4882a593Smuzhiyun * Low-level ftrace handling
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
5*4882a593Smuzhiyun * Copyright (C) 2009 PetaLogix
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General
8*4882a593Smuzhiyun * Public License. See the file COPYING in the main directory of this
9*4882a593Smuzhiyun * archive for more details.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun#include <linux/linkage.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun#define NOALIGN_ENTRY(name)	.globl name; name:
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun/* FIXME MS: I think that I don't need to save all regs */
17*4882a593Smuzhiyun#define SAVE_REGS		\
18*4882a593Smuzhiyun	addik	r1, r1, -120;	\
19*4882a593Smuzhiyun	swi	r2, r1, 4;	\
20*4882a593Smuzhiyun	swi	r3, r1, 8;	\
21*4882a593Smuzhiyun	swi	r4, r1, 12;	\
22*4882a593Smuzhiyun	swi	r5, r1, 116;	\
23*4882a593Smuzhiyun	swi	r6, r1, 16;	\
24*4882a593Smuzhiyun	swi	r7, r1, 20;	\
25*4882a593Smuzhiyun	swi	r8, r1, 24;	\
26*4882a593Smuzhiyun	swi	r9, r1, 28;	\
27*4882a593Smuzhiyun	swi	r10, r1, 32;	\
28*4882a593Smuzhiyun	swi	r11, r1, 36;	\
29*4882a593Smuzhiyun	swi	r12, r1, 40;	\
30*4882a593Smuzhiyun	swi	r13, r1, 44;	\
31*4882a593Smuzhiyun	swi	r14, r1, 48;	\
32*4882a593Smuzhiyun	swi	r16, r1, 52;	\
33*4882a593Smuzhiyun	swi	r17, r1, 56;	\
34*4882a593Smuzhiyun	swi	r18, r1, 60;	\
35*4882a593Smuzhiyun	swi	r19, r1, 64;	\
36*4882a593Smuzhiyun	swi	r20, r1, 68;	\
37*4882a593Smuzhiyun	swi	r21, r1, 72;	\
38*4882a593Smuzhiyun	swi	r22, r1, 76;	\
39*4882a593Smuzhiyun	swi	r23, r1, 80;	\
40*4882a593Smuzhiyun	swi	r24, r1, 84;	\
41*4882a593Smuzhiyun	swi	r25, r1, 88;	\
42*4882a593Smuzhiyun	swi	r26, r1, 92;	\
43*4882a593Smuzhiyun	swi	r27, r1, 96;	\
44*4882a593Smuzhiyun	swi	r28, r1, 100;	\
45*4882a593Smuzhiyun	swi	r29, r1, 104;	\
46*4882a593Smuzhiyun	swi	r30, r1, 108;	\
47*4882a593Smuzhiyun	swi	r31, r1, 112;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun#define RESTORE_REGS		\
50*4882a593Smuzhiyun	lwi	r2, r1, 4;	\
51*4882a593Smuzhiyun	lwi	r3, r1, 8;	\
52*4882a593Smuzhiyun	lwi	r4, r1, 12;	\
53*4882a593Smuzhiyun	lwi	r5, r1, 116;	\
54*4882a593Smuzhiyun	lwi	r6, r1, 16;	\
55*4882a593Smuzhiyun	lwi	r7, r1, 20;	\
56*4882a593Smuzhiyun	lwi	r8, r1, 24;	\
57*4882a593Smuzhiyun	lwi	r9, r1, 28;	\
58*4882a593Smuzhiyun	lwi	r10, r1, 32;	\
59*4882a593Smuzhiyun	lwi	r11, r1, 36;	\
60*4882a593Smuzhiyun	lwi	r12, r1, 40;	\
61*4882a593Smuzhiyun	lwi	r13, r1, 44;	\
62*4882a593Smuzhiyun	lwi	r14, r1, 48;	\
63*4882a593Smuzhiyun	lwi	r16, r1, 52;	\
64*4882a593Smuzhiyun	lwi	r17, r1, 56;	\
65*4882a593Smuzhiyun	lwi	r18, r1, 60;	\
66*4882a593Smuzhiyun	lwi	r19, r1, 64;	\
67*4882a593Smuzhiyun	lwi	r20, r1, 68;	\
68*4882a593Smuzhiyun	lwi	r21, r1, 72;	\
69*4882a593Smuzhiyun	lwi	r22, r1, 76;	\
70*4882a593Smuzhiyun	lwi	r23, r1, 80;	\
71*4882a593Smuzhiyun	lwi	r24, r1, 84;	\
72*4882a593Smuzhiyun	lwi	r25, r1, 88;	\
73*4882a593Smuzhiyun	lwi	r26, r1, 92;	\
74*4882a593Smuzhiyun	lwi	r27, r1, 96;	\
75*4882a593Smuzhiyun	lwi	r28, r1, 100;	\
76*4882a593Smuzhiyun	lwi	r29, r1, 104;	\
77*4882a593Smuzhiyun	lwi	r30, r1, 108;	\
78*4882a593Smuzhiyun	lwi	r31, r1, 112;	\
79*4882a593Smuzhiyun	addik	r1, r1, 120;
80*4882a593Smuzhiyun
81*4882a593SmuzhiyunENTRY(ftrace_stub)
82*4882a593Smuzhiyun	rtsd	r15, 8;
83*4882a593Smuzhiyun	nop;
84*4882a593Smuzhiyun
85*4882a593SmuzhiyunENTRY(_mcount)
86*4882a593Smuzhiyun#ifdef CONFIG_DYNAMIC_FTRACE
87*4882a593SmuzhiyunENTRY(ftrace_caller)
88*4882a593Smuzhiyun	/* MS: It is just barrier which is removed from C code */
89*4882a593Smuzhiyun	rtsd	r15, 8
90*4882a593Smuzhiyun	nop
91*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */
92*4882a593Smuzhiyun	SAVE_REGS
93*4882a593Smuzhiyun	swi	r15, r1, 0;
94*4882a593Smuzhiyun#ifdef CONFIG_FUNCTION_GRAPH_TRACER
95*4882a593Smuzhiyun#ifndef CONFIG_DYNAMIC_FTRACE
96*4882a593Smuzhiyun	lwi	r5, r0, ftrace_graph_return;
97*4882a593Smuzhiyun	addik	r6, r0, ftrace_stub; /* asm implementation */
98*4882a593Smuzhiyun	cmpu	r5, r5, r6; /* ftrace_graph_return != ftrace_stub */
99*4882a593Smuzhiyun	beqid	r5, end_graph_tracer;
100*4882a593Smuzhiyun	nop;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun	lwi	r6, r0, ftrace_graph_entry;
103*4882a593Smuzhiyun	addik	r5, r0, ftrace_graph_entry_stub; /* implemented in C */
104*4882a593Smuzhiyun	cmpu	r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */
105*4882a593Smuzhiyun	beqid	r5, end_graph_tracer;
106*4882a593Smuzhiyun	nop;
107*4882a593Smuzhiyun#else /* CONFIG_DYNAMIC_FTRACE */
108*4882a593SmuzhiyunNOALIGN_ENTRY(ftrace_call_graph)
109*4882a593Smuzhiyun	/* MS: jump over graph function - replaced from C code */
110*4882a593Smuzhiyun	bri	end_graph_tracer
111*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */
112*4882a593Smuzhiyun	addik	r5, r1, 120; /* MS: load parent addr */
113*4882a593Smuzhiyun	addik	r6, r15, 0; /* MS: load current function addr */
114*4882a593Smuzhiyun	bralid	r15, prepare_ftrace_return;
115*4882a593Smuzhiyun	nop;
116*4882a593Smuzhiyun	/* MS: graph was taken that's why - can jump over function trace */
117*4882a593Smuzhiyun	brid	end;
118*4882a593Smuzhiyun	nop;
119*4882a593Smuzhiyunend_graph_tracer:
120*4882a593Smuzhiyun#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
121*4882a593Smuzhiyun#ifndef CONFIG_DYNAMIC_FTRACE
122*4882a593Smuzhiyun	/* MS: test function trace if is taken or not */
123*4882a593Smuzhiyun	lwi	r20, r0, ftrace_trace_function;
124*4882a593Smuzhiyun	addik	r6, r0, ftrace_stub;
125*4882a593Smuzhiyun	cmpu	r5, r20, r6; /* ftrace_trace_function != ftrace_stub */
126*4882a593Smuzhiyun	beqid	r5, end; /* MS: not taken -> jump over */
127*4882a593Smuzhiyun	nop;
128*4882a593Smuzhiyun#else /* CONFIG_DYNAMIC_FTRACE */
129*4882a593SmuzhiyunNOALIGN_ENTRY(ftrace_call)
130*4882a593Smuzhiyun/* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */
131*4882a593Smuzhiyun	nop
132*4882a593Smuzhiyun	nop
133*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */
134*4882a593Smuzhiyun/* static normal trace */
135*4882a593Smuzhiyun	lwi	r6, r1, 120; /* MS: load parent addr */
136*4882a593Smuzhiyun	addik	r5, r15, -4; /* MS: load current function addr */
137*4882a593Smuzhiyun	/* MS: here is dependency on previous code */
138*4882a593Smuzhiyun	brald	r15, r20; /* MS: jump to ftrace handler */
139*4882a593Smuzhiyun	nop;
140*4882a593Smuzhiyunend:
141*4882a593Smuzhiyun	lwi	r15, r1, 0;
142*4882a593Smuzhiyun	RESTORE_REGS
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun	rtsd	r15, 8; /* MS: jump back */
145*4882a593Smuzhiyun	nop;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun#ifdef CONFIG_FUNCTION_GRAPH_TRACER
148*4882a593SmuzhiyunENTRY(return_to_handler)
149*4882a593Smuzhiyun	nop; /* MS: just barrier for rtsd r15, 8 */
150*4882a593Smuzhiyun	nop;
151*4882a593Smuzhiyun	SAVE_REGS
152*4882a593Smuzhiyun	swi	r15, r1, 0;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun	/* MS: find out returning address */
155*4882a593Smuzhiyun	bralid	r15, ftrace_return_to_handler;
156*4882a593Smuzhiyun	nop;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun	/* MS: return value from ftrace_return_to_handler is my returning addr
159*4882a593Smuzhiyun	 * must be before restore regs because I have to restore r3 content */
160*4882a593Smuzhiyun	addik	r15, r3, 0;
161*4882a593Smuzhiyun	RESTORE_REGS
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun	rtsd	r15, 8; /* MS: jump back */
164*4882a593Smuzhiyun	nop;
165*4882a593Smuzhiyun#endif	/* CONFIG_FUNCTION_TRACER */
166