Commit c93d4f6e authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman
Browse files

powerpc/ftrace: Add module_trampoline_target() for PPC32



module_trampoline_target() is used by __ftrace_modify_call().

Implement it for PPC32 so that CONFIG_DYNAMIC_FTRACE_WITH_REGS
can be activated on PPC32 as well.

Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/42345f464fb465f0fc76f3090e250be8fc1729f0.1635423081.git.christophe.leroy@csgroup.eu
parent 88670fdb
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -273,6 +273,31 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
}
}


#ifdef CONFIG_DYNAMIC_FTRACE
#ifdef CONFIG_DYNAMIC_FTRACE
int module_trampoline_target(struct module *mod, unsigned long addr,
			     unsigned long *target)
{
	unsigned int jmp[4];

	/* Find where the trampoline jumps to */
	if (copy_from_kernel_nofault(jmp, (void *)addr, sizeof(jmp)))
		return -EFAULT;

	/* verify that this is what we expect it to be */
	if ((jmp[0] & 0xffff0000) != PPC_RAW_LIS(_R12, 0) ||
	    (jmp[1] & 0xffff0000) != PPC_RAW_ADDI(_R12, _R12, 0) ||
	    jmp[2] != PPC_RAW_MTCTR(_R12) ||
	    jmp[3] != PPC_RAW_BCTR())
		return -EINVAL;

	addr = (jmp[1] & 0xffff) | ((jmp[0] & 0xffff) << 16);
	if (addr & 0x8000)
		addr -= 0x10000;

	*target = addr;

	return 0;
}

int module_finalize_ftrace(struct module *module, const Elf_Shdr *sechdrs)
int module_finalize_ftrace(struct module *module, const Elf_Shdr *sechdrs)
{
{
	module->arch.tramp = do_plt_call(module->core_layout.base,
	module->arch.tramp = do_plt_call(module->core_layout.base,
+4 −33
Original line number Original line Diff line number Diff line
@@ -222,9 +222,8 @@ __ftrace_make_nop(struct module *mod,
		  struct dyn_ftrace *rec, unsigned long addr)
		  struct dyn_ftrace *rec, unsigned long addr)
{
{
	struct ppc_inst op;
	struct ppc_inst op;
	unsigned int jmp[4];
	unsigned long ip = rec->ip;
	unsigned long ip = rec->ip;
	unsigned long tramp;
	unsigned long tramp, ptr;


	if (copy_from_kernel_nofault(&op, (void *)ip, MCOUNT_INSN_SIZE))
	if (copy_from_kernel_nofault(&op, (void *)ip, MCOUNT_INSN_SIZE))
		return -EFAULT;
		return -EFAULT;
@@ -238,41 +237,13 @@ __ftrace_make_nop(struct module *mod,
	/* lets find where the pointer goes */
	/* lets find where the pointer goes */
	tramp = find_bl_target(ip, op);
	tramp = find_bl_target(ip, op);


	/*
	 * On PPC32 the trampoline looks like:
	 *  0x3d, 0x80, 0x00, 0x00  lis r12,sym@ha
	 *  0x39, 0x8c, 0x00, 0x00  addi r12,r12,sym@l
	 *  0x7d, 0x89, 0x03, 0xa6  mtctr r12
	 *  0x4e, 0x80, 0x04, 0x20  bctr
	 */

	pr_devel("ip:%lx jumps to %lx", ip, tramp);

	/* Find where the trampoline jumps to */
	/* Find where the trampoline jumps to */
	if (copy_from_kernel_nofault(jmp, (void *)tramp, sizeof(jmp))) {
	if (module_trampoline_target(mod, tramp, &ptr)) {
		pr_err("Failed to read %lx\n", tramp);
		pr_err("Failed to get trampoline target\n");
		return -EFAULT;
		return -EFAULT;
	}
	}


	pr_devel(" %08x %08x ", jmp[0], jmp[1]);
	if (ptr != addr) {

	/* verify that this is what we expect it to be */
	if (((jmp[0] & 0xffff0000) != 0x3d800000) ||
	    ((jmp[1] & 0xffff0000) != 0x398c0000) ||
	    (jmp[2] != 0x7d8903a6) ||
	    (jmp[3] != 0x4e800420)) {
		pr_err("Not a trampoline\n");
		return -EINVAL;
	}

	tramp = (jmp[1] & 0xffff) |
		((jmp[0] & 0xffff) << 16);
	if (tramp & 0x8000)
		tramp -= 0x10000;

	pr_devel(" %lx ", tramp);

	if (tramp != addr) {
		pr_err("Trampoline location %08lx does not match addr\n",
		pr_err("Trampoline location %08lx does not match addr\n",
		       tramp);
		       tramp);
		return -EINVAL;
		return -EINVAL;