summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi <memxor@gmail.com>2026-07-24 22:20:10 +0200
committerKumar Kartikeya Dwivedi <memxor@gmail.com>2026-07-24 22:21:10 +0200
commit159d4fbb6ca5a527ffd0d37e9c8dae882038ae80 (patch)
tree2aa146ac23c1d759d2387fed58a2493824bf0817
parent87267b89459813cb50ab5377e076b639c07b4491 (diff)
parent3c2be3cbeb1b6899d53ed1f2a01b5a279d4f222c (diff)
downloadlinux-next-159d4fbb6ca5a527ffd0d37e9c8dae882038ae80.tar.gz
linux-next-159d4fbb6ca5a527ffd0d37e9c8dae882038ae80.zip
Merge branch 'bpf-riscv-add-timed-may_goto-support'
Feng Jiang says: ==================== bpf, riscv: add timed may_goto support This series adds RISC-V JIT support for the timed may_goto loop bound. Patch 1 implements arch_bpf_timed_may_goto() and enables bpf_jit_supports_timed_may_goto() so the verifier uses the timed expansion path. Patch 2 adds a test that checks R0-R5 are preserved across arch_bpf_timed_may_goto() calls. Patch 3 enables the verifier_may_goto_1, stream_cond_break, and may_goto_interaction fastcall tests on riscv64. Tested on riscv64 QEMU (rva23s64): may_goto programs load and JIT correctly, and the 250ms timeout path works as expected. Signed-off-by: Feng Jiang <jiangfeng@kylinos.cn> Tested-by: Pu Lehui <pulehui@huawei.com> Reviewed-by: Björn Töpel <bjorn@kernel.org> Acked-by: Björn Töpel <bjorn@kernel.org> --- Changes in v5: - Use REG_S/REG_L/SZREG in arch_bpf_timed_may_goto assembly. (Pu Lehui) - Add __arch_s390x to the timed_may_goto_preserves_regs test. (Pu Lehui) - Switch the preserves-regs test to SEC("syscall") to fix bpf_prog_test_run() EINVAL. - Link to v4: https://lore.kernel.org/r/20260722-riscv-bpf-timed-may-goto-v4-0-e117e6337bc7@kylinos.cn Changes in v4: - Add 'bpf-next' prefix to match the BPF kernel tree workflow. - Add a test checking that R0-R5 are preserved across arch_bpf_timed_may_goto() calls. Use bpf_get_prandom_u32() to prevent the verifier from removing the checks via DCE. - Rename may_goto_interaction_arm64() to may_goto_interaction(). - Wrap the arch_bpf_timed_may_goto address check to a single line. - Link to v3: https://lore.kernel.org/r/20260715-riscv-bpf-timed-may-goto-v3-0-cf2a9c3d843f@kylinos.cn Changes in v3: - Set up the frame pointer in arch_bpf_timed_may_goto() so the function does not break stack unwinding under CONFIG_FRAME_POINTER. Changes in v2: - Fix BPF_REG_0 being clobbered after arch_bpf_timed_may_goto() calls. - Enable the may_goto_interaction fastcall test on riscv64. --- ==================== Link: https://patch.msgid.link/20260723-riscv-bpf-timed-may-goto-v5-0-86acb54e5642@kylinos.cn Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
-rw-r--r--arch/riscv/net/Makefile2
-rw-r--r--arch/riscv/net/bpf_jit_comp64.c12
-rw-r--r--arch/riscv/net/bpf_timed_may_goto.S47
-rw-r--r--tools/testing/selftests/bpf/progs/stream.c1
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c3
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_may_goto_1.c62
6 files changed, 124 insertions, 3 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..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 <jiangfeng@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, -(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)
diff --git a/tools/testing/selftests/bpf/progs/stream.c b/tools/testing/selftests/bpf/progs/stream.c
index 92ba1d72e0ec..8d8e53d37266 100644
--- a/tools/testing/selftests/bpf/progs/stream.c
+++ b/tools/testing/selftests/bpf/progs/stream.c
@@ -64,6 +64,7 @@ SEC("syscall")
__arch_x86_64
__arch_arm64
__arch_s390x
+__arch_riscv64
__success __retval(0)
__stderr("ERROR: Timeout detected for may_goto instruction")
__stderr("CPU: {{[0-9]+}} UID: 0 PID: {{[0-9]+}} Comm: {{.*}}")
diff --git a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
index 8d7ff38e4c06..83707faea049 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bpf_fastcall.c
@@ -660,6 +660,7 @@ __naked void may_goto_interaction_x86_64(void)
SEC("raw_tp")
__arch_arm64
+__arch_riscv64
__log_level(4) __msg("stack depth 24")
/* may_goto counter at -24 */
__xlated("0: *(u64 *)(r10 -24) =")
@@ -679,7 +680,7 @@ __xlated("10: *(u64 *)(r10 -24) = r12")
__xlated("11: *(u64 *)(r10 -8) = r1")
__xlated("12: exit")
__success
-__naked void may_goto_interaction_arm64(void)
+__naked void may_goto_interaction(void)
{
asm volatile (
"r1 = 1;"
diff --git a/tools/testing/selftests/bpf/progs/verifier_may_goto_1.c b/tools/testing/selftests/bpf/progs/verifier_may_goto_1.c
index 4bdf4256a41e..0e211f030d0d 100644
--- a/tools/testing/selftests/bpf/progs/verifier_may_goto_1.c
+++ b/tools/testing/selftests/bpf/progs/verifier_may_goto_1.c
@@ -11,6 +11,7 @@ __description("may_goto 0")
__arch_x86_64
__arch_s390x
__arch_arm64
+__arch_riscv64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
@@ -31,6 +32,7 @@ __description("batch 2 of may_goto 0")
__arch_x86_64
__arch_s390x
__arch_arm64
+__arch_riscv64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
@@ -53,6 +55,7 @@ __description("may_goto batch with offsets 2/1/0")
__arch_x86_64
__arch_s390x
__arch_arm64
+__arch_riscv64
__xlated("0: r0 = 1")
__xlated("1: exit")
__success
@@ -79,6 +82,7 @@ __description("may_goto batch with offsets 2/0")
__arch_x86_64
__arch_s390x
__arch_arm64
+__arch_riscv64
__xlated("0: *(u64 *)(r10 -16) = 65535")
__xlated("1: *(u64 *)(r10 -8) = 0")
__xlated("2: r12 = *(u64 *)(r10 -16)")
@@ -106,4 +110,62 @@ __naked void may_goto_batch_2(void)
: __clobber_all);
}
+/*
+ * Use bpf_get_prandom_u32() to prevent DCE from removing the checks.
+ * retval: 0=all ok, 1-6=R0-R5 clobbered.
+ */
+SEC("syscall")
+__description("timed may_goto preserves R0-R5")
+__arch_x86_64
+__arch_s390x
+__arch_arm64
+__arch_riscv64
+__success
+__retval(0)
+__naked void timed_may_goto_preserves_regs(void)
+{
+ asm volatile (
+ "call %[bpf_get_prandom_u32];"
+ "r6 = r0;"
+ "r0 = 0x1111;"
+ "r0 += r6;"
+ "r1 = 0x2222;"
+ "r1 += r6;"
+ "r2 = 0x3333;"
+ "r2 += r6;"
+ "r3 = 0x4444;"
+ "r3 += r6;"
+ "r4 = 0x5555;"
+ "r4 += r6;"
+ "r5 = 0x6666;"
+ "r5 += r6;"
+ ".8byte %[may_goto];"
+ ".8byte %[loop];"
+ "r0 -= r6;"
+ "r1 -= r6;"
+ "r2 -= r6;"
+ "r3 -= r6;"
+ "r4 -= r6;"
+ "r5 -= r6;"
+ "if r0 != 0x1111 goto 1f;"
+ "if r1 != 0x2222 goto 2f;"
+ "if r2 != 0x3333 goto 3f;"
+ "if r3 != 0x4444 goto 4f;"
+ "if r4 != 0x5555 goto 5f;"
+ "if r5 != 0x6666 goto 6f;"
+ "r0 = 0;"
+ "exit;"
+ "1: r0 = 1; exit;"
+ "2: r0 = 2; exit;"
+ "3: r0 = 3; exit;"
+ "4: r0 = 4; exit;"
+ "5: r0 = 5; exit;"
+ "6: r0 = 6; exit;"
+ :
+ : __imm(bpf_get_prandom_u32),
+ __imm_insn(may_goto, BPF_RAW_INSN(BPF_JMP | BPF_JCOND, 0, 0, 1, 0)),
+ __imm_insn(loop, BPF_RAW_INSN(BPF_JMP | BPF_JA, 0, 0, -2, 0))
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";