Skip to content

Commit

Permalink
ARM: 7331/1: extract out insn generation code from ftrace
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rabin Vincent authored and Russell King committed Mar 24, 2012
1 parent 4394e28 commit d82227c
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 59 deletions.
5 changes: 3 additions & 2 deletions arch/arm/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
61 changes: 4 additions & 57 deletions arch/arm/kernel/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
61 changes: 61 additions & 0 deletions arch/arm/kernel/insn.c
Original file line number Diff line number Diff line change
@@ -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);
}
19 changes: 19 additions & 0 deletions arch/arm/kernel/insn.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit d82227c

Please sign in to comment.