diff options
author | Rabin Vincent <rabin@rab.in> | 2012-02-18 11:52:41 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-03-24 05:38:56 -0400 |
commit | 09f05d8529ff4aa92311c1a55ce35ac98cb59b8c (patch) | |
tree | 0196ddc9e80d74c8d3e3473bd7bc21b3e520c3d9 | |
parent | a9468f30b5eac6957c86aea97954553bfb7c1f18 (diff) |
ARM: 7334/1: add jump label support
Add the arch-specific code to support jump labels for ARM and Thumb-2.
This code will only be activated on compilers that are capable of
building it. It has been tested with GCC 4.6 patched with the patch
from GCC bug 48637.
Cc: Jason Baron <jbaron@redhat.com>
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/jump_label.h | 41 | ||||
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/insn.h | 10 | ||||
-rw-r--r-- | arch/arm/kernel/jump_label.c | 39 |
5 files changed, 92 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6b5f84887ce5..ee6c7154c9a1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -9,6 +9,7 @@ config ARM | |||
9 | select SYS_SUPPORTS_APM_EMULATION | 9 | select SYS_SUPPORTS_APM_EMULATION |
10 | select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) | 10 | select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) |
11 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) | 11 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) |
12 | select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL | ||
12 | select HAVE_ARCH_KGDB | 13 | select HAVE_ARCH_KGDB |
13 | select HAVE_KPROBES if !XIP_KERNEL | 14 | select HAVE_KPROBES if !XIP_KERNEL |
14 | select HAVE_KRETPROBES if (HAVE_KPROBES) | 15 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h new file mode 100644 index 000000000000..5c5ca2ea62b0 --- /dev/null +++ b/arch/arm/include/asm/jump_label.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef _ASM_ARM_JUMP_LABEL_H | ||
2 | #define _ASM_ARM_JUMP_LABEL_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #include <linux/types.h> | ||
7 | #include <asm/system.h> | ||
8 | |||
9 | #define JUMP_LABEL_NOP_SIZE 4 | ||
10 | |||
11 | #ifdef CONFIG_THUMB2_KERNEL | ||
12 | #define JUMP_LABEL_NOP "nop.w" | ||
13 | #else | ||
14 | #define JUMP_LABEL_NOP "nop" | ||
15 | #endif | ||
16 | |||
17 | static __always_inline bool arch_static_branch(struct jump_label_key *key) | ||
18 | { | ||
19 | asm goto("1:\n\t" | ||
20 | JUMP_LABEL_NOP "\n\t" | ||
21 | ".pushsection __jump_table, \"aw\"\n\t" | ||
22 | ".word 1b, %l[l_yes], %c0\n\t" | ||
23 | ".popsection\n\t" | ||
24 | : : "i" (key) : : l_yes); | ||
25 | |||
26 | return false; | ||
27 | l_yes: | ||
28 | return true; | ||
29 | } | ||
30 | |||
31 | #endif /* __KERNEL__ */ | ||
32 | |||
33 | typedef u32 jump_label_t; | ||
34 | |||
35 | struct jump_entry { | ||
36 | jump_label_t code; | ||
37 | jump_label_t target; | ||
38 | jump_label_t key; | ||
39 | }; | ||
40 | |||
41 | #endif | ||
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 8c63ee8d3c48..1b7d9a390971 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -38,6 +38,7 @@ obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o | |||
38 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o | 38 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o |
39 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o | 39 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o |
40 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o | 40 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o |
41 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o | ||
41 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 42 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
42 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o | 43 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o |
43 | ifdef CONFIG_THUMB2_KERNEL | 44 | ifdef CONFIG_THUMB2_KERNEL |
diff --git a/arch/arm/kernel/insn.h b/arch/arm/kernel/insn.h index 994d60fd3ff5..e96065da4dae 100644 --- a/arch/arm/kernel/insn.h +++ b/arch/arm/kernel/insn.h | |||
@@ -1,6 +1,16 @@ | |||
1 | #ifndef __ASM_ARM_INSN_H | 1 | #ifndef __ASM_ARM_INSN_H |
2 | #define __ASM_ARM_INSN_H | 2 | #define __ASM_ARM_INSN_H |
3 | 3 | ||
4 | static inline unsigned long | ||
5 | arm_gen_nop(void) | ||
6 | { | ||
7 | #ifdef CONFIG_THUMB2_KERNEL | ||
8 | return 0xf3af8000; /* nop.w */ | ||
9 | #else | ||
10 | return 0xe1a00000; /* mov r0, r0 */ | ||
11 | #endif | ||
12 | } | ||
13 | |||
4 | unsigned long | 14 | unsigned long |
5 | __arm_gen_branch(unsigned long pc, unsigned long addr, bool link); | 15 | __arm_gen_branch(unsigned long pc, unsigned long addr, bool link); |
6 | 16 | ||
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c new file mode 100644 index 000000000000..4ce4f789446d --- /dev/null +++ b/arch/arm/kernel/jump_label.c | |||
@@ -0,0 +1,39 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/jump_label.h> | ||
3 | |||
4 | #include "insn.h" | ||
5 | #include "patch.h" | ||
6 | |||
7 | #ifdef HAVE_JUMP_LABEL | ||
8 | |||
9 | static void __arch_jump_label_transform(struct jump_entry *entry, | ||
10 | enum jump_label_type type, | ||
11 | bool is_static) | ||
12 | { | ||
13 | void *addr = (void *)entry->code; | ||
14 | unsigned int insn; | ||
15 | |||
16 | if (type == JUMP_LABEL_ENABLE) | ||
17 | insn = arm_gen_branch(entry->code, entry->target); | ||
18 | else | ||
19 | insn = arm_gen_nop(); | ||
20 | |||
21 | if (is_static) | ||
22 | __patch_text(addr, insn); | ||
23 | else | ||
24 | patch_text(addr, insn); | ||
25 | } | ||
26 | |||
27 | void arch_jump_label_transform(struct jump_entry *entry, | ||
28 | enum jump_label_type type) | ||
29 | { | ||
30 | __arch_jump_label_transform(entry, type, false); | ||
31 | } | ||
32 | |||
33 | void arch_jump_label_transform_static(struct jump_entry *entry, | ||
34 | enum jump_label_type type) | ||
35 | { | ||
36 | __arch_jump_label_transform(entry, type, true); | ||
37 | } | ||
38 | |||
39 | #endif | ||