ARM: ftrace: use canonical Thumb-2 wide instruction format
Subsystems (3)
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
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 | 29 ++++++++++++++++++----------- 1 files changed, 18 insertions(+), 11 deletions(-)
arch/arm/kernel/ftrace.c +18 -11
@@ -19,7 +19,7 @@#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 +88,7 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,if (link) second |=1 <<14 ; -return (second <<16 ) | first; +return (first <<16 ) | second; }#else static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
@@ -125,11 +125,20 @@ 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 ; +#ifndef __ARMEB__ +if (IS_ENABLED (CONFIG_THUMB2_KERNEL )) { + old = (old >>16 ) | (old <<16 ); + new = (new >>16 ) | (new <<16 ); + } +#endif -if (replaced != old) -return -EINVAL ; +if (old) { +if (probe_kernel_read (&replaced, (void *)pc,MCOUNT_INSN_SIZE )) +return -EFAULT ; + +if (replaced != old) +return -EINVAL ; + }if (probe_kernel_write ((void *)pc, &new,MCOUNT_INSN_SIZE ))return -EPERM ;
@@ -141,23 +150,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.7.3
PATCH 2/4 ARM: extract out insn generation code from ftrace
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 | 60 +++++++++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/insn.h | 19 ++++++++++++++ 4 files changed, 86 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
@@ -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 +60 -0
60 lines not on this page · raw message
arch/arm/kernel/insn.h new file +19 -0
@@ -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.7.3
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 14 lines · Rabin Vincent
Extract out the instruction generation code so that it can be used for jump labels too.
Signed-off-by Rabin Vincent <[email protected]>--- arch/arm/kernel/Makefile | 5 ++- arch/arm/kernel/ftrace.c | 61 +++------------------------------------------- arch/arm/kernel/insn.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/insn.h | 19 ++++++++++++++ 4 files changed, 86 insertions(+), 59 deletions(-) create mode 100644 arch/arm/kernel/insn.c create mode 100644 arch/arm/kernel/insn.harch/arm/kernel/Makefile +0
-0
[...]
arch/arm/kernel/Makefile static int __ftrace_modify_caller(unsigned long *callsite, · line 207
Quoted 8 lines
static int ftrace_modify_code(unsigned long pc, unsigned long old,
arch/arm/kernel/Makefile +1
-1@@ -256,7 +203,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 */
Does this code get used in Thumb-2 kernels? So far as I can tell, this code is used... but it looks like it shouldn't work, due to the ARM specifics.
Cheers
---Dave
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 13 lines · Dave Martin
Quoted 8 lines · Rabin Vincent
?static int ftrace_modify_code(unsigned long pc, unsigned long old,
(quoted diff) +1
-1@@ -256,7 +203,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 */Does this code get used in Thumb-2 kernels? ?So far as I can tell, this code is used... but it looks like it shouldn't work, due to the ARM specifics.
It's not used on Thumb-2. This is only used by the function graph tracer and that depends on !THUMB2_KERNEL.
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 15 lines · Rabin Vincent
Quoted 13 lines · Dave Martin
Quoted 8 lines · Rabin Vincent
?static int ftrace_modify_code(unsigned long pc, unsigned long old,
(quoted diff) +1
-1@@ -256,7 +203,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 */Does this code get used in Thumb-2 kernels? ?So far as I can tell, this code is used... but it looks like it shouldn't work, due to the ARM specifics.
Quoted 2 lines
It's not used on Thumb-2. This is only used by the function graph tracer and that depends on !THUMB2_KERNEL.
I assume there's no special reason why this doesn't work with a Thumb-2 kernel, other than that it simply hasn't implemented yet?
Are there any particular problems blocking this?
Cheers
---Dave
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 6 lines · Dave Martin
Quoted 2 lines · Rabin Vincent
It's not used on Thumb-2. ?This is only used by the function graph tracer and that depends on !THUMB2_KERNEL.
I assume there's no special reason why this doesn't work with a Thumb-2 kernel, other than that it simply hasn't implemented yet?
The function graph tracer expects to get a pointer to the saved return address of the function (on the stack). It changes this to its own return_hooker function where it records the exit from the function and jumps to the real return address.
We do this for ARM (the instruction set) by building with frame pointers, and the function prologues always save the registers in the expected order and the epilogues restore them out from the saved locations.
However, with Thumb-2, we don't get frame pointers even if we ask for them. So to support Thumb-2 we'd probably need a way to find and modify the LR without it being at a fixed location (MIPS does something similar IIRC). I haven't really looked into it.
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 13 lines · Rabin Vincent
Quoted 6 lines · Dave Martin
Quoted 2 lines · Rabin Vincent
It's not used on Thumb-2. ?This is only used by the function graph tracer and that depends on !THUMB2_KERNEL.
I assume there's no special reason why this doesn't work with a Thumb-2 kernel, other than that it simply hasn't implemented yet?
The function graph tracer expects to get a pointer to the saved return address of the function (on the stack). It changes this to its own
return_hookerfunction where it records the exit from the function and jumps to the real return address.
Quoted 8 lines
We do this for ARM (the instruction set) by building with frame pointers, and the function prologues always save the registers in the expected order and the epilogues restore them out from the saved locations.
However, with Thumb-2, we don't get frame pointers even if we ask for them. So to support Thumb-2 we'd probably need a way to find and modify the LR without it being at a fixed location (MIPS does something similar IIRC). I haven't really looked into it.
The unwind tables contain the information required to find the link register. This is how the backtracer works in Thumb-2 kernels or withCONFIG_ARM_UNWIND. This adds some complexity, but it also has some
advantages such as elimiating the runtime stack and instruction overhead associated with maintaining a framepointer chain.
Really, "find/change frame's stored return address" is a generic operation which is closely related to stack unwinding, and would best be implemented along with the unwinder code. Ideally, ftrace should not need to know or care _how_ this is accomplished. Indeed, at this level the operation isn't even arch-specific.
I will take a look at the ARM unwind/backtrace code and think about whether this could be factored out or exposed in a helpful way. Certainly we shouldn't implement a second unwind table parser in ftrace...
Are there any other dependencies on framepointers, or is that the only thing?
Cheers
---Dave
PATCH 2/4 ARM: extract out insn generation code from ftrace
Quoted 2 lines · Dave Martin
Are there any other dependencies on framepointers, or is that the only thing?
That's the only thing.
PATCH 3/4 ARM: extract out code patch function from kprobes
In reply to Rabin VincentExtract 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 | 72 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/patch.h | 7 ++++ 4 files changed, 105 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
@@ -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 +72 -0
72 lines not on this page · raw message
arch/arm/kernel/patch.h new file +7 -0
@@ -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.7.3
PATCH 3/4 ARM: extract out code patch function from kprobes
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 fromstop_machine()directly
Quoted 6 lines
- Patches the text on all CPUs only on processors requiring software broadcasting of cache operations
Cc Jon Medhurst <[email protected]>Signed-off-by Rabin Vincent <[email protected]>---
Looks good. I've a couple of minor inline comments below.
Quoted 167 lines
arch/arm/kernel/Makefile | 3 +- arch/arm/kernel/kprobes.c | 86 ++++++++++++-------------------------------- arch/arm/kernel/patch.c | 72 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/patch.h | 7 ++++ 4 files changed, 105 insertions(+), 63 deletions(-) create mode 100644 arch/arm/kernel/patch.c create mode 100644 arch/arm/kernel/patch.harch/arm/kernel/Makefile +2
-1@@ -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 elsearch/arm/kernel/kprobes.c +24
-62@@ -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 +13
-0@@ -0,0 +1,72 @@ +#include <linux/kernel.h> +#include <linux/kprobes.h> +#include <linux/stop_machine.h> + +#include <asm/cacheflush.h> +#include <asm/smp_plat.h> + +#include "patch.h" + +struct patch { +void *addr; +unsigned int insn; +};
arch/arm/kernel/patch.c line 23
Quoted 10 lines
arch/arm/kernel/patch.c new file +10
-0+ +void __kprobes __patch_text (void *addr,unsigned int insn) +{ +bool thumb2 =IS_ENABLED (CONFIG_THUMB2_KERNEL ); +int size; + +if (thumb2 && !is_wide_instruction (insn)) { + *(u16 *)addr = insn; + size =sizeof (u16); + }else if (thumb2 && ((unsigned long )addr &2 )) {
For pointer arithmetic, is casting to (uintptr_t) preferred to (unsigned long)? (There are several other places in this file where this comment applies.)
arch/arm/kernel/patch.c line 24
Quoted 1 line
arch/arm/kernel/patch.c new file +1
-0+u16 *addrw = addr;
Here's some very pedantic nit-picking...
I guess the 'w' in 'addrw' comes from X86 land meaning 'word'? 'h' for 'half-word' would be more appropriate for ARM.
Quoted 38 lines
arch/arm/kernel/patch.c new file +38
-0+ + addrw[0 ] = insn >>16 ; + addrw[1 ] = insn &0xffff ; + + size =sizeof (u32); + }else { +#ifndef __ARMEB__ +if (thumb2) + insn = (insn >>16 ) | (insn <<16 ); +#endif + + *(u32 *)addr = insn; + size =sizeof (u32); + } + +flush_icache_range ((unsigned long )(addr), + (unsigned long )(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) +{ +bool stopmachine; +struct patch patch = { + .addr = addr, + .insn = insn, + }; + + stopmachine =cache_ops_need_broadcast () || + (IS_ENABLED(CONFIG_THUMB2_KERNEL)
arch/arm/kernel/patch.c line 72
Quoted 10 lines
arch/arm/kernel/patch.c new file +10
-0+ &&is_wide_instruction (insn) + && ((unsigned long)addr & 2)); + +if (!stopmachine) +__patch_text (addr, insn); +else if (cache_ops_need_broadcast ()) +stop_machine (patch_text_stop_machine, &patch, cpu_online_mask); +else +stop_machine (patch_text_stop_machine, &patch,NULL ); +}
This inlines the cache_ops_need_broadcast() code twice. We could instead either cache the result in a local variable, or rewrite if/else clause to something like...
if (cache_ops_need_broadcast())
stop_machine(patch_text_stop_machine, &patch, cpu_online_mask);
else {
bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL)
&& is_wide_instruction(insn)
&& ((unsigned long)addr & 2))
if (straddles_word)
stop_machine(patch_text_stop_machine, &patch, NULL);
else
__patch_text(addr, insn);
}Quoted 13 lines
arch/arm/kernel/patch.h new file +7
-0@@ -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
PATCH 3/4 ARM: extract out code patch function from kprobes
Quoted 11 lines · Tixy
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 8 lines
Quoted 6 lines
?- Patches the text on all CPUs only on processors requiring software ? ?broadcasting of cache operations
Cc Jon Medhurst <[email protected]>Signed-off-by Rabin Vincent <[email protected]>---
Looks good. I've a couple of minor inline comments below.
Thank you for the review. I'll address all your comments in v2.
PATCH 4/4 ARM: add jump label support
In reply to Rabin VincentAdd the arch-specific code to support jump labels for ARM and Thumb-2.
Note that to build succesfully it requires (what will be) GCC 4.7.0 because of incomplete support for the '%c' specifier in earlier versions:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/jump_label.h | 41 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/Makefile | 1 + arch/arm/kernel/insn.h | 12 ++++++++++ arch/arm/kernel/jump_label.c | 35 +++++++++++++++++++++++++++++++ 5 files changed, 90 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
@@ -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
@@ -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 +12 -0
@@ -1,6 +1,18 @@#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 */ +#elif defined(CONFIG_CPU_32v6K) +return 0xe320f000 ;/* nop */ +#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
@@ -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.7.3
PATCH 4/4 ARM: add jump label support
Quoted 10 lines · Rabin Vincent
Add the arch-specific code to support jump labels for ARM and Thumb-2.
Note that to build succesfully it requires (what will be) GCC 4.7.0 because of incomplete support for the '%c' specifier in earlier versions:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637Cc Jason Baron <[email protected]>Signed-off-by Rabin Vincent <[email protected]>
This appears to imply that with this patch, we're upping the minimum gcc version for successfully building kernels to 4.7.0. That's _way_ too early (I'm using 4.3.5 here and don't have plans to update.)
arch/arm/kernel/insn.h line 12
Quoted 9 lines
arch/arm/kernel/insn.h +9
-0+static inline unsigned long +arm_gen_nop (void ) +{ +#ifdef CONFIG_THUMB2_KERNEL +return 0xf3af8000 ;/* nop.w */ +#elif defined(CONFIG_CPU_32v6K) +return 0xe320f000 ;/* nop */ +#else +return 0xe1a00000 ;/* mov r0, r0 */
There really is no point making the distinction between the new nop and the old nop instructions. The difference between them is that the new nop is a true 'no operation' whereas the old nop causes exactly what the instruction says to happen - which in effect is a no-op.
Obviously, doing a true no-operation may require in less power, but if you're using this code, you're debugging, so power usage isn't really a concern. So lets keep the code simple and just use the old nop here. It won't go away.
PATCH 4/4 ARM: add jump label support
Quoted 7 lines · Russell King - ARM Linux
Quoted 6 lines · Rabin Vincent
Add the arch-specific code to support jump labels for ARM and Thumb-2.
Note that to build succesfully it requires (what will be) GCC 4.7.0 because of incomplete support for the '%c' specifier in earlier versions:
Quoted 7 lines
Quoted 4 lines
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637Cc Jason Baron <[email protected]>Signed-off-by Rabin Vincent <[email protected]>This appears to imply that with this patch, we're upping the minimum gcc version for successfully building kernels to 4.7.0. That's _way_ too early (I'm using 4.3.5 here and don't have plans to update.)
Is there a way to detect that the compiler doesn't support %c? Perhaps we can do that in the same spirit of how we detect asm goto support for jump labels.
Signature · 2 lines
Sent by an employee of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
PATCH 4/4 ARM: add jump label support
Quoted 12 lines · Stephen Boyd
Quoted 11 lines · Russell King - ARM Linux
Quoted 10 lines · Rabin Vincent
Add the arch-specific code to support jump labels for ARM and Thumb-2.
Note that to build succesfully it requires (what will be) GCC 4.7.0 because of incomplete support for the '%c' specifier in earlier versions:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48637Cc Jason Baron <[email protected]>Signed-off-by Rabin Vincent <[email protected]>
Quoted 8 lines
Quoted 3 lines
This appears to imply that with this patch, we're upping the minimum gcc version for successfully building kernels to 4.7.0. That's _way_ too early (I'm using 4.3.5 here and don't have plans to update.)
Is there a way to detect that the compiler doesn't support %c? Perhaps we can do that in the same spirit of how we detect asm goto support for jump labels.
Right, for jump labels we have a script at: scripts/gcc-goto.sh, which basically just checks if we can compile 'asm goto' without error, so for %c, you could probably have some simple 'asm()' that uses %c, and see if it compiles. Although, I'm not sure if there's a arch specific dir, for such a thing?
thanks,
-Jason
PATCH 4/4 ARM: add jump label support
Quoted 9 lines · Jason Baron
Right, for jump labels we have a script at:
scripts/gcc-goto.sh, which basically just checks if we can compile 'asm goto' without error, so for %c, you could probably have some simple 'asm()' that uses %c, and see if it compiles. Although, I'm not sure if there's a arch specific dir, for such a thing?thanks,
-Jason
hmm...actually we could add it to the top level scripts/gcc-goto.sh, that would be fine, I can take a look at that...
-Jason
Re: [PATCH 4/4] ARM: add jump label support
Quoted 7 lines · Jason Baron
Quoted 6 lines · Jason Baron
Right, for jump labels we have a script at:
scripts/gcc-goto.sh, which basically just checks if we can compile 'asm goto' without error, so for %c, you could probably have some simple 'asm()' that uses %c, and see if it compiles. Although, I'm not sure if there's a arch specific dir, for such a thing?
Quoted 6 lines
Quoted 3 lines
thanks,
-Jason
hmm...actually we could add it to the top level
scripts/gcc-goto.sh, that would be fine, I can take a look at that...
Here's a patch. Atleast on MIPS %c means something else so I had to ifdef it for ARM:
8<----------------------------
Quoted 1 line
From
ea211ce77e0ea9c5b8cd32b99bfb24e0140f0068Mon 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 don't support the %c specifier fully, but do support asm goto. 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
@@ -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.7.3
Re: [PATCH 4/4] ARM: add jump label support
Quoted 37 lines · Rabin Vincent
Here's a patch. Atleast on MIPS %c means something else so I had to ifdef it for ARM:
8<----------------------------
Quoted 1 line
From
ea211ce77e0ea9c5b8cd32b99bfb24e0140f0068Mon Sep 17 00:00:00 2001From: Rabin Vincent <[email protected]>
Date: Wed, 23 Nov 2011 20:05:09 +0530
Subject: [PATCH] jump label: detect %c support for ARMSome versions of ARM GCC don't support the %c specifier fully, but do support asm goto. 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
Signed-off-by Rabin Vincent <[email protected]>--- scripts/gcc-goto.sh | 18 +++++++++++++++++- 1 files changed, 17 insertions(+), 1 deletions(-)scripts/gcc-goto.sh +7
-1@@ -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).
scripts/gcc-goto.sh line 21
Quoted 10 lines
scripts/gcc-goto.sh +10
-0+ */ + static struct { int dummy; int state; } tp; + asm ("@ %c0" :: "i" (&tp.state)); +#endif + +entry: + asm goto ("" :::: entry); + return 0; +} +END
Is the presence of asm goto and %c something we want to test together or separately? I suspect it's something we want to do separately.
Re: [PATCH 4/4] ARM: add jump label support
Quoted 13 lines · Russell King - ARM Linux
Quoted 12 lines · Rabin Vincent
scripts/gcc-goto.sh +12
-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)); +#endif +
Quoted 8 lines
scripts/gcc-goto.sh line 21
Quoted 5 lines
scripts/gcc-goto.sh +5
-0+entry: + ? ? asm goto ("" :::: entry); + ? ? return 0; +} +ENDIs the presence of asm goto and %c something we want to test together or separately? ?I suspect it's something we want to do separately.
Why would we want to do it separately?
The only reason I see is because the results of this test are assigned to a variable called CC_HAVE_ASM_GOTO and that is not an entirely accurate name (on ARM) after the addition of this test. If that's the concern, perhaps this variable could just be renamed?
PATCH 4/4 ARM: add jump label support
In reply to Russell King - ARM LinuxQuoted 16 lines · Russell King - ARM Linux
arch/arm/kernel/insn.h line 12
Quoted 9 lines · Rabin Vincent
arch/arm/kernel/insn.h +9
-0+static inline unsigned long +arm_gen_nop (void ) +{ +#ifdef CONFIG_THUMB2_KERNEL +return 0xf3af8000 ;/* nop.w */ +#elif defined(CONFIG_CPU_32v6K) +return 0xe320f000 ;/* nop */ +#else +return 0xe1a00000 ;/* mov r0, r0 */ There really is no point making the distinction between the new nop and the old nop instructions. The difference between them is that the new nop is a true 'no operation' whereas the old nop causes exactly what the instruction says to happen - which in effect is a no-op.
Quoted 4 lines
Obviously, doing a true no-operation may require in less power, but if you're using this code, you're debugging, so power usage isn't really a concern. So lets keep the code simple and just use the old nop here. It won't go away.
Is "if you're using this code, you're debugging" really correct here? Because the the purpose of jump labels is to reduce the overhead of tracepoints when they aren't activated, i.e. when you're not actively debugging.
PATCH 4/4 ARM: add jump label support
Quoted 22 lines · Rabin Vincent
Quoted 16 lines · Russell King - ARM Linux
arch/arm/kernel/insn.h line 12
Quoted 9 lines · Rabin Vincent
arch/arm/kernel/insn.h +9
-0+static inline unsigned long +arm_gen_nop (void ) +{ +#ifdef CONFIG_THUMB2_KERNEL +return 0xf3af8000 ;/* nop.w */ +#elif defined(CONFIG_CPU_32v6K) +return 0xe320f000 ;/* nop */ +#else +return 0xe1a00000 ;/* mov r0, r0 */ There really is no point making the distinction between the new nop and the old nop instructions. The difference between them is that the new nop is a true 'no operation' whereas the old nop causes exactly what the instruction says to happen - which in effect is a no-op.
Quoted 4 lines
Obviously, doing a true no-operation may require in less power, but if you're using this code, you're debugging, so power usage isn't really a concern. So lets keep the code simple and just use the old nop here. It won't go away.
Quoted 4 lines
Is "if you're using this code, you're debugging" really correct here? Because the the purpose of jump labels is to reduce the overhead of tracepoints when they aren't activated, i.e. when you're not actively debugging.
Let me repeat: the difference is power. Nothing more nothing less. 'nop' was invented to allow some vendors to 'optimize' nop from a power management point of view. Nothing more, nothing less.
'nop' will be executed as a true 'no operation' where as 'mov r0, r0' will tell the CPU to load the value of r0 and store it back into the register - which involves doing an operation.
There's no difference between "nop" vs "mov r0, r0" in terms of performance. It's purely a power thing.
If you have tracepoints enabled, then you're taking a performance hit anyway by having all those sites inserted. So, the only time you'd sanely enable them is if you're doing development work. You wouldn't enable them for production, unless you had some desire to waste CPU cycles needlessly in your end users products (maybe you're trying to go for the worlds slowest device?)
PATCH 4/4 ARM: add jump label support
Quoted 11 lines · Russell King - ARM Linux
Let me repeat: the difference is power. Nothing more nothing less. 'nop' was invented to allow some vendors to 'optimize' nop from a power management point of view. Nothing more, nothing less.
'nop' will be executed as a true 'no operation' where as 'mov r0, r0' will tell the CPU to load the value of r0 and store it back into the register - which involves doing an operation.
There's no difference between "nop" vs "mov r0, r0" in terms of performance. It's purely a power thing.
Quoted 6 lines
If you have tracepoints enabled, then you're taking a performance hit anyway by having all those sites inserted. So, the only time you'd sanely enable them is if you're doing development work. You wouldn't enable them for production, unless you had some desire to waste CPU cycles needlessly in your end users products (maybe you're trying to go for the worlds slowest device?)
I was thinking not of end user products but of distro kernels. For example Debian does have tracepoints built in into the standard kernels (at least on x86).
I will drop the "real nop" usage from v2 of this patchset as you suggested since the power impact of these few nops is vanishingly negligible.
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
In reply to Rabin VincentQuoted 38 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.
Signed-off-by Rabin Vincent <[email protected]>--- arch/arm/kernel/ftrace.c | 29 ++++++++++++++++++----------- 1 files changed, 18 insertions(+), 11 deletions(-)arch/arm/kernel/ftrace.c +2
-2@@ -19,7 +19,7 @@#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 +88,7 @@ static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,if (link) second |=1 <<14 ; -return (second <<16 ) | first; +return (first <<16 ) | second; }#else static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr,
arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 131
Quoted 9 lines
arch/arm/kernel/ftrace.c +4
-2@@ -125,11 +125,20 @@ 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 ; +#ifndef __ARMEB__ +if (IS_ENABLED (CONFIG_THUMB2_KERNEL )) { + old = (old >>16 ) | (old <<16 ); + new = (new >>16 ) | (new <<16 );
I think swahw32() in <linux/swab.h> can be used for this operation.
Really though, we need a common set of "load and store instruction" macros, rather than duplicating this knowledge everywhere.
In particular, we really want those macros to encapsulate the #ifdef __ARMEB__ stuff.
Quoted 31 lines
arch/arm/kernel/ftrace.c +11
-5+ } +#endif -if (replaced != old) -return -EINVAL ; +if (old) { +if (probe_kernel_read (&replaced, (void *)pc,MCOUNT_INSN_SIZE )) +return -EFAULT ; + +if (replaced != old) +return -EINVAL ; + }if (probe_kernel_write ((void *)pc, &new,MCOUNT_INSN_SIZE ))return -EPERM ;@@ -141,23 +150,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);
arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old, · line 169
Quoted 10 lines
arch/arm/kernel/ftrace.c +1
-2#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
Why don't we check the old value any more?
It would be good to see something in comments or the commit log clarifying this.
To what extent can this be unified with the kprobes functionality? (if you've already done that, ignore this comment -- I confess I don't understand all the details of these patches...)
Cheers
---Dave
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
Quoted 7 lines · Dave Martin
Quoted 4 lines · Rabin Vincent
+#ifndef
__ARMEB__
+ ? ? if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ ? ? ? ? ? ? old = (old >> 16) | (old << 16);
+ ? ? ? ? ? ? new = (new >> 16) | (new << 16);I think
swahw32()in <linux/swab.h> can be used for this operation.
Yes.
Quoted 2 lines
Really though, we need a common set of "load and store instruction" macros, rather than duplicating this knowledge everywhere.
Yes, though this ftrace code may not be able to use them directly since it uses probe_kernel_read()/write().
Quoted 2 lines
In particular, we really want those macros to encapsulate the #ifdef
__ARMEB__stuff.
The ifdef for ARMEB is a bit jarring, especially since now we can even get rid of ifdefs for CONFIG_THUMB2_KERNEL. An arm_is_bigendian() or somesuch macro in a header would be preferable for this, I think.
Quoted 39 lines
Quoted 39 lines
+ ? ? }
(quoted diff) +8
-2+#endif - ? ? if (replaced != old) - ? ? ? ? ? ? return -EINVAL; + ? ? if (old) { + ? ? ? ? ? ? if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) + ? ? ? ? ? ? ? ? ? ? return -EFAULT; + + ? ? ? ? ? ? if (replaced != old) + ? ? ? ? ? ? ? ? ? ? return -EINVAL; + ? ? }? ? ? if (
probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE)) ? ? ? ? ? ? ? return-EPERM;(quoted diff) +2
-3@@ -141,23 +150,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);
Quoted 6 lines
Quoted 4 lines
- ? ? ? ? ? ? ret =
ftrace_modify_code(pc, old, new);
+ ? ? ? ? ? ? ret =ftrace_modify_code(pc, 0, new); ? ? ? }
?#endifWhy don't we check the old value any more?
The ftrace_modify_code() checks the location its modifying to ensure that the old value was what it expected it to be -- this is useful for example if we have problems with the recordmcount code that makes it record wrong locations.
In this particular case however, what we're modifying is not code at an mcount location but some of the code in entry-common.S which is at the location of a known symbol. The safety check for the old value was quite useless in this case because we were just memcpy()ing the content of the location and passing that in as the old value.
The reason it's done in this patch is that because of converting to the canonical format, we'd need an additional ifdef-ARMEB/swahw32() here after doing the memcpy(), for the memcmp() in ftrace_modify_code() to succeed. Instead, we just avoid the comparison for this case.
Quoted 2 lines
It would be good to see something in comments or the commit log clarifying this.
Agreed. Perhaps it should even be done in a separate patch.
Quoted 4 lines
To what extent can this be unified with the kprobes functionality? (if you've already done that, ignore this comment -- I confess I don't understand all the details of these patches...)
With this patch series:
- kprobes and jump labels use the common text patching code
- jump labels and ftrace use the common instruction generation code
kprobes and ftrace, however, don't share anything. We could make ftrace use __patch_text(), although that would only save half-a-dozen lines of code and also remove the use of probe_kernel_write(), which all the other arch ftrace implementations use.
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
Quoted 9 lines · Rabin Vincent
Quoted 7 lines · Dave Martin
Quoted 4 lines · Rabin Vincent
+#ifndef
__ARMEB__
+ ? ? if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ ? ? ? ? ? ? old = (old >> 16) | (old << 16);
+ ? ? ? ? ? ? new = (new >> 16) | (new << 16);I think
swahw32()in <linux/swab.h> can be used for this operation.
Quoted 7 lines
Yes.
Quoted 2 lines
Really though, we need a common set of "load and store instruction" macros, rather than duplicating this knowledge everywhere.
Yes, though this ftrace code may not be able to use them directly since it uses probe_kernel_read()/write().
In that case what we would want are macros to convert instructions between integer and in-memory representation, rather than conflating all that together in some memory accessor macros.
How about:
#include <linux/swab.h>
#ifdef __ARMEB__
#define insn_to_mem_arm(insn) swab32(insn)
#define insn_to_mem_thumb16(insn) swab16(insn)
#define insn_to_mem_thumb32(insn) swab16(insn)
#else
#define insn_to_mem_arm(insn) (insn)
#define insn_to_mem_thumb16(insn) (insn)
#define insn_to_mem_thumb32(insn) shahw32(insn)
#endif
#define mem_to_insn_arm(insn) insn_to_mem_asm(insn) #define mem_to_insn_thumb16(insn) insn_to_mem_thumb16(insn) #define mem_to_insn_thumb32(insn) insn_to_mem_thumb32(insn)
Because these are all straightforward swap operations, we don't really need separate forwards and backwards operations, but having the separate names may make calling code easier to read.
I'm still not sure exactly which header this belongs in, but it's a core ARM thing; not local to kprobes or ftrace, etc.
If this looks sensible, it would also make sense for Junxiao Bi to build his big-endian fixes on it.
Cheers
---Dave
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
Quoted 44 lines · Dave Martin
Quoted 11 lines · Rabin Vincent
Quoted 9 lines · Dave Martin
arch/arm/kernel/ftrace.c static int ftrace_modify_code(unsigned long pc, unsigned long old,
Quoted 5 lines · Rabin Vincent
arch/arm/kernel/ftrace.c +4
-0+#ifndef __ARMEB__ +if (IS_ENABLED (CONFIG_THUMB2_KERNEL )) { + old = (old>>16 ) | (old<<16 ); + new = (new>>16 ) | (new<<16 );I think
swahw32()in<linux/swab.h> can be used for this operation.Quoted 9 lines
Yes.
Quoted 3 lines
Really though, we need a common set of "load and store instruction" macros, rather than duplicating this knowledge everywhere.
Yes, though this ftrace code may not be able to use them directly since it uses probe_kernel_read()/write().
In that case what we would want are macros to convert instructions between integer and in-memory representation, rather than conflating all that together in some memory accessor macros.
How about:
#include<linux/swab.h>
#ifdef
__ARMEB__
#defineinsn_to_mem_arm(insn)swab32(insn)
#defineinsn_to_mem_thumb16(insn)swab16(insn)
#defineinsn_to_mem_thumb32(insn)swab16(insn)
#else
#defineinsn_to_mem_arm(insn)(insn)
#defineinsn_to_mem_thumb16(insn)(insn)
#defineinsn_to_mem_thumb32(insn)shahw32(insn)
#endif#define
mem_to_insn_arm(insn)insn_to_mem_asm(insn)#definemem_to_insn_thumb16(insn)insn_to_mem_thumb16(insn)#definemem_to_insn_thumb32(insn)insn_to_mem_thumb32(insn)
Quoted 8 lines
Because these are all straightforward swap operations, we don't really need separate forwards and backwards operations, but having the separate names may make calling code easier to read.
I'm still not sure exactly which header this belongs in, but it's a core ARM thing; not local to kprobes or ftrace, etc.
Yes, these macros are useful for be8 support. Do they deserve a separated header file as there is no appropriate one for them now?
Quoted 7 lines
If this looks sensible, it would also make sense for Junxiao Bi to build his big-endian fixes on it.
Cheers
---Dave
PATCH 1/4 ARM: ftrace: use canonical Thumb-2 wide instruction format
Quoted 41 lines · Bi Junxiao
Quoted 40 lines · Dave Martin
Quoted 6 lines · Rabin Vincent
Quoted 5 lines · Dave Martin
Quoted 4 lines · Rabin Vincent
arch/arm/kernel/ftrace.c +4
-0+#ifndef __ARMEB__ +if (IS_ENABLED (CONFIG_THUMB2_KERNEL )) { + old = (old>>16 ) | (old<<16 ); + new = (new>>16 ) | (new<<16 );Quoted 7 lines
Quoted 1 line
I think
swahw32()in<linux/swab.h> can be used for this operation.Yes.
Quoted 2 lines
Really though, we need a common set of "load and store instruction" macros, rather than duplicating this knowledge everywhere.
Yes, though this ftrace code may not be able to use them directly since it uses probe_kernel_read()/write().
In that case what we would want are macros to convert instructions between integer and in-memory representation, rather than conflating all that together in some memory accessor macros.
How about:
#include<linux/swab.h>
#ifdef
__ARMEB__
#defineinsn_to_mem_arm(insn)swab32(insn)
#defineinsn_to_mem_thumb16(insn)swab16(insn)
#defineinsn_to_mem_thumb32(insn)swab16(insn)
#else
#defineinsn_to_mem_arm(insn)(insn)
#defineinsn_to_mem_thumb16(insn)(insn)
#defineinsn_to_mem_thumb32(insn)shahw32(insn)
#endif#define
mem_to_insn_arm(insn)insn_to_mem_asm(insn)#definemem_to_insn_thumb16(insn)insn_to_mem_thumb16(insn)#definemem_to_insn_thumb32(insn)insn_to_mem_thumb32(insn)Because these are all straightforward swap operations, we don't really need separate forwards and backwards operations, but having the separate names may make calling code easier to read.
Quoted 7 lines
Quoted 3 lines
I'm still not sure exactly which header this belongs in, but it's a core ARM thing; not local to kprobes or ftrace, etc.
Yes, these macros are useful for be8 support. Do they deserve a separated header file as there is no appropriate one for them now?
Quoted 2 lines
If this looks sensible, it would also make sense for Junxiao Bi to build his big-endian fixes on it.
I don't really see a header where this stuff fits.
I'll post an RFC.
Cheers
---Dave