On 2026/7/23 13:41, Feng Jiang wrote:
Implement arch_bpf_timed_may_goto() for the RV64 JIT. The argument and
return value are carried in BPF_REG_AX, and BPF R0-R5 are preserved
across the call to the generic bpf_check_timed_may_goto().

Enable bpf_jit_supports_timed_may_goto() so the verifier uses the timed
expansion path.

Signed-off-by: Feng Jiang <[email protected]>
---
  arch/riscv/net/Makefile             |  2 +-
  arch/riscv/net/bpf_jit_comp64.c     | 12 +++++++++-
  arch/riscv/net/bpf_timed_may_goto.S | 47 +++++++++++++++++++++++++++++++++++++
  3 files changed, 59 insertions(+), 2 deletions(-)


Reviewed-by: Pu Lehui <[email protected]>


diff --git a/arch/riscv/net/Makefile b/arch/riscv/net/Makefile
index 9a1e5f0a94e5..6458d4d51990 100644
--- a/arch/riscv/net/Makefile
+++ b/arch/riscv/net/Makefile
@@ -3,7 +3,7 @@
  obj-$(CONFIG_BPF_JIT) += bpf_jit_core.o
ifeq ($(CONFIG_ARCH_RV64I),y)
-       obj-$(CONFIG_BPF_JIT) += bpf_jit_comp64.o
+       obj-$(CONFIG_BPF_JIT) += bpf_jit_comp64.o bpf_timed_may_goto.o
  else
        obj-$(CONFIG_BPF_JIT) += bpf_jit_comp32.o
  endif
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index ad089a9a4ea9..8fe8969fb8a0 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -1841,7 +1841,12 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, 
struct rv_jit_context *ctx,
                if (aux->tail_call_reachable && insn->src_reg == 
BPF_PSEUDO_CALL)
                        emit_sd(RV_REG_SP, ctx->tcc_offset, RV_REG_TCC, ctx);
- if (insn->src_reg != BPF_PSEUDO_CALL)
+               /*
+                * arch_bpf_timed_may_goto() is emitted by the verifier and
+                * returns its result in BPF_REG_AX instead of BPF_REG_0, so
+                * skip the normal "move return register into R0".
+                */
+               if (insn->src_reg != BPF_PSEUDO_CALL && addr != 
(u64)arch_bpf_timed_may_goto)
                        emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_A0, ctx);
                break;
        }
@@ -2161,3 +2166,8 @@ bool bpf_jit_supports_subprog_tailcalls(void)
  {
        return true;
  }
+
+bool bpf_jit_supports_timed_may_goto(void)
+{
+       return true;
+}
diff --git a/arch/riscv/net/bpf_timed_may_goto.S 
b/arch/riscv/net/bpf_timed_may_goto.S
new file mode 100644
index 000000000000..02c637d87420
--- /dev/null
+++ b/arch/riscv/net/bpf_timed_may_goto.S
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2026 Feng Jiang <[email protected]> */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+/*
+ * Trampoline for the BPF timed may_goto loop bound. Custom calling convention:
+ *     - input:  stack offset in BPF_REG_AX (t0)
+ *     - output: updated count in BPF_REG_AX (t0)
+ *
+ * Calls bpf_check_timed_may_goto(ptr) with the standard RISC-V ABI, where
+ * ptr = BPF_REG_FP (s5) + BPF_REG_AX (t0). BPF R0-R5 (a5, a0-a4) are saved
+ * across the call; BPF_REG_FP (s5) is callee-saved and needs no saving.
+ */
+
+SYM_FUNC_START(arch_bpf_timed_may_goto)
+       addi    sp, sp, -(8*SZREG)
+       REG_S   ra, 7*SZREG(sp)
+       REG_S   s0, 6*SZREG(sp)
+       addi    s0, sp, 8*SZREG
+
+       /* Save BPF registers R0-R5 (a5, a0-a4) */
+       REG_S   a5, 5*SZREG(sp)
+       REG_S   a0, 4*SZREG(sp)
+       REG_S   a1, 3*SZREG(sp)
+       REG_S   a2, 2*SZREG(sp)
+       REG_S   a3, 1*SZREG(sp)
+       REG_S   a4, 0*SZREG(sp)
+
+       add     a0, t0, s5
+       call    bpf_check_timed_may_goto
+       mv      t0, a0
+
+       /* Restore BPF registers R0-R5 */
+       REG_L   a4, 0*SZREG(sp)
+       REG_L   a3, 1*SZREG(sp)
+       REG_L   a2, 2*SZREG(sp)
+       REG_L   a1, 3*SZREG(sp)
+       REG_L   a0, 4*SZREG(sp)
+       REG_L   a5, 5*SZREG(sp)
+
+       REG_L   s0, 6*SZREG(sp)
+       REG_L   ra, 7*SZREG(sp)
+       addi    sp, sp, 8*SZREG
+       ret
+SYM_FUNC_END(arch_bpf_timed_may_goto)



Reply via email to