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

powerpc64/bpf: Fold bpf_jit_emit_func_call_hlp() into bpf_jit_emit_func_call_rel()



Commit 61688a82 ("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.

Signed-off-by: default avatarNaveen N Rao <naveen@kernel.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://patch.msgid.link/20241030070850.1361304-10-hbathini@linux.ibm.com
parent ed614465
Loading
Loading
Loading
Loading
+17 −44
Original line number Diff line number Diff line
@@ -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,6 +274,7 @@ 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).
			 */
			if (is_module_text_address(func_addr))
				EMIT(PPC_RAW_LD(_R2, bpf_to_ppc(TMP_REG_2), 8));
		} else {
			PPC_LI64(_R12, func);
@@ -276,6 +285,7 @@ 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.
		 */
		if (is_module_text_address(func_addr))
			EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc)));
	}
#endif
@@ -283,39 +293,6 @@ bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx,
	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 code
			if (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);

			if (ret)
				return ret;