powerpc64/bpf: Fold bpf_jit_emit_func_call_hlp() into bpf_jit_emit_func_call_rel()
authorNaveen N Rao <naveen@kernel.org>
Wed, 30 Oct 2024 07:08:42 +0000 (12:38 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 31 Oct 2024 00:00:54 +0000 (11:00 +1100)
Commit 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.

Signed-off-by: Naveen N Rao <naveen@kernel.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://patch.msgid.link/20241030070850.1361304-10-hbathini@linux.ibm.com
arch/powerpc/net/bpf_jit_comp64.c

index 2cbcdf9..f3be024 100644 (file)
@@ -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 @@ emit_clear:
                        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);
-
+                       ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr);
                        if (ret)
                                return ret;