> diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
> index b804382075c40..e0c2f73bc646a 100644
> --- a/arch/riscv/net/bpf_jit_comp64.c
> +++ b/arch/riscv/net/bpf_jit_comp64.c
> @@ -56,6 +56,29 @@ static const int pt_regmap[] = {
> [RV_REG_T0] = offsetof(struct pt_regs, t0),
> };
>
> +/* Full set of RISC-V callee-saved GP registers (ra, s0-s11) saved by a
> program
> + * acting as an exception boundary, in the order they are stored on the
> stack.
^^
This isn't a bug, but Bjorn Topel requested netdev-style multi-line
comments in v2. Should the opening /* be on the same line as the first
text instead of on its own line?
> + * RA and FP come first so the saved ra/fp pair forms a valid stackframe
> record
> + * at [FP-8]/[FP-16] for the unwinder. The exception callback reuses the
> + * boundary program's frame and restores this same set in its epilogue, so
> both
> + * paths must agree on the contents and ordering of this list.
> + */
> +static const int rv_exception_csave_regs[] = {
> + RV_REG_RA,
> + RV_REG_FP,
> + RV_REG_S1,
> + RV_REG_S2,
> + RV_REG_S3,
> + RV_REG_S4,
> + RV_REG_S5,
> + RV_REG_S6,
> + RV_REG_S7,
> + RV_REG_S8,
> + RV_REG_S9,
> + RV_REG_S10,
> + RV_REG_S11,
> +};
[ ... ]
> @@ -312,11 +335,67 @@ static void emit_normal_restore(struct rv_jit_context
> *ctx, int stack_adjust)
> emit_ld(RV_REG_TCC, ctx->tcc_offset, RV_REG_SP, ctx);
> }
>
> +static bool is_exception_prog(const struct bpf_prog *prog)
> +{
> + return prog->aux->exception_boundary || prog->aux->exception_cb;
> +}
> +
> +static void emit_exception_boundary_prologue(struct rv_jit_context *ctx,
> + int stack_adjust)
> +{
> + int store_offset = stack_adjust - 8;
> + int i;
> +
> + emit_addi(RV_REG_SP, RV_REG_SP, -stack_adjust, ctx);
> + for (i = 0; i < ARRAY_SIZE(rv_exception_csave_regs); i++) {
> + emit_sd(RV_REG_SP, store_offset, rv_exception_csave_regs[i],
> ctx);
> + store_offset -= 8;
> + }
> +
> + /* store TCC from RV_REG_TCC to stack */
> + emit_sd(RV_REG_SP, store_offset, RV_REG_TCC, ctx);
> + ctx->tcc_offset = store_offset;
> +
> + emit_addi(RV_REG_FP, RV_REG_SP, stack_adjust, ctx);
> +}
> +
> +/* reuses the boundary program's frame, whose frame pointer
> + * is passed in a2 (since it's the third argument from bpf_throw()).
^^
Same comment style here - should this also follow netdev style?
> + * Setting SP = FP - stack_adjust lines the epilogue's loads up with
> + * the registers the boundary saved.
> + */
> +static void emit_exception_cb_prologue(struct rv_jit_context *ctx,
> + int stack_adjust)
> +{
> + emit_mv(RV_REG_FP, RV_REG_A2, ctx);
> + emit_addi(RV_REG_SP, RV_REG_FP, -stack_adjust, ctx);
> + ctx->tcc_offset = stack_adjust - 8 -
> ARRAY_SIZE(rv_exception_csave_regs) * 8;
> +}
> +
> +/* Used by both the boundary program and the exception callback alike, since
> the
> + * callback runs on the boundary's frame.
^^
And here as well.
> + */
> +static void emit_exception_restore(struct rv_jit_context *ctx, int
> stack_adjust)
> +{
> + int store_offset = stack_adjust - 8;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(rv_exception_csave_regs); i++) {
> + emit_ld(rv_exception_csave_regs[i], store_offset, RV_REG_SP,
> ctx);
> + store_offset -= 8;
> + }
> + /* restore TCC from stack to RV_REG_TCC */
> + emit_ld(RV_REG_TCC, ctx->tcc_offset, RV_REG_SP, ctx);
> +}
> +
> static void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
> {
> int stack_adjust = ctx->stack_size;
>
> - emit_normal_restore(ctx, stack_adjust);
> + if (is_exception_prog(ctx->prog))
> + emit_exception_restore(ctx, stack_adjust);
> + else
> + emit_normal_restore(ctx, stack_adjust);
>
> emit_addi(RV_REG_SP, RV_REG_SP, stack_adjust, ctx);
> /* Set return value. */
[ ... ]
> @@ -2183,3 +2280,12 @@ bool bpf_jit_supports_subprog_tailcalls(void)
> {
> return true;
> }
> +
> +bool bpf_jit_supports_exceptions(void)
> +{
> + /* bpf_throw() unwinds by walking the frame-pointer chain from inside
> + * the kernel back into the BPF frames (see arch_bpf_stack_walk()), so
^^
And one more multi-line comment here with the same style.
> + * exceptions require the frame-pointer unwinder to be enabled.
> + */
> + return IS_ENABLED(CONFIG_FRAME_POINTER);
> +}
---
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/29929750005