ARM: 7331/1: extract out insn generation code from ftrace
authorRabin Vincent <rabin@rab.in>
Sat, 18 Feb 2012 16:50:06 +0000 (17:50 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 24 Mar 2012 09:38:55 +0000 (09:38 +0000)
Extract out the instruction generation code so that it can be used
for jump labels too.

Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/Makefile
arch/arm/kernel/ftrace.c
arch/arm/kernel/insn.c [new file with mode: 0644]
arch/arm/kernel/insn.h [new file with mode: 0644]

index 43b740d..dd3d5f1 100644 (file)
@@ -7,6 +7,7 @@ AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_insn.o = -pg
 endif
 
 CFLAGS_REMOVE_return_address.o = -pg
@@ -34,8 +35,8 @@ obj-$(CONFIG_HAVE_SCHED_CLOCK)        += sched_clock.o
 obj-$(CONFIG_SMP)              += smp.o smp_tlb.o
 obj-$(CONFIG_HAVE_ARM_SCU)     += smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)     += smp_twd.o
-obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o
-obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
+obj-$(CONFIG_DYNAMIC_FTRACE)   += ftrace.o insn.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o insn.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)          += kprobes.o kprobes-common.o
 ifdef CONFIG_THUMB2_KERNEL
index 5c9cecf..df0bf0c 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/opcodes.h>
 #include <asm/ftrace.h>
 
+#include "insn.h"
+
 #ifdef CONFIG_THUMB2_KERNEL
 #define        NOP             0xf85deb04      /* pop.w {lr} */
 #else
@@ -61,64 +63,9 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
 }
 #endif
 
-#ifdef CONFIG_THUMB2_KERNEL
-static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
-                                      bool link)
-{
-       unsigned long s, j1, j2, i1, i2, imm10, imm11;
-       unsigned long first, second;
-       long offset;
-
-       offset = (long)addr - (long)(pc + 4);
-       if (offset < -16777216 || offset > 16777214) {
-               WARN_ON_ONCE(1);
-               return 0;
-       }
-
-       s       = (offset >> 24) & 0x1;
-       i1      = (offset >> 23) & 0x1;
-       i2      = (offset >> 22) & 0x1;
-       imm10   = (offset >> 12) & 0x3ff;
-       imm11   = (offset >>  1) & 0x7ff;
-
-       j1 = (!i1) ^ s;
-       j2 = (!i2) ^ s;
-
-       first = 0xf000 | (s << 10) | imm10;
-       second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
-       if (link)
-               second |= 1 << 14;
-
-       return __opcode_thumb32_compose(first, second);
-}
-#else
-static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
-                                      bool link)
-{
-       unsigned long opcode = 0xea000000;
-       long offset;
-
-       if (link)
-               opcode |= 1 << 24;
-
-       offset = (long)addr - (long)(pc + 8);
-       if (unlikely(offset < -33554432 || offset > 33554428)) {
-               /* Can't generate branches that far (from ARM ARM). Ftrace
-                * doesn't generate branches outside of kernel text.
-                */
-               WARN_ON_ONCE(1);
-               return 0;
-       }
-
-       offset = (offset >> 2) & 0x00ffffff;
-
-       return opcode | offset;
-}
-#endif
-
 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
-       return ftrace_gen_branch(pc, addr, true);
+       return arm_gen_branch_link(pc, addr);
 }
 
 static int ftrace_modify_code(unsigned long pc, unsigned long old,
@@ -258,7 +205,7 @@ static int __ftrace_modify_caller(unsigned long *callsite,
 {
        unsigned long caller_fn = (unsigned long) func;
        unsigned long pc = (unsigned long) callsite;
-       unsigned long branch = ftrace_gen_branch(pc, caller_fn, false);
+       unsigned long branch = arm_gen_branch(pc, caller_fn);
        unsigned long nop = 0xe1a00000; /* mov r0, r0 */
        unsigned long old = enable ? nop : branch;
        unsigned long new = enable ? branch : nop;
diff --git a/arch/arm/kernel/insn.c b/arch/arm/kernel/insn.c
new file mode 100644 (file)
index 0000000..ab312e5
--- /dev/null
@@ -0,0 +1,61 @@
+#include <linux/kernel.h>
+#include <asm/opcodes.h>
+
+static unsigned long
+__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link)
+{
+       unsigned long s, j1, j2, i1, i2, imm10, imm11;
+       unsigned long first, second;
+       long offset;
+
+       offset = (long)addr - (long)(pc + 4);
+       if (offset < -16777216 || offset > 16777214) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       s       = (offset >> 24) & 0x1;
+       i1      = (offset >> 23) & 0x1;
+       i2      = (offset >> 22) & 0x1;
+       imm10   = (offset >> 12) & 0x3ff;
+       imm11   = (offset >>  1) & 0x7ff;
+
+       j1 = (!i1) ^ s;
+       j2 = (!i2) ^ s;
+
+       first = 0xf000 | (s << 10) | imm10;
+       second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11;
+       if (link)
+               second |= 1 << 14;
+
+       return __opcode_thumb32_compose(first, second);
+}
+
+static unsigned long
+__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link)
+{
+       unsigned long opcode = 0xea000000;
+       long offset;
+
+       if (link)
+               opcode |= 1 << 24;
+
+       offset = (long)addr - (long)(pc + 8);
+       if (unlikely(offset < -33554432 || offset > 33554428)) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       offset = (offset >> 2) & 0x00ffffff;
+
+       return opcode | offset;
+}
+
+unsigned long
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link)
+{
+       if (IS_ENABLED(CONFIG_THUMB2_KERNEL))
+               return __arm_gen_branch_thumb2(pc, addr, link);
+       else
+               return __arm_gen_branch_arm(pc, addr, link);
+}
diff --git a/arch/arm/kernel/insn.h b/arch/arm/kernel/insn.h
new file mode 100644 (file)
index 0000000..994d60f
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __ASM_ARM_INSN_H
+#define __ASM_ARM_INSN_H
+
+unsigned long
+__arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
+
+static inline unsigned long
+arm_gen_branch(unsigned long pc, unsigned long addr)
+{
+       return __arm_gen_branch(pc, addr, false);
+}
+
+static inline unsigned long
+arm_gen_branch_link(unsigned long pc, unsigned long addr)
+{
+       return __arm_gen_branch(pc, addr, true);
+}
+
+#endif