Skip to contentSkip to conversation

ARM: jump label support

PATCH Superseded Rabin Vincent 6 participants 25 messages Jan 28, 2012 – Feb 29, 2012

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v2 cover ARM: jump label support

v2:
- Use helper macros from Dave Martin's "ARM: Add generic instruction opcode manipulation helpers"
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7278/1

- Add compiler bug detection so the option is not visible on unsupported compilers

- patch.c: use uintptr_t, h for half-word, call cache_ops_need_broadcast() only once

- Split ftrace.c patch into two

- Remove nop instruction; use mov r0, r0 instead

Rabin Vincent (6):
ARM: ftrace: remove useless memory checks
ARM: ftrace: use canonical Thumb-2 wide instruction format
ARM: extract out insn generation code from ftrace
ARM: extract out code patch function from kprobes jump label: detect %c support for ARM
ARM: add jump label support

 arch/arm/Kconfig                  |    1 +
 arch/arm/include/asm/jump_label.h |   41 +++++++++++++++++
 arch/arm/kernel/Makefile          |    9 +++-
 arch/arm/kernel/ftrace.c          |   90 +++++++++---------------------------
 arch/arm/kernel/insn.c            |   61 +++++++++++++++++++++++++
 arch/arm/kernel/insn.h            |   29 ++++++++++++
 arch/arm/kernel/jump_label.c      |   35 ++++++++++++++
 arch/arm/kernel/kprobes.c         |   86 ++++++++++-------------------------
 arch/arm/kernel/patch.c           |   73 ++++++++++++++++++++++++++++++
 arch/arm/kernel/patch.h           |    7 +++
 scripts/gcc-goto.sh               |   18 +++++++-
 11 files changed, 317 insertions(+), 133 deletions(-)
 create mode 100644 arch/arm/include/asm/jump_label.h
 create mode 100644 arch/arm/kernel/insn.c
 create mode 100644 arch/arm/kernel/insn.h
 create mode 100644 arch/arm/kernel/jump_label.c
 create mode 100644 arch/arm/kernel/patch.c
 create mode 100644 arch/arm/kernel/patch.h
Signature · 1 line
1.7.8.3
#1 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Before replacing an instruction, the ftrace code determines what the old instruction should be and verifies that that's what's really there in memory before replacing it. This is useful if for example a bug in mcountrecord causes it to record wrong locations.

However, in cases where we replace call sites in entry-common.S, these checks are not needed. For these, we currently just memcpy() the memory content and then "verify" it -- this is quite useless and can be removed.

---
 arch/arm/kernel/ftrace.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)
arch/arm/kernel/ftrace.c +9 -9
index c0062ad..e9488ad 100644
@@ -125,11 +125,13 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (old) {
+		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+			return -EFAULT;
 
-	if (replaced != old)
-		return -EINVAL;
+		if (replaced != old)
+			return -EINVAL;
+	}
 
 	if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
 		return -EPERM;
@@ -141,23 +143,21 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-	unsigned long pc, old;
+	unsigned long pc;
 	unsigned long new;
 	int ret;
 
 	pc = (unsigned long)&ftrace_call;
-	memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
 	new = ftrace_call_replace(pc, (unsigned long)func);
 
-	ret = ftrace_modify_code(pc, old, new);
+	ret = ftrace_modify_code(pc, 0, new);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (!ret) {
 		pc = (unsigned long)&ftrace_call_old;
-		memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
 		new = ftrace_call_replace(pc, (unsigned long)func);
 
-		ret = ftrace_modify_code(pc, old, new);
+		ret = ftrace_modify_code(pc, 0, new);
 	}
 #endif
 
Signature · 1 line
1.7.8.3
#2 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Quoted 9 lines · Rabin Vincent

Before replacing an instruction, the ftrace code determines what the old instruction should be and verifies that that's what's really there in memory before replacing it. This is useful if for example a bug in mcountrecord causes it to record wrong locations.

However, in cases where we replace call sites in entry-common.S, these checks are not needed. For these, we currently just memcpy() the memory content and then "verify" it -- this is quite useless and can be removed.

Yes, I know this is a little late, but...

Quoted 11 lines
---
 arch/arm/kernel/ftrace.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)
arch/arm/kernel/ftrace.c +0 -0
index c0062ad..e9488ad 100644

arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 128

Quoted 6 lines
arch/arm/kernel/ftrace.c +1 -2
@@ -125,11 +125,13 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (old) {

So, we're using the instruction value '0' to mean that we don't want to check? Wouldn'it it be better to pass a flag in to indicate this instead of creating a magic value?

#3 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Quoted 9 lines · Russell King - ARM Linux
Quoted 8 lines · Rabin Vincent
arch/arm/kernel/ftrace.c +0 -0
index c0062ad..e9488ad 100644
@@ -125,11 +125,13 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
Quoted 7 lines

arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 128

Quoted 3 lines
arch/arm/kernel/ftrace.c +1 -2
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (old) {

So, we're using the instruction value '0' to mean that we don't want to check? Wouldn'it it be better to pass a flag in to indicate this instead of creating a magic value?

OK. I think you applied this patch as-is anyway, so here is a follow-on patch:

8<------------

Quoted 1 line

From 18ad9e696a3b3986babb1c91807d3f39d6468176 Mon Sep 17 00:00:00 2001

From: Rabin Vincent <[email protected]>
Date: Wed, 22 Feb 2012 19:11:46 +0530
Subject: [PATCH] ARM: ftrace: use flag for memory check

We currently use a (magic) value of 0 for the old instruction value to detect if we should verify the old value in memory or not. Pass a flag instead.

---
 arch/arm/kernel/ftrace.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)
arch/arm/kernel/ftrace.c +8 -8
index 858c63f..df0bf0c 100644
@@ -69,7 +69,7 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 }
 
 static int ftrace_modify_code(unsigned long pc, unsigned long old,
-			      unsigned long new)
+			      unsigned long new, bool validate)
 {
 	unsigned long replaced;
 
@@ -81,7 +81,7 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 		new = __opcode_to_mem_arm(new);
 	}
 
-	if (old) {
+	if (validate) {
 		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
 			return -EFAULT;
 
@@ -106,14 +106,14 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
 	pc = (unsigned long)&ftrace_call;
 	new = ftrace_call_replace(pc, (unsigned long)func);
 
-	ret = ftrace_modify_code(pc, 0, new);
+	ret = ftrace_modify_code(pc, 0, new, false);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (!ret) {
 		pc = (unsigned long)&ftrace_call_old;
 		new = ftrace_call_replace(pc, (unsigned long)func);
 
-		ret = ftrace_modify_code(pc, 0, new);
+		ret = ftrace_modify_code(pc, 0, new, false);
 	}
 #endif
 
@@ -128,7 +128,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	old = ftrace_nop_replace(rec);
 	new = ftrace_call_replace(ip, adjust_address(rec, addr));
 
-	return ftrace_modify_code(rec->ip, old, new);
+	return ftrace_modify_code(rec->ip, old, new, true);
 }
 
 int ftrace_make_nop(struct module *mod,
@@ -141,7 +141,7 @@ int ftrace_make_nop(struct module *mod,
 
 	old = ftrace_call_replace(ip, adjust_address(rec, addr));
 	new = ftrace_nop_replace(rec);
-	ret = ftrace_modify_code(ip, old, new);
+	ret = ftrace_modify_code(ip, old, new, true);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (ret == -EINVAL && addr == MCOUNT_ADDR) {
@@ -149,7 +149,7 @@ int ftrace_make_nop(struct module *mod,
 
 		old = ftrace_call_replace(ip, adjust_address(rec, addr));
 		new = ftrace_nop_replace(rec);
-		ret = ftrace_modify_code(ip, old, new);
+		ret = ftrace_modify_code(ip, old, new, true);
 	}
 #endif
 
@@ -210,7 +210,7 @@ static int __ftrace_modify_caller(unsigned long *callsite,
 	unsigned long old = enable ? nop : branch;
 	unsigned long new = enable ? branch : nop;
 
-	return ftrace_modify_code(pc, old, new);
+	return ftrace_modify_code(pc, old, new, true);
 }
 
 static int ftrace_modify_graph_caller(bool enable)
Signature · 1 line
1.7.9
#4 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Quoted 18 lines · Rabin Vincent
Quoted 9 lines · Russell King - ARM Linux
Quoted 8 lines · Rabin Vincent
arch/arm/kernel/ftrace.c +0 -0
index c0062ad..e9488ad 100644
@@ -125,11 +125,13 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
Quoted 7 lines

arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 128

Quoted 3 lines
arch/arm/kernel/ftrace.c +1 -2
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (old) {

So, we're using the instruction value '0' to mean that we don't want to check? Wouldn'it it be better to pass a flag in to indicate this instead of creating a magic value?

Quoted 2 lines

OK. I think you applied this patch as-is anyway, so here is a follow-on patch:

I'd still much prefer it to be part of the original patch. I can replace the patch I've merged or augment it with another patch - whichever way you prefer.

#5 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Quoted 19 lines · Russell King - ARM Linux
Quoted 18 lines · Rabin Vincent
Quoted 16 lines · Russell King - ARM Linux

arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 128

Quoted 11 lines · Rabin Vincent
arch/arm/kernel/ftrace.c +1 -2
index c0062ad..e9488ad 100644
@@ -125,11 +125,13 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (old) {

So, we're using the instruction value '0' to mean that we don't want to check? Wouldn'it it be better to pass a flag in to indicate this instead of creating a magic value?

Quoted 6 lines
Quoted 2 lines

OK. I think you applied this patch as-is anyway, so here is a follow-on patch:

I'd still much prefer it to be part of the original patch. I can replace the patch I've merged or augment it with another patch - whichever way you prefer.

Replacing the original is OK with me, new patch below. Note that "ARM:
ftrace: use canonical Thumb-2 wide instruction format" will need to be manually rebased on top of it since there is a change in the context.

8<----------------

Quoted 1 line

From 11a4aea10f1b2d56c70c34def29b3f8d56b88dd5 Mon Sep 17 00:00:00 2001

From: Rabin Vincent <[email protected]>
Date: Sat, 21 Jan 2012 21:52:19 +0530
Subject: [PATCH] ARM: ftrace: remove useless memory checks

Before replacing an instruction, the ftrace code determines what the old instruction should be and verifies that that's what's really there in memory before replacing it. This is useful if for example a bug in mcountrecord causes it to record wrong locations.

However, in cases where we replace call sites in entry-common.S, these checks are not needed. For these, we currently just memcpy() the memory content and then "verify" it -- this is quite useless and can be removed.

---
 arch/arm/kernel/ftrace.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)
arch/arm/kernel/ftrace.c +14 -14
index c0062ad..6fd7c4a 100644
@@ -121,15 +121,17 @@ static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 }
 
 static int ftrace_modify_code(unsigned long pc, unsigned long old,
-			      unsigned long new)
+			      unsigned long new, bool validate)
 {
 	unsigned long replaced;
 
-	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
-		return -EFAULT;
+	if (validate) {
+		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+			return -EFAULT;
 
-	if (replaced != old)
-		return -EINVAL;
+		if (replaced != old)
+			return -EINVAL;
+	}
 
 	if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
 		return -EPERM;
@@ -141,23 +143,21 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-	unsigned long pc, old;
+	unsigned long pc;
 	unsigned long new;
 	int ret;
 
 	pc = (unsigned long)&ftrace_call;
-	memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
 	new = ftrace_call_replace(pc, (unsigned long)func);
 
-	ret = ftrace_modify_code(pc, old, new);
+	ret = ftrace_modify_code(pc, 0, new, false);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (!ret) {
 		pc = (unsigned long)&ftrace_call_old;
-		memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
 		new = ftrace_call_replace(pc, (unsigned long)func);
 
-		ret = ftrace_modify_code(pc, old, new);
+		ret = ftrace_modify_code(pc, 0, new, false);
 	}
 #endif
 
@@ -172,7 +172,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 	old = ftrace_nop_replace(rec);
 	new = ftrace_call_replace(ip, adjust_address(rec, addr));
 
-	return ftrace_modify_code(rec->ip, old, new);
+	return ftrace_modify_code(rec->ip, old, new, true);
 }
 
 int ftrace_make_nop(struct module *mod,
@@ -185,7 +185,7 @@ int ftrace_make_nop(struct module *mod,
 
 	old = ftrace_call_replace(ip, adjust_address(rec, addr));
 	new = ftrace_nop_replace(rec);
-	ret = ftrace_modify_code(ip, old, new);
+	ret = ftrace_modify_code(ip, old, new, true);
 
 #ifdef CONFIG_OLD_MCOUNT
 	if (ret == -EINVAL && addr == MCOUNT_ADDR) {
@@ -193,7 +193,7 @@ int ftrace_make_nop(struct module *mod,
 
 		old = ftrace_call_replace(ip, adjust_address(rec, addr));
 		new = ftrace_nop_replace(rec);
-		ret = ftrace_modify_code(ip, old, new);
+		ret = ftrace_modify_code(ip, old, new, true);
 	}
 #endif
 
@@ -254,7 +254,7 @@ static int __ftrace_modify_caller(unsigned long *callsite,
 	unsigned long old = enable ? nop : branch;
 	unsigned long new = enable ? branch : nop;
 
-	return ftrace_modify_code(pc, old, new);
+	return ftrace_modify_code(pc, old, new, true);
 }
 
 static int ftrace_modify_graph_caller(bool enable)
Signature · 1 line
1.7.9
#6 lore raw

PATCH v2 1/6 ARM: ftrace: remove useless memory checks

Quoted 3 lines · Rabin Vincent

Replacing the original is OK with me, new patch below. Note that "ARM:
ftrace: use canonical Thumb-2 wide instruction format" will need to be manually rebased on top of it since there is a change in the context.

Ok, please put this in the patch system, thanks.

#7 lore raw

PATCH v2 2/6 ARM: ftrace: use canonical Thumb-2 wide instruction format

In reply to Rabin Vincent

As commit 592201a9f15 (ARM: Thumb-2: Support Thumb-2 in undefined instruction handler) says:

32-bit Thumb instructions are specified in the form:
((first_half << 16 ) | second_half)
which matches the layout used by the ARM ARM.

Convert the ftrace code to use the same format to avoid the usage of different formats in kernel code.

---
 arch/arm/kernel/ftrace.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)
arch/arm/kernel/ftrace.c +11 -2
index e9488ad..72a381a 100644
@@ -16,10 +16,11 @@
 #include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
+#include <asm/opcodes.h>
 #include <asm/ftrace.h>
 
 #ifdef CONFIG_THUMB2_KERNEL
-#define	NOP		0xeb04f85d	/* pop.w {lr} */
+#define	NOP		0xf85deb04	/* pop.w {lr} */
 #else
 #define	NOP		0xe8bd4000	/* pop {lr} */
 #endif
@@ -88,7 +89,7 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
 	if (link)
 		second |= 1 << 14;
 
-	return (second << 16) | first;
+	return __opcode_thumb32_compose(first, second);
 }
 #else
 static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
@@ -125,6 +126,14 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+		old = __opcode_to_mem_thumb32(old);
+		new = __opcode_to_mem_thumb32(new);
+	} else {
+		old = __opcode_to_mem_arm(old);
+		new = __opcode_to_mem_arm(new);
+	}
+
 	if (old) {
 		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
 			return -EFAULT;
Signature · 1 line
1.7.8.3
#8 lore raw

PATCH v2 2/6 ARM: ftrace: use canonical Thumb-2 wide instruction format

Quoted 11 lines · Rabin Vincent

As commit 592201a9f15 (ARM: Thumb-2: Support Thumb-2 in undefined instruction handler) says:

32-bit Thumb instructions are specified in the form:
((first_half << 16 ) | second_half)
which matches the layout used by the ARM ARM.

Convert the ftrace code to use the same format to avoid the usage of different formats in kernel code.

I haven't tried it out, but the use of the opcode helpers looks correct.

Cheers
---Dave

Quoted 53 lines
---
 arch/arm/kernel/ftrace.c |   13 +++++++++++--
 1 files changed, 11 insertions(+), 2 deletions(-)
arch/arm/kernel/ftrace.c +11 -2
index e9488ad..72a381a 100644
@@ -16,10 +16,11 @@
 #include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
+#include <asm/opcodes.h>
 #include <asm/ftrace.h>
 
 #ifdef CONFIG_THUMB2_KERNEL
-#define	NOP		0xeb04f85d	/* pop.w {lr} */
+#define	NOP		0xf85deb04	/* pop.w {lr} */
 #else
 #define	NOP		0xe8bd4000	/* pop {lr} */
 #endif
@@ -88,7 +89,7 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
 	if (link)
 		second |= 1 << 14;
 
-	return (second << 16) | first;
+	return __opcode_thumb32_compose(first, second);
 }
 #else
 static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
@@ -125,6 +126,14 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old,
 {
 	unsigned long replaced;
 
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+		old = __opcode_to_mem_thumb32(old);
+		new = __opcode_to_mem_thumb32(new);
+	} else {
+		old = __opcode_to_mem_arm(old);
+		new = __opcode_to_mem_arm(new);
+	}
+
 	if (old) {
 		if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
 			return -EFAULT;
Signature · 7 lines
1.7.8.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#9 lore raw

PATCH v2 3/6 ARM: extract out insn generation code from ftrace

In reply to Rabin Vincent

Extract out the instruction generation code so that it can be used for jump labels too.

---
 arch/arm/kernel/Makefile |    5 ++-
 arch/arm/kernel/ftrace.c |   61 +++-------------------------------------------
 arch/arm/kernel/insn.c   |   61 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/insn.h   |   19 ++++++++++++++
 4 files changed, 87 insertions(+), 59 deletions(-)
 create mode 100644 arch/arm/kernel/insn.c
 create mode 100644 arch/arm/kernel/insn.h
arch/arm/kernel/Makefile +3 -2
index 43b740d..dd3d5f1 100644
@@ -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
arch/arm/kernel/ftrace.c +4 -57

81 lines not on this page · raw message

arch/arm/kernel/insn.c new file +61 -0

61 lines not on this page · raw message

arch/arm/kernel/insn.h new file +19 -0
new file mode 100644
index 0000000..994d60f
@@ -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
Signature · 1 line
1.7.8.3
#10 lore raw

PATCH v2 4/6 ARM: extract out code patch function from kprobes

In reply to Rabin Vincent

Extract out the code patching code from kprobes so that it can be used from the jump label code. Additionally, the separated code:

- Uses the IS_ENABLED() macros instead of the #ifdefs for THUMB2 support

- Unifies the two separate functions in kprobes, providing one function that uses stop_machine() internally, and one that can be called from stop_machine() directly

- Patches the text on all CPUs only on processors requiring software broadcasting of cache operations

---
 arch/arm/kernel/Makefile  |    3 +-
 arch/arm/kernel/kprobes.c |   86 ++++++++++++--------------------------------
 arch/arm/kernel/patch.c   |   73 ++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/patch.h   |    7 ++++
 4 files changed, 106 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm/kernel/patch.c
 create mode 100644 arch/arm/kernel/patch.h
arch/arm/kernel/Makefile +2 -1
index dd3d5f1..8c63ee8 100644
@@ -8,6 +8,7 @@ AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_insn.o = -pg
+CFLAGS_REMOVE_patch.o = -pg
 endif
 
 CFLAGS_REMOVE_return_address.o = -pg
@@ -38,7 +39,7 @@ obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.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
+obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
 obj-$(CONFIG_KPROBES)		+= kprobes-thumb.o
 else
arch/arm/kernel/kprobes.c +24 -62

112 lines not on this page · raw message

arch/arm/kernel/patch.c new file +73 -0

73 lines not on this page · raw message

arch/arm/kernel/patch.h new file +7 -0
new file mode 100644
index 0000000..b4731f2
@@ -0,0 +1,7 @@
+#ifndef _ARM_KERNEL_PATCH_H
+#define _ARM_KERNEL_PATCH_H
+
+void patch_text(void *addr, unsigned int insn);
+void __patch_text(void *addr, unsigned int insn);
+
+#endif
Signature · 1 line
1.7.8.3
#11 lore raw

PATCH v2 4/6 ARM: extract out code patch function from kprobes

Quoted 23 lines · Rabin Vincent

Extract out the code patching code from kprobes so that it can be used from the jump label code. Additionally, the separated code:

- Uses the IS_ENABLED() macros instead of the #ifdefs for THUMB2 support

- Unifies the two separate functions in kprobes, providing one function that uses stop_machine() internally, and one that can be called from stop_machine() directly

- Patches the text on all CPUs only on processors requiring software broadcasting of cache operations

---
 arch/arm/kernel/Makefile  |    3 +-
 arch/arm/kernel/kprobes.c |   86 ++++++++++++--------------------------------
 arch/arm/kernel/patch.c   |   73 ++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/patch.h   |    7 ++++
 4 files changed, 106 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm/kernel/patch.c
 create mode 100644 arch/arm/kernel/patch.h

[...]

Quoted 6 lines
arch/arm/kernel/patch.c new file +0 -0
new file mode 100644
index 0000000..30eff23
@@ -0,0 +1,73 @@

[...]

arch/arm/kernel/patch.c line 28

Quoted 13 lines
arch/arm/kernel/patch.c new file +13 -0
+void __kprobes __patch_text(void *addr, unsigned int insn)
+{
+	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
+	int size;
+
+	if (thumb2 && __opcode_is_thumb16(insn)) {
+		*(u16 *)addr = __opcode_to_mem_thumb16(insn);
+		size = sizeof(u16);
+	} else if (thumb2 && ((uintptr_t)addr & 2)) {
+		u16 *addrh = addr;
+
+		addrh[0] = __opcode_thumb32_first(insn);
+		addrh[1] = __opcode_thumb32_second(insn);

It looks like we never convert to memory byte order in this case.

If not, should this be as follows?

	addrh[0] = __opcode_to_mem_thumb16(__opcode_thumb32_first(insn));
	addrh[1] = __opcode_to_mem_thumb16(__opcode_thumb32_second(insn));
Quoted 5 lines
arch/arm/kernel/patch.c new file +5 -0
+
+		size = sizeof(u32);
+	} else {
+		if (thumb2)
+			insn = __opcode_to_mem_thumb32(insn);

arch/arm/kernel/patch.c line 43

Quoted 10 lines
arch/arm/kernel/patch.c new file +10 -0
+		else
+			insn = __opcode_to_mem_arm(insn);
+
+		*(u32 *)addr = insn;
+		size = sizeof(u32);
+	}
+
+	flush_icache_range((uintptr_t)(addr),
+			   (uintptr_t)(addr) + size);
+}

[...]

Cheers
---Dave

#12 lore raw

PATCH v3 1/1 ARM: extract out code patch function from kprobes

Extract out the code patching code from kprobes so that it can be used from the jump label code. Additionally, the separated code:

- Uses the IS_ENABLED() macros instead of the #ifdefs for THUMB2 support

- Unifies the two separate functions in kprobes, providing one function that uses stop_machine() internally, and one that can be called from stop_machine() directly

- Patches the text on all CPUs only on processors requiring software broadcasting of cache operations

---
v3: add missing __opcode_to_mem_thumb16 for the split thumb2 case

 arch/arm/kernel/Makefile  |    3 +-
 arch/arm/kernel/kprobes.c |   86 ++++++++++++--------------------------------
 arch/arm/kernel/patch.c   |   75 +++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/patch.h   |    7 ++++
 4 files changed, 108 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm/kernel/patch.c
 create mode 100644 arch/arm/kernel/patch.h
arch/arm/kernel/Makefile +2 -1
index dd3d5f1..8c63ee8 100644
@@ -8,6 +8,7 @@ AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_insn.o = -pg
+CFLAGS_REMOVE_patch.o = -pg
 endif
 
 CFLAGS_REMOVE_return_address.o = -pg
@@ -38,7 +39,7 @@ obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.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
+obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
 obj-$(CONFIG_KPROBES)		+= kprobes-thumb.o
 else
arch/arm/kernel/kprobes.c +24 -62

112 lines not on this page · raw message

arch/arm/kernel/patch.c new file +75 -0

75 lines not on this page · raw message

arch/arm/kernel/patch.h new file +7 -0
new file mode 100644
index 0000000..b4731f2
@@ -0,0 +1,7 @@
+#ifndef _ARM_KERNEL_PATCH_H
+#define _ARM_KERNEL_PATCH_H
+
+void patch_text(void *addr, unsigned int insn);
+void __patch_text(void *addr, unsigned int insn);
+
+#endif
Signature · 1 line
1.7.9
#13 lore raw

PATCH v2 4/6 ARM: extract out code patch function from kprobes

In reply to Rabin Vincent
Quoted 10 lines · Rabin Vincent

Extract out the code patching code from kprobes so that it can be used from the jump label code. Additionally, the separated code:

- Uses the IS_ENABLED() macros instead of the #ifdefs for THUMB2 support

- Unifies the two separate functions in kprobes, providing one function that uses stop_machine() internally, and one that can be called from stop_machine() directly

Quoted 5 lines

- Patches the text on all CPUs only on processors requiring software broadcasting of cache operations

I haven't tested on a big endian machine, but from code review, Dave's suggested change to __patch_text() looks like it is needed...
http://lists.arm.linux.org.uk/lurker/message/20120130.170006.8dea4fe6.en.html

With this change, these kprobes patches are

Quoted 241 lines
---
 arch/arm/kernel/Makefile  |    3 +-
 arch/arm/kernel/kprobes.c |   86 ++++++++++++--------------------------------
 arch/arm/kernel/patch.c   |   73 ++++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/patch.h   |    7 ++++
 4 files changed, 106 insertions(+), 63 deletions(-)
 create mode 100644 arch/arm/kernel/patch.c
 create mode 100644 arch/arm/kernel/patch.h
arch/arm/kernel/Makefile +2 -1
index dd3d5f1..8c63ee8 100644
@@ -8,6 +8,7 @@ AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_insn.o = -pg
+CFLAGS_REMOVE_patch.o = -pg
 endif
 
 CFLAGS_REMOVE_return_address.o = -pg
@@ -38,7 +39,7 @@ obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.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
+obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
 obj-$(CONFIG_KPROBES)		+= kprobes-thumb.o
 else
arch/arm/kernel/kprobes.c +24 -62
index 129c116..ab1869d 100644
@@ -29,6 +29,7 @@
 #include <asm/cacheflush.h>
 
 #include "kprobes.h"
+#include "patch.h"
 
 #define MIN_STACK_SIZE(addr) 				\
 	min((unsigned long)MAX_STACK_SIZE,		\
@@ -103,57 +104,33 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
 	return 0;
 }
 
-#ifdef CONFIG_THUMB2_KERNEL
-
-/*
- * For a 32-bit Thumb breakpoint spanning two memory words we need to take
- * special precautions to insert the breakpoint atomically, especially on SMP
- * systems. This is achieved by calling this arming function using stop_machine.
- */
-static int __kprobes set_t32_breakpoint(void *addr)
-{
-	((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16;
-	((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff;
-	flush_insns(addr, 2*sizeof(u16));
-	return 0;
-}
-
 void __kprobes arch_arm_kprobe(struct kprobe *p)
 {
-	uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */
-
-	if (!is_wide_instruction(p->opcode)) {
-		*(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
-		flush_insns(addr, sizeof(u16));
-	} else if (addr & 2) {
-		/* A 32-bit instruction spanning two words needs special care */
-		stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
+	unsigned int brkp;
+	void *addr;
+
+	if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+		/* Remove any Thumb flag */
+		addr = (void *)((uintptr_t)p->addr & ~1);
+
+		if (is_wide_instruction(p->opcode))
+			brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
+		else
+			brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
 	} else {
-		/* Word aligned 32-bit instruction can be written atomically */
-		u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
-#ifndef __ARMEB__ /* Swap halfwords for little-endian */
-		bkp = (bkp >> 16) | (bkp << 16);
-#endif
-		*(u32 *)addr = bkp;
-		flush_insns(addr, sizeof(u32));
-	}
-}
+		kprobe_opcode_t insn = p->opcode;
 
-#else /* !CONFIG_THUMB2_KERNEL */
+		addr = p->addr;
+		brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
 
-void __kprobes arch_arm_kprobe(struct kprobe *p)
-{
-	kprobe_opcode_t insn = p->opcode;
-	kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
-	if (insn >= 0xe0000000)
-		brkp |= 0xe0000000;  /* Unconditional instruction */
-	else
-		brkp |= insn & 0xf0000000;  /* Copy condition from insn */
-	*p->addr = brkp;
-	flush_insns(p->addr, sizeof(p->addr[0]));
-}
+		if (insn >= 0xe0000000)
+			brkp |= 0xe0000000;  /* Unconditional instruction */
+		else
+			brkp |= insn & 0xf0000000;  /* Copy condition from insn */
+	}
 
-#endif /* !CONFIG_THUMB2_KERNEL */
+	patch_text(addr, brkp);
+}
 
 /*
  * The actual disarming is done here on each CPU and synchronized using
@@ -166,25 +143,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
 int __kprobes __arch_disarm_kprobe(void *p)
 {
 	struct kprobe *kp = p;
-#ifdef CONFIG_THUMB2_KERNEL
-	u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1);
-	kprobe_opcode_t insn = kp->opcode;
-	unsigned int len;
+	void *addr = (void *)((uintptr_t)kp->addr & ~1);
 
-	if (is_wide_instruction(insn)) {
-		((u16 *)addr)[0] = insn>>16;
-		((u16 *)addr)[1] = insn;
-		len = 2*sizeof(u16);
-	} else {
-		((u16 *)addr)[0] = insn;
-		len = sizeof(u16);
-	}
-	flush_insns(addr, len);
+	__patch_text(addr, kp->opcode);
 
-#else /* !CONFIG_THUMB2_KERNEL */
-	*kp->addr = kp->opcode;
-	flush_insns(kp->addr, sizeof(kp->addr[0]));
-#endif
 	return 0;
 }
 
arch/arm/kernel/patch.c new file +73 -0
new file mode 100644
index 0000000..30eff23
@@ -0,0 +1,73 @@
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/stop_machine.h>
+
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/opcodes.h>
+
+#include "patch.h"
+
+struct patch {
+	void *addr;
+	unsigned int insn;
+};
+
+void __kprobes __patch_text(void *addr, unsigned int insn)
+{
+	bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
+	int size;
+
+	if (thumb2 && __opcode_is_thumb16(insn)) {
+		*(u16 *)addr = __opcode_to_mem_thumb16(insn);
+		size = sizeof(u16);
+	} else if (thumb2 && ((uintptr_t)addr & 2)) {
+		u16 *addrh = addr;
+
+		addrh[0] = __opcode_thumb32_first(insn);
+		addrh[1] = __opcode_thumb32_second(insn);
+
+		size = sizeof(u32);
+	} else {
+		if (thumb2)
+			insn = __opcode_to_mem_thumb32(insn);
+		else
+			insn = __opcode_to_mem_arm(insn);
+
+		*(u32 *)addr = insn;
+		size = sizeof(u32);
+	}
+
+	flush_icache_range((uintptr_t)(addr),
+			   (uintptr_t)(addr) + size);
+}
+
+static int __kprobes patch_text_stop_machine(void *data)
+{
+	struct patch *patch = data;
+
+	__patch_text(patch->addr, patch->insn);
+
+	return 0;
+}
+
+void __kprobes patch_text(void *addr, unsigned int insn)
+{
+	struct patch patch = {
+		.addr = addr,
+		.insn = insn,
+	};
+
+	if (cache_ops_need_broadcast()) {
+		stop_machine(patch_text_stop_machine, &patch, cpu_online_mask);
+	} else {
+		bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL)
+				      && __opcode_is_thumb32(insn)
+				      && ((uintptr_t)addr & 2);
+
+		if (straddles_word)
+			stop_machine(patch_text_stop_machine, &patch, NULL);
+		else
+			__patch_text(addr, insn);
+	}
+}
arch/arm/kernel/patch.h new file +7 -0
new file mode 100644
index 0000000..b4731f2
@@ -0,0 +1,7 @@
+#ifndef _ARM_KERNEL_PATCH_H
+#define _ARM_KERNEL_PATCH_H
+
+void patch_text(void *addr, unsigned int insn);
+void __patch_text(void *addr, unsigned int insn);
+
+#endif
#14 lore raw

PATCH v2 5/6 jump label: detect %c support for ARM

In reply to Rabin Vincent

Some versions of ARM GCC which do support asm goto, have problems handling the the %c specifier. Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

Cc Jason Baron <[email protected]>
Cc linux-kernel at vger.kernel.org
---
 scripts/gcc-goto.sh |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)
scripts/gcc-goto.sh +17 -1
index 98cffcb..9b744de 100644
@@ -2,4 +2,20 @@
 # Test for gcc 'asm goto' support
 # Copyright (C) 2010, Jason Baron <[email protected]>
 
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+	/*
+	 * Not related to asm goto, but used by jump label
+	 * and broken on some ARM GCC versions (see GCC Bug 48637).
+	 */
+	static struct { int dummy; int state; } tp;
+	asm ("@ %c0" :: "i" (&tp.state));
+#endif
+
+entry:
+	asm goto ("" :::: entry);
+	return 0;
+}
+END
Signature · 1 line
1.7.8.3
#15 lore raw

Re: [PATCHv2 5/6] jump label: detect %c support for ARM

Jason,

Quoted 10 lines · Rabin Vincent

Some versions of ARM GCC which do support asm goto, have problems handling the the %c specifier. ?Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

Cc Jason Baron <[email protected]>
Cc linux-kernel at vger.kernel.org

Could you please ack this patch if it's OK for you? Then I could try to send it via rmk's ARM patch system along with the rest of the series.

Thanks.

Quoted 33 lines

---
?scripts/gcc-goto.sh | ? 18 +++++++++++++++++- ?1 files changed, 17 insertions(+), 1 deletions(-)

scripts/gcc-goto.sh +0 -0
index 98cffcb..9b744de 100644
@@ -2,4 +2,20 @@

?# Test for gcc 'asm goto' support
?# Copyright (C) 2010, Jason Baron <[email protected]>

scripts/gcc-goto.sh +17 -2
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+ ? ? ? /*
+ ? ? ? ?* Not related to asm goto, but used by jump label
+ ? ? ? ?* and broken on some ARM GCC versions (see GCC Bug 48637).
+ ? ? ? ?*/
+ ? ? ? static struct { int dummy; int state; } tp;
+ ? ? ? asm ("@ %c0" :: "i" (&tp.state));
+#endif
+
+entry:
+ ? ? ? asm goto ("" :::: entry);
+ ? ? ? return 0;
+}
+END
--

1.7.8.3

Acked-by
#16 lore raw

Re: [PATCHv2 5/6] jump label: detect %c support for ARM

Quoted 44 lines · Rabin Vincent

Jason,

Quoted 10 lines · Rabin Vincent

Some versions of ARM GCC which do support asm goto, have problems handling the the %c specifier. ?Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

Cc Jason Baron <[email protected]>
Cc linux-kernel at vger.kernel.org

Could you please ack this patch if it's OK for you? Then I could try to send it via rmk's ARM patch system along with the rest of the series.

Thanks.

Quoted 25 lines

---
?scripts/gcc-goto.sh | ? 18 +++++++++++++++++- ?1 files changed, 17 insertions(+), 1 deletions(-)

scripts/gcc-goto.sh +0 -0
index 98cffcb..9b744de 100644
@@ -2,4 +2,20 @@

?# Test for gcc 'asm goto' support
?# Copyright (C) 2010, Jason Baron <[email protected]>

scripts/gcc-goto.sh +12 -1
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+ ? ? ? /*
+ ? ? ? ?* Not related to asm goto, but used by jump label
+ ? ? ? ?* and broken on some ARM GCC versions (see GCC Bug 48637).
+ ? ? ? ?*/
+ ? ? ? static struct { int dummy; int state; } tp;
+ ? ? ? asm ("@ %c0" :: "i" (&tp.state));
+#endif
+
Quoted 8 lines
Quoted 8 lines
scripts/gcc-goto.sh +5 -1
+entry:
+ ? ? ? asm goto ("" :::: entry);
+ ? ? ? return 0;
+}
+END
--

1.7.8.3

Sure, patch works for me.

#17 lore raw

Re: [PATCHv2 5/6] jump label: detect %c support for ARM

In reply to Rabin Vincent
Quoted 4 lines · Rabin Vincent

Some versions of ARM GCC which do support asm goto, have problems handling the the %c specifier. Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

I'm not sure how this detects properly working %c support. %c support has been rather flakey on ARM for some time, I'm not sure which version of gcc was fixed for it.

Quoted 18 lines

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

Cc Jason Baron <[email protected]>
Cc linux-kernel at vger.kernel.org
---
 scripts/gcc-goto.sh |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)
scripts/gcc-goto.sh +0 -1
index 98cffcb..9b744de 100644
@@ -2,4 +2,20 @@
 # Test for gcc 'asm goto' support
 # Copyright (C) 2010, Jason Baron <[email protected]>
 
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"

scripts/gcc-goto.sh line 14

Quoted 10 lines
scripts/gcc-goto.sh +10 -0
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+	/*
+	 * Not related to asm goto, but used by jump label
+	 * and broken on some ARM GCC versions (see GCC Bug 48637).
+	 */
+	static struct { int dummy; int state; } tp;
+	asm ("@ %c0" :: "i" (&tp.state));

While this detects the presence of the ICE, previous compilers included the '#' before the constant, which leads to problems. I think a better check would be:

	asm(".long %c0" :: "i" (&tp.state));

to make sure that it spits out something purely numeric, rather than something prefixed with a '#'.

author Acked-by Jason Baron
#18 lore raw

Re: [PATCHv2 5/6] jump label: detect %c support for ARM

Quoted 9 lines · Russell King - ARM Linux
Quoted 4 lines · Rabin Vincent

Some versions of ARM GCC which do support asm goto, have problems handling the the %c specifier. Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

I'm not sure how this detects properly working %c support. %c support has been rather flakey on ARM for some time, I'm not sure which version of gcc was fixed for it.

Right, it only detects that %c on a sym+offset doesn't ICE, which was what it had been doing since atleast version 4.3.

The assumption was that since asm goto was only added in ~4.5, all older compilers (regardless of their state of %c support) would choke (as we want them to) on the existing second half of this script.

I have added the change you suggested below.

Quoted 33 lines
Quoted 19 lines

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

Cc Jason Baron <[email protected]>
Cc linux-kernel at vger.kernel.org
---
 scripts/gcc-goto.sh |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)
scripts/gcc-goto.sh +0 -1
index 98cffcb..9b744de 100644
@@ -2,4 +2,20 @@
 # Test for gcc 'asm goto' support
 # Copyright (C) 2010, Jason Baron <[email protected]>
 
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"

scripts/gcc-goto.sh line 14

Quoted 10 lines
scripts/gcc-goto.sh +10 -0
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+	/*
+	 * Not related to asm goto, but used by jump label
+	 * and broken on some ARM GCC versions (see GCC Bug 48637).
+	 */
+	static struct { int dummy; int state; } tp;
+	asm ("@ %c0" :: "i" (&tp.state));

While this detects the presence of the ICE, previous compilers included the '#' before the constant, which leads to problems. I think a better check would be:

Quoted 4 lines
	asm(".long %c0" :: "i" (&tp.state));

to make sure that it spits out something purely numeric, rather than something prefixed with a '#'.

OK, done:

8<----------------

Quoted 1 line

From f3a3bd64f72720def5cfbaedf6ff83ca54f1644b Mon Sep 17 00:00:00 2001

From: Rabin Vincent <[email protected]>
Date: Wed, 23 Nov 2011 20:05:09 +0530
Subject: [PATCH] jump label: detect %c support for ARM

Some versions of ARM GCC which do support asm goto, do not support the %c specifier. Since we need the %c to support jump labels on ARM, detect that too in the asm goto detection script to avoid build errors with these versions.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637

---
 scripts/gcc-goto.sh |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)
scripts/gcc-goto.sh +17 -1
index 98cffcb..a2af2e8 100644
@@ -2,4 +2,20 @@
 # Test for gcc 'asm goto' support
 # Copyright (C) 2010, Jason Baron <[email protected]>
 
-echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
+int main(void)
+{
+#ifdef __arm__
+	/*
+	 * Not related to asm goto, but used by jump label
+	 * and broken on some ARM GCC versions (see GCC Bug 48637).
+	 */
+	static struct { int dummy; int state; } tp;
+	asm (".long %c0" :: "i" (&tp.state));
+#endif
+
+entry:
+	asm goto ("" :::: entry);
+	return 0;
+}
+END
Signature · 1 line
1.7.9
#19 lore raw

PATCH v2 6/6 ARM: add jump label support

In reply to Rabin Vincent

Add the arch-specific code to support jump labels for ARM and Thumb-2.

The option will only be available on compilers that are capable of building it. It has been tested with GCC 4.6 patched with the patch from GCC bug 48637.

---
 arch/arm/Kconfig                  |    1 +
 arch/arm/include/asm/jump_label.h |   41 +++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/Makefile          |    1 +
 arch/arm/kernel/insn.h            |   10 +++++++++
 arch/arm/kernel/jump_label.c      |   35 +++++++++++++++++++++++++++++++
 5 files changed, 88 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/jump_label.h
 create mode 100644 arch/arm/kernel/jump_label.c
arch/arm/Kconfig +1 -0
index 24626b0..a1c8911 100644
@@ -9,6 +9,7 @@ config ARM
 	select SYS_SUPPORTS_APM_EMULATION
 	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
 	select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
+	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
 	select HAVE_ARCH_KGDB
 	select HAVE_KPROBES if !XIP_KERNEL
 	select HAVE_KRETPROBES if (HAVE_KPROBES)
arch/arm/include/asm/jump_label.h new file +41 -0

41 lines not on this page · raw message

arch/arm/kernel/Makefile +1 -0
index 8c63ee8..1b7d9a3 100644
@@ -38,6 +38,7 @@ obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
+obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
arch/arm/kernel/insn.h +10 -0
index 994d60f..e96065d 100644
@@ -1,6 +1,16 @@
 #ifndef __ASM_ARM_INSN_H
 #define __ASM_ARM_INSN_H
 
+static inline unsigned long
+arm_gen_nop(void)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+	return 0xf3af8000; /* nop.w */
+#else
+	return 0xe1a00000; /* mov r0, r0 */
+#endif
+}
+
 unsigned long
 __arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
 
arch/arm/kernel/jump_label.c new file +35 -0
new file mode 100644
index 0000000..7900914
@@ -0,0 +1,35 @@
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+
+#include "insn.h"
+#include "patch.h"
+
+static void __arch_jump_label_transform(struct jump_entry *entry,
+					enum jump_label_type type,
+					bool is_static)
+{
+	void *addr = (void *)entry->code;
+	unsigned int insn;
+
+	if (type == JUMP_LABEL_ENABLE)
+		insn = arm_gen_branch(entry->code, entry->target);
+	else
+		insn = arm_gen_nop();
+
+	if (is_static)
+		__patch_text(addr, insn);
+	else
+		patch_text(addr, insn);
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, false);
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+				      enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, true);
+}
Signature · 1 line
1.7.8.3
#20 lore raw

PATCH v3 1/1 ARM: 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.

---
v3: add missing #ifdef HAVE_JUMP_LABEL around the code in the C file

 arch/arm/Kconfig                  |    1 +
 arch/arm/include/asm/jump_label.h |   41 +++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/Makefile          |    1 +
 arch/arm/kernel/insn.h            |   10 +++++++++
 arch/arm/kernel/jump_label.c      |   39 +++++++++++++++++++++++++++++++++++
 5 files changed, 92 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/jump_label.h
 create mode 100644 arch/arm/kernel/jump_label.c
arch/arm/Kconfig +1 -0
index 57b6e96..aaf9a3c 100644
@@ -9,6 +9,7 @@ config ARM
 	select SYS_SUPPORTS_APM_EMULATION
 	select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
 	select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
+	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
 	select HAVE_ARCH_KGDB
 	select HAVE_KPROBES if !XIP_KERNEL
 	select HAVE_KRETPROBES if (HAVE_KPROBES)
arch/arm/include/asm/jump_label.h new file +41 -0

41 lines not on this page · raw message

arch/arm/kernel/Makefile +1 -0
index 8c63ee8..1b7d9a3 100644
@@ -38,6 +38,7 @@ obj-$(CONFIG_HAVE_ARM_SCU)	+= smp_scu.o
 obj-$(CONFIG_HAVE_ARM_TWD)	+= smp_twd.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o
+obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o kprobes-common.o patch.o
 ifdef CONFIG_THUMB2_KERNEL
arch/arm/kernel/insn.h +10 -0
index 994d60f..e96065d 100644
@@ -1,6 +1,16 @@
 #ifndef __ASM_ARM_INSN_H
 #define __ASM_ARM_INSN_H
 
+static inline unsigned long
+arm_gen_nop(void)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+	return 0xf3af8000; /* nop.w */
+#else
+	return 0xe1a00000; /* mov r0, r0 */
+#endif
+}
+
 unsigned long
 __arm_gen_branch(unsigned long pc, unsigned long addr, bool link);
 
arch/arm/kernel/jump_label.c new file +39 -0
new file mode 100644
index 0000000..4ce4f78
@@ -0,0 +1,39 @@
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+
+#include "insn.h"
+#include "patch.h"
+
+#ifdef HAVE_JUMP_LABEL
+
+static void __arch_jump_label_transform(struct jump_entry *entry,
+					enum jump_label_type type,
+					bool is_static)
+{
+	void *addr = (void *)entry->code;
+	unsigned int insn;
+
+	if (type == JUMP_LABEL_ENABLE)
+		insn = arm_gen_branch(entry->code, entry->target);
+	else
+		insn = arm_gen_nop();
+
+	if (is_static)
+		__patch_text(addr, insn);
+	else
+		patch_text(addr, insn);
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, false);
+}
+
+void arch_jump_label_transform_static(struct jump_entry *entry,
+				      enum jump_label_type type)
+{
+	__arch_jump_label_transform(entry, type, true);
+}
+
+#endif
Signature · 1 line
1.7.9
#21 lore raw

PATCH v3 1/1 ARM: add jump label support

Quoted 9 lines · Rabin Vincent

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.

---

...

Quoted 1 line

+static __always_inline bool arch_static_branch(struct jump_label_key *key)

Hmm, there's now a patch in linux-next ("static keys: Introduce 'struct static_key', static_key_true()/false() and static_key_slow_[inc|dec]()") via the -tip tree which would cause this not to build anymore since struct jump_label_key was renamed to struct static_key.

I'm not sure how this could be handled to keep this compiling both in the arm tree separately and in linux-next. I guess the easiest is to delay this until the next cycle, since it's not applied yet.

#22 lore raw

PATCH v3 1/1 ARM: add jump label support

Quoted 13 lines · Rabin Vincent
Quoted 9 lines · Rabin Vincent

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.

---

...

Quoted 1 line

+static __always_inline bool arch_static_branch(struct jump_label_key *key)

Quoted 8 lines

Hmm, there's now a patch in linux-next ("static keys: Introduce 'struct static_key', static_key_true()/false() and static_key_slow_[inc|dec]()") via the -tip tree which would cause this not to build anymore since struct jump_label_key was renamed to struct static_key.

I'm not sure how this could be handled to keep this compiling both in the arm tree separately and in linux-next. I guess the easiest is to delay this until the next cycle, since it's not applied yet.

hmm...Maybe the rename patches could be pulled into the arm tree somehow? Waiting a cycle works too...

Thanks,

-Jason

#23 lore raw

v2 cover ARM: jump label support

In reply to Rabin Vincent
Quoted 4 lines · Rabin Vincent

v2:
- Use helper macros from Dave Martin's "ARM: Add generic instruction opcode manipulation helpers"
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7278/1

This patch is broken, it contains two diff listings for arch/arm/include/asm/opcodes.h

The second one looks more correct as the diff accounts for commit 0c9030deaf59d444 (ARM: 7206/1: Add generic ARM instruction set condition code checks). However, when opcodes.h is included in assembler files it produces error as it #includes C headers.

Moving the #ifndef __ASSEMBLY__ to above the #includes makes things compile cleanly...

+#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/swab.h>

-#ifndef __ASSEMBLY__

Signature · 1 line
Tixy
#24 lore raw

v2 cover ARM: jump label support

Quoted 6 lines · Jon Medhurst (Tixy)
Quoted 4 lines · Rabin Vincent

v2:
- Use helper macros from Dave Martin's "ARM: Add generic instruction opcode manipulation helpers"
http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7278/1

Quoted 7 lines

This patch is broken, it contains two diff listings for arch/arm/include/asm/opcodes.h

The second one looks more correct as the diff accounts for commit 0c9030deaf59d444 (ARM: 7206/1: Add generic ARM instruction set condition code checks). However, when opcodes.h is included in assembler files it produces error as it #includes C headers.

Erm, I'm really not sure what happened there... it looks like I somehow pasted together an old and a new submission in one file whem I submittedo it. The mind boggles.

Review

Quoted 9 lines

Moving the #ifndef __ASSEMBLY__ to above the #includes makes things compile cleanly...

(quoted diff) +1 -1
+#ifndef __ASSEMBLY__
 #include <linux/types.h>
 #include <linux/swab.h>
 
-#ifndef __ASSEMBLY__

This is straightforwardly fixed -- I'll fix these issues and post back to the list.

Now reposted here:

http://lists.infradead.org/pipermail/linux-arm-kernel/2012-January/082603.html

When people have had a chance to review, I'll update the patch in the patch system.

Cheers
---Dave