Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/microblaze/kernel/ftrace.c
10817 views
1
/*
2
* Ftrace support for Microblaze.
3
*
4
* Copyright (C) 2009 Michal Simek <[email protected]>
5
* Copyright (C) 2009 PetaLogix
6
*
7
* Based on MIPS and PowerPC ftrace code
8
*
9
* This file is subject to the terms and conditions of the GNU General Public
10
* License. See the file "COPYING" in the main directory of this archive
11
* for more details.
12
*/
13
14
#include <asm/cacheflush.h>
15
#include <linux/ftrace.h>
16
17
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
18
/*
19
* Hook the return address and push it in the stack of return addrs
20
* in current thread info.
21
*/
22
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
23
{
24
unsigned long old;
25
int faulted, err;
26
struct ftrace_graph_ent trace;
27
unsigned long return_hooker = (unsigned long)
28
&return_to_handler;
29
30
if (unlikely(atomic_read(&current->tracing_graph_pause)))
31
return;
32
33
/*
34
* Protect against fault, even if it shouldn't
35
* happen. This tool is too much intrusive to
36
* ignore such a protection.
37
*/
38
asm volatile(" 1: lwi %0, %2, 0; \
39
2: swi %3, %2, 0; \
40
addik %1, r0, 0; \
41
3: \
42
.section .fixup, \"ax\"; \
43
4: brid 3b; \
44
addik %1, r0, 1; \
45
.previous; \
46
.section __ex_table,\"a\"; \
47
.word 1b,4b; \
48
.word 2b,4b; \
49
.previous;" \
50
: "=&r" (old), "=r" (faulted)
51
: "r" (parent), "r" (return_hooker)
52
);
53
54
flush_dcache_range((u32)parent, (u32)parent + 4);
55
flush_icache_range((u32)parent, (u32)parent + 4);
56
57
if (unlikely(faulted)) {
58
ftrace_graph_stop();
59
WARN_ON(1);
60
return;
61
}
62
63
err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
64
if (err == -EBUSY) {
65
*parent = old;
66
return;
67
}
68
69
trace.func = self_addr;
70
/* Only trace if the calling function expects to */
71
if (!ftrace_graph_entry(&trace)) {
72
current->curr_ret_stack--;
73
*parent = old;
74
}
75
}
76
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
77
78
#ifdef CONFIG_DYNAMIC_FTRACE
79
/* save value to addr - it is save to do it in asm */
80
static int ftrace_modify_code(unsigned long addr, unsigned int value)
81
{
82
int faulted = 0;
83
84
__asm__ __volatile__(" 1: swi %2, %1, 0; \
85
addik %0, r0, 0; \
86
2: \
87
.section .fixup, \"ax\"; \
88
3: brid 2b; \
89
addik %0, r0, 1; \
90
.previous; \
91
.section __ex_table,\"a\"; \
92
.word 1b,3b; \
93
.previous;" \
94
: "=r" (faulted)
95
: "r" (addr), "r" (value)
96
);
97
98
if (unlikely(faulted))
99
return -EFAULT;
100
101
flush_dcache_range(addr, addr + 4);
102
flush_icache_range(addr, addr + 4);
103
104
return 0;
105
}
106
107
#define MICROBLAZE_NOP 0x80000000
108
#define MICROBLAZE_BRI 0xb800000C
109
110
static unsigned int recorded; /* if save was or not */
111
static unsigned int imm; /* saving whole imm instruction */
112
113
/* There are two approaches howto solve ftrace_make nop function - look below */
114
#undef USE_FTRACE_NOP
115
116
#ifdef USE_FTRACE_NOP
117
static unsigned int bralid; /* saving whole bralid instruction */
118
#endif
119
120
int ftrace_make_nop(struct module *mod,
121
struct dyn_ftrace *rec, unsigned long addr)
122
{
123
/* we have this part of code which we are working with
124
* b000c000 imm -16384
125
* b9fc8e30 bralid r15, -29136 // c0008e30 <_mcount>
126
* 80000000 or r0, r0, r0
127
*
128
* The first solution (!USE_FTRACE_NOP-could be called branch solution)
129
* b000c000 bri 12 (0xC - jump to any other instruction)
130
* b9fc8e30 bralid r15, -29136 // c0008e30 <_mcount>
131
* 80000000 or r0, r0, r0
132
* any other instruction
133
*
134
* The second solution (USE_FTRACE_NOP) - no jump just nops
135
* 80000000 or r0, r0, r0
136
* 80000000 or r0, r0, r0
137
* 80000000 or r0, r0, r0
138
*/
139
int ret = 0;
140
141
if (recorded == 0) {
142
recorded = 1;
143
imm = *(unsigned int *)rec->ip;
144
pr_debug("%s: imm:0x%x\n", __func__, imm);
145
#ifdef USE_FTRACE_NOP
146
bralid = *(unsigned int *)(rec->ip + 4);
147
pr_debug("%s: bralid 0x%x\n", __func__, bralid);
148
#endif /* USE_FTRACE_NOP */
149
}
150
151
#ifdef USE_FTRACE_NOP
152
ret = ftrace_modify_code(rec->ip, MICROBLAZE_NOP);
153
ret += ftrace_modify_code(rec->ip + 4, MICROBLAZE_NOP);
154
#else /* USE_FTRACE_NOP */
155
ret = ftrace_modify_code(rec->ip, MICROBLAZE_BRI);
156
#endif /* USE_FTRACE_NOP */
157
return ret;
158
}
159
160
/* I believe that first is called ftrace_make_nop before this function */
161
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
162
{
163
int ret;
164
pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
165
__func__, (unsigned int)addr, (unsigned int)rec->ip, imm);
166
ret = ftrace_modify_code(rec->ip, imm);
167
#ifdef USE_FTRACE_NOP
168
pr_debug("%s: bralid:0x%x\n", __func__, bralid);
169
ret += ftrace_modify_code(rec->ip + 4, bralid);
170
#endif /* USE_FTRACE_NOP */
171
return ret;
172
}
173
174
int __init ftrace_dyn_arch_init(void *data)
175
{
176
/* The return code is retured via data */
177
*(unsigned long *)data = 0;
178
179
return 0;
180
}
181
182
int ftrace_update_ftrace_func(ftrace_func_t func)
183
{
184
unsigned long ip = (unsigned long)(&ftrace_call);
185
unsigned int upper = (unsigned int)func;
186
unsigned int lower = (unsigned int)func;
187
int ret = 0;
188
189
/* create proper saving to ftrace_call poll */
190
upper = 0xb0000000 + (upper >> 16); /* imm func_upper */
191
lower = 0x32800000 + (lower & 0xFFFF); /* addik r20, r0, func_lower */
192
193
pr_debug("%s: func=0x%x, ip=0x%x, upper=0x%x, lower=0x%x\n",
194
__func__, (unsigned int)func, (unsigned int)ip, upper, lower);
195
196
/* save upper and lower code */
197
ret = ftrace_modify_code(ip, upper);
198
ret += ftrace_modify_code(ip + 4, lower);
199
200
/* We just need to replace the rtsd r15, 8 with NOP */
201
ret += ftrace_modify_code((unsigned long)&ftrace_caller,
202
MICROBLAZE_NOP);
203
204
return ret;
205
}
206
207
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
208
unsigned int old_jump; /* saving place for jump instruction */
209
210
int ftrace_enable_ftrace_graph_caller(void)
211
{
212
unsigned int ret;
213
unsigned long ip = (unsigned long)(&ftrace_call_graph);
214
215
old_jump = *(unsigned int *)ip; /* save jump over instruction */
216
ret = ftrace_modify_code(ip, MICROBLAZE_NOP);
217
218
pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump);
219
return ret;
220
}
221
222
int ftrace_disable_ftrace_graph_caller(void)
223
{
224
unsigned int ret;
225
unsigned long ip = (unsigned long)(&ftrace_call_graph);
226
227
ret = ftrace_modify_code(ip, old_jump);
228
229
pr_debug("%s\n", __func__);
230
return ret;
231
}
232
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
233
#endif /* CONFIG_DYNAMIC_FTRACE */
234
235