Skip to content

Commit 0f71dcf

Browse files
rnavmpe
authored andcommitted
powerpc/ftrace: Add support for -fpatchable-function-entry
GCC v13.1 updated support for -fpatchable-function-entry on ppc64le to emit nops after the local entry point, rather than before it. This allows us to use this in the kernel for ftrace purposes. A new script is added under arch/powerpc/tools/ to help detect if nops are emitted after the function local entry point, or before the global entry point. With -fpatchable-function-entry, we no longer have the profiling instructions generated at function entry, so we only need to validate the presence of two nops at the ftrace location in ftrace_init_nop(). We patch the preceding instruction with 'mflr r0' to match the -mprofile-kernel ABI for subsequent ftrace use. This changes the profiling instructions used on ppc32. The default -pg option emits an additional 'stw' instruction after 'mflr r0' and before the branch to _mcount 'bl _mcount'. This is very similar to the original -mprofile-kernel implementation on ppc64le, where an additional 'std' instruction was used to save LR to its save location in the caller's stackframe. Subsequently, this additional store was removed in later compiler versions for performance reasons. The same reasons apply for ppc32 so we only patch in a 'mflr r0'. Signed-off-by: Naveen N Rao <[email protected]> Reviewed-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/68586d22981a2c3bb45f27a2b621173d10a7d092.1687166935.git.naveen@kernel.org
1 parent c91c5a8 commit 0f71dcf

File tree

8 files changed

+64
-9
lines changed

8 files changed

+64
-9
lines changed

arch/powerpc/Kconfig

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ config PPC
186186
select DYNAMIC_FTRACE if FUNCTION_TRACER
187187
select EDAC_ATOMIC_SCRUB
188188
select EDAC_SUPPORT
189+
select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if ARCH_USING_PATCHABLE_FUNCTION_ENTRY
189190
select GENERIC_ATOMIC64 if PPC32
190191
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
191192
select GENERIC_CMOS_UPDATE
@@ -227,8 +228,8 @@ config PPC
227228
select HAVE_DEBUG_KMEMLEAK
228229
select HAVE_DEBUG_STACKOVERFLOW
229230
select HAVE_DYNAMIC_FTRACE
230-
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if MPROFILE_KERNEL || PPC32
231-
select HAVE_DYNAMIC_FTRACE_WITH_REGS if MPROFILE_KERNEL || PPC32
231+
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32
232+
select HAVE_DYNAMIC_FTRACE_WITH_REGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32
232233
select HAVE_EBPF_JIT
233234
select HAVE_EFFICIENT_UNALIGNED_ACCESS
234235
select HAVE_FAST_GUP
@@ -256,7 +257,7 @@ config PPC
256257
select HAVE_MOD_ARCH_SPECIFIC
257258
select HAVE_NMI if PERF_EVENTS || (PPC64 && PPC_BOOK3S)
258259
select HAVE_OPTPROBES
259-
select HAVE_OBJTOOL if PPC32 || MPROFILE_KERNEL
260+
select HAVE_OBJTOOL if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32
260261
select HAVE_OBJTOOL_MCOUNT if HAVE_OBJTOOL
261262
select HAVE_PERF_EVENTS
262263
select HAVE_PERF_EVENTS_NMI if PPC64
@@ -554,6 +555,13 @@ config MPROFILE_KERNEL
554555
def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-mprofile-kernel.sh $(CC) -mlittle-endian) if CPU_LITTLE_ENDIAN
555556
def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-mprofile-kernel.sh $(CC) -mbig-endian) if CPU_BIG_ENDIAN
556557

558+
config ARCH_USING_PATCHABLE_FUNCTION_ENTRY
559+
depends on FUNCTION_TRACER && (PPC32 || PPC64_ELF_ABI_V2)
560+
depends on $(cc-option,-fpatchable-function-entry=2)
561+
def_bool y if PPC32
562+
def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN
563+
def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mbig-endian) if PPC64 && CPU_BIG_ENDIAN
564+
557565
config HOTPLUG_CPU
558566
bool "Support for enabling/disabling CPUs"
559567
depends on SMP && (PPC_PSERIES || \

arch/powerpc/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,16 @@ CFLAGS-$(CONFIG_PPC32) += $(call cc-option, $(MULTIPLEWORD))
143143
CFLAGS-$(CONFIG_PPC32) += $(call cc-option,-mno-readonly-in-sdata)
144144

145145
ifdef CONFIG_FUNCTION_TRACER
146+
ifdef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY
147+
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY
148+
CC_FLAGS_FTRACE := -fpatchable-function-entry=2
149+
else
146150
CC_FLAGS_FTRACE := -pg
147151
ifdef CONFIG_MPROFILE_KERNEL
148152
CC_FLAGS_FTRACE += -mprofile-kernel
149153
endif
150154
endif
155+
endif
151156

152157
CFLAGS-$(CONFIG_TARGET_CPU_BOOL) += -mcpu=$(CONFIG_TARGET_CPU)
153158
AFLAGS-$(CONFIG_TARGET_CPU_BOOL) += -mcpu=$(CONFIG_TARGET_CPU)

arch/powerpc/include/asm/ftrace.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
1212

1313
/* Ignore unused weak functions which will have larger offsets */
14-
#ifdef CONFIG_MPROFILE_KERNEL
14+
#if defined(CONFIG_MPROFILE_KERNEL) || defined(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)
1515
#define FTRACE_MCOUNT_MAX_OFFSET 16
1616
#elif defined(CONFIG_PPC32)
1717
#define FTRACE_MCOUNT_MAX_OFFSET 8
@@ -22,7 +22,9 @@ extern void _mcount(void);
2222

2323
static inline unsigned long ftrace_call_adjust(unsigned long addr)
2424
{
25-
/* relocation of mcount call site is the same as the address */
25+
if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY))
26+
addr += MCOUNT_INSN_SIZE;
27+
2628
return addr;
2729
}
2830

arch/powerpc/include/asm/vermagic.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#ifndef _ASM_VERMAGIC_H
33
#define _ASM_VERMAGIC_H
44

5-
#ifdef CONFIG_MPROFILE_KERNEL
5+
#ifdef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY
6+
#define MODULE_ARCH_VERMAGIC_FTRACE "patchable-function-entry "
7+
#elif defined(CONFIG_MPROFILE_KERNEL)
68
#define MODULE_ARCH_VERMAGIC_FTRACE "mprofile-kernel "
79
#else
810
#define MODULE_ARCH_VERMAGIC_FTRACE ""

arch/powerpc/kernel/module_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
465465
return 0;
466466
}
467467

468-
#ifdef CONFIG_MPROFILE_KERNEL
468+
#if defined(CONFIG_MPROFILE_KERNEL) || defined(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)
469469

470470
static u32 stub_insns[] = {
471471
#ifdef CONFIG_PPC_KERNEL_PCREL

arch/powerpc/kernel/trace/ftrace.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,12 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
220220
int ret = 0;
221221

222222
/* Verify instructions surrounding the ftrace location */
223-
if (IS_ENABLED(CONFIG_PPC32)) {
223+
if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) {
224+
/* Expect nops */
225+
ret = ftrace_validate_inst(ip - 4, ppc_inst(PPC_RAW_NOP()));
226+
if (!ret)
227+
ret = ftrace_validate_inst(ip, ppc_inst(PPC_RAW_NOP()));
228+
} else if (IS_ENABLED(CONFIG_PPC32)) {
224229
/* Expected sequence: 'mflr r0', 'stw r0,4(r1)', 'bl _mcount' */
225230
ret = ftrace_validate_inst(ip - 8, ppc_inst(PPC_RAW_MFLR(_R0)));
226231
if (!ret)
@@ -250,7 +255,12 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
250255
/* Nop-out the ftrace location */
251256
new = ppc_inst(PPC_RAW_NOP());
252257
addr = MCOUNT_ADDR;
253-
if (is_offset_in_branch_range(addr - ip)) {
258+
if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) {
259+
/* we instead patch-in the 'mflr r0' */
260+
old = ppc_inst(PPC_RAW_NOP());
261+
new = ppc_inst(PPC_RAW_MFLR(_R0));
262+
ret = ftrace_modify_code(ip - 4, old, new);
263+
} else if (is_offset_in_branch_range(addr - ip)) {
254264
/* Within range */
255265
old = ftrace_create_branch_inst(ip, addr, 1);
256266
ret = ftrace_modify_code(ip, old, new);

arch/powerpc/kernel/trace/ftrace_entry.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,15 @@ livepatch_handler:
250250
blr
251251
#endif /* CONFIG_LIVEPATCH */
252252

253+
#ifndef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY
253254
_GLOBAL(mcount)
254255
_GLOBAL(_mcount)
255256
EXPORT_SYMBOL(_mcount)
256257
mflr r12
257258
mtctr r12
258259
mtlr r0
259260
bctr
261+
#endif
260262

261263
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
262264
_GLOBAL(return_to_handler)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
set -e
5+
set -o pipefail
6+
7+
# To debug, uncomment the following line
8+
# set -x
9+
10+
# Output from -fpatchable-function-entry can only vary on ppc64 elfv2, so this
11+
# should not be invoked for other targets. Therefore we can pass in -m64 and
12+
# -mabi explicitly, to take care of toolchains defaulting to other targets.
13+
14+
# Test whether the compile option -fpatchable-function-entry exists and
15+
# generates appropriate code
16+
echo "int func() { return 0; }" | \
17+
$* -m64 -mabi=elfv2 -S -x c -O2 -fpatchable-function-entry=2 - -o - 2> /dev/null | \
18+
grep -q "__patchable_function_entries"
19+
20+
# Test whether nops are generated after the local entry point
21+
echo "int x; int func() { return x; }" | \
22+
$* -m64 -mabi=elfv2 -S -x c -O2 -fpatchable-function-entry=2 - -o - 2> /dev/null | \
23+
awk 'BEGIN { RS = ";" } /\.localentry.*nop.*\n[[:space:]]*nop/ { print $0 }' | \
24+
grep -q "func:"
25+
26+
exit 0

0 commit comments

Comments
 (0)