mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf-next v3 0/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
@ 2026-08-14  1:29 Feng Jiang
  2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
  2026-08-14  1:29 ` [PATCH bpf-next v3 2/2] selftests/bpf: Enable stack argument tests for RV64 Feng Jiang
  0 siblings, 2 replies; 8+ messages in thread
From: Feng Jiang @ 2026-08-14  1:29 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Pu Lehui, Puranjay Mohan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm, Feng Jiang

Port the BPF stack argument feature (BPF_REG_PARAMS / r11) to the
RV64 JIT, matching what x86 and arm64 already do.

BPF-to-BPF calls keep all extra arguments on the stack.  For kfunc
calls, the JIT loads arguments 6-8 into A5-A7 at the call site to
satisfy the RISC-V C calling convention.

Tested on riscv64 QEMU with LLVM main [1]; BPF-to-BPF and kfunc
selftests pass.

[1] https://github.com/llvm/llvm-project/pull/189060

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
Changes in v3:
- Drop the exceptions.c guard change: the guarded programs use
  bpf_throw(), unsupported by the RV64 JIT, so the test is denylisted
  on riscv64 and the guard has no effect. (BPF CI)
- Link to v2: https://lore.kernel.org/r/20260813-bpf-riscv-stack-args-v2-0-efea8f9b3fe1@kylinos.cn

Changes in v2:
- Sign-extend 32-bit kfunc arguments passed on the stack (args 9+),
  matching the register path and the RISC-V psABI. (Sashiko)
- Restrict the riscv selftest guard to __riscv_xlen == 64 so the
  tests are not enabled on RV32. (Sashiko)
- Link to v1: https://lore.kernel.org/r/20260812-bpf-riscv-stack-args-v1-0-67b246806e59@kylinos.cn

---
Feng Jiang (2):
      bpf, riscv: Add BPF stack arguments support for RV64 JIT
      selftests/bpf: Enable stack argument tests for RV64

 arch/riscv/net/bpf_jit.h                           |  1 +
 arch/riscv/net/bpf_jit_comp64.c                    | 79 +++++++++++++++++++++-
 arch/riscv/net/bpf_jit_core.c                      |  4 ++
 .../selftests/bpf/progs/btf__stack_arg_precision.c |  3 +-
 .../bpf/progs/btf__verifier_stack_arg_order.c      |  3 +-
 tools/testing/selftests/bpf/progs/stack_arg.c      |  3 +-
 .../testing/selftests/bpf/progs/stack_arg_kfunc.c  |  3 +-
 .../selftests/bpf/progs/stack_arg_precision.c      |  3 +-
 .../selftests/bpf/progs/verifier_stack_arg.c       |  3 +-
 .../selftests/bpf/progs/verifier_stack_arg_order.c |  3 +-
 10 files changed, 95 insertions(+), 10 deletions(-)
---
base-commit: d114bb98936770c501c958bf2bc5fb6b7c0bad7b
change-id: 20260728-bpf-riscv-stack-args-6350d066a1e9

Best regards,
-- 
Feng Jiang <jiangfeng@kylinos.cn>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-14  1:29 [PATCH bpf-next v3 0/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT Feng Jiang
@ 2026-08-14  1:29 ` Feng Jiang
  2026-08-14  2:34   ` bot+bpf-ci
                     ` (2 more replies)
  2026-08-14  1:29 ` [PATCH bpf-next v3 2/2] selftests/bpf: Enable stack argument tests for RV64 Feng Jiang
  1 sibling, 3 replies; 8+ messages in thread
From: Feng Jiang @ 2026-08-14  1:29 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Pu Lehui, Puranjay Mohan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm, Feng Jiang

Add bpf_jit_supports_stack_args() for the RV64 JIT so BPF subprograms
and kfuncs can receive more than 5 arguments via the stack
(BPF_REG_PARAMS / r11).

For BPF-to-BPF calls the caller writes outgoing arguments at the
bottom of its frame (SP-relative). The callee reads them with
FP-relative loads. Its FP is set to the caller SP in the prologue,
so the offsets match.

The RISC-V ABI puts arguments 6-8 in A5-A7 and arguments 9+ at
SP+0. Before each kfunc call, load arguments 6-8 from the outgoing
area into A5-A7 and copy any remaining arguments down so argument 9
lands at SP+0.

A5 (BPF_REG_0), A6 (TCC) and A7 are safe to clobber here: R0 is not
live before a call, TCC is backed up on the stack, and A7 is unused
by the JIT.

Limit the existing kfunc sign-extension loop to MAX_BPF_FUNC_REG_ARGS
iterations; otherwise idx >= 5 resolves to S1-S5 (BPF_R6-FP) and
corrupts callee-saved registers.

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 arch/riscv/net/bpf_jit.h        |  1 +
 arch/riscv/net/bpf_jit_comp64.c | 79 +++++++++++++++++++++++++++++++++++++++--
 arch/riscv/net/bpf_jit_core.c   |  4 +++
 3 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
index 419b9d795f2a..9eb4e149505d 100644
--- a/arch/riscv/net/bpf_jit.h
+++ b/arch/riscv/net/bpf_jit.h
@@ -82,6 +82,7 @@ struct rv_jit_context {
 	unsigned long flags;
 	int stack_size;
 	int tcc_offset;
+	u16 stack_arg_size;
 	u64 arena_vm_start;
 	u64 user_vm_start;
 };
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index 6b9972b07c1b..58cb3e5ff6b4 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -1815,18 +1815,43 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 
 		if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
 			const struct btf_func_model *fm;
-			int idx;
+			int idx, nargs;
 
 			fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
 			if (!fm)
 				return -EINVAL;
 
-			for (idx = 0; idx < fm->nr_args; idx++) {
+			nargs = min_t(int, fm->nr_args, MAX_BPF_FUNC_REG_ARGS);
+			for (idx = 0; idx < nargs; idx++) {
 				u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);
 
 				if (fm->arg_size[idx] == sizeof(int))
 					emit_sextw(reg, reg, ctx);
 			}
+
+			/* BPF stack args -> RISC-V ABI: args 6-8 in A5-A7, 9+ at SP+0 */
+			if (fm->nr_args > MAX_BPF_FUNC_REG_ARGS) {
+				int n_stack = fm->nr_args - MAX_BPF_FUNC_REG_ARGS;
+				int n_reg = min_t(int, n_stack,
+						  RV_MAX_REG_ARGS - MAX_BPF_FUNC_REG_ARGS);
+
+				for (idx = 0; idx < n_reg; idx++) {
+					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
+
+					emit_ld(RV_REG_A5 + idx, idx * 8, RV_REG_SP, ctx);
+					if (sz == sizeof(int))
+						emit_sextw(RV_REG_A5 + idx, RV_REG_A5 + idx, ctx);
+				}
+
+				for (idx = n_reg; idx < n_stack; idx++) {
+					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
+
+					emit_ld(RV_REG_T1, idx * 8, RV_REG_SP, ctx);
+					if (sz == sizeof(int))
+						emit_sextw(RV_REG_T1, RV_REG_T1, ctx);
+					emit_sd(RV_REG_SP, (idx - n_reg) * 8, RV_REG_T1, ctx);
+				}
+			}
 		}
 
 		/* restore TCC to RV_REG_TCC before bpf2bpf call */
@@ -1891,6 +1916,21 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_LDX | BPF_MEM | BPF_H:
 	case BPF_LDX | BPF_MEM | BPF_W:
 	case BPF_LDX | BPF_MEM | BPF_DW:
+		if (insn->src_reg == BPF_REG_PARAMS) {
+			int idx = off / 8 - 1;
+
+			if (is_12b_int(idx * 8)) {
+				emit_ldx_insn(rd, idx * 8, RV_REG_FP, BPF_SIZE(code), false, ctx);
+			} else {
+				emit_imm(RV_REG_T1, idx * 8, ctx);
+				emit_add(RV_REG_T1, RV_REG_T1, RV_REG_FP, ctx);
+				emit_ldx_insn(rd, 0, RV_REG_T1, BPF_SIZE(code), false, ctx);
+			}
+			if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
+				return 1;
+			break;
+		}
+		fallthrough;
 	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
 	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
 	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
@@ -1938,6 +1978,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_ST | BPF_MEM | BPF_H:
 	case BPF_ST | BPF_MEM | BPF_W:
 	case BPF_ST | BPF_MEM | BPF_DW:
+		if (insn->dst_reg == BPF_REG_PARAMS) {
+			int idx = -off / 8 - 1;
+
+			emit_imm(RV_REG_T1, imm, ctx);
+			if (is_12b_int(idx * 8)) {
+				emit_stx_insn(RV_REG_SP, idx * 8, RV_REG_T1, BPF_SIZE(code), ctx);
+			} else {
+				emit_imm(RV_REG_T2, idx * 8, ctx);
+				emit_add(RV_REG_T2, RV_REG_SP, RV_REG_T2, ctx);
+				emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, BPF_SIZE(code), ctx);
+			}
+			break;
+		}
+		fallthrough;
 	/* ST | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = imm */
 	case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
 	case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
@@ -1960,6 +2014,19 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_STX | BPF_MEM | BPF_H:
 	case BPF_STX | BPF_MEM | BPF_W:
 	case BPF_STX | BPF_MEM | BPF_DW:
+		if (insn->dst_reg == BPF_REG_PARAMS) {
+			int idx = -off / 8 - 1;
+
+			if (is_12b_int(idx * 8)) {
+				emit_stx_insn(RV_REG_SP, idx * 8, rs, BPF_SIZE(code), ctx);
+			} else {
+				emit_imm(RV_REG_T1, idx * 8, ctx);
+				emit_add(RV_REG_T1, RV_REG_SP, RV_REG_T1, ctx);
+				emit_stx_insn(RV_REG_T1, 0, rs, BPF_SIZE(code), ctx);
+			}
+			break;
+		}
+		fallthrough;
 	/* STX | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = src */
 	case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
 	case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
@@ -2036,6 +2103,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
 
 	stack_adjust = round_up(stack_adjust, STACK_ALIGN);
 	stack_adjust += bpf_stack_adjust;
+	stack_adjust += ctx->stack_arg_size;
 
 	store_offset = stack_adjust - 8;
 
@@ -2093,7 +2161,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
 	emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);
 
 	if (bpf_stack_adjust)
-		emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx);
+		emit_addi(RV_REG_S5, RV_REG_SP, ctx->stack_arg_size + bpf_stack_adjust, ctx);
 
 	ctx->stack_size = stack_adjust;
 
@@ -2171,3 +2239,8 @@ bool bpf_jit_supports_timed_may_goto(void)
 {
 	return true;
 }
+
+bool bpf_jit_supports_stack_args(void)
+{
+	return true;
+}
diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
index cbfcd287ea16..844a0f3e0fa9 100644
--- a/arch/riscv/net/bpf_jit_core.c
+++ b/arch/riscv/net/bpf_jit_core.c
@@ -72,6 +72,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
 	ctx->arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
 	ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
 	ctx->prog = prog;
+
+	ctx->stack_arg_size = round_up(bpf_out_stack_arg_cnt(env, prog) *
+				       sizeof(u64), STACK_ALIGN);
+
 	ctx->offset = kvzalloc_objs(int, prog->len);
 	if (!ctx->offset)
 		goto out_offset;

-- 
2.53.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf-next v3 2/2] selftests/bpf: Enable stack argument tests for RV64
  2026-08-14  1:29 [PATCH bpf-next v3 0/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT Feng Jiang
  2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
@ 2026-08-14  1:29 ` Feng Jiang
  1 sibling, 0 replies; 8+ messages in thread
From: Feng Jiang @ 2026-08-14  1:29 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Pu Lehui, Puranjay Mohan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Shuah Khan, Nathan Chancellor,
	Nick Desaulniers, Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm, Feng Jiang

Enable the stack argument selftests for RV64. The riscv guard is
restricted to __riscv_xlen == 64 since stack arguments are only
supported by the RV64 JIT.

Keep the __BPF_FEATURE_STACK_ARGUMENT gate, defined by clang with
BPF stack argument support [1].

[1] https://github.com/llvm/llvm-project/pull/189060

Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
---
 tools/testing/selftests/bpf/progs/btf__stack_arg_precision.c      | 3 ++-
 tools/testing/selftests/bpf/progs/btf__verifier_stack_arg_order.c | 3 ++-
 tools/testing/selftests/bpf/progs/stack_arg.c                     | 3 ++-
 tools/testing/selftests/bpf/progs/stack_arg_kfunc.c               | 3 ++-
 tools/testing/selftests/bpf/progs/stack_arg_precision.c           | 3 ++-
 tools/testing/selftests/bpf/progs/verifier_stack_arg.c            | 3 ++-
 tools/testing/selftests/bpf/progs/verifier_stack_arg_order.c      | 3 ++-
 7 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/bpf/progs/btf__stack_arg_precision.c b/tools/testing/selftests/bpf/progs/btf__stack_arg_precision.c
index 8d38aafe66a2..ab12397a9b52 100644
--- a/tools/testing/selftests/bpf/progs/btf__stack_arg_precision.c
+++ b/tools/testing/selftests/bpf/progs/btf__stack_arg_precision.c
@@ -4,7 +4,8 @@
 #include <bpf/bpf_helpers.h>
 #include "../test_kmods/bpf_testmod_kfunc.h"
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 long subprog_call_mem_kfunc(long a, long b, long c, long d, long e, long size)
diff --git a/tools/testing/selftests/bpf/progs/btf__verifier_stack_arg_order.c b/tools/testing/selftests/bpf/progs/btf__verifier_stack_arg_order.c
index 99bc115f8380..a980a3a399d3 100644
--- a/tools/testing/selftests/bpf/progs/btf__verifier_stack_arg_order.c
+++ b/tools/testing/selftests/bpf/progs/btf__verifier_stack_arg_order.c
@@ -3,7 +3,8 @@
 #include <vmlinux.h>
 #include <bpf/bpf_helpers.h>
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 int subprog_bad_order_6args(int a, int b, int c, int d, int e, int f)
diff --git a/tools/testing/selftests/bpf/progs/stack_arg.c b/tools/testing/selftests/bpf/progs/stack_arg.c
index 944e3bb603e7..3e9ed37c57bb 100644
--- a/tools/testing/selftests/bpf/progs/stack_arg.c
+++ b/tools/testing/selftests/bpf/progs/stack_arg.c
@@ -21,7 +21,8 @@ struct {
 
 int timer_result;
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 const volatile bool has_stack_arg = true;
diff --git a/tools/testing/selftests/bpf/progs/stack_arg_kfunc.c b/tools/testing/selftests/bpf/progs/stack_arg_kfunc.c
index 345f2da2e361..b6b1a8aa7f44 100644
--- a/tools/testing/selftests/bpf/progs/stack_arg_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/stack_arg_kfunc.c
@@ -6,7 +6,8 @@
 #include "bpf_kfuncs.h"
 #include "../test_kmods/bpf_testmod_kfunc.h"
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 const volatile bool has_stack_arg = true;
diff --git a/tools/testing/selftests/bpf/progs/stack_arg_precision.c b/tools/testing/selftests/bpf/progs/stack_arg_precision.c
index bee2eeec021d..6eebafe7f2f8 100644
--- a/tools/testing/selftests/bpf/progs/stack_arg_precision.c
+++ b/tools/testing/selftests/bpf/progs/stack_arg_precision.c
@@ -6,7 +6,8 @@
 #include "../test_kmods/bpf_testmod_kfunc.h"
 #include "bpf_misc.h"
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 /* Force kfunc extern BTF generation for inline asm call below.
diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
index 7e0ce5db28a0..e8cd296fe763 100644
--- a/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
+++ b/tools/testing/selftests/bpf/progs/verifier_stack_arg.c
@@ -12,7 +12,8 @@ struct {
 	__type(value, long long);
 } map_hash_8b SEC(".maps");
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 __noinline __used
diff --git a/tools/testing/selftests/bpf/progs/verifier_stack_arg_order.c b/tools/testing/selftests/bpf/progs/verifier_stack_arg_order.c
index c9fe4857da3f..562e8319ffc2 100644
--- a/tools/testing/selftests/bpf/progs/verifier_stack_arg_order.c
+++ b/tools/testing/selftests/bpf/progs/verifier_stack_arg_order.c
@@ -5,7 +5,8 @@
 #include <bpf/bpf_helpers.h>
 #include "bpf_misc.h"
 
-#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64)) && \
+#if (defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_arm64) || \
+	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) && \
 	defined(__BPF_FEATURE_STACK_ARGUMENT)
 
 __noinline __used __naked

-- 
2.53.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
@ 2026-08-14  2:34   ` bot+bpf-ci
  2026-08-14  6:49   ` Pu Lehui
  2026-08-17  1:52   ` Pu Lehui
  2 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-08-14  2:34 UTC (permalink / raw)
  To: jiangfeng, ast, daniel, andrii, eddyz87, memxor, martin.lau,
	song, yonghong.song, jolsa, emil, ihor.solodrai, luke.r.nels,
	xi.wang, bjorn, pulehui, puranjay, pjw, palmer, aou, alex, shuah,
	nathan, ndesaulniers, morbo, justinstitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm, jiangfeng,
	ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 2422 bytes --]

> diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
> index 2504df1fa1118..62c84de22163f 100644
> --- a/arch/riscv/net/bpf_jit_comp64.c
> +++ b/arch/riscv/net/bpf_jit_comp64.c

[ ... ]

> @@ -1891,6 +1916,21 @@ int bpf_jit_emit_insn
>  	case BPF_LDX | BPF_MEM | BPF_H:
>  	case BPF_LDX | BPF_MEM | BPF_W:
>  	case BPF_LDX | BPF_MEM | BPF_DW:
> +		if (insn->src_reg == BPF_REG_PARAMS) {
> +			int idx = off / 8 - 1;
> +
> +			if (is_12b_int(idx * 8)) {
> +				emit_ldx_insn(rd, idx * 8, RV_REG_FP, BPF_SIZE(code), false, ctx);
> +			} else {
> +				emit_imm(RV_REG_T1, idx * 8, ctx);
> +				emit_add(RV_REG_T1, RV_REG_T1, RV_REG_FP, ctx);
> +				emit_ldx_insn(rd, 0, RV_REG_T1, BPF_SIZE(code), false, ctx);
> +			}
> +			if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
> +				return 1;
> +			break;
> +		}
> +		fallthrough;

Does this new BPF-to-BPF stack argument convention work correctly with
the existing RV64 trampoline code?

The convention here reads incoming stack arguments from FP+0, FP+8, etc
(callee FP == caller SP). But looking at store_args() in this same file,
the trampoline appears to use the native RISC-V ABI instead:

arch/riscv/net/bpf_jit_comp64.c:store_args() {
    for (i = 0; i < nr_arg_slots; i++) {
        if (i < RV_MAX_REG_ARGS)
            emit_sd(RV_REG_FP, -args_off, RV_REG_A0 + i, ctx);
        else
            emit_ld(RV_REG_T1, 16 + (i - RV_MAX_REG_ARGS) * 8, RV_REG_FP, ctx);

where RV_MAX_REG_ARGS is 8, so it expects arguments 6, 7, 8 in a5, a6, a7
and arguments 9+ at FP+16.

For a BPF subprogram using this new convention, arguments 6+ arrive in
memory, not in a5-a7. When an fentry or fexit program attaches to such a
subprogram, wouldn't it read unrelated register values instead of the real
arguments?

Both arm64 and x86-64 appear to avoid this by keeping their BPF stack
argument convention identical to their native ABIs. arm64 uses
`stack_arg_reg[] = { A64_R(5), A64_R(6), A64_R(7) }` and x86-64 keeps arg6
in r9, so their trampolines work without changes.

Can fentry/fexit attach to static BPF subprograms with more than 5
arguments, or is there a verifier check that prevents this?

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31761418445

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
  2026-08-14  2:34   ` bot+bpf-ci
@ 2026-08-14  6:49   ` Pu Lehui
  2026-08-14  7:49     ` Feng Jiang
  2026-08-17  1:52   ` Pu Lehui
  2 siblings, 1 reply; 8+ messages in thread
From: Pu Lehui @ 2026-08-14  6:49 UTC (permalink / raw)
  To: Feng Jiang, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Puranjay Mohan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Shuah Khan, Nathan Chancellor, Nick Desaulniers,
	Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm


On 2026/8/14 9:29, Feng Jiang wrote:
> Add bpf_jit_supports_stack_args() for the RV64 JIT so BPF subprograms
> and kfuncs can receive more than 5 arguments via the stack
> (BPF_REG_PARAMS / r11).
> 
> For BPF-to-BPF calls the caller writes outgoing arguments at the
> bottom of its frame (SP-relative). The callee reads them with
> FP-relative loads. Its FP is set to the caller SP in the prologue,
> so the offsets match.
> 
> The RISC-V ABI puts arguments 6-8 in A5-A7 and arguments 9+ at
> SP+0. Before each kfunc call, load arguments 6-8 from the outgoing
> area into A5-A7 and copy any remaining arguments down so argument 9
> lands at SP+0.
> 
> A5 (BPF_REG_0), A6 (TCC) and A7 are safe to clobber here: R0 is not
> live before a call, TCC is backed up on the stack, and A7 is unused
> by the JIT.
> 
> Limit the existing kfunc sign-extension loop to MAX_BPF_FUNC_REG_ARGS
> iterations; otherwise idx >= 5 resolves to S1-S5 (BPF_R6-FP) and
> corrupts callee-saved registers.
> 
> Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
> ---
>   arch/riscv/net/bpf_jit.h        |  1 +
>   arch/riscv/net/bpf_jit_comp64.c | 79 +++++++++++++++++++++++++++++++++++++++--
>   arch/riscv/net/bpf_jit_core.c   |  4 +++
>   3 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
> index 419b9d795f2a..9eb4e149505d 100644
> --- a/arch/riscv/net/bpf_jit.h
> +++ b/arch/riscv/net/bpf_jit.h
> @@ -82,6 +82,7 @@ struct rv_jit_context {
>   	unsigned long flags;
>   	int stack_size;
>   	int tcc_offset;
> +	u16 stack_arg_size;
>   	u64 arena_vm_start;
>   	u64 user_vm_start;
>   };
> diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
> index 6b9972b07c1b..58cb3e5ff6b4 100644
> --- a/arch/riscv/net/bpf_jit_comp64.c
> +++ b/arch/riscv/net/bpf_jit_comp64.c
> @@ -1815,18 +1815,43 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   
>   		if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
>   			const struct btf_func_model *fm;
> -			int idx;
> +			int idx, nargs;
>   
>   			fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
>   			if (!fm)
>   				return -EINVAL;
>   
> -			for (idx = 0; idx < fm->nr_args; idx++) {
> +			nargs = min_t(int, fm->nr_args, MAX_BPF_FUNC_REG_ARGS);
> +			for (idx = 0; idx < nargs; idx++) {
>   				u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);
>   
>   				if (fm->arg_size[idx] == sizeof(int))
>   					emit_sextw(reg, reg, ctx);
>   			}
> +
> +			/* BPF stack args -> RISC-V ABI: args 6-8 in A5-A7, 9+ at SP+0 */
> +			if (fm->nr_args > MAX_BPF_FUNC_REG_ARGS) {
> +				int n_stack = fm->nr_args - MAX_BPF_FUNC_REG_ARGS;
> +				int n_reg = min_t(int, n_stack,
> +						  RV_MAX_REG_ARGS - MAX_BPF_FUNC_REG_ARGS);
> +
> +				for (idx = 0; idx < n_reg; idx++) {
> +					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
> +
> +					emit_ld(RV_REG_A5 + idx, idx * 8, RV_REG_SP, ctx);
> +					if (sz == sizeof(int))
> +						emit_sextw(RV_REG_A5 + idx, RV_REG_A5 + idx, ctx);

Hi Feng Jiang,

Thanks for doing this. I'll squeeze the time to review this patchset, 
but there is currently an issue with RV64 kfunc [0]. Let's hold off for 
a moment.:)

[0] 
https://lore.kernel.org/bpf/20260814064726.3607615-1-pulehui@huaweicloud.com

> +				}
> +
> +				for (idx = n_reg; idx < n_stack; idx++) {
> +					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
> +
> +					emit_ld(RV_REG_T1, idx * 8, RV_REG_SP, ctx);
> +					if (sz == sizeof(int))
> +						emit_sextw(RV_REG_T1, RV_REG_T1, ctx);
> +					emit_sd(RV_REG_SP, (idx - n_reg) * 8, RV_REG_T1, ctx);
> +				}
> +			}
>   		}
>   
>   		/* restore TCC to RV_REG_TCC before bpf2bpf call */
> @@ -1891,6 +1916,21 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_LDX | BPF_MEM | BPF_H:
>   	case BPF_LDX | BPF_MEM | BPF_W:
>   	case BPF_LDX | BPF_MEM | BPF_DW:
> +		if (insn->src_reg == BPF_REG_PARAMS) {
> +			int idx = off / 8 - 1;
> +
> +			if (is_12b_int(idx * 8)) {
> +				emit_ldx_insn(rd, idx * 8, RV_REG_FP, BPF_SIZE(code), false, ctx);
> +			} else {
> +				emit_imm(RV_REG_T1, idx * 8, ctx);
> +				emit_add(RV_REG_T1, RV_REG_T1, RV_REG_FP, ctx);
> +				emit_ldx_insn(rd, 0, RV_REG_T1, BPF_SIZE(code), false, ctx);
> +			}
> +			if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
> +				return 1;
> +			break;
> +		}
> +		fallthrough;
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
> @@ -1938,6 +1978,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_ST | BPF_MEM | BPF_H:
>   	case BPF_ST | BPF_MEM | BPF_W:
>   	case BPF_ST | BPF_MEM | BPF_DW:
> +		if (insn->dst_reg == BPF_REG_PARAMS) {
> +			int idx = -off / 8 - 1;
> +
> +			emit_imm(RV_REG_T1, imm, ctx);
> +			if (is_12b_int(idx * 8)) {
> +				emit_stx_insn(RV_REG_SP, idx * 8, RV_REG_T1, BPF_SIZE(code), ctx);
> +			} else {
> +				emit_imm(RV_REG_T2, idx * 8, ctx);
> +				emit_add(RV_REG_T2, RV_REG_SP, RV_REG_T2, ctx);
> +				emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, BPF_SIZE(code), ctx);
> +			}
> +			break;
> +		}
> +		fallthrough;
>   	/* ST | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = imm */
>   	case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
>   	case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
> @@ -1960,6 +2014,19 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_STX | BPF_MEM | BPF_H:
>   	case BPF_STX | BPF_MEM | BPF_W:
>   	case BPF_STX | BPF_MEM | BPF_DW:
> +		if (insn->dst_reg == BPF_REG_PARAMS) {
> +			int idx = -off / 8 - 1;
> +
> +			if (is_12b_int(idx * 8)) {
> +				emit_stx_insn(RV_REG_SP, idx * 8, rs, BPF_SIZE(code), ctx);
> +			} else {
> +				emit_imm(RV_REG_T1, idx * 8, ctx);
> +				emit_add(RV_REG_T1, RV_REG_SP, RV_REG_T1, ctx);
> +				emit_stx_insn(RV_REG_T1, 0, rs, BPF_SIZE(code), ctx);
> +			}
> +			break;
> +		}
> +		fallthrough;
>   	/* STX | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = src */
>   	case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
>   	case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
> @@ -2036,6 +2103,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
>   
>   	stack_adjust = round_up(stack_adjust, STACK_ALIGN);
>   	stack_adjust += bpf_stack_adjust;
> +	stack_adjust += ctx->stack_arg_size;
>   
>   	store_offset = stack_adjust - 8;
>   
> @@ -2093,7 +2161,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
>   	emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);
>   
>   	if (bpf_stack_adjust)
> -		emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx);
> +		emit_addi(RV_REG_S5, RV_REG_SP, ctx->stack_arg_size + bpf_stack_adjust, ctx);
>   
>   	ctx->stack_size = stack_adjust;
>   
> @@ -2171,3 +2239,8 @@ bool bpf_jit_supports_timed_may_goto(void)
>   {
>   	return true;
>   }
> +
> +bool bpf_jit_supports_stack_args(void)
> +{
> +	return true;
> +}
> diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
> index cbfcd287ea16..844a0f3e0fa9 100644
> --- a/arch/riscv/net/bpf_jit_core.c
> +++ b/arch/riscv/net/bpf_jit_core.c
> @@ -72,6 +72,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
>   	ctx->arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
>   	ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>   	ctx->prog = prog;
> +
> +	ctx->stack_arg_size = round_up(bpf_out_stack_arg_cnt(env, prog) *
> +				       sizeof(u64), STACK_ALIGN);
> +
>   	ctx->offset = kvzalloc_objs(int, prog->len);
>   	if (!ctx->offset)
>   		goto out_offset;
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-14  6:49   ` Pu Lehui
@ 2026-08-14  7:49     ` Feng Jiang
  0 siblings, 0 replies; 8+ messages in thread
From: Feng Jiang @ 2026-08-14  7:49 UTC (permalink / raw)
  To: Pu Lehui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Puranjay Mohan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Shuah Khan, Nathan Chancellor, Nick Desaulniers,
	Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm

On 2026/8/14 14:49, Pu Lehui wrote:
> 
> On 2026/8/14 9:29, Feng Jiang wrote:
>> Add bpf_jit_supports_stack_args() for the RV64 JIT so BPF subprograms
>> and kfuncs can receive more than 5 arguments via the stack
>> (BPF_REG_PARAMS / r11).
>>
>> For BPF-to-BPF calls the caller writes outgoing arguments at the
>> bottom of its frame (SP-relative). The callee reads them with
>> FP-relative loads. Its FP is set to the caller SP in the prologue,
>> so the offsets match.
>>
>> The RISC-V ABI puts arguments 6-8 in A5-A7 and arguments 9+ at
>> SP+0. Before each kfunc call, load arguments 6-8 from the outgoing
>> area into A5-A7 and copy any remaining arguments down so argument 9
>> lands at SP+0.
>>
>> A5 (BPF_REG_0), A6 (TCC) and A7 are safe to clobber here: R0 is not
>> live before a call, TCC is backed up on the stack, and A7 is unused
>> by the JIT.
>>
>> Limit the existing kfunc sign-extension loop to MAX_BPF_FUNC_REG_ARGS
>> iterations; otherwise idx >= 5 resolves to S1-S5 (BPF_R6-FP) and
>> corrupts callee-saved registers.
>>
>> Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
>> ---
>>   arch/riscv/net/bpf_jit.h        |  1 +
>>   arch/riscv/net/bpf_jit_comp64.c | 79 +++++++++++++++++++++++++++++++++++++++--
>>   arch/riscv/net/bpf_jit_core.c   |  4 +++
>>   3 files changed, 81 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
>> index 419b9d795f2a..9eb4e149505d 100644
>> --- a/arch/riscv/net/bpf_jit.h
>> +++ b/arch/riscv/net/bpf_jit.h
>> @@ -82,6 +82,7 @@ struct rv_jit_context {
>>       unsigned long flags;
>>       int stack_size;
>>       int tcc_offset;
>> +    u16 stack_arg_size;
>>       u64 arena_vm_start;
>>       u64 user_vm_start;
>>   };
>> diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
>> index 6b9972b07c1b..58cb3e5ff6b4 100644
>> --- a/arch/riscv/net/bpf_jit_comp64.c
>> +++ b/arch/riscv/net/bpf_jit_comp64.c
>> @@ -1815,18 +1815,43 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>>             if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
>>               const struct btf_func_model *fm;
>> -            int idx;
>> +            int idx, nargs;
>>                 fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
>>               if (!fm)
>>                   return -EINVAL;
>>   -            for (idx = 0; idx < fm->nr_args; idx++) {
>> +            nargs = min_t(int, fm->nr_args, MAX_BPF_FUNC_REG_ARGS);
>> +            for (idx = 0; idx < nargs; idx++) {
>>                   u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);
>>                     if (fm->arg_size[idx] == sizeof(int))
>>                       emit_sextw(reg, reg, ctx);
>>               }
>> +
>> +            /* BPF stack args -> RISC-V ABI: args 6-8 in A5-A7, 9+ at SP+0 */
>> +            if (fm->nr_args > MAX_BPF_FUNC_REG_ARGS) {
>> +                int n_stack = fm->nr_args - MAX_BPF_FUNC_REG_ARGS;
>> +                int n_reg = min_t(int, n_stack,
>> +                          RV_MAX_REG_ARGS - MAX_BPF_FUNC_REG_ARGS);
>> +
>> +                for (idx = 0; idx < n_reg; idx++) {
>> +                    int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
>> +
>> +                    emit_ld(RV_REG_A5 + idx, idx * 8, RV_REG_SP, ctx);
>> +                    if (sz == sizeof(int))
>> +                        emit_sextw(RV_REG_A5 + idx, RV_REG_A5 + idx, ctx);
> 
> Hi Feng Jiang,
> 
> Thanks for doing this. I'll squeeze the time to review this patchset, but there is currently an issue with RV64 kfunc [0]. Let's hold off for a moment.:)
> 
> [0] https://lore.kernel.org/bpf/20260814064726.3607615-1-pulehui@huaweicloud.com
> 

Thanks for the heads-up. I'll wait for it to land and rebase on top.

-- 
With Best Regards,
Feng Jiang


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
  2026-08-14  2:34   ` bot+bpf-ci
  2026-08-14  6:49   ` Pu Lehui
@ 2026-08-17  1:52   ` Pu Lehui
  2026-08-18  3:48     ` Pu Lehui
  2 siblings, 1 reply; 8+ messages in thread
From: Pu Lehui @ 2026-08-17  1:52 UTC (permalink / raw)
  To: Feng Jiang, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Puranjay Mohan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Shuah Khan, Nathan Chancellor, Nick Desaulniers,
	Bill Wendling, Justin Stitt
  Cc: bpf, linux-riscv, linux-kernel, linux-kselftest, llvm

Hi Feng Jiang,

On 2026/8/14 9:29, Feng Jiang wrote:
> Add bpf_jit_supports_stack_args() for the RV64 JIT so BPF subprograms
> and kfuncs can receive more than 5 arguments via the stack
> (BPF_REG_PARAMS / r11).
> 
> For BPF-to-BPF calls the caller writes outgoing arguments at the
> bottom of its frame (SP-relative). The callee reads them with
> FP-relative loads. Its FP is set to the caller SP in the prologue,
> so the offsets match.
> 
> The RISC-V ABI puts arguments 6-8 in A5-A7 and arguments 9+ at
> SP+0. Before each kfunc call, load arguments 6-8 from the outgoing
> area into A5-A7 and copy any remaining arguments down so argument 9
> lands at SP+0.

bpf2bpf calls pass extra arguments entirely on the stack, whereas kfuncs 
pass them via a mix of registers and the stack. This inconsistency not 
only wastes stack slots in kfunc scenarios but is also error-prone and 
easy to overlook during maintenance.

To make argument passing more straightforward and consistent, I think we 
can align it with the standard riscv calling convention: use a0-a7 for 
the first 8 arguments and pass any remaining arguments on the stack.

To support this, the current bpf-to-rv register mapping needs to be revised:

T0 -> BPF_REG_0 (ftrace use T0 too, but it might not be an issue / needs 
verification)
T6 -> TCC
T7 -> BPF_REG_AX (rarely used, so let's move to t7)

Note that this remapping affects multiple places and requires careful 
auditing.

> 
> A5 (BPF_REG_0), A6 (TCC) and A7 are safe to clobber here: R0 is not
> live before a call, TCC is backed up on the stack, and A7 is unused
> by the JIT.



> 
> Limit the existing kfunc sign-extension loop to MAX_BPF_FUNC_REG_ARGS
> iterations; otherwise idx >= 5 resolves to S1-S5 (BPF_R6-FP) and
> corrupts callee-saved registers.
> 
> Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
> ---
>   arch/riscv/net/bpf_jit.h        |  1 +
>   arch/riscv/net/bpf_jit_comp64.c | 79 +++++++++++++++++++++++++++++++++++++++--
>   arch/riscv/net/bpf_jit_core.c   |  4 +++
>   3 files changed, 81 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
> index 419b9d795f2a..9eb4e149505d 100644
> --- a/arch/riscv/net/bpf_jit.h
> +++ b/arch/riscv/net/bpf_jit.h
> @@ -82,6 +82,7 @@ struct rv_jit_context {
>   	unsigned long flags;
>   	int stack_size;
>   	int tcc_offset;
> +	u16 stack_arg_size;
>   	u64 arena_vm_start;
>   	u64 user_vm_start;
>   };
> diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
> index 6b9972b07c1b..58cb3e5ff6b4 100644
> --- a/arch/riscv/net/bpf_jit_comp64.c
> +++ b/arch/riscv/net/bpf_jit_comp64.c
> @@ -1815,18 +1815,43 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   
>   		if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
>   			const struct btf_func_model *fm;
> -			int idx;
> +			int idx, nargs;
>   
>   			fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
>   			if (!fm)
>   				return -EINVAL;
>   
> -			for (idx = 0; idx < fm->nr_args; idx++) {
> +			nargs = min_t(int, fm->nr_args, MAX_BPF_FUNC_REG_ARGS);
> +			for (idx = 0; idx < nargs; idx++) {
>   				u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);
>   
>   				if (fm->arg_size[idx] == sizeof(int))
>   					emit_sextw(reg, reg, ctx);
>   			}
> +
> +			/* BPF stack args -> RISC-V ABI: args 6-8 in A5-A7, 9+ at SP+0 */
> +			if (fm->nr_args > MAX_BPF_FUNC_REG_ARGS) {
> +				int n_stack = fm->nr_args - MAX_BPF_FUNC_REG_ARGS;
> +				int n_reg = min_t(int, n_stack,
> +						  RV_MAX_REG_ARGS - MAX_BPF_FUNC_REG_ARGS);
> +
> +				for (idx = 0; idx < n_reg; idx++) {
> +					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
> +
> +					emit_ld(RV_REG_A5 + idx, idx * 8, RV_REG_SP, ctx);
> +					if (sz == sizeof(int))
> +						emit_sextw(RV_REG_A5 + idx, RV_REG_A5 + idx, ctx);
> +				}
> +
> +				for (idx = n_reg; idx < n_stack; idx++) {
> +					int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
> +
> +					emit_ld(RV_REG_T1, idx * 8, RV_REG_SP, ctx);
> +					if (sz == sizeof(int))
> +						emit_sextw(RV_REG_T1, RV_REG_T1, ctx);
> +					emit_sd(RV_REG_SP, (idx - n_reg) * 8, RV_REG_T1, ctx);
> +				}
> +			}

looks a bit complicated, how about the following after redefine regmap:

```
for (idx = 0; idx < fm->nr_args; idx++) {
   if (idx < RV_MAX_REG_ARGS) {
     u8 reg = RV_REG_A0 + idx;

     sign_extend(reg, reg, xxx)
   } else {
     load from stack to T1
     sign_extend
     retore from T1 to orig stack slot
   }
}
```

>   		}
>   
>   		/* restore TCC to RV_REG_TCC before bpf2bpf call */
> @@ -1891,6 +1916,21 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_LDX | BPF_MEM | BPF_H:
>   	case BPF_LDX | BPF_MEM | BPF_W:
>   	case BPF_LDX | BPF_MEM | BPF_DW:
> +		if (insn->src_reg == BPF_REG_PARAMS) {

pls use is_stack_arg_ldx/st/stx instead.

> +			int idx = off / 8 - 1;
> +
> +			if (is_12b_int(idx * 8)) {
> +				emit_ldx_insn(rd, idx * 8, RV_REG_FP, BPF_SIZE(code), false, ctx);
> +			} else {
> +				emit_imm(RV_REG_T1, idx * 8, ctx);
> +				emit_add(RV_REG_T1, RV_REG_T1, RV_REG_FP, ctx);
> +				emit_ldx_insn(rd, 0, RV_REG_T1, BPF_SIZE(code), false, ctx);
> +			}
> +			if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
> +				return 1;
> +			break;

This piece of code was refactored not long ago. Let's see if we can 
merge it into the logic below or fold it into emit_ldx—let's give it a try.

> +		}
> +		fallthrough;
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_B:
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_H:
>   	case BPF_LDX | BPF_PROBE_MEM | BPF_W:
> @@ -1938,6 +1978,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_ST | BPF_MEM | BPF_H:
>   	case BPF_ST | BPF_MEM | BPF_W:
>   	case BPF_ST | BPF_MEM | BPF_DW:
> +		if (insn->dst_reg == BPF_REG_PARAMS) {
> +			int idx = -off / 8 - 1;
> +
> +			emit_imm(RV_REG_T1, imm, ctx);
> +			if (is_12b_int(idx * 8)) {
> +				emit_stx_insn(RV_REG_SP, idx * 8, RV_REG_T1, BPF_SIZE(code), ctx);
> +			} else {
> +				emit_imm(RV_REG_T2, idx * 8, ctx);
> +				emit_add(RV_REG_T2, RV_REG_SP, RV_REG_T2, ctx);
> +				emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, BPF_SIZE(code), ctx);
> +			}
> +			break;
> +		}
> +		fallthrough;

ditto

>   	/* ST | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = imm */
>   	case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
>   	case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
> @@ -1960,6 +2014,19 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	case BPF_STX | BPF_MEM | BPF_H:
>   	case BPF_STX | BPF_MEM | BPF_W:
>   	case BPF_STX | BPF_MEM | BPF_DW:
> +		if (insn->dst_reg == BPF_REG_PARAMS) {
> +			int idx = -off / 8 - 1;
> +
> +			if (is_12b_int(idx * 8)) {
> +				emit_stx_insn(RV_REG_SP, idx * 8, rs, BPF_SIZE(code), ctx);
> +			} else {
> +				emit_imm(RV_REG_T1, idx * 8, ctx);
> +				emit_add(RV_REG_T1, RV_REG_SP, RV_REG_T1, ctx);
> +				emit_stx_insn(RV_REG_T1, 0, rs, BPF_SIZE(code), ctx);
> +			}
> +			break;
> +		}
> +		fallthrough;

ditto

>   	/* STX | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = src */
>   	case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
>   	case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
> @@ -2036,6 +2103,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
>   
>   	stack_adjust = round_up(stack_adjust, STACK_ALIGN);
>   	stack_adjust += bpf_stack_adjust;
> +	stack_adjust += ctx->stack_arg_size;
>   
>   	store_offset = stack_adjust - 8;
>   
> @@ -2093,7 +2161,7 @@ void bpf_jit_build_prologue(struct rv_jit_context *ctx, bool is_subprog)
>   	emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);
>   
>   	if (bpf_stack_adjust)
> -		emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx);
> +		emit_addi(RV_REG_S5, RV_REG_SP, ctx->stack_arg_size + bpf_stack_adjust, ctx);
>   
>   	ctx->stack_size = stack_adjust;
>   
> @@ -2171,3 +2239,8 @@ bool bpf_jit_supports_timed_may_goto(void)
>   {
>   	return true;
>   }
> +
> +bool bpf_jit_supports_stack_args(void)
> +{
> +	return true;
> +}
> diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
> index cbfcd287ea16..844a0f3e0fa9 100644
> --- a/arch/riscv/net/bpf_jit_core.c
> +++ b/arch/riscv/net/bpf_jit_core.c
> @@ -72,6 +72,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
>   	ctx->arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
>   	ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>   	ctx->prog = prog;
> +
> +	ctx->stack_arg_size = round_up(bpf_out_stack_arg_cnt(env, prog) *
> +				       sizeof(u64), STACK_ALIGN);

It's not u64—since every stack slot is aligned to the pointer size 
(sizeof(long)), I think using 8 is fine.

> +
>   	ctx->offset = kvzalloc_objs(int, prog->len);
>   	if (!ctx->offset)
>   		goto out_offset;
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf-next v3 1/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT
  2026-08-17  1:52   ` Pu Lehui
@ 2026-08-18  3:48     ` Pu Lehui
  0 siblings, 0 replies; 8+ messages in thread
From: Pu Lehui @ 2026-08-18  3:48 UTC (permalink / raw)
  To: Feng Jiang
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau,
	Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis,
	Ihor Solodrai, Luke Nelson, Xi Wang, Björn Töpel,
	Puranjay Mohan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Shuah Khan, Nathan Chancellor, Nick Desaulniers,
	Bill Wendling, Justin Stitt, bpf, linux-riscv, linux-kernel,
	linux-kselftest, llvm


On 2026/8/17 9:52, Pu Lehui wrote:
> Hi Feng Jiang,
> 
> On 2026/8/14 9:29, Feng Jiang wrote:
>> Add bpf_jit_supports_stack_args() for the RV64 JIT so BPF subprograms
>> and kfuncs can receive more than 5 arguments via the stack
>> (BPF_REG_PARAMS / r11).
>>
>> For BPF-to-BPF calls the caller writes outgoing arguments at the
>> bottom of its frame (SP-relative). The callee reads them with
>> FP-relative loads. Its FP is set to the caller SP in the prologue,
>> so the offsets match.
>>
>> The RISC-V ABI puts arguments 6-8 in A5-A7 and arguments 9+ at
>> SP+0. Before each kfunc call, load arguments 6-8 from the outgoing
>> area into A5-A7 and copy any remaining arguments down so argument 9
>> lands at SP+0.
> 
> bpf2bpf calls pass extra arguments entirely on the stack, whereas kfuncs 
> pass them via a mix of registers and the stack. This inconsistency not 
> only wastes stack slots in kfunc scenarios but is also error-prone and 
> easy to overlook during maintenance.
> 
> To make argument passing more straightforward and consistent, I think we 
> can align it with the standard riscv calling convention: use a0-a7 for 
> the first 8 arguments and pass any remaining arguments on the stack.
> 
> To support this, the current bpf-to-rv register mapping needs to be 
> revised:
> 
> T0 -> BPF_REG_0 (ftrace use T0 too, but it might not be an issue / needs 
> verification)
> T6 -> TCC
> T7 -> BPF_REG_AX (rarely used, so let's move to t7)
> 
> Note that this remapping affects multiple places and requires careful 
> auditing.

Discussed offline with Feng Jiang; I will take over refactoring this 
patch and post an updated version once it's ready.

> 
>>
>> A5 (BPF_REG_0), A6 (TCC) and A7 are safe to clobber here: R0 is not
>> live before a call, TCC is backed up on the stack, and A7 is unused
>> by the JIT.
> 
> 
> 
>>
>> Limit the existing kfunc sign-extension loop to MAX_BPF_FUNC_REG_ARGS
>> iterations; otherwise idx >= 5 resolves to S1-S5 (BPF_R6-FP) and
>> corrupts callee-saved registers.
>>
>> Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn>
>> ---
>>   arch/riscv/net/bpf_jit.h        |  1 +
>>   arch/riscv/net/bpf_jit_comp64.c | 79 
>> +++++++++++++++++++++++++++++++++++++++--
>>   arch/riscv/net/bpf_jit_core.c   |  4 +++
>>   3 files changed, 81 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
>> index 419b9d795f2a..9eb4e149505d 100644
>> --- a/arch/riscv/net/bpf_jit.h
>> +++ b/arch/riscv/net/bpf_jit.h
>> @@ -82,6 +82,7 @@ struct rv_jit_context {
>>       unsigned long flags;
>>       int stack_size;
>>       int tcc_offset;
>> +    u16 stack_arg_size;
>>       u64 arena_vm_start;
>>       u64 user_vm_start;
>>   };
>> diff --git a/arch/riscv/net/bpf_jit_comp64.c 
>> b/arch/riscv/net/bpf_jit_comp64.c
>> index 6b9972b07c1b..58cb3e5ff6b4 100644
>> --- a/arch/riscv/net/bpf_jit_comp64.c
>> +++ b/arch/riscv/net/bpf_jit_comp64.c
>> @@ -1815,18 +1815,43 @@ int bpf_jit_emit_insn(const struct bpf_insn 
>> *insn, struct rv_jit_context *ctx,
>>           if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
>>               const struct btf_func_model *fm;
>> -            int idx;
>> +            int idx, nargs;
>>               fm = bpf_jit_find_kfunc_model(ctx->prog, insn);
>>               if (!fm)
>>                   return -EINVAL;
>> -            for (idx = 0; idx < fm->nr_args; idx++) {
>> +            nargs = min_t(int, fm->nr_args, MAX_BPF_FUNC_REG_ARGS);
>> +            for (idx = 0; idx < nargs; idx++) {
>>                   u8 reg = bpf_to_rv_reg(BPF_REG_1 + idx, ctx);
>>                   if (fm->arg_size[idx] == sizeof(int))
>>                       emit_sextw(reg, reg, ctx);
>>               }
>> +
>> +            /* BPF stack args -> RISC-V ABI: args 6-8 in A5-A7, 9+ at 
>> SP+0 */
>> +            if (fm->nr_args > MAX_BPF_FUNC_REG_ARGS) {
>> +                int n_stack = fm->nr_args - MAX_BPF_FUNC_REG_ARGS;
>> +                int n_reg = min_t(int, n_stack,
>> +                          RV_MAX_REG_ARGS - MAX_BPF_FUNC_REG_ARGS);
>> +
>> +                for (idx = 0; idx < n_reg; idx++) {
>> +                    int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
>> +
>> +                    emit_ld(RV_REG_A5 + idx, idx * 8, RV_REG_SP, ctx);
>> +                    if (sz == sizeof(int))
>> +                        emit_sextw(RV_REG_A5 + idx, RV_REG_A5 + idx, 
>> ctx);
>> +                }
>> +
>> +                for (idx = n_reg; idx < n_stack; idx++) {
>> +                    int sz = fm->arg_size[MAX_BPF_FUNC_REG_ARGS + idx];
>> +
>> +                    emit_ld(RV_REG_T1, idx * 8, RV_REG_SP, ctx);
>> +                    if (sz == sizeof(int))
>> +                        emit_sextw(RV_REG_T1, RV_REG_T1, ctx);
>> +                    emit_sd(RV_REG_SP, (idx - n_reg) * 8, RV_REG_T1, 
>> ctx);
>> +                }
>> +            }
> 
> looks a bit complicated, how about the following after redefine regmap:
> 
> ```
> for (idx = 0; idx < fm->nr_args; idx++) {
>    if (idx < RV_MAX_REG_ARGS) {
>      u8 reg = RV_REG_A0 + idx;
> 
>      sign_extend(reg, reg, xxx)
>    } else {
>      load from stack to T1
>      sign_extend
>      retore from T1 to orig stack slot
>    }
> }
> ```
> 
>>           }
>>           /* restore TCC to RV_REG_TCC before bpf2bpf call */
>> @@ -1891,6 +1916,21 @@ int bpf_jit_emit_insn(const struct bpf_insn 
>> *insn, struct rv_jit_context *ctx,
>>       case BPF_LDX | BPF_MEM | BPF_H:
>>       case BPF_LDX | BPF_MEM | BPF_W:
>>       case BPF_LDX | BPF_MEM | BPF_DW:
>> +        if (insn->src_reg == BPF_REG_PARAMS) {
> 
> pls use is_stack_arg_ldx/st/stx instead.
> 
>> +            int idx = off / 8 - 1;
>> +
>> +            if (is_12b_int(idx * 8)) {
>> +                emit_ldx_insn(rd, idx * 8, RV_REG_FP, BPF_SIZE(code), 
>> false, ctx);
>> +            } else {
>> +                emit_imm(RV_REG_T1, idx * 8, ctx);
>> +                emit_add(RV_REG_T1, RV_REG_T1, RV_REG_FP, ctx);
>> +                emit_ldx_insn(rd, 0, RV_REG_T1, BPF_SIZE(code), 
>> false, ctx);
>> +            }
>> +            if (BPF_SIZE(code) != BPF_DW && insn_is_zext(&insn[1]))
>> +                return 1;
>> +            break;
> 
> This piece of code was refactored not long ago. Let's see if we can 
> merge it into the logic below or fold it into emit_ldx—let's give it a try.
> 
>> +        }
>> +        fallthrough;
>>       case BPF_LDX | BPF_PROBE_MEM | BPF_B:
>>       case BPF_LDX | BPF_PROBE_MEM | BPF_H:
>>       case BPF_LDX | BPF_PROBE_MEM | BPF_W:
>> @@ -1938,6 +1978,20 @@ int bpf_jit_emit_insn(const struct bpf_insn 
>> *insn, struct rv_jit_context *ctx,
>>       case BPF_ST | BPF_MEM | BPF_H:
>>       case BPF_ST | BPF_MEM | BPF_W:
>>       case BPF_ST | BPF_MEM | BPF_DW:
>> +        if (insn->dst_reg == BPF_REG_PARAMS) {
>> +            int idx = -off / 8 - 1;
>> +
>> +            emit_imm(RV_REG_T1, imm, ctx);
>> +            if (is_12b_int(idx * 8)) {
>> +                emit_stx_insn(RV_REG_SP, idx * 8, RV_REG_T1, 
>> BPF_SIZE(code), ctx);
>> +            } else {
>> +                emit_imm(RV_REG_T2, idx * 8, ctx);
>> +                emit_add(RV_REG_T2, RV_REG_SP, RV_REG_T2, ctx);
>> +                emit_stx_insn(RV_REG_T2, 0, RV_REG_T1, 
>> BPF_SIZE(code), ctx);
>> +            }
>> +            break;
>> +        }
>> +        fallthrough;
> 
> ditto
> 
>>       /* ST | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = imm */
>>       case BPF_ST | BPF_PROBE_MEM32 | BPF_B:
>>       case BPF_ST | BPF_PROBE_MEM32 | BPF_H:
>> @@ -1960,6 +2014,19 @@ int bpf_jit_emit_insn(const struct bpf_insn 
>> *insn, struct rv_jit_context *ctx,
>>       case BPF_STX | BPF_MEM | BPF_H:
>>       case BPF_STX | BPF_MEM | BPF_W:
>>       case BPF_STX | BPF_MEM | BPF_DW:
>> +        if (insn->dst_reg == BPF_REG_PARAMS) {
>> +            int idx = -off / 8 - 1;
>> +
>> +            if (is_12b_int(idx * 8)) {
>> +                emit_stx_insn(RV_REG_SP, idx * 8, rs, BPF_SIZE(code), 
>> ctx);
>> +            } else {
>> +                emit_imm(RV_REG_T1, idx * 8, ctx);
>> +                emit_add(RV_REG_T1, RV_REG_SP, RV_REG_T1, ctx);
>> +                emit_stx_insn(RV_REG_T1, 0, rs, BPF_SIZE(code), ctx);
>> +            }
>> +            break;
>> +        }
>> +        fallthrough;
> 
> ditto
> 
>>       /* STX | PROBE_MEM32: *(size *)(dst + RV_REG_ARENA + off) = src */
>>       case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
>>       case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
>> @@ -2036,6 +2103,7 @@ void bpf_jit_build_prologue(struct 
>> rv_jit_context *ctx, bool is_subprog)
>>       stack_adjust = round_up(stack_adjust, STACK_ALIGN);
>>       stack_adjust += bpf_stack_adjust;
>> +    stack_adjust += ctx->stack_arg_size;
>>       store_offset = stack_adjust - 8;
>> @@ -2093,7 +2161,7 @@ void bpf_jit_build_prologue(struct 
>> rv_jit_context *ctx, bool is_subprog)
>>       emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);
>>       if (bpf_stack_adjust)
>> -        emit_addi(RV_REG_S5, RV_REG_SP, bpf_stack_adjust, ctx);
>> +        emit_addi(RV_REG_S5, RV_REG_SP, ctx->stack_arg_size + 
>> bpf_stack_adjust, ctx);
>>       ctx->stack_size = stack_adjust;
>> @@ -2171,3 +2239,8 @@ bool bpf_jit_supports_timed_may_goto(void)
>>   {
>>       return true;
>>   }
>> +
>> +bool bpf_jit_supports_stack_args(void)
>> +{
>> +    return true;
>> +}
>> diff --git a/arch/riscv/net/bpf_jit_core.c 
>> b/arch/riscv/net/bpf_jit_core.c
>> index cbfcd287ea16..844a0f3e0fa9 100644
>> --- a/arch/riscv/net/bpf_jit_core.c
>> +++ b/arch/riscv/net/bpf_jit_core.c
>> @@ -72,6 +72,10 @@ struct bpf_prog *bpf_int_jit_compile(struct 
>> bpf_verifier_env *env, struct bpf_pr
>>       ctx->arena_vm_start = 
>> bpf_arena_get_kern_vm_start(prog->aux->arena);
>>       ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>>       ctx->prog = prog;
>> +
>> +    ctx->stack_arg_size = round_up(bpf_out_stack_arg_cnt(env, prog) *
>> +                       sizeof(u64), STACK_ALIGN);
> 
> It's not u64—since every stack slot is aligned to the pointer size 
> (sizeof(long)), I think using 8 is fine.
> 
>> +
>>       ctx->offset = kvzalloc_objs(int, prog->len);
>>       if (!ctx->offset)
>>           goto out_offset;
>>
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-08-18  3:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-14  1:29 [PATCH bpf-next v3 0/2] bpf, riscv: Add BPF stack arguments support for RV64 JIT Feng Jiang
2026-08-14  1:29 ` [PATCH bpf-next v3 1/2] " Feng Jiang
2026-08-14  2:34   ` bot+bpf-ci
2026-08-14  6:49   ` Pu Lehui
2026-08-14  7:49     ` Feng Jiang
2026-08-17  1:52   ` Pu Lehui
2026-08-18  3:48     ` Pu Lehui
2026-08-14  1:29 ` [PATCH bpf-next v3 2/2] selftests/bpf: Enable stack argument tests for RV64 Feng Jiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®