powerpc: Core ftrace rework, support for ftrace direct and bpf trampolines
Naveen N Rao
reviewerv4 cover powerpc: Core ftrace rework, support for ftrace direct and bpf trampolines
This is v4 of the series posted here:
http://lkml.kernel.org/r/[email protected]
This series reworks core ftrace support on powerpc to have the function profiling sequence moved out of line. This enables us to have a single nop at kernel function entry virtually eliminating effect of the function tracer when it is not enabled. The function profile sequence is moved out of line and is allocated at two separate places depending on a new config option.
For 64-bit powerpc, the function profiling sequence is also updated to include an additional instruction 'mtlr r0' after the usual two-instruction sequence to fix link stack imbalance (return address predictor) when ftrace is enabled. This showed an improvement of ~22% in null_syscall benchmark on a Power 10 system with ftrace enabled.
Finally, support for ftrace direct calls is added based on support for DYNAMIC_FTRACE_WITH_CALL_OPS. BPF Trampoline support is added atop this.
Support for ftrace direct calls is added for 32-bit powerpc. There is some code to enable bpf trampolines for 32-bit powerpc, but it is not complete and will need to be pursued separately.
This is marked RFC so that this can get more testing. Patches 1 to 10 are independent of this series and can go in separately though. Rest of the patches depend on the series from Benjamin Gray adding support for patch_uint() and patch_ulong():
http://lkml.kernel.org/r/[email protected]
Changelog v4:
- Patches 1, 10 and 13 are new.
- Address review comments from Nick. Numerous changes throughout the patch series.
- Extend support for ftrace ool to vmlinux text up to 64MB (patch 13).
- Address remaining TODOs in support for BPF Trampolines.
- Update synchronization when patching instructions during trampoline attach/detach.
- Naveen
Naveen N Rao (17):
powerpc/trace: Account for -fpatchable-function-entry support by
toolchain
powerpc/kprobes: Use ftrace to determine if a probe is at function
entry
powerpc64/ftrace: Nop out additional 'std' instruction emitted by gcc
v5.x
powerpc32/ftrace: Unify 32-bit and 64-bit ftrace entry code powerpc/module_64: Convert #ifdef to IS_ENABLED() powerpc/ftrace: Remove pointer to struct module from dyn_arch_ftrace powerpc/ftrace: Skip instruction patching if the instructions are the
same
powerpc/ftrace: Move ftrace stub used for init text before _einittext powerpc64/bpf: Fold bpf_jit_emit_func_call_hlp() into
bpf_jit_emit_func_call_rel()
powerpc/ftrace: Add a postlink script to validate function tracer
kbuild: Add generic hook for architectures to use before the final
vmlinux link
powerpc64/ftrace: Move ftrace sequence out of line powerpc64/ftrace: Support .text larger than 32MB with out-of-line
stubs
powerpc/ftrace: Add support for DYNAMIC_FTRACE_WITH_CALL_OPS powerpc/ftrace: Add support for DYNAMIC_FTRACE_WITH_DIRECT_CALLS samples/ftrace: Add support for ftrace direct samples on powerpc powerpc64/bpf: Add support for bpf trampolines
arch/Kconfig | 6 + arch/powerpc/Kconfig | 23 +- arch/powerpc/Makefile | 8 + arch/powerpc/Makefile.postlink | 8 + arch/powerpc/include/asm/ftrace.h | 32 +- arch/powerpc/include/asm/module.h | 5 + arch/powerpc/include/asm/ppc-opcode.h | 14 + arch/powerpc/kernel/asm-offsets.c | 11 + arch/powerpc/kernel/kprobes.c | 18 +- arch/powerpc/kernel/module_64.c | 66 +- arch/powerpc/kernel/trace/Makefile | 11 +- arch/powerpc/kernel/trace/ftrace.c | 295 ++++++- arch/powerpc/kernel/trace/ftrace_64_pg.c | 69 +- arch/powerpc/kernel/trace/ftrace_entry.S | 246 ++++-- arch/powerpc/kernel/vmlinux.lds.S | 3 +- arch/powerpc/net/bpf_jit.h | 12 + arch/powerpc/net/bpf_jit_comp.c | 842 +++++++++++++++++++- arch/powerpc/net/bpf_jit_comp32.c | 7 +- arch/powerpc/net/bpf_jit_comp64.c | 68 +- arch/powerpc/tools/Makefile | 10 + arch/powerpc/tools/ftrace-gen-ool-stubs.sh | 52 ++ arch/powerpc/tools/ftrace_check.sh | 45 ++ samples/ftrace/ftrace-direct-modify.c | 85 +- samples/ftrace/ftrace-direct-multi-modify.c | 101 ++- samples/ftrace/ftrace-direct-multi.c | 79 +- samples/ftrace/ftrace-direct-too.c | 83 +- samples/ftrace/ftrace-direct.c | 69 +- scripts/Makefile.vmlinux | 8 + scripts/link-vmlinux.sh | 11 +- 29 files changed, 2083 insertions(+), 204 deletions(-) create mode 100644 arch/powerpc/tools/Makefile create mode 100755 arch/powerpc/tools/ftrace-gen-ool-stubs.sh create mode 100755 arch/powerpc/tools/ftrace_check.sh
base-commit: 582b0e554593e530b1386eacafee6c412c5673cc
prerequisite-patch-id: a1d50e589288239d5a8b1c1f354cd4737057c9d3
prerequisite-patch-id: da4142d56880861bd0ad7ad7087c9e2670a2ee54
prerequisite-patch-id: 609d292e054b2396b603890522a940fa0bdfb6d8
prerequisite-patch-id: 6f7213fb77b1260defbf43be0e47bff9c80054cc
prerequisite-patch-id: ad3b71bf071ae4ba1bee5b087e61a2055772a74f
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 1/17 powerpc/trace: Account for -fpatchable-function-entry support by toolchain
So far, we have relied on the fact that gcc supports both -mprofile-kernel, as well as -fpatchable-function-entry, and clang supports neither. Our Makefile only checks for CONFIG_MPROFILE_KERNEL to decide which files to build. Clang has a feature request out [*] to implement -fpatchable-function-entry, and is unlikely to support -mprofile-kernel.
Update our Makefile checks so that we pick up the correct files to build once clang picks up support for -fpatchable-function-entry.
[*] https://github.com/llvm/llvm-project/issues/57031
--- arch/powerpc/kernel/trace/Makefile | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
arch/powerpc/kernel/trace/Makefile +7 -4
@@ -9,12 +9,15 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_ftrace_64_pg.o = $(CC_FLAGS_FTRACE) endif -obj32-$(CONFIG_FUNCTION_TRACER) += ftrace.o ftrace_entry.o -ifdef CONFIG_MPROFILE_KERNEL -obj64-$(CONFIG_FUNCTION_TRACER) += ftrace.o ftrace_entry.o +ifdef CONFIG_FUNCTION_TRACER +obj32-y += ftrace.o ftrace_entry.o +ifeq ($(CONFIG_MPROFILE_KERNEL)$(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY),) +obj64-y += ftrace_64_pg.o ftrace_64_pg_entry.o else -obj64-$(CONFIG_FUNCTION_TRACER) += ftrace_64_pg.o ftrace_64_pg_entry.o +obj64-y += ftrace.o ftrace_entry.o endif +endif + obj-$(CONFIG_TRACING) += trace_clock.o obj-$(CONFIG_PPC64) += $(obj64-y)
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 2/17 powerpc/kprobes: Use ftrace to determine if a probe is at function entry
In reply to Naveen N RaoRather than hard-coding the offset into a function to be used to determine if a kprobe is at function entry, use ftrace_location() to determine the ftrace location within the function and categorize all instructions till that offset to be function entry.
For functions that cannot be traced, we fall back to using a fixed offset of 8 (two instructions) to categorize a probe as being at function entry for 64-bit elfv2, unless we are using pcrel.
--- arch/powerpc/kernel/kprobes.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
arch/powerpc/kernel/kprobes.c +8 -10
@@ -105,24 +105,22 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset)return addr; } -static bool arch_kprobe_on_func_entry (unsigned long offset) +static bool arch_kprobe_on_func_entry (unsigned long addr,unsigned long offset) { -#ifdef CONFIG_PPC64_ELF_ABI_V2 -#ifdef CONFIG_KPROBES_ON_FTRACE -return offset <=16 ; -#else -return offset <=8 ; -#endif -#else +unsigned long ip =ftrace_location (addr); + +if (ip) +return offset <= (ip - addr); +if (IS_ENABLED (CONFIG_PPC64_ELF_ABI_V2 ) && !IS_ENABLED (CONFIG_PPC_KERNEL_PCREL )) +return offset <=8 ;return !offset; -#endif }/* XXX try and fold the magic of kprobe_lookup_name() in this */ kprobe_opcode_t *arch_adjust_kprobe_addr (unsigned long addr,unsigned long offset,bool *on_func_entry) { - *on_func_entry =arch_kprobe_on_func_entry (offset); + *on_func_entry =arch_kprobe_on_func_entry (addr, offset);return (kprobe_opcode_t *)(addr + offset); }
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 3/17 powerpc64/ftrace: Nop out additional 'std' instruction emitted by gcc v5.x
In reply to Naveen N RaoGcc v5.x emits a 3-instruction sequence for -mprofile-kernel:
mflr r0 std r0, 16(r1) bl _mcount
Gcc v6.x moved to a simpler 2-instruction sequence by removing the 'std' instruction. The store saved the return address in the LR save area in the caller stack frame for stack unwinding. However, with dynamic ftrace, we no longer have a call to _mcount on kernel boot when ftrace is not enabled. When ftrace is enabled, that store is performed within ftrace_caller(). As such, the additional 'std' instruction is redundant. Nop it out on kernel boot.
With this change, we now use the same 2-instruction profiling sequence with both -mprofile-kernel, as well as -fpatchable-function-entry on 64-bit powerpc.
--- arch/powerpc/kernel/trace/ftrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/powerpc/kernel/trace/ftrace.c +5 -1
@@ -246,8 +246,12 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)/* Expected sequence: 'mflr r0', ['std r0,16(r1)'], 'bl _mcount' */ ret =ftrace_read_inst (ip -4 , &old);if (!ret && !ppc_inst_equal (old,ppc_inst (PPC_RAW_MFLR (_R0)))) { +/* Gcc v5.x emit the additional 'std' instruction, gcc v6.x don't */ ret =ftrace_validate_inst (ip -8 ,ppc_inst (PPC_RAW_MFLR (_R0))); - ret |=ftrace_validate_inst (ip -4 ,ppc_inst (PPC_RAW_STD (_R0, _R1,16 ))); +if (ret) +return ret; + ret =ftrace_modify_code (ip -4 ,ppc_inst (PPC_RAW_STD (_R0, _R1,16 )), +ppc_inst (PPC_RAW_NOP ())); } }else {return -EINVAL ;
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 4/17 powerpc32/ftrace: Unify 32-bit and 64-bit ftrace entry code
In reply to Naveen N RaoOn 32-bit powerpc, gcc generates a three instruction sequence for function profiling:
mflr r0 stw r0, 4(r1) bl _mcount
On kernel boot, the call to _mcount() is nop-ed out, to be patched back in when ftrace is actually enabled. The 'stw' instruction therefore is not necessary unless ftrace is enabled. Nop it out during ftrace init.
When ftrace is enabled, we want the 'stw' so that stack unwinding works properly. Perform the same within the ftrace handler, similar to 64-bit powerpc.
--- arch/powerpc/kernel/trace/ftrace.c | 6 ++++-- arch/powerpc/kernel/trace/ftrace_entry.S | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-)
arch/powerpc/kernel/trace/ftrace.c +4 -2
@@ -240,8 +240,10 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) }else if (IS_ENABLED (CONFIG_PPC32 )) {/* Expected sequence: 'mflr r0', 'stw r0,4(r1)', 'bl _mcount' */ ret =ftrace_validate_inst (ip -8 ,ppc_inst (PPC_RAW_MFLR (_R0))); -if (!ret) - ret =ftrace_validate_inst (ip -4 ,ppc_inst (PPC_RAW_STW (_R0, _R1,4 ))); +if (ret) +return ret; + ret =ftrace_modify_code (ip -4 ,ppc_inst (PPC_RAW_STW (_R0, _R1,4 )), +ppc_inst (PPC_RAW_NOP ())); }else if (IS_ENABLED (CONFIG_MPROFILE_KERNEL )) {/* Expected sequence: 'mflr r0', ['std r0,16(r1)'], 'bl _mcount' */ ret =ftrace_read_inst (ip -4 , &old);
arch/powerpc/kernel/trace/ftrace_entry.S +2 -2
@@ -33,6 +33,8 @@ * and then arrange for the ftrace function to be called. */ .macro ftrace_regs_entry allregs + /* Save the original return address in A's stack frame */ + PPC_STL r0, LRSAVE(r1) /* Create a minimal stack frame for representing B */ PPC_STLU r1, -STACK_FRAME_MIN_SIZE(r1)
@@ -44,8 +46,6 @@ SAVE_GPRS(3, 10, r1) #ifdef CONFIG_PPC64 - /* Save the original return address in A's stack frame */ - std r0, LRSAVE+SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE(r1) /* Ok to continue? */ lbz r3, PACA_FTRACE_ENABLED(r13) cmpdi r3, 0
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 5/17 powerpc/module_64: Convert #ifdef to IS_ENABLED()
In reply to Naveen N RaoMinor refactor for converting #ifdef to IS_ENABLED().
--- arch/powerpc/kernel/module_64.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
arch/powerpc/kernel/module_64.c +2 -8
@@ -241,14 +241,8 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, } } -#ifdef CONFIG_DYNAMIC_FTRACE -/* make the trampoline to the ftrace_caller */ - relocs++; -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS -/* an additional one for ftrace_regs_caller */ - relocs++; -#endif -#endif +/* stubs for ftrace_caller and ftrace_regs_caller */ + relocs +=IS_ENABLED (CONFIG_DYNAMIC_FTRACE ) +IS_ENABLED (CONFIG_DYNAMIC_FTRACE_WITH_REGS );pr_debug ("Looks like a total of %lu stubs, max\n" , relocs);return relocs *sizeof (struct ppc64_stub_entry );
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 6/17 powerpc/ftrace: Remove pointer to struct module from dyn_arch_ftrace
In reply to Naveen N RaoPointer to struct module is only relevant for ftrace records belonging to kernel modules. Having this field in dyn_arch_ftrace wastes memory for all ftrace records belonging to the kernel. Remove the same in favour of looking up the module from the ftrace record address, similar to other architectures.
--- arch/powerpc/include/asm/ftrace.h | 1 - arch/powerpc/kernel/trace/ftrace.c | 49 +++++++++-------- arch/powerpc/kernel/trace/ftrace_64_pg.c | 69 ++++++++++-------------- 3 files changed, 56 insertions(+), 63 deletions(-)
arch/powerpc/include/asm/ftrace.h +0 -1
@@ -26,7 +26,6 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,struct module ;struct dyn_ftrace ;struct dyn_arch_ftrace { -struct module *mod; };#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
arch/powerpc/kernel/trace/ftrace.c +28 -21
70 lines not on this page · raw message
arch/powerpc/kernel/trace/ftrace_64_pg.c +28 -41
111 lines not on this page · raw message
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 7/17 powerpc/ftrace: Skip instruction patching if the instructions are the same
In reply to Naveen N RaoTo simplify upcoming changes to ftrace, add a check to skip actual instruction patching if the old and new instructions are the same. We still validate that the instruction is what we expect, but don't actually patch the same instruction again.
--- arch/powerpc/kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/trace/ftrace.c +1 -1
@@ -82,7 +82,7 @@ static inline int ftrace_modify_code(unsigned long ip, ppc_inst_t old, ppc_inst_ {int ret =ftrace_validate_inst (ip, old); -if (!ret) +if (!ret && !ppc_inst_equal (old, new)) ret =patch_instruction ((u32 *)ip, new);return ret;
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 8/17 powerpc/ftrace: Move ftrace stub used for init text before _einittext
In reply to Naveen N RaoMove the ftrace stub used to cover inittext before _einittext so that it is within kernel text, as seen through core_kernel_text(). This is required for a subsequent change to ftrace.
--- arch/powerpc/kernel/vmlinux.lds.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
arch/powerpc/kernel/vmlinux.lds.S +1 -2
@@ -267,14 +267,13 @@ SECTIONS .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; INIT_TEXT - + *(.tramp.ftrace.init); /* *.init.text might be RO so we must ensure this section ends on * a page boundary. */ . = ALIGN(PAGE_SIZE); _einittext = .; - *(.tramp.ftrace.init); } :text /* .exit.text is discarded at runtime, not link time,
Signature · 1 line
2.45.2
Nicholas Piggin
reviewerRe: [RFC PATCH v4 08/17] powerpc/ftrace: Move ftrace stub used for init text before _einittext
Quoted 3 lines · Naveen N Rao
Move the ftrace stub used to cover inittext before
_einittextso that it is within kernel text, as seen throughcore_kernel_text(). This is required for a subsequent change to ftrace.
Hmm, is there a reason it was outside einittext anyway?
Does it do anything else? Other than symbols, on some 32-bit platforms it looks like it could change some of the initial mapping/pinning. Maybe they jut get lucky and always map it before the change anyway?
It looks like the right thing to do even without the subsequent ftrace change though.
Thanks,
Nick
Quoted 26 lines
Signed-off-by Naveen N Rao <[email protected]>--- arch/powerpc/kernel/vmlinux.lds.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)arch/powerpc/kernel/vmlinux.lds.S +1
-2@@ -267,14 +267,13 @@ SECTIONS .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; INIT_TEXT - + *(.tramp.ftrace.init); /* *.init.text might be RO so we must ensure this section ends on * a page boundary. */ . = ALIGN(PAGE_SIZE); _einittext = .; - *(.tramp.ftrace.init); } :text /* .exit.text is discarded at runtime, not link time,
Naveen N Rao
reviewerRFC PATCH v4 9/17 powerpc64/bpf: Fold bpf_jit_emit_func_call_hlp() into bpf_jit_emit_func_call_rel()
In reply to Naveen N RaoCommit 61688a82e047 ("powerpc/bpf: enable kfunc call") enhanced bpf_jit_emit_func_call_hlp() to handle calls out to module region, where bpf progs are generated. The only difference now between bpf_jit_emit_func_call_hlp() and bpf_jit_emit_func_call_rel() is in handling of the initial pass where target function address is not known. Fold that logic into bpf_jit_emit_func_call_hlp() and rename it to bpf_jit_emit_func_call_rel() to simplify bpf function call JIT code.
We don't actually need to load/restore TOC across a call out to a different kernel helper or to a different bpf program since they all work with the kernel TOC. We only need to do it if we have to call out to a module function. So, guard TOC load/restore with appropriate conditions.
--- arch/powerpc/net/bpf_jit_comp64.c | 61 +++++++++---------------------- 1 file changed, 17 insertions(+), 44 deletions(-)
arch/powerpc/net/bpf_jit_comp64.c +17 -44
@@ -202,14 +202,22 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)EMIT (PPC_RAW_BLR ()); } -static int -bpf_jit_emit_func_call_hlp (u32 *image,u32 *fimage,struct codegen_context *ctx,u64 func) +int bpf_jit_emit_func_call_rel (u32 *image,u32 *fimage,struct codegen_context *ctx,u64 func) {unsigned long func_addr = func ?ppc_function_entry ((void *)func) :0 ;long reladdr; -if (WARN_ON_ONCE (!kernel_text_address (func_addr))) -return -EINVAL ; +/* bpf to bpf call, func is not known in the initial pass. Emit 5 nops as a placeholder */ +if (!func) { +for (int i =0 ; i <5 ; i++) +EMIT (PPC_RAW_NOP ()); +/* elfv1 needs an additional instruction to load addr from descriptor */ +if (IS_ENABLED (CONFIG_PPC64_ELF_ABI_V1 )) +EMIT (PPC_RAW_NOP ()); +EMIT (PPC_RAW_MTCTR (_R12)); +EMIT (PPC_RAW_BCTRL ()); +return 0 ; + }#ifdef CONFIG_PPC_KERNEL_PCREL reladdr = func_addr - local_paca->kernelbase;
@@ -266,7 +274,8 @@ bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx,* We can clobber r2 since we get called through a * function pointer (so caller will save/restore r2). */ -EMIT (PPC_RAW_LD (_R2,bpf_to_ppc (TMP_REG_2 ),8 )); +if (is_module_text_address (func_addr)) +EMIT (PPC_RAW_LD (_R2,bpf_to_ppc (TMP_REG_2 ),8 )); }else {PPC_LI64 (_R12, func);EMIT (PPC_RAW_MTCTR (_R12));
@@ -276,46 +285,14 @@ bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx,* Load r2 with kernel TOC as kernel TOC is used if function address falls * within core kernel text. */ -EMIT (PPC_RAW_LD (_R2, _R13, offsetof(struct paca_struct , kernel_toc))); +if (is_module_text_address (func_addr)) + EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))); }#endif return 0 ; } -int bpf_jit_emit_func_call_rel (u32 *image,u32 *fimage,struct codegen_context *ctx,u64 func) -{ -unsigned int i, ctx_idx = ctx->idx; - -if (WARN_ON_ONCE (func &&is_module_text_address (func))) -return -EINVAL ; - -/* skip past descriptor if elf v1 */ - func +=FUNCTION_DESCR_SIZE ; - -/* Load function address into r12 */ -PPC_LI64 (_R12, func); - -/* For bpf-to-bpf function calls, the callee's address is unknown -* until the last extra pass. As seen above, we use PPC_LI64() to -* load the callee's address, but this may optimize the number of -* instructions required based on the nature of the address. -* -* Since we don't want the number of instructions emitted to increase, -* we pad the optimized PPC_LI64() call with NOPs to guarantee that -* we always have a five-instruction sequence, which is the maximum -* that PPC_LI64() can emit. -*/ -if (!image) -for (i = ctx->idx - ctx_idx; i <5 ; i++) -EMIT (PPC_RAW_NOP ()); - -EMIT (PPC_RAW_MTCTR (_R12)); -EMIT (PPC_RAW_BCTRL ()); - -return 0 ; -} -static int bpf_jit_emit_tail_call (u32 *image,struct codegen_context *ctx,u32 out) {/*
@@ -1102,11 +1079,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codeif (ret <0 )return ret; -if (func_addr_fixed) - ret =bpf_jit_emit_func_call_hlp (image, fimage, ctx, func_addr); -else - ret =bpf_jit_emit_func_call_rel (image, fimage, ctx, func_addr); - + ret =bpf_jit_emit_func_call_rel (image, fimage, ctx, func_addr);if (ret)return ret;
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 10/17 powerpc/ftrace: Add a postlink script to validate function tracer
In reply to Naveen N RaoFunction tracer on powerpc can only work with vmlinux having a .text size of up to ~64MB due to powerpc branch instruction having a limited relative branch range of 32MB. Today, this is only detected on kernel boot when ftrace is init'ed. Add a post-link script to check the size of .text so that we can detect this at build time, and break the build if necessary.
We add a dependency on !COMPILE_TEST for CONFIG_HAVE_FUNCTION_TRACER so that allyesconfig and other test builds can continue to work without enabling ftrace.
--- arch/powerpc/Kconfig | 2 +- arch/powerpc/Makefile.postlink | 8 ++++++ arch/powerpc/tools/ftrace_check.sh | 45 ++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100755 arch/powerpc/tools/ftrace_check.sh
arch/powerpc/Kconfig +1 -1
@@ -244,7 +244,7 @@ config PPC select HAVE_FUNCTION_DESCRIPTORS if PPC64_ELF_ABI_V1 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_TRACER if PPC64 || (PPC32 && CC_IS_GCC) + select HAVE_FUNCTION_TRACER if !COMPILE_TEST && (PPC64 || (PPC32 && CC_IS_GCC)) select HAVE_GCC_PLUGINS if GCC_VERSION >= 50200 # plugin support on gcc <= 5.1 is buggy on PPC select HAVE_GENERIC_VDSO select HAVE_HARDLOCKUP_DETECTOR_ARCH if PPC_BOOK3S_64 && SMP
arch/powerpc/Makefile.postlink +8 -0
@@ -24,6 +24,9 @@ else $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@" endif +quiet_cmd_ftrace_check = CHKFTRC $@ + cmd_ftrace_check = $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/ftrace_check.sh "$(NM)" "$@" + # `@true` prevents complaint when there is nothing to be done vmlinux: FORCE
@@ -34,6 +37,11 @@ endif ifdef CONFIG_RELOCATABLE $(call if_changed,relocs_check) endif +ifdef CONFIG_FUNCTION_TRACER +ifndef CONFIG_PPC64_ELF_ABI_V1 + $(call cmd,ftrace_check) +endif +endif clean: rm -f .tmp_symbols.txt
arch/powerpc/tools/ftrace_check.sh new file +45 -0
45 lines not on this page · raw message
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 11/17 kbuild: Add generic hook for architectures to use before the final vmlinux link
In reply to Naveen N RaoOn powerpc, we would like to be able to make a pass on vmlinux.o and generate a new object file to be linked into vmlinux. Add a generic pass in Makefile.vmlinux that architectures can use for this purpose.
Architectures need to select CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX and must provide arch/<arch>/tools/Makefile with .arch.vmlinux.o target, which will be invoked prior to the final vmlinux link step.
--- arch/Kconfig | 6 ++++++ scripts/Makefile.vmlinux | 8 ++++++++ scripts/link-vmlinux.sh | 11 ++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-)
arch/Kconfig +6 -0
@@ -1643,4 +1643,10 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT config ARCH_NEED_CMPXCHG_1_EMU bool +config ARCH_WANTS_PRE_LINK_VMLINUX + def_bool n + help + An architecture can select this if it provides arch/<arch>/tools/Makefile + with .arch.vmlinux.o target to be linked into vmlinux. + endmenu
scripts/Makefile.vmlinux +8 -0
@@ -22,6 +22,14 @@ targets += .vmlinux.export.o vmlinux: .vmlinux.export.o endif +ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX +targets += .arch.vmlinux.o +.arch.vmlinux.o: vmlinux.o FORCE + $(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools .arch.vmlinux.o + +vmlinux: .arch.vmlinux.o +endif + ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Final link of vmlinux with optional arch pass after final link
scripts/link-vmlinux.sh +8 -3
@@ -122,7 +122,7 @@ gen_btf() return 1 fi - vmlinux_link ${1} + vmlinux_link ${1} ${arch_vmlinux_o} info "BTF" ${2} LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
@@ -178,7 +178,7 @@ kallsyms_step() kallsymso=${kallsyms_vmlinux}.o kallsyms_S=${kallsyms_vmlinux}.S - vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} + vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} ${arch_vmlinux_o} mksysmap ${kallsyms_vmlinux} ${kallsyms_vmlinux}.syms kallsyms ${kallsyms_vmlinux}.syms ${kallsyms_S}
@@ -223,6 +223,11 @@ fi ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o +arch_vmlinux_o="" +if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then + arch_vmlinux_o=.arch.vmlinux.o +fi + btf_vmlinux_bin_o="" if is_enabled CONFIG_DEBUG_INFO_BTF; then btf_vmlinux_bin_o=.btf.vmlinux.bin.o
@@ -273,7 +278,7 @@ if is_enabled CONFIG_KALLSYMS; then fi fi -vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} +vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} ${arch_vmlinux_o} # fill in BTF IDs if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
Signature · 1 line
2.45.2
Nicholas Piggin
reviewerRe: [RFC PATCH v4 11/17] kbuild: Add generic hook for architectures to use before the final vmlinux link
Quoted 7 lines · Naveen N Rao
On powerpc, we would like to be able to make a pass on vmlinux.o and generate a new object file to be linked into vmlinux. Add a generic pass in Makefile.vmlinux that architectures can use for this purpose.
Architectures need to select
CONFIG_ARCH_WANTS_PRE_LINK_VMLINUXand must provide arch/<arch>/tools/Makefile with .arch.vmlinux.o target, which will be invoked prior to the final vmlinux link step.
Maybe POSTLINK should move to more like this with explicit config option too rather than just picking up Makefile.postlink...
Quoted 13 lines
Signed-off-by Naveen N Rao <[email protected]>--- arch/Kconfig | 6 ++++++ scripts/Makefile.vmlinux | 8 ++++++++ scripts/link-vmlinux.sh | 11 ++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-)arch/Kconfig +0
-0
arch/Kconfig config CC_HAS_SANE_FUNCTION_ALIGNMENT · line 1650
Quoted 8 lines
arch/Kconfig +5
-0@@ -1643,4 +1643,10 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT config ARCH_NEED_CMPXCHG_1_EMU bool +config ARCH_WANTS_PRE_LINK_VMLINUX + def_bool n + help + An architecture can select this if it provides arch/<arch>/tools/Makefile + with .arch.vmlinux.o target to be linked into vmlinux.
Someone bikeshedded me before for putting comments for putting comment for non-user-selectable option in 'help'. Even though heaps of options are like that here, apparently they preferred # comment above the option for developer comments. I personally thought this looks nicer but do Kconfig maintainers prefer #?
Quoted 7 lines
arch/Kconfig +1
-0+ endmenuscripts/Makefile.vmlinux +0
-0
scripts/Makefile.vmlinux targets += .vmlinux.export.o · line 31
Quoted 10 lines
scripts/Makefile.vmlinux +7
-0@@ -22,6 +22,14 @@ targets += .vmlinux.export.o vmlinux: .vmlinux.export.o endif +ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX +targets += .arch.vmlinux.o +.arch.vmlinux.o: vmlinux.o FORCE + $(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools .arch.vmlinux.o + +vmlinux: .arch.vmlinux.o +endif
Does .vmlinux.arch.o follow convention better? I guess the btf does not. So, nevermind.
Could this just be done entirely in link-vmlinux.sh like kallsyms and btf?
Quoted 9 lines
scripts/Makefile.vmlinux +1
-0+ ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Final link of vmlinux with optional arch pass after final linkscripts/link-vmlinux.sh +0
-0
scripts/link-vmlinux.sh gen_btf() · line 128
Quoted 8 lines
scripts/link-vmlinux.sh +1
-1@@ -122,7 +122,7 @@ gen_btf() return 1 fi - vmlinux_link ${1} + vmlinux_link ${1} ${arch_vmlinux_o} info "BTF" ${2} LLVM_OBJCOPY="${OBJCOPY}" ${PAHOLE} -J ${PAHOLE_FLAGS} ${1}
BTF generation needs the prelink .o?
Quoted 23 lines
scripts/link-vmlinux.sh +6
-1@@ -178,7 +178,7 @@ kallsyms_step() kallsymso=${kallsyms_vmlinux}.o kallsyms_S=${kallsyms_vmlinux}.S - vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} + vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} ${arch_vmlinux_o} mksysmap ${kallsyms_vmlinux} ${kallsyms_vmlinux}.syms kallsyms ${kallsyms_vmlinux}.syms ${kallsyms_S}@@ -223,6 +223,11 @@ fi ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o +arch_vmlinux_o="" +if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then + arch_vmlinux_o=.arch.vmlinux.o +fi + btf_vmlinux_bin_o="" if is_enabled CONFIG_DEBUG_INFO_BTF; then btf_vmlinux_bin_o=.btf.vmlinux.bin.o
scripts/link-vmlinux.sh if is_enabled CONFIG_KALLSYMS; then · line 284
Quoted 8 lines
scripts/link-vmlinux.sh +1
-1@@ -273,7 +278,7 @@ if is_enabled CONFIG_KALLSYMS; then fi fi -vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} +vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} ${arch_vmlinux_o} # fill in BTF IDs if is_enabled CONFIG_DEBUG_INFO_BTF && is_enabled CONFIG_BPF; then
I guess it looks okay, similar to btf although I'm not a kbuild expert.
Thanks,
Nick
Naveen N Rao
reviewerRFC PATCH v4 12/17 powerpc64/ftrace: Move ftrace sequence out of line
In reply to Naveen N RaoFunction profile sequence on powerpc includes two instructions at the beginning of each function:
mflr r0 bl ftrace_caller
The call to ftrace_caller() gets nop'ed out during kernel boot and is patched in when ftrace is enabled.
Given the sequence, we cannot return from ftrace_caller with 'blr' as we need to keep LR and r0 intact. This results in link stack (return address predictor) imbalance when ftrace is enabled. To address that, we would like to use a three instruction sequence:
mflr r0 bl ftrace_caller mtlr r0
Further more, to support DYNAMIC_FTRACE_WITH_CALL_OPS, we need to reserve two instruction slots before the function. This results in a total of five instruction slots to be reserved for ftrace use on each function that is traced.
Move the function profile sequence out-of-line to minimize its impact. To do this, we reserve a single nop at function entry using -fpatchable-function-entry=1 and add a pass on vmlinux.o to determine the total number of functions that can be traced. This is then used to generate a .S file reserving the appropriate amount of space for use as ftrace stubs, which is built and linked into vmlinux.
On bootup, the stub space is split into separate stubs per function and populated with the proper instruction sequence. A pointer to the associated stub is maintained in dyn_arch_ftrace.
For modules, space for ftrace stubs is reserved from the generic module stub space.
This is restricted to and enabled by default only on 64-bit powerpc, though there are some changes to accommodate 32-bit powerpc. This is done so that 32-bit powerpc could choose to opt into this based on further tests and benchmarks.
As an example, after this patch, kernel functions will have a single nop at function entry:
<kernel_clone>:
addis r2,r12,467 addi r2,r2,-16028 nop mfocrf r11,8 ...
When ftrace is enabled, the nop is converted to an unconditional branch to the stub associated with that function:
<kernel_clone>:
addis r2,r12,467 addi r2,r2,-16028 b ftrace_ool_stub_text_end+0x11b28 mfocrf r11,8 ...
The associated stub:
<ftrace_ool_stub_text_end+0x11b28>:
mflr r0 bl ftrace_caller mtlr r0 b kernel_clone+0xc ...
--- arch/powerpc/Kconfig | 5 + arch/powerpc/Makefile | 4 + arch/powerpc/include/asm/ftrace.h | 11 ++ arch/powerpc/include/asm/module.h | 5 + arch/powerpc/kernel/asm-offsets.c | 4 + arch/powerpc/kernel/module_64.c | 58 +++++++- arch/powerpc/kernel/trace/ftrace.c | 157 +++++++++++++++++++-- arch/powerpc/kernel/trace/ftrace_entry.S | 116 +++++++++++---- arch/powerpc/tools/Makefile | 10 ++ arch/powerpc/tools/ftrace-gen-ool-stubs.sh | 48 +++++++ 10 files changed, 381 insertions(+), 37 deletions(-) create mode 100644 arch/powerpc/tools/Makefile create mode 100755 arch/powerpc/tools/ftrace-gen-ool-stubs.sh
arch/powerpc/Kconfig +5 -0
@@ -568,6 +568,11 @@ config ARCH_USING_PATCHABLE_FUNCTION_ENTRY def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mbig-endian) if PPC64 && CPU_BIG_ENDIAN +config PPC_FTRACE_OUT_OF_LINE + def_bool PPC64 && ARCH_USING_PATCHABLE_FUNCTION_ENTRY + depends on PPC64 + select ARCH_WANTS_PRE_LINK_VMLINUX + config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \
arch/powerpc/Makefile +4 -0
@@ -155,7 +155,11 @@ CC_FLAGS_NO_FPU := $(call cc-option,-msoft-float) ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY +ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +CC_FLAGS_FTRACE := -fpatchable-function-entry=1 +else CC_FLAGS_FTRACE := -fpatchable-function-entry=2 +endif else CC_FLAGS_FTRACE := -pg ifdef CONFIG_MPROFILE_KERNEL
arch/powerpc/include/asm/ftrace.h +11 -0
@@ -26,6 +26,10 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,struct module ;struct dyn_ftrace ;struct dyn_arch_ftrace { +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +/* pointer to the associated out-of-line stub */ +unsigned long ool_stub; +#endif };#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
@@ -132,6 +136,13 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }#ifdef CONFIG_FUNCTION_TRACER extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[]; +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +struct ftrace_ool_stub { +u32 insn[4 ]; +}; +extern struct ftrace_ool_stub ftrace_ool_stub_text_end[], ftrace_ool_stub_inittext[]; +extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_inittext_count; +#endif void ftrace_free_init_tramp (void );unsigned long ftrace_call_adjust (unsigned long addr);#else
arch/powerpc/include/asm/module.h +5 -0
@@ -47,6 +47,11 @@ struct mod_arch_specific {#ifdef CONFIG_DYNAMIC_FTRACE unsigned long tramp;unsigned long tramp_regs; +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +struct ftrace_ool_stub *ool_stubs; +unsigned int ool_stub_count; +unsigned int ool_stub_index; +#endif #endif };
arch/powerpc/kernel/asm-offsets.c +4 -0
@@ -674,5 +674,9 @@ int main(void)DEFINE (BPT_SIZE ,BPT_SIZE );#endif +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +DEFINE (FTRACE_OOL_STUB_SIZE ,sizeof (struct ftrace_ool_stub )); +#endif +return 0 ; }
arch/powerpc/kernel/module_64.c +56 -2
88 lines not on this page · raw message
arch/powerpc/kernel/trace/ftrace.c +147 -10
221 lines not on this page · raw message
arch/powerpc/kernel/trace/ftrace_entry.S +91 -25
203 lines not on this page · raw message
arch/powerpc/tools/Makefile new file +10 -0
@@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +quiet_cmd_gen_ftrace_ool_stubs = FTRACE $@ + cmd_gen_ftrace_ool_stubs = $< $(objtree)/vmlinux.o $@ + +targets += .arch.vmlinux.o +.arch.vmlinux.o: $(srctree)/arch/powerpc/tools/ftrace-gen-ool-stubs.sh $(objtree)/vmlinux.o FORCE + $(call if_changed,gen_ftrace_ool_stubs) + +clean-files += $(objtree)/.arch.vmlinux.S $(objtree)/.arch.vmlinux.o
arch/powerpc/tools/ftrace-gen-ool-stubs.sh new file +48 -0
48 lines not on this page · raw message
Signature · 1 line
2.45.2
Nicholas Piggin
reviewerRe: [RFC PATCH v4 12/17] powerpc64/ftrace: Move ftrace sequence out of line
Quoted 21 lines · Naveen N Rao
Function profile sequence on powerpc includes two instructions at the beginning of each function:
mflr r0 bl ftrace_callerThe call to
ftrace_caller()gets nop'ed out during kernel boot and is patched in when ftrace is enabled.Given the sequence, we cannot return from
ftrace_callerwith 'blr' as we need to keep LR and r0 intact. This results in link stack (return address predictor) imbalance when ftrace is enabled. To address that, we would like to use a three instruction sequence:mflr r0 bl ftrace_caller mtlr r0Further more, to support
DYNAMIC_FTRACE_WITH_CALL_OPS, we need to reserve two instruction slots before the function. This results in a total of five instruction slots to be reserved for ftrace use on each function that is traced.
Quoted 6 lines
Move the function profile sequence out-of-line to minimize its impact. To do this, we reserve a single nop at function entry using -fpatchable-function-entry=1 and add a pass on vmlinux.o to determine the total number of functions that can be traced. This is then used to generate a .S file reserving the appropriate amount of space for use as ftrace stubs, which is built and linked into vmlinux.
These are all going into .tramp.ftrace.text AFAIKS? Should that be moved after some of the other text in the linker script then if it could get quite large? sched and lock and other things should be closer to the rest of text and hot code.
Thanks,
Nick
RE: [RFC PATCH v4 12/17] powerpc64/ftrace: Move ftrace sequence out of line
From: Nicholas Piggin
Quoted 31 lines
Sent: 15 July 2024 09:25
Quoted 21 lines · Naveen N Rao
Function profile sequence on powerpc includes two instructions at the beginning of each function:
mflr r0 bl ftrace_callerThe call to
ftrace_caller()gets nop'ed out during kernel boot and is patched in when ftrace is enabled.Given the sequence, we cannot return from
ftrace_callerwith 'blr' as we need to keep LR and r0 intact. This results in link stack (return address predictor) imbalance when ftrace is enabled. To address that, we would like to use a three instruction sequence:mflr r0 bl ftrace_caller mtlr r0Further more, to support
DYNAMIC_FTRACE_WITH_CALL_OPS, we need to reserve two instruction slots before the function. This results in a total of five instruction slots to be reserved for ftrace use on each function that is traced.Quoted 6 lines
Move the function profile sequence out-of-line to minimize its impact. To do this, we reserve a single nop at function entry using -fpatchable-function-entry=1 and add a pass on vmlinux.o to determine the total number of functions that can be traced. This is then used to generate a .S file reserving the appropriate amount of space for use as ftrace stubs, which is built and linked into vmlinux.
Quoted 4 lines
These are all going into .tramp.ftrace.text AFAIKS? Should that be moved after some of the other text in the linker script then if it could get quite large? sched and lock and other things should be closer to the rest of text and hot code.
Can't you allocate the space for the 'function profile sequence' at run-time when (if) ftrace is enabled?
When ftrace gets disabled it is likely possible to save the trampoline number in the nop - so the same memory can be used next time.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [RFC PATCH v4 12/17] powerpc64/ftrace: Move ftrace sequence out of line
In reply to Naveen N RaoQuoted 77 lines · Naveen N Rao
Function profile sequence on powerpc includes two instructions at the beginning of each function:
mflr r0
blftrace_callerThe call to
ftrace_caller()gets nop'ed out during kernel boot and is patched in when ftrace is enabled.Given the sequence, we cannot return from
ftrace_callerwith 'blr' as we need to keep LR and r0 intact. This results in link stack (return address predictor) imbalance when ftrace is enabled. To address that, we would like to use a three instruction sequence:mflr r0 bl ftrace_caller mtlr r0Further more, to support
DYNAMIC_FTRACE_WITH_CALL_OPS, we need to reserve two instruction slots before the function. This results in a total of five instruction slots to be reserved for ftrace use on each function that is traced.Move the function profile sequence out-of-line to minimize its impact. To do this, we reserve a single nop at function entry using -fpatchable-function-entry=1 and add a pass on vmlinux.o to determine the total number of functions that can be traced. This is then used to generate a .S file reserving the appropriate amount of space for use as ftrace stubs, which is built and linked into vmlinux.
On bootup, the stub space is split into separate stubs per function and populated with the proper instruction sequence. A pointer to the associated stub is maintained in
dyn_arch_ftrace.For modules, space for ftrace stubs is reserved from the generic module stub space.
This is restricted to and enabled by default only on 64-bit powerpc, though there are some changes to accommodate 32-bit powerpc. This is done so that 32-bit powerpc could choose to opt into this based on further tests and benchmarks.
As an example, after this patch, kernel functions will have a single nop at function entry:
<kernel_clone>:addis r2,r12,467 addi r2,r2,-16028 nop mfocrf r11,8 ...When ftrace is enabled, the nop is converted to an unconditional branch to the stub associated with that function:
<kernel_clone>:addis r2,r12,467 addi r2,r2,-16028 b ftrace_ool_stub_text_end+0x11b28 mfocrf r11,8 ...The associated stub:
<ftrace_ool_stub_text_end+0x11b28>:mflr r0 bl ftrace_caller mtlr r0 b kernel_clone+0xc ...Signed-off-by Naveen N Rao <[email protected]>arch/powerpc/tools/Makefile new file +0
-0
arch/powerpc/tools/Makefile line 3
Quoted 3 lines
arch/powerpc/tools/Makefile new file +3
-0@@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +quiet_cmd_gen_ftrace_ool_stubs = FTRACE $@
This is not "FTRACE".
"GEN" or something like that.
arch/powerpc/tools/Makefile line 10
Quoted 7 lines
arch/powerpc/tools/Makefile new file +7
-0+ cmd_gen_ftrace_ool_stubs = $< $(objtree)/vmlinux.o $@ + +targets += .arch.vmlinux.o +.arch.vmlinux.o: $(srctree)/arch/powerpc/tools/ftrace-gen-ool-stubs.sh $(objtree)/vmlinux.o FORCE + $(call if_changed,gen_ftrace_ool_stubs) + +clean-files += $(objtree)/.arch.vmlinux.S $(objtree)/.arch.vmlinux.o
This is wrong. $(objtree) is always '.'
It will attempt to clean up:
arch/powerpc/tools/.arch.vmlinux.Sarch/powerpc/tools/.arch.vmlinux.o
You must not create the intermediate file,.arch.vmlinux.S at the top directory because
this build step is pretty much PowerPC-specific.
Rather, I'd recommend to create *.S and *.o inarch/powerpc/tools/:
arch/powerpc/tools/vmlinux.Sarch/powerpc/tools/vmlinux.o
When you submit the next version, please run 'make clean' and confirm that any powerpc-specific build artifacts not being left-over.
Quoted 44 lines
arch/powerpc/tools/ftrace-gen-ool-stubs.sh new file +38
-0@@ -0,0 +1,48 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +# Error out on error +set -e + +is_enabled() { + grep -q "^$1=y" include/config/auto.conf +} + +vmlinux_o=${1} +arch_vmlinux_o=${2} +arch_vmlinux_S=$(dirname ${arch_vmlinux_o})/$(basename ${arch_vmlinux_o} .o).S + +RELOCATION=R_PPC64_ADDR64 +if is_enabled CONFIG_PPC32; then + RELOCATION=R_PPC_ADDR32 +fi + +num_ool_stubs_text=$(${CROSS_COMPILE}objdump -r -j __patchable_function_entries ${vmlinux_o} | + grep -v ".init.text" | grep "${RELOCATION}" | wc -l) +num_ool_stubs_inittext=$(${CROSS_COMPILE}objdump -r -j __patchable_function_entries ${vmlinux_o} | + grep ".init.text" | grep "${RELOCATION}" | wc -l) + +cat > ${arch_vmlinux_S} <<EOF +#include <asm/asm-offsets.h> +#include <linux/linkage.h> + +.pushsection .tramp.ftrace.text,"aw" +SYM_DATA(ftrace_ool_stub_text_end_count, .long ${num_ool_stubs_text}) + +SYM_CODE_START(ftrace_ool_stub_text_end) + .space ${num_ool_stubs_text} * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_text_end) +.popsection + +.pushsection .tramp.ftrace.init,"aw" +SYM_DATA(ftrace_ool_stub_inittext_count, .long ${num_ool_stubs_inittext})
arch/powerpc/tools/ftrace-gen-ool-stubs.sh line 48
Quoted 10 lines
arch/powerpc/tools/ftrace-gen-ool-stubs.sh new file +10
-0+ +SYM_CODE_START(ftrace_ool_stub_inittext) + .space ${num_ool_stubs_inittext} * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_inittext) +.popsection +EOF + +${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS} \ + ${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ + -c -o ${arch_vmlinux_o} ${arch_vmlinux_S}
Please do not compile this within a shell script.
scripts/Makefile.build provides rule_as_o_S to do this.
[1] vmlinux.o --> arch/powerpc/tools/vmlinux.S
[2] arch/powerpc/tools/vmlinux.S --> arch/powerpc/tools/vmlinux.o
Please split these in separate build rules.
Quoted 3 lines
--
2.45.2
--
Best Regards
Masahiro Yamada
Naveen N Rao
reviewerRFC PATCH v4 13/17 powerpc64/ftrace: Support .text larger than 32MB with out-of-line stubs
In reply to Naveen N RaoWe are restricted to a .text size of ~32MB when using out-of-line function profile sequence. Allow this to be extended up to the previous limit of ~64MB by reserving space in the middle of .text.
A new config option CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE is introduced to specify the number of function stubs that are reserved in .text. On boot, ftrace utilizes stubs from this area first before using the stub area at the end of .text.
A ppc64le defconfig has ~44k functions that can be traced. A more conservative value of 32k functions is chosen as the default value of PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE so that we do not allot more space than necessary by default. If building a kernel that only has 32k trace-able functions, we won't allot any more space at the end of .text during the pass on vmlinux.o. Otherwise, only the remaining functions get space for stubs at the end of .text. This default value should help cover a .text size of ~48MB in total (including space reserved at the end of .text which can cover up to 32MB), which should be sufficient for most common builds. For a very small kernel build, this can be set to 0. Or, this can be bumped up to a larger value to support vmlinux .text size up to ~64MB.
--- arch/powerpc/Kconfig | 12 ++++++++++++ arch/powerpc/include/asm/ftrace.h | 6 ++++-- arch/powerpc/kernel/trace/ftrace.c | 21 +++++++++++++++++---- arch/powerpc/kernel/trace/ftrace_entry.S | 8 ++++++++ arch/powerpc/tools/Makefile | 2 +- arch/powerpc/tools/ftrace-gen-ool-stubs.sh | 11 +++++++---- 6 files changed, 49 insertions(+), 11 deletions(-)
arch/powerpc/Kconfig +12 -0
@@ -573,6 +573,18 @@ config PPC_FTRACE_OUT_OF_LINE depends on PPC64 select ARCH_WANTS_PRE_LINK_VMLINUX +config PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE + int "Number of ftrace out-of-line stubs to reserve within .text" + default 32768 if PPC_FTRACE_OUT_OF_LINE + default 0 + help + Number of stubs to reserve for use by ftrace. This space is + reserved within .text, and is distinct from any additional space + added at the end of .text before the final vmlinux link. Set to + zero to have stubs only be generated at the end of vmlinux (only + if the size of vmlinux is less than 32MB). Set to a higher value + if building vmlinux larger than 48MB. + config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \
arch/powerpc/include/asm/ftrace.h +4 -2
@@ -140,8 +140,10 @@ extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];struct ftrace_ool_stub {u32 insn[4 ]; }; -extern struct ftrace_ool_stub ftrace_ool_stub_text_end[], ftrace_ool_stub_inittext[]; -extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_inittext_count; +extern struct ftrace_ool_stub ftrace_ool_stub_text_end[], ftrace_ool_stub_text[], + ftrace_ool_stub_inittext[]; +extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_text_count, + ftrace_ool_stub_inittext_count;#endif void ftrace_free_init_tramp (void );unsigned long ftrace_call_adjust (unsigned long addr);
arch/powerpc/kernel/trace/ftrace.c +17 -4
@@ -168,7 +168,7 @@ static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_static int ftrace_init_ool_stub (struct module *mod,struct dyn_ftrace *rec) {#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE -static int ool_stub_text_end_index, ool_stub_inittext_index; +static int ool_stub_text_index, ool_stub_text_end_index, ool_stub_inittext_index;int ret =0 , ool_stub_count, *ool_stub_index;ppc_inst_t inst;/*
@@ -191,9 +191,22 @@ static int ftrace_init_ool_stub(struct module *mod, struct dyn_ftrace *rec) ool_stub_index = &ool_stub_inittext_index; ool_stub_count = ftrace_ool_stub_inittext_count; }else if (is_kernel_text (rec->ip)) { - ool_stub = ftrace_ool_stub_text_end; - ool_stub_index = &ool_stub_text_end_index; - ool_stub_count = ftrace_ool_stub_text_end_count; +/* +* ftrace records are sorted, so we first use up the stub area within .text +* (ftrace_ool_stub_text) before using the area at the end of .text +* (ftrace_ool_stub_text_end), unless the stub is out of range of the record. +*/ +if (ool_stub_text_index >= ftrace_ool_stub_text_count || + !is_offset_in_branch_range ((long )rec->ip - + (long )&ftrace_ool_stub_text[ool_stub_text_index])) { + ool_stub = ftrace_ool_stub_text_end; + ool_stub_index = &ool_stub_text_end_index; + ool_stub_count = ftrace_ool_stub_text_end_count; + }else { + ool_stub = ftrace_ool_stub_text; + ool_stub_index = &ool_stub_text_index; + ool_stub_count = ftrace_ool_stub_text_count; + } #ifdef CONFIG_MODULES }else if (mod) { ool_stub = mod->arch.ool_stubs;
arch/powerpc/kernel/trace/ftrace_entry.S +8 -0
@@ -374,6 +374,14 @@ _GLOBAL(return_to_handler) blr #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +SYM_DATA(ftrace_ool_stub_text_count, .long CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE) + +SYM_CODE_START(ftrace_ool_stub_text) + .space CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_text) +#endif + .pushsection ".tramp.ftrace.text","aw",@progbits; .globl ftrace_tramp_text ftrace_tramp_text:
arch/powerpc/tools/Makefile +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later quiet_cmd_gen_ftrace_ool_stubs = FTRACE $@ - cmd_gen_ftrace_ool_stubs = $< $(objtree)/vmlinux.o $@ + cmd_gen_ftrace_ool_stubs = $< $(CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE) $(objtree)/vmlinux.o $@ targets += .arch.vmlinux.o .arch.vmlinux.o: $(srctree)/arch/powerpc/tools/ftrace-gen-ool-stubs.sh $(objtree)/vmlinux.o FORCE
arch/powerpc/tools/ftrace-gen-ool-stubs.sh +7 -4
@@ -8,8 +8,8 @@ is_enabled() { grep -q "^$1=y" include/config/auto.conf } -vmlinux_o=${1} -arch_vmlinux_o=${2} +vmlinux_o=${2} +arch_vmlinux_o=${3} arch_vmlinux_S=$(dirname ${arch_vmlinux_o})/$(basename ${arch_vmlinux_o} .o).S RELOCATION=R_PPC64_ADDR64
@@ -22,15 +22,18 @@ num_ool_stubs_text=$(${CROSS_COMPILE}objdump -r -j __patchable_function_entries num_ool_stubs_inittext=$(${CROSS_COMPILE}objdump -r -j __patchable_function_entries ${vmlinux_o} | grep ".init.text" | grep "${RELOCATION}" | wc -l) +num_ool_stubs_text_builtin=${1} +num_ool_stubs_text_end=$(expr ${num_ool_stubs_text} - ${num_ool_stubs_text_builtin}) + cat > ${arch_vmlinux_S} <<EOF #include <asm/asm-offsets.h> #include <linux/linkage.h> .pushsection .tramp.ftrace.text,"aw" -SYM_DATA(ftrace_ool_stub_text_end_count, .long ${num_ool_stubs_text}) +SYM_DATA(ftrace_ool_stub_text_end_count, .long ${num_ool_stubs_text_end}) SYM_CODE_START(ftrace_ool_stub_text_end) - .space ${num_ool_stubs_text} * FTRACE_OOL_STUB_SIZE + .space ${num_ool_stubs_text_end} * FTRACE_OOL_STUB_SIZE SYM_CODE_END(ftrace_ool_stub_text_end) .popsection
Signature · 1 line
2.45.2
Nicholas Piggin
reviewerRe: [RFC PATCH v4 13/17] powerpc64/ftrace: Support .text larger than 32MB with out-of-line stubs
Quoted 8 lines · Naveen N Rao
We are restricted to a .text size of ~32MB when using out-of-line function profile sequence. Allow this to be extended up to the previous limit of ~64MB by reserving space in the middle of .text.
A new config option
CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVEis introduced to specify the number of function stubs that are reserved in .text. On boot, ftrace utilizes stubs from this area first before using the stub area at the end of .text.
[snip]
Quoted 9 lines
arch/powerpc/kernel/trace/ftrace_entry.S +1
-0@@ -374,6 +374,14 @@ _GLOBAL(return_to_handler) blr #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE
arch/powerpc/kernel/trace/ftrace_entry.S _GLOBAL(return_to_handler) · line 387
Quoted 10 lines
arch/powerpc/kernel/trace/ftrace_entry.S +7
-0+SYM_DATA(ftrace_ool_stub_text_count, .long CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE) + +SYM_CODE_START(ftrace_ool_stub_text) + .space CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_text) +#endif + .pushsection ".tramp.ftrace.text","aw",@progbits; .globl ftrace_tramp_text ftrace_tramp_text:
How are you ensuring these new stubs get to the middle of kernel text? I guess you just put it in regular .text and hope the linker puts it in a good place?
Thanks,
Nick
Naveen N Rao
reviewerRFC PATCH v4 14/17 powerpc/ftrace: Add support for DYNAMIC_FTRACE_WITH_CALL_OPS
In reply to Naveen N RaoImplement support for DYNAMIC_FTRACE_WITH_CALL_OPS similar to the arm64 implementation.
This works by patching-in a pointer to an associated ftrace_ops structure before each traceable function. If multiple ftrace_ops are associated with a call site, then a special ftrace_list_ops is used to enable iterating over all the registered ftrace_ops. If no ftrace_ops are associated with a call site, then a special ftrace_nop_ops structure is used to render the ftrace call as a no-op. ftrace trampoline can then read the associated ftrace_ops for a call site by loading from an offset from the LR, and branch directly to the associated function.
The primary advantage with this approach is that we don't have to iterate over all the registered ftrace_ops for call sites that have a single ftrace_ops registered. This is the equivalent of implementing support for dynamic ftrace trampolines, which set up a special ftrace trampoline for each registered ftrace_ops and have individual call sites branch into those directly.
A secondary advantage is that this gives us a way to add support for direct ftrace callers without having to resort to using stubs. The address of the direct call trampoline can be loaded from the ftrace_ops structure.
To support this, we reserve a nop before each function on 32-bit powerpc. For 64-bit powerpc, two nops are reserved before each out-of-line stub. During ftrace activation, we update this location with the associated ftrace_ops pointer. Then, on ftrace entry, we load from this location and call into ftrace_ops->func().
For 64-bit powerpc, we ensure that the out-of-line stub area is doubleword aligned so that ftrace_ops address can be updated atomically.
--- arch/powerpc/Kconfig | 1 + arch/powerpc/Makefile | 4 ++ arch/powerpc/include/asm/ftrace.h | 5 +- arch/powerpc/kernel/asm-offsets.c | 4 ++ arch/powerpc/kernel/trace/ftrace.c | 59 +++++++++++++++++++++- arch/powerpc/kernel/trace/ftrace_entry.S | 36 ++++++++++--- arch/powerpc/tools/ftrace-gen-ool-stubs.sh | 5 +- 7 files changed, 102 insertions(+), 12 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -235,6 +235,7 @@ config PPC select HAVE_DEBUG_STACKOVERFLOW select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_ARGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if PPC_FTRACE_OUT_OF_LINE || (PPC32 && ARCH_USING_PATCHABLE_FUNCTION_ENTRY) select HAVE_DYNAMIC_FTRACE_WITH_REGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 select HAVE_EBPF_JIT select HAVE_EFFICIENT_UNALIGNED_ACCESS
arch/powerpc/Makefile +4 -0
@@ -158,8 +158,12 @@ KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE CC_FLAGS_FTRACE := -fpatchable-function-entry=1 else +ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS # PPC32 only +CC_FLAGS_FTRACE := -fpatchable-function-entry=3,1 +else CC_FLAGS_FTRACE := -fpatchable-function-entry=2 endif +endif else CC_FLAGS_FTRACE := -pg ifdef CONFIG_MPROFILE_KERNEL
arch/powerpc/include/asm/ftrace.h +4 -1
@@ -138,8 +138,11 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE struct ftrace_ool_stub { +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS +struct ftrace_ops *ftrace_op; +#endif u32 insn[4 ]; -}; +}__aligned(sizeof(unsigned long)) ;extern struct ftrace_ool_stub ftrace_ool_stub_text_end[], ftrace_ool_stub_text[], ftrace_ool_stub_inittext[]; extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_text_count,
arch/powerpc/kernel/asm-offsets.c +4 -0
@@ -678,5 +678,9 @@ int main(void)DEFINE (FTRACE_OOL_STUB_SIZE ,sizeof (struct ftrace_ool_stub ));#endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS +OFFSET (FTRACE_OPS_FUNC , ftrace_ops, func); +#endif +return 0 ; }
arch/powerpc/kernel/trace/ftrace.c +58 -1
100 lines not on this page · raw message
arch/powerpc/kernel/trace/ftrace_entry.S +28 -8
@@ -85,11 +85,21 @@ /* Save callee's TOC in the ABI compliant location */ std r2, STK_GOT(r1) LOAD_PACA_TOC() /* get kernel TOC in r2 */ +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + /* r7 points to the instruction following the call to ftrace */ + PPC_LL r5, -(MCOUNT_INSN_SIZE*2 + SZL)(r7) + PPC_LL r12, FTRACE_OPS_FUNC(r5) + mtctr r12 +#else /* !CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS */ +#ifdef CONFIG_PPC64 LOAD_REG_ADDR(r3, function_trace_op) ld r5,0(r3) #else lis r3,function_trace_op@ha lwz r5,function_trace_op@l(r3) +#endif #endif /* Save special regs */
@@ -205,20 +215,30 @@ #endif .endm -_GLOBAL(ftrace_regs_caller) - ftrace_regs_entry 1 - /* ftrace_call(r3, r4, r5, r6) */ +.macro ftrace_regs_func allregs +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + bctrl +#else + .if \allregs == 1 .globl ftrace_regs_call ftrace_regs_call: + .else +.globl ftrace_call +ftrace_call: + .endif + /* ftrace_call(r3, r4, r5, r6) */ bl ftrace_stub +#endif +.endm + +_GLOBAL(ftrace_regs_caller) + ftrace_regs_entry 1 + ftrace_regs_func 1 ftrace_regs_exit 1 _GLOBAL(ftrace_caller) ftrace_regs_entry 0 - /* ftrace_call(r3, r4, r5, r6) */ -.globl ftrace_call -ftrace_call: - bl ftrace_stub + ftrace_regs_func 0 ftrace_regs_exit 0 _GLOBAL(ftrace_stub)
@@ -377,7 +397,7 @@ _GLOBAL(return_to_handler) #ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE SYM_DATA(ftrace_ool_stub_text_count, .long CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE) -SYM_CODE_START(ftrace_ool_stub_text) +SYM_START(ftrace_ool_stub_text, SYM_L_GLOBAL, .balign SZL) .space CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE * FTRACE_OOL_STUB_SIZE SYM_CODE_END(ftrace_ool_stub_text) #endif
arch/powerpc/tools/ftrace-gen-ool-stubs.sh +3 -2
@@ -27,12 +27,13 @@ num_ool_stubs_text_end=$(expr ${num_ool_stubs_text} - ${num_ool_stubs_text_built cat > ${arch_vmlinux_S} <<EOF #include <asm/asm-offsets.h> +#include <asm/ppc_asm.h> #include <linux/linkage.h> .pushsection .tramp.ftrace.text,"aw" SYM_DATA(ftrace_ool_stub_text_end_count, .long ${num_ool_stubs_text_end}) -SYM_CODE_START(ftrace_ool_stub_text_end) +SYM_START(ftrace_ool_stub_text_end, SYM_L_GLOBAL, .balign SZL) .space ${num_ool_stubs_text_end} * FTRACE_OOL_STUB_SIZE SYM_CODE_END(ftrace_ool_stub_text_end) .popsection
@@ -40,7 +41,7 @@ SYM_CODE_END(ftrace_ool_stub_text_end) .pushsection .tramp.ftrace.init,"aw" SYM_DATA(ftrace_ool_stub_inittext_count, .long ${num_ool_stubs_inittext}) -SYM_CODE_START(ftrace_ool_stub_inittext) +SYM_START(ftrace_ool_stub_inittext, SYM_L_GLOBAL, .balign SZL) .space ${num_ool_stubs_inittext} * FTRACE_OOL_STUB_SIZE SYM_CODE_END(ftrace_ool_stub_inittext) .popsection
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 15/17 powerpc/ftrace: Add support for DYNAMIC_FTRACE_WITH_DIRECT_CALLS
In reply to Naveen N RaoAdd support for DYNAMIC_FTRACE_WITH_DIRECT_CALLS similar to the arm64 implementation.
ftrace direct calls allow custom trampolines to be called into directly from function ftrace call sites, bypassing the ftrace trampoline completely. This functionality is currently utilized by BPF trampolines to hook into kernel function entries.
Since we have limited relative branch range, we support ftrace direct calls through support for DYNAMIC_FTRACE_WITH_CALL_OPS. In this approach, ftrace trampoline is not entirely bypassed. Rather, it is re-purposed into a stub that reads direct_call field from the associated ftrace_ops structure and branches into that, if it is not NULL. For this, it is sufficient if we can ensure that the ftrace trampoline is reachable from all traceable functions.
When multiple ftrace_ops are associated with a call site, we utilize a call back to set pt_regs->orig_gpr3 that can then be tested on the return path from the ftrace trampoline to branch into the direct caller.
--- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/ftrace.h | 15 +++ arch/powerpc/kernel/asm-offsets.c | 3 + arch/powerpc/kernel/trace/ftrace.c | 9 ++ arch/powerpc/kernel/trace/ftrace_entry.S | 114 +++++++++++++++++------ 5 files changed, 113 insertions(+), 29 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -236,6 +236,7 @@ config PPC select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_ARGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if PPC_FTRACE_OUT_OF_LINE || (PPC32 && ARCH_USING_PATCHABLE_FUNCTION_ENTRY) + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS if HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS select HAVE_DYNAMIC_FTRACE_WITH_REGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 select HAVE_EBPF_JIT select HAVE_EFFICIENT_UNALIGNED_ACCESS
arch/powerpc/include/asm/ftrace.h +15 -0
@@ -150,6 +150,21 @@ extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_text_count,#endif void ftrace_free_init_tramp (void );unsigned long ftrace_call_adjust (unsigned long addr); + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +/* +* When an ftrace registered caller is tracing a function that is also set by a +* register_ftrace_direct() call, it needs to be differentiated in the +* ftrace_caller trampoline so that the direct call can be invoked after the +* other ftrace ops. To do this, place the direct caller in the orig_gpr3 field +* of pt_regs. This tells ftrace_caller that there's a direct caller. +*/ +static inline void arch_ftrace_set_direct_caller (struct ftrace_regs *fregs,unsigned long addr) +{ +struct pt_regs *regs = &fregs->regs; + regs->orig_gpr3 = addr; +} +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ #else static inline void ftrace_free_init_tramp (void ) { }static inline unsigned long ftrace_call_adjust (unsigned long addr) {return addr; }
arch/powerpc/kernel/asm-offsets.c +3 -0
@@ -680,6 +680,9 @@ int main(void)#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS OFFSET (FTRACE_OPS_FUNC , ftrace_ops, func); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +OFFSET (FTRACE_OPS_DIRECT_CALL , ftrace_ops, direct_call); +#endif #endif return 0 ;
arch/powerpc/kernel/trace/ftrace.c +9 -0
@@ -150,6 +150,15 @@ static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_else ip = rec->ip; +if (!is_offset_in_branch_range (addr - ip) && addr !=FTRACE_ADDR && addr !=FTRACE_REGS_ADDR ) { +/* This can only happen with ftrace direct */ +if (!IS_ENABLED (CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS )) { +pr_err ("0x%lx (0x%lx): Unexpected target address 0x%lx\n" , ip, rec->ip, addr); +return -EINVAL ; + } + addr =FTRACE_ADDR ; + } +if (is_offset_in_branch_range (addr - ip))/* Within range */ stub = addr;
arch/powerpc/kernel/trace/ftrace_entry.S +85 -29
219 lines not on this page · raw message
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 16/17 samples/ftrace: Add support for ftrace direct samples on powerpc
In reply to Naveen N RaoAdd powerpc 32-bit and 64-bit samples for ftrace direct. This serves to show the sample instruction sequence to be used by ftrace direct calls to adhere to the ftrace ABI.
On 64-bit powerpc, TOC setup requires some additional work.
--- arch/powerpc/Kconfig | 2 + samples/ftrace/ftrace-direct-modify.c | 85 +++++++++++++++- samples/ftrace/ftrace-direct-multi-modify.c | 101 +++++++++++++++++++- samples/ftrace/ftrace-direct-multi.c | 79 ++++++++++++++- samples/ftrace/ftrace-direct-too.c | 83 +++++++++++++++- samples/ftrace/ftrace-direct.c | 69 ++++++++++++- 6 files changed, 414 insertions(+), 5 deletions(-)
arch/powerpc/Kconfig +2 -0
@@ -275,6 +275,8 @@ config PPC select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE select HAVE_RSEQ + select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_SETUP_PER_CPU_AREA if PPC64 select HAVE_SOFTIRQ_ON_OWN_STACK select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2)
samples/ftrace/ftrace-direct-modify.c +84 -1
97 lines not on this page · raw message
samples/ftrace/ftrace-direct-multi-modify.c +100 -1
113 lines not on this page · raw message
samples/ftrace/ftrace-direct-multi.c +78 -1
91 lines not on this page · raw message
samples/ftrace/ftrace-direct-too.c +82 -1
95 lines not on this page · raw message
samples/ftrace/ftrace-direct.c +68 -1
81 lines not on this page · raw message
Signature · 1 line
2.45.2
Naveen N Rao
reviewerRFC PATCH v4 17/17 powerpc64/bpf: Add support for bpf trampolines
In reply to Naveen N RaoAdd support for bpf_arch_text_poke() and arch_prepare_bpf_trampoline() for 64-bit powerpc. While the code is generic, BPF trampolines are only enabled on 64-bit powerpc. 32-bit powerpc will need testing and some updates.
BPF Trampolines adhere to the existing ftrace ABI utilizing a two-instruction profiling sequence, as well as the newer ABI utilizing a three-instruction profiling sequence enabling return with a 'blr'. The trampoline code itself closely follows x86 implementation.
BPF prog JIT is extended to mimic 64-bit powerpc approach for ftrace having a single nop at function entry, followed by the function profiling sequence out-of-line and a separate long branch stub for calls to trampolines that are out of range. A dummy_tramp is provided to simplify synchronization similar to arm64.
When attaching a bpf trampoline to a bpf prog, we can patch up to three things:
- the nop at bpf prog entry to go to the out-of-line stub
- the instruction in the out-of-line stub to either call the bpf trampoline directly, or to branch to the long_branch stub.
- the trampoline address before the long_branch stub.
We do not need any synchronization here since we always have a valid branch target regardless of the order in which the above stores are seen. dummy_tramp ensures that the long_branch stub goes to a valid destination on other cpus, even when the branch to the long_branch stub is seen before the updated trampoline address.
However, when detaching a bpf trampoline from a bpf prog, or if changing the bpf trampoline address, we need synchronization to ensure that other cpus can no longer branch into the older trampoline so that it can be safely freed. bpf_tramp_image_put() uses rcu_tasks to ensure all cpus make forward progress, but we still need to ensure that other cpus execute isync (or some CSI) so that they don't go back into the trampoline again.
--- arch/powerpc/include/asm/ppc-opcode.h | 14 + arch/powerpc/net/bpf_jit.h | 12 + arch/powerpc/net/bpf_jit_comp.c | 842 +++++++++++++++++++++++++- arch/powerpc/net/bpf_jit_comp32.c | 7 +- arch/powerpc/net/bpf_jit_comp64.c | 7 +- 5 files changed, 879 insertions(+), 3 deletions(-)
arch/powerpc/include/asm/ppc-opcode.h +14 -0
@@ -587,12 +587,26 @@#define PPC_RAW_MTSPR (spr, d) (0x7c0003a6 | ___PPC_RS(d) | __PPC_SPR(spr))#define PPC_RAW_EIEIO () (0x7c0006ac) +/* bcl 20,31,$+4 */ +#define PPC_RAW_BCL4 () (0x429f0005)#define PPC_RAW_BRANCH (offset) (0x48000000 | PPC_LI(offset))#define PPC_RAW_BL (offset) (0x48000001 | PPC_LI(offset))#define PPC_RAW_TW (t0, a, b) (0x7c000008 | ___PPC_RS(t0) | ___PPC_RA(a) | ___PPC_RB(b))#define PPC_RAW_TRAP () PPC_RAW_TW(31, 0, 0)#define PPC_RAW_SETB (t, bfa) (0x7c000100 | ___PPC_RT(t) | ___PPC_RA((bfa) << 2)) +#ifdef CONFIG_PPC32 +#define PPC_RAW_STL PPC_RAW_STW +#define PPC_RAW_STLU PPC_RAW_STWU +#define PPC_RAW_LL PPC_RAW_LWZ +#define PPC_RAW_CMPLI PPC_RAW_CMPWI +#else +#define PPC_RAW_STL PPC_RAW_STD +#define PPC_RAW_STLU PPC_RAW_STDU +#define PPC_RAW_LL PPC_RAW_LD +#define PPC_RAW_CMPLI PPC_RAW_CMPDI +#endif +/* Deal with instructions that older assemblers aren't aware of */ #define PPC_BCCTR_FLUSH stringify_in_c(.long PPC_INST_BCCTR_FLUSH)#define PPC_CP_ABORT stringify_in_c(.long PPC_RAW_CP_ABORT)
arch/powerpc/net/bpf_jit.h +12 -0
@@ -12,6 +12,7 @@#include <asm/types.h> #include <asm/ppc-opcode.h> +#include <linux/build_bug.h> #ifdef CONFIG_PPC64_ELF_ABI_V1 #define FUNCTION_DESCR_SIZE 24
@@ -21,6 +22,9 @@#define CTX_NIA (ctx) ((unsigned long)ctx->idx * 4) +#define SZL sizeof(unsigned long) +#define BPF_INSN_SAFETY 64 +#define PLANT_INSTR (d, idx, instr) \ do { if (d) { (d)[idx] = instr; } idx++; } while (0)#define EMIT (instr) PLANT_INSTR(image, ctx->idx, instr)
@@ -81,6 +85,13 @@EMIT (PPC_RAW_ORI (d, d, (uintptr_t )(i) & \0xffff )); \ } } while (0) +#define PPC_LI_ADDR PPC_LI64 +#define PPC64_LOAD_PACA () \ + EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))) +#else +#define PPC_LI64 (d, i) BUILD_BUG() +#define PPC_LI_ADDR PPC_LI32 +#define PPC64_LOAD_PACA () BUILD_BUG()#endif /*
@@ -165,6 +176,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code u32 *addrs, int pass, bool extra_pass);void bpf_jit_build_prologue (u32 *image,struct codegen_context *ctx);void bpf_jit_build_epilogue (u32 *image,struct codegen_context *ctx); +void bpf_jit_build_fentry_stubs (u32 *image,struct codegen_context *ctx);void bpf_jit_realloc_regs (struct codegen_context *ctx);int bpf_jit_emit_exit_insn (u32 *image,struct codegen_context *ctx,int tmp_reg,long exit_addr);
arch/powerpc/net/bpf_jit_comp.c +841 -1
862 lines not on this page · raw message
arch/powerpc/net/bpf_jit_comp32.c +6 -1
@@ -127,13 +127,16 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) {int i; +/* Instruction for trampoline attach */ +EMIT (PPC_RAW_NOP ()); +/* Initialize tail_call_cnt, to be skipped if we do tail calls. */ if (ctx->seen &SEEN_TAILCALL )EMIT (PPC_RAW_LI (_R4,0 ));else EMIT (PPC_RAW_NOP ()); -#define BPF_TAILCALL_PROLOGUE_SIZE 4 +#define BPF_TAILCALL_PROLOGUE_SIZE 8if (bpf_has_stack_frame (ctx))EMIT (PPC_RAW_STWU (_R1, _R1, -BPF_PPC_STACKFRAME (ctx)));
@@ -198,6 +201,8 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)bpf_jit_emit_common_epilogue (image, ctx);EMIT (PPC_RAW_BLR ()); + +bpf_jit_build_fentry_stubs (image, ctx); }/* Relative offset needs to be calculated based on final image location */
arch/powerpc/net/bpf_jit_comp64.c +6 -1
@@ -126,6 +126,9 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) {int i; +/* Instruction for trampoline attach */ +EMIT (PPC_RAW_NOP ()); +#ifndef CONFIG_PPC_KERNEL_PCREL if (IS_ENABLED (CONFIG_PPC64_ELF_ABI_V2 ))EMIT (PPC_RAW_LD (_R2, _R13, offsetof(struct paca_struct , kernel_toc)));
@@ -200,6 +203,8 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)EMIT (PPC_RAW_MR (_R3,bpf_to_ppc (BPF_REG_0 )));EMIT (PPC_RAW_BLR ()); + +bpf_jit_build_fentry_stubs (image, ctx); }int bpf_jit_emit_func_call_rel (u32 *image,u32 *fimage,struct codegen_context *ctx,u64 func)
@@ -303,7 +308,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o*/ int b2p_bpf_array =bpf_to_ppc (BPF_REG_2 );int b2p_index =bpf_to_ppc (BPF_REG_3 ); -int bpf_tailcall_prologue_size =8 ; +int bpf_tailcall_prologue_size =12 ;if (!IS_ENABLED (CONFIG_PPC_KERNEL_PCREL ) &&IS_ENABLED (CONFIG_PPC64_ELF_ABI_V2 )) bpf_tailcall_prologue_size +=4 ;/* skip past the toc load */
Signature · 1 line
2.45.2