diff options
Diffstat (limited to 'arch/arm/kernel/ftrace.c')
-rw-r--r-- | arch/arm/kernel/ftrace.c | 61 |
1 files changed, 4 insertions, 57 deletions
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 5c9cecfaeb21..df0bf0c8cb79 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <asm/opcodes.h> | 19 | #include <asm/opcodes.h> |
20 | #include <asm/ftrace.h> | 20 | #include <asm/ftrace.h> |
21 | 21 | ||
22 | #include "insn.h" | ||
23 | |||
22 | #ifdef CONFIG_THUMB2_KERNEL | 24 | #ifdef CONFIG_THUMB2_KERNEL |
23 | #define NOP 0xf85deb04 /* pop.w {lr} */ | 25 | #define NOP 0xf85deb04 /* pop.w {lr} */ |
24 | #else | 26 | #else |
@@ -61,64 +63,9 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) | |||
61 | } | 63 | } |
62 | #endif | 64 | #endif |
63 | 65 | ||
64 | #ifdef CONFIG_THUMB2_KERNEL | ||
65 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
66 | bool link) | ||
67 | { | ||
68 | unsigned long s, j1, j2, i1, i2, imm10, imm11; | ||
69 | unsigned long first, second; | ||
70 | long offset; | ||
71 | |||
72 | offset = (long)addr - (long)(pc + 4); | ||
73 | if (offset < -16777216 || offset > 16777214) { | ||
74 | WARN_ON_ONCE(1); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | s = (offset >> 24) & 0x1; | ||
79 | i1 = (offset >> 23) & 0x1; | ||
80 | i2 = (offset >> 22) & 0x1; | ||
81 | imm10 = (offset >> 12) & 0x3ff; | ||
82 | imm11 = (offset >> 1) & 0x7ff; | ||
83 | |||
84 | j1 = (!i1) ^ s; | ||
85 | j2 = (!i2) ^ s; | ||
86 | |||
87 | first = 0xf000 | (s << 10) | imm10; | ||
88 | second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; | ||
89 | if (link) | ||
90 | second |= 1 << 14; | ||
91 | |||
92 | return __opcode_thumb32_compose(first, second); | ||
93 | } | ||
94 | #else | ||
95 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
96 | bool link) | ||
97 | { | ||
98 | unsigned long opcode = 0xea000000; | ||
99 | long offset; | ||
100 | |||
101 | if (link) | ||
102 | opcode |= 1 << 24; | ||
103 | |||
104 | offset = (long)addr - (long)(pc + 8); | ||
105 | if (unlikely(offset < -33554432 || offset > 33554428)) { | ||
106 | /* Can't generate branches that far (from ARM ARM). Ftrace | ||
107 | * doesn't generate branches outside of kernel text. | ||
108 | */ | ||
109 | WARN_ON_ONCE(1); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | offset = (offset >> 2) & 0x00ffffff; | ||
114 | |||
115 | return opcode | offset; | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) | 66 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) |
120 | { | 67 | { |
121 | return ftrace_gen_branch(pc, addr, true); | 68 | return arm_gen_branch_link(pc, addr); |
122 | } | 69 | } |
123 | 70 | ||
124 | static int ftrace_modify_code(unsigned long pc, unsigned long old, | 71 | static int ftrace_modify_code(unsigned long pc, unsigned long old, |
@@ -258,7 +205,7 @@ static int __ftrace_modify_caller(unsigned long *callsite, | |||
258 | { | 205 | { |
259 | unsigned long caller_fn = (unsigned long) func; | 206 | unsigned long caller_fn = (unsigned long) func; |
260 | unsigned long pc = (unsigned long) callsite; | 207 | unsigned long pc = (unsigned long) callsite; |
261 | unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); | 208 | unsigned long branch = arm_gen_branch(pc, caller_fn); |
262 | unsigned long nop = 0xe1a00000; /* mov r0, r0 */ | 209 | unsigned long nop = 0xe1a00000; /* mov r0, r0 */ |
263 | unsigned long old = enable ? nop : branch; | 210 | unsigned long old = enable ? nop : branch; |
264 | unsigned long new = enable ? branch : nop; | 211 | unsigned long new = enable ? branch : nop; |