Commit 09f05d8529ff4aa92311c1a55ce35ac98cb59b8c
Committed by
Russell King
1 parent
a9468f30b5
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 5 changed files with 92 additions and 0 deletions Side-by-side Diff
arch/arm/Kconfig
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | select SYS_SUPPORTS_APM_EMULATION |
10 | 10 | select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) |
11 | 11 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) |
12 | + select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL | |
12 | 13 | select HAVE_ARCH_KGDB |
13 | 14 | select HAVE_KPROBES if !XIP_KERNEL |
14 | 15 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
arch/arm/include/asm/jump_label.h
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 |
arch/arm/kernel/Makefile
... | ... | @@ -38,6 +38,7 @@ |
38 | 38 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o |
39 | 39 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o |
40 | 40 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o |
41 | +obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o | |
41 | 42 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
42 | 43 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o |
43 | 44 | ifdef CONFIG_THUMB2_KERNEL |
arch/arm/kernel/insn.h
1 | 1 | #ifndef __ASM_ARM_INSN_H |
2 | 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 | 14 | unsigned long |
5 | 15 | __arm_gen_branch(unsigned long pc, unsigned long addr, bool link); |
6 | 16 |
arch/arm/kernel/jump_label.c
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 |