diff options
author | Mike Frysinger <vapier@gentoo.org> | 2010-07-21 09:13:02 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-08-06 12:55:54 -0400 |
commit | f5074429621ceb0ec42f8116bd51d02c031faf82 (patch) | |
tree | a5d22f85446c63be25961e2ea04321e197c615db /arch/blackfin/kernel/ftrace.c | |
parent | 67df6cc665dc3441bf5eb2ad7018e969463a2588 (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.c | 86 |
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 | |||
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 | ||
12 | 77 | ||
13 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 78 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
14 | 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 | |||
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. |