Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/blackfin/kernel/ftrace.c
10817 views
1
/*
2
* ftrace graph code
3
*
4
* Copyright (C) 2009-2010 Analog Devices Inc.
5
* Licensed under the GPL-2 or later.
6
*/
7
8
#include <linux/ftrace.h>
9
#include <linux/kernel.h>
10
#include <linux/sched.h>
11
#include <linux/uaccess.h>
12
#include <asm/atomic.h>
13
#include <asm/cacheflush.h>
14
15
#ifdef CONFIG_DYNAMIC_FTRACE
16
17
static const unsigned char mnop[] = {
18
0x03, 0xc0, 0x00, 0x18, /* MNOP; */
19
0x03, 0xc0, 0x00, 0x18, /* MNOP; */
20
};
21
22
static void bfin_make_pcrel24(unsigned char *insn, unsigned long src,
23
unsigned long dst)
24
{
25
uint32_t pcrel = (dst - src) >> 1;
26
insn[0] = pcrel >> 16;
27
insn[1] = 0xe3;
28
insn[2] = pcrel;
29
insn[3] = pcrel >> 8;
30
}
31
#define bfin_make_pcrel24(insn, src, dst) bfin_make_pcrel24(insn, src, (unsigned long)(dst))
32
33
static int ftrace_modify_code(unsigned long ip, const unsigned char *code,
34
unsigned long len)
35
{
36
int ret = probe_kernel_write((void *)ip, (void *)code, len);
37
flush_icache_range(ip, ip + len);
38
return ret;
39
}
40
41
int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
42
unsigned long addr)
43
{
44
/* Turn the mcount call site into two MNOPs as those are 32bit insns */
45
return ftrace_modify_code(rec->ip, mnop, sizeof(mnop));
46
}
47
48
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
49
{
50
/* Restore the mcount call site */
51
unsigned char call[8];
52
call[0] = 0x67; /* [--SP] = RETS; */
53
call[1] = 0x01;
54
bfin_make_pcrel24(&call[2], rec->ip + 2, addr);
55
call[6] = 0x27; /* RETS = [SP++]; */
56
call[7] = 0x01;
57
return ftrace_modify_code(rec->ip, call, sizeof(call));
58
}
59
60
int ftrace_update_ftrace_func(ftrace_func_t func)
61
{
62
unsigned char call[4];
63
unsigned long ip = (unsigned long)&ftrace_call;
64
bfin_make_pcrel24(call, ip, func);
65
return ftrace_modify_code(ip, call, sizeof(call));
66
}
67
68
int __init ftrace_dyn_arch_init(void *data)
69
{
70
/* return value is done indirectly via data */
71
*(unsigned long *)data = 0;
72
73
return 0;
74
}
75
76
#endif
77
78
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
79
80
# ifdef CONFIG_DYNAMIC_FTRACE
81
82
extern void ftrace_graph_call(void);
83
84
int ftrace_enable_ftrace_graph_caller(void)
85
{
86
unsigned long ip = (unsigned long)&ftrace_graph_call;
87
uint16_t jump_pcrel12 = ((unsigned long)&ftrace_graph_caller - ip) >> 1;
88
jump_pcrel12 |= 0x2000;
89
return ftrace_modify_code(ip, (void *)&jump_pcrel12, sizeof(jump_pcrel12));
90
}
91
92
int ftrace_disable_ftrace_graph_caller(void)
93
{
94
return ftrace_modify_code((unsigned long)&ftrace_graph_call, empty_zero_page, 2);
95
}
96
97
# endif
98
99
/*
100
* Hook the return address and push it in the stack of return addrs
101
* in current thread info.
102
*/
103
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
104
unsigned long frame_pointer)
105
{
106
struct ftrace_graph_ent trace;
107
unsigned long return_hooker = (unsigned long)&return_to_handler;
108
109
if (unlikely(atomic_read(&current->tracing_graph_pause)))
110
return;
111
112
if (ftrace_push_return_trace(*parent, self_addr, &trace.depth,
113
frame_pointer) == -EBUSY)
114
return;
115
116
trace.func = self_addr;
117
118
/* Only trace if the calling function expects to */
119
if (!ftrace_graph_entry(&trace)) {
120
current->curr_ret_stack--;
121
return;
122
}
123
124
/* all is well in the world ! hijack RETS ... */
125
*parent = return_hooker;
126
}
127
128
#endif
129
130