* [PATCH 1/2] powerpc/bpf: ensure module addresses are supported
@ 2023-12-20 16:56 Hari Bathini
2023-12-20 16:56 ` [PATCH 2/2] powerpc/bpf: enable kfunc call Hari Bathini
2023-12-22 14:29 ` [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Naveen N Rao
0 siblings, 2 replies; 3+ messages in thread
From: Hari Bathini @ 2023-12-20 16:56 UTC (permalink / raw)
To: bpf, linuxppc-dev
Cc: Song Liu, Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko,
Naveen N. Rao, Martin KaFai Lau
Currently, bpf jit code on powerpc assumes all the bpf functions and
helpers to be kernel text. This is false for kfunc case, as function
addresses are mostly module addresses in that case. Ensure module
addresses are supported to enable kfunc support.
This effectively reverts commit feb6307289d8 ("powerpc64/bpf: Optimize
instruction sequence used for function calls") and commit 43d636f8b4fd
("powerpc64/bpf elfv1: Do not load TOC before calling functions") that
assumed only kernel text for bpf functions/helpers.
Also, commit b10cb163c4b3 ("powerpc64/bpf elfv2: Setup kernel TOC in
r2 on entry") that paved the way for the commits mentioned above is
reverted.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/net/bpf_jit.h | 2 +-
arch/powerpc/net/bpf_jit_comp32.c | 8 +--
arch/powerpc/net/bpf_jit_comp64.c | 90 +++++++++++++++++--------------
3 files changed, 52 insertions(+), 48 deletions(-)
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index cdea5dccaefe..48503caa5b58 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -160,7 +160,7 @@ static inline void bpf_clear_seen_register(struct codegen_context *ctx, int i)
}
void bpf_jit_init_reg_mapping(struct codegen_context *ctx);
-int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func);
+void bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func);
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
u32 *addrs, int pass, bool extra_pass);
void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx);
diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c
index 2f39c50ca729..1236a75c04ea 100644
--- a/arch/powerpc/net/bpf_jit_comp32.c
+++ b/arch/powerpc/net/bpf_jit_comp32.c
@@ -201,7 +201,7 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
}
/* Relative offset needs to be calculated based on final image location */
-int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func)
+void bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func)
{
s32 rel = (s32)func - (s32)(fimage + ctx->idx);
@@ -214,8 +214,6 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *
EMIT(PPC_RAW_MTCTR(_R0));
EMIT(PPC_RAW_BCTRL());
}
-
- return 0;
}
static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out)
@@ -1054,9 +1052,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
EMIT(PPC_RAW_STW(bpf_to_ppc(BPF_REG_5), _R1, 12));
}
- ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr);
- if (ret)
- return ret;
+ bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr);
EMIT(PPC_RAW_MR(bpf_to_ppc(BPF_REG_0) - 1, _R3));
EMIT(PPC_RAW_MR(bpf_to_ppc(BPF_REG_0), _R4));
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 79f23974a320..e7199c202a00 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -126,11 +126,6 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
{
int i;
-#ifndef CONFIG_PPC_KERNEL_PCREL
- if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2))
- EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc)));
-#endif
-
/*
* Initialize tail_call_cnt if we do tail calls.
* Otherwise, put in NOPs so that it can be skipped when we are
@@ -145,6 +140,8 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
EMIT(PPC_RAW_NOP());
}
+#define BPF_TAILCALL_PROLOGUE_SIZE 8
+
if (bpf_has_stack_frame(ctx)) {
/*
* We need a stack frame, but we don't necessarily need to
@@ -204,14 +201,9 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
static int bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, u64 func)
{
- unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0;
- long reladdr;
-
- if (WARN_ON_ONCE(!core_kernel_text(func_addr)))
- return -EINVAL;
-
if (IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) {
- reladdr = func_addr - CTX_NIA(ctx);
+ unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0;
+ long reladdr = func_addr - CTX_NIA(ctx);
if (reladdr >= (long)SZ_8G || reladdr < -(long)SZ_8G) {
pr_err("eBPF: address of %ps out of range of pcrel address.\n",
@@ -225,31 +217,35 @@ static int bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, u
EMIT(PPC_RAW_BCTR());
} else {
- reladdr = func_addr - kernel_toc_addr();
- if (reladdr > 0x7FFFFFFF || reladdr < -(0x80000000L)) {
- pr_err("eBPF: address of %ps out of range of kernel_toc.\n", (void *)func);
- return -ERANGE;
- }
-
- EMIT(PPC_RAW_ADDIS(_R12, _R2, PPC_HA(reladdr)));
- EMIT(PPC_RAW_ADDI(_R12, _R12, PPC_LO(reladdr)));
- EMIT(PPC_RAW_MTCTR(_R12));
+#ifdef PPC64_ELF_ABI_v1
+ /* func points to the function descriptor */
+ PPC_LI64(b2p[TMP_REG_2], func);
+ /* Load actual entry point from function descriptor */
+ PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
+ /* ... and move it to CTR */
+ EMIT(PPC_RAW_MTCTR(b2p[TMP_REG_1]));
+ /*
+ * Load TOC from function descriptor at offset 8.
+ * We can clobber r2 since we get called through a
+ * function pointer (so caller will save/restore r2)
+ * and since we don't use a TOC ourself.
+ */
+ PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
+#else
+ /* We can clobber r12 */
+ PPC_LI64(12, func);
+ EMIT(PPC_RAW_MTCTR(12));
+#endif
EMIT(PPC_RAW_BCTRL());
}
return 0;
}
-int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func)
+void 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);
@@ -267,10 +263,20 @@ int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *
for (i = ctx->idx - ctx_idx; i < 5; i++)
EMIT(PPC_RAW_NOP());
+#ifdef PPC64_ELF_ABI_v1
+ /*
+ * Load TOC from function descriptor at offset 8.
+ * We can clobber r2 since we get called through a
+ * function pointer (so caller will save/restore r2)
+ * and since we don't use a TOC ourself.
+ */
+ PPC_BPF_LL(2, 12, 8);
+ /* Load actual entry point from function descriptor */
+ PPC_BPF_LL(12, 12, 0);
+#endif
+
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)
@@ -283,10 +289,6 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
*/
int b2p_bpf_array = bpf_to_ppc(BPF_REG_2);
int b2p_index = bpf_to_ppc(BPF_REG_3);
- int bpf_tailcall_prologue_size = 8;
-
- if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2))
- bpf_tailcall_prologue_size += 4; /* skip past the toc load */
/*
* if (index >= array->map.max_entries)
@@ -325,8 +327,14 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o
/* goto *(prog->bpf_func + prologue_size); */
EMIT(PPC_RAW_LD(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_1), offsetof(struct bpf_prog, bpf_func)));
+#ifdef PPC64_ELF_ABI_v1
+ /* skip past the function descriptor */
EMIT(PPC_RAW_ADDI(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_1),
- FUNCTION_DESCR_SIZE + bpf_tailcall_prologue_size));
+ FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE));
+#else
+ EMIT(PPC_RAW_ADDI(bpf_to_ppc(TMP_REG_1), bpf_to_ppc(TMP_REG_1),
+ BPF_TAILCALL_PROLOGUE_SIZE));
+#endif
EMIT(PPC_RAW_MTCTR(bpf_to_ppc(TMP_REG_1)));
/* tear down stack, restore NVRs, ... */
@@ -992,13 +1000,13 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code
if (ret < 0)
return ret;
- if (func_addr_fixed)
+ if (func_addr_fixed) {
ret = bpf_jit_emit_func_call_hlp(image, ctx, func_addr);
- else
- ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr);
-
- if (ret)
- return ret;
+ if (ret)
+ return ret;
+ } else {
+ bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr);
+ }
/* move return value from r3 to BPF_REG_0 */
EMIT(PPC_RAW_MR(bpf_to_ppc(BPF_REG_0), _R3));
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] powerpc/bpf: enable kfunc call
2023-12-20 16:56 [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Hari Bathini
@ 2023-12-20 16:56 ` Hari Bathini
2023-12-22 14:29 ` [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Naveen N Rao
1 sibling, 0 replies; 3+ messages in thread
From: Hari Bathini @ 2023-12-20 16:56 UTC (permalink / raw)
To: bpf, linuxppc-dev
Cc: Song Liu, Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko,
Naveen N. Rao, Martin KaFai Lau
With module addresses supported, override bpf_jit_supports_kfunc_call()
to enable kfunc support. Module address offsets can be more than 32-bit
long, so override bpf_jit_supports_far_kfunc_call() to enable 64-bit
pointers.
Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
arch/powerpc/net/bpf_jit_comp.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 0f9a21783329..a6151a5ef9a5 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -359,3 +359,13 @@ void bpf_jit_free(struct bpf_prog *fp)
bpf_prog_unlock_free(fp);
}
+
+bool bpf_jit_supports_kfunc_call(void)
+{
+ return true;
+}
+
+bool bpf_jit_supports_far_kfunc_call(void)
+{
+ return true;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 1/2] powerpc/bpf: ensure module addresses are supported
2023-12-20 16:56 [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Hari Bathini
2023-12-20 16:56 ` [PATCH 2/2] powerpc/bpf: enable kfunc call Hari Bathini
@ 2023-12-22 14:29 ` Naveen N Rao
1 sibling, 0 replies; 3+ messages in thread
From: Naveen N Rao @ 2023-12-22 14:29 UTC (permalink / raw)
To: Hari Bathini
Cc: Song Liu, Daniel Borkmann, Martin KaFai Lau, Andrii Nakryiko,
Alexei Starovoitov, bpf, linuxppc-dev
On Wed, Dec 20, 2023 at 10:26:21PM +0530, Hari Bathini wrote:
> Currently, bpf jit code on powerpc assumes all the bpf functions and
> helpers to be kernel text. This is false for kfunc case, as function
> addresses are mostly module addresses in that case. Ensure module
> addresses are supported to enable kfunc support.
>
> This effectively reverts commit feb6307289d8 ("powerpc64/bpf: Optimize
> instruction sequence used for function calls") and commit 43d636f8b4fd
> ("powerpc64/bpf elfv1: Do not load TOC before calling functions") that
> assumed only kernel text for bpf functions/helpers.
>
> Also, commit b10cb163c4b3 ("powerpc64/bpf elfv2: Setup kernel TOC in
> r2 on entry") that paved the way for the commits mentioned above is
> reverted.
Instead of that, can we detect kfunc and use separate set of
instructions just for those?
Unless unavoidable, I would prefer to retain the existing optimal
sequence using TOC for calls to bpf kernel helpers, since those are a
lot more common than kfunc.
- Naveen
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-12-22 14:35 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-20 16:56 [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Hari Bathini
2023-12-20 16:56 ` [PATCH 2/2] powerpc/bpf: enable kfunc call Hari Bathini
2023-12-22 14:29 ` [PATCH 1/2] powerpc/bpf: ensure module addresses are supported Naveen N Rao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).