[PATCH bpf-next v4 1/3] bpf, riscv: add support for timed may_goto

Pu Lehui pulehui at huawei.com
Wed Jul 22 03:18:04 PDT 2026


On 2026/7/22 12:21, 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 <jiangfeng at kylinos.cn>
> ---
>   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(-)
> 
> 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..f4bf2cd10586
> --- /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 <jiangfeng at kylinos.cn> */
> +
> +#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, -64
> +	sd	ra, 56(sp)
> +	sd	s0, 48(sp)
> +	addi	s0, sp, 64
> +
> +	/* Save BPF registers R0-R5 (a5, a0-a4) */
> +	sd	a5, 40(sp)
> +	sd	a0, 32(sp)
> +	sd	a1, 24(sp)
> +	sd	a2, 16(sp)
> +	sd	a3, 8(sp)
> +	sd	a4, 0(sp)
> +
> +	add	a0, t0, s5
> +	call	bpf_check_timed_may_goto
> +	mv	t0, a0
> +
> +	/* Restore BPF registers R0-R5 */
> +	ld	a4, 0(sp)
> +	ld	a3, 8(sp)
> +	ld	a2, 16(sp)
> +	ld	a1, 24(sp)
> +	ld	a0, 32(sp)
> +	ld	a5, 40(sp)
> +
> +	ld	s0, 48(sp)
> +	ld	ra, 56(sp)
> +	addi	sp, sp, 64
> +	ret
> +SYM_FUNC_END(arch_bpf_timed_may_goto)

I think we should use REG_S/REG_L/SZREG like in arch/riscv ([0]) – it 
keeps us in sync with upstream and will make it easier if we may later 
port timed_may_goto to RV32.

[0] arch/riscv/kernel/mcount.S



More information about the linux-riscv mailing list