aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/ftrace.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2010-07-21 09:13:02 -0400
committerMike Frysinger <vapier@gentoo.org>2010-08-06 12:55:54 -0400
commitf5074429621ceb0ec42f8116bd51d02c031faf82 (patch)
treea5d22f85446c63be25961e2ea04321e197c615db /arch/blackfin/kernel/ftrace.c
parent67df6cc665dc3441bf5eb2ad7018e969463a2588 (diff)
Blackfin: add support for dynamic ftrace
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel/ftrace.c')
-rw-r--r--arch/blackfin/kernel/ftrace.c86
1 files changed, 85 insertions, 1 deletions
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
index a61d948ea925..48808a12b427 100644
--- a/arch/blackfin/kernel/ftrace.c
+++ b/arch/blackfin/kernel/ftrace.c
@@ -1,17 +1,101 @@
1/* 1/*
2 * ftrace graph code 2 * ftrace graph code
3 * 3 *
4 * Copyright (C) 2009 Analog Devices Inc. 4 * Copyright (C) 2009-2010 Analog Devices Inc.
5 * Licensed under the GPL-2 or later. 5 * Licensed under the GPL-2 or later.
6 */ 6 */
7 7
8#include <linux/ftrace.h> 8#include <linux/ftrace.h>
9#include <linux/kernel.h> 9#include <linux/kernel.h>
10#include <linux/sched.h> 10#include <linux/sched.h>
11#include <linux/uaccess.h>
11#include <asm/atomic.h> 12#include <asm/atomic.h>
13#include <asm/cacheflush.h>
14
15#ifdef CONFIG_DYNAMIC_FTRACE
16
17static const unsigned char mnop[] = {
18 0x03, 0xc0, 0x00, 0x18, /* MNOP; */
19 0x03, 0xc0, 0x00, 0x18, /* MNOP; */
20};
21
22static 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
33static 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
41int 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
48int 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
60int 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
68int __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
12 77
13#ifdef CONFIG_FUNCTION_GRAPH_TRACER 78#ifdef CONFIG_FUNCTION_GRAPH_TRACER
14 79
80# ifdef CONFIG_DYNAMIC_FTRACE
81
82extern void ftrace_graph_call(void);
83
84int 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
92int 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
15/* 99/*
16 * Hook the return address and push it in the stack of return addrs 100 * Hook the return address and push it in the stack of return addrs
17 * in current thread info. 101 * in current thread info.