Commit f3993a03 authored by Naveen N Rao's avatar Naveen N Rao Committed by Michael Ellerman
Browse files

powerpc/ftrace: Extend ftrace support for large kernels to ppc32



Commit 67361cf8 ("powerpc/ftrace: Handle large kernel configs")
added ftrace support for ppc64 kernel images with a text section larger
than 32MB. The approach itself isn't specific to ppc64, so extend the
same to also work on ppc32.

While at it, reduce the space reserved for the stub from 64 bytes to 32
bytes since the different stub variants are all less than 8
instructions.

To reduce use of #ifdef, a stub implementation is provided for
kernel_toc_address() and -SZ_2G is cast to 'long long' to prevent
errors on ppc32.

Signed-off-by: default avatarNaveen N Rao <naveen@kernel.org>
Reviewed-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/9fa3258cbb9105cf8a0a8135214d44ffbc75fe84.1687166935.git.naveen@kernel.org
parent b5efb61c
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -124,15 +124,19 @@ static inline u8 this_cpu_get_ftrace_enabled(void)
{
	return get_paca()->ftrace_enabled;
}

void ftrace_free_init_tramp(void);
#else /* CONFIG_PPC64 */
static inline void this_cpu_disable_ftrace(void) { }
static inline void this_cpu_enable_ftrace(void) { }
static inline void this_cpu_set_ftrace_enabled(u8 ftrace_enabled) { }
static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }
static inline void ftrace_free_init_tramp(void) { }
#endif /* CONFIG_PPC64 */

#ifdef CONFIG_FUNCTION_TRACER
extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
void ftrace_free_init_tramp(void);
#else
static inline void ftrace_free_init_tramp(void) { }
#endif
#endif /* !__ASSEMBLY__ */

#endif /* _ASM_POWERPC_FTRACE */
+2 −0
Original line number Diff line number Diff line
@@ -74,6 +74,8 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
		(unsigned long)_stext < end;
}

#else
static inline unsigned long kernel_toc_addr(void) { BUILD_BUG(); return -1UL; }
#endif

#endif /* __KERNEL__ */
+21 −18
Original line number Diff line number Diff line
@@ -707,11 +707,6 @@ void arch_ftrace_update_code(int command)
	ftrace_modify_all_code(command);
}

#ifdef CONFIG_PPC64
#define PACATOC offsetof(struct paca_struct, kernel_toc)

extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];

void ftrace_free_init_tramp(void)
{
	int i;
@@ -725,28 +720,30 @@ void ftrace_free_init_tramp(void)

int __init ftrace_dyn_arch_init(void)
{
	int i;
	unsigned int *tramp[] = { ftrace_tramp_text, ftrace_tramp_init };
#ifdef CONFIG_PPC_KERNEL_PCREL
	unsigned long addr = FTRACE_REGS_ADDR;
	long reladdr;
	int i;
	u32 stub_insns[] = {
#ifdef CONFIG_PPC_KERNEL_PCREL
		/* pla r12,addr */
		PPC_PREFIX_MLS | __PPC_PRFX_R(1),
		PPC_INST_PADDI | ___PPC_RT(_R12),
		PPC_RAW_MTCTR(_R12),
		PPC_RAW_BCTR()
	};
#else
	u32 stub_insns[] = {
		PPC_RAW_LD(_R12, _R13, PACATOC),
#elif defined(CONFIG_PPC64)
		PPC_RAW_LD(_R12, _R13, offsetof(struct paca_struct, kernel_toc)),
		PPC_RAW_ADDIS(_R12, _R12, 0),
		PPC_RAW_ADDI(_R12, _R12, 0),
		PPC_RAW_MTCTR(_R12),
		PPC_RAW_BCTR()
	};
#else
		PPC_RAW_LIS(_R12, 0),
		PPC_RAW_ADDI(_R12, _R12, 0),
		PPC_RAW_MTCTR(_R12),
		PPC_RAW_BCTR()
#endif

	unsigned long addr = FTRACE_REGS_ADDR;
	long reladdr;
	};

	if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) {
		for (i = 0; i < 2; i++) {
@@ -763,10 +760,10 @@ int __init ftrace_dyn_arch_init(void)
			tramp[i][1] |= IMM_L(reladdr);
			add_ftrace_tramp((unsigned long)tramp[i]);
		}
	} else {
	} else if (IS_ENABLED(CONFIG_PPC64)) {
		reladdr = addr - kernel_toc_addr();

		if (reladdr >= (long)SZ_2G || reladdr < -(long)SZ_2G) {
		if (reladdr >= (long)SZ_2G || reladdr < -(long long)SZ_2G) {
			pr_err("Address of %ps out of range of kernel_toc.\n",
				(void *)addr);
			return -1;
@@ -778,11 +775,17 @@ int __init ftrace_dyn_arch_init(void)
			tramp[i][2] |= PPC_LO(reladdr);
			add_ftrace_tramp((unsigned long)tramp[i]);
		}
	} else {
		for (i = 0; i < 2; i++) {
			memcpy(tramp[i], stub_insns, sizeof(stub_insns));
			tramp[i][0] |= PPC_HA(addr);
			tramp[i][1] |= PPC_LO(addr);
			add_ftrace_tramp((unsigned long)tramp[i]);
		}
	}

	return 0;
}
#endif

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
+2 −4
Original line number Diff line number Diff line
@@ -10,19 +10,17 @@
#include <asm/ftrace.h>
#include <asm/ppc-opcode.h>

#ifdef CONFIG_PPC64
.pushsection ".tramp.ftrace.text","aw",@progbits;
.globl ftrace_tramp_text
ftrace_tramp_text:
	.space 64
	.space 32
.popsection

.pushsection ".tramp.ftrace.init","aw",@progbits;
.globl ftrace_tramp_init
ftrace_tramp_init:
	.space 64
	.space 32
.popsection
#endif

_GLOBAL(mcount)
_GLOBAL(_mcount)
+0 −4
Original line number Diff line number Diff line
@@ -107,9 +107,7 @@ SECTIONS
#endif
		/* careful! __ftr_alt_* sections need to be close to .text */
		*(.text.hot .text.hot.* TEXT_MAIN .text.fixup .text.unlikely .text.unlikely.* .fixup __ftr_alt_* .ref.text);
#ifdef CONFIG_PPC64
		*(.tramp.ftrace.text);
#endif
		NOINSTR_TEXT
		SCHED_TEXT
		LOCK_TEXT
@@ -276,9 +274,7 @@ SECTIONS
		 */
		. = ALIGN(PAGE_SIZE);
		_einittext = .;
#ifdef CONFIG_PPC64
		*(.tramp.ftrace.init);
#endif
	} :text

	/* .exit.text is discarded at runtime, not link time,