[RFC bpf-next 2/2] bpf, mips: Add BPF_MEMSX support to the JITs
Nicholas Dudar <[email protected]>
| Newsgroups | org.kernel.vger.linux-mips,org.kernel.vger.bpf,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
BPF_LDX with BPF_MEMSX loads a signed byte, half-word, or word and sign-extends it through the full 64-bit destination. Both MIPS JITs predate this mode and reject all three verifier-valid encodings when JIT execution is required. Teach the narrow-load helpers to select signed native loads. MIPS64 gets the full result from lb, lh, or lw. MIPS32 loads the low half, observes the MIPS I load-delay rule, and propagates bit 31 into the high half. Keep BPF_MEMSX with BPF_DW unsupported, and leave ordinary loads on their existing unsigned helper path. The existing BPF_LDX_MEMSX byte, half-word, and word test_bpf cases cover the verifier-valid widths. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Nicholas Dudar <[email protected]> --- arch/mips/net/bpf_jit_comp32.c | 31 +++++++++++++++++++++++++++---- arch/mips/net/bpf_jit_comp64.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c index 48a3c834453f2..3de7aac72fb83 100644 --- a/arch/mips/net/bpf_jit_comp32.c +++ b/arch/mips/net/bpf_jit_comp32.c @@ -709,16 +709,23 @@ static void emit_trunc_r64(struct jit_context *ctx, const u8 dst[], u32 width) /* Narrow load operation: dst = *(size *)(src + off) */ static void emit_ldx_narrow(struct jit_context *ctx, - u8 dst, u8 src, s16 off, u8 size) + u8 dst, u8 src, s16 off, u8 size, + bool sign_extend) { switch (size) { /* Load a byte */ case BPF_B: - emit(ctx, lbu, dst, off, src); + if (sign_extend) + emit(ctx, lb, dst, off, src); + else + emit(ctx, lbu, dst, off, src); break; /* Load a half word */ case BPF_H: - emit(ctx, lhu, dst, off, src); + if (sign_extend) + emit(ctx, lh, dst, off, src); + else + emit(ctx, lhu, dst, off, src); break; /* Load a word */ case BPF_W: @@ -736,7 +743,7 @@ static void emit_ldx(struct jit_context *ctx, case BPF_B: case BPF_H: case BPF_W: - emit_ldx_narrow(ctx, lo(dst), src, off, size); + emit_ldx_narrow(ctx, lo(dst), src, off, size, false); emit(ctx, move, hi(dst), MIPS_R_ZERO); break; /* Load a double word */ @@ -754,6 +761,16 @@ static void emit_ldx(struct jit_context *ctx, clobber_reg64(ctx, dst); } +/* Load operation with sign extension: dst = *(signed size *)(src + off) */ +static void emit_ldsx(struct jit_context *ctx, + const u8 dst[], u8 src, s16 off, u8 size) +{ + emit_ldx_narrow(ctx, lo(dst), src, off, size, true); + emit_load_delay(ctx); + emit(ctx, sra, hi(dst), lo(dst), 31); + clobber_reg64(ctx, dst); +} + /* Store operation: *(size *)(dst + off) = src */ static void emit_stx(struct jit_context *ctx, const u8 dst, const u8 src[], s16 off, u8 size) @@ -1725,6 +1742,12 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) case BPF_LDX | BPF_MEM | BPF_DW: emit_ldx(ctx, dst, lo(src), off, BPF_SIZE(code)); break; + /* LDSX: dst = *(signed size *)(src + off) */ + case BPF_LDX | BPF_MEMSX | BPF_W: + case BPF_LDX | BPF_MEMSX | BPF_H: + case BPF_LDX | BPF_MEMSX | BPF_B: + emit_ldsx(ctx, dst, lo(src), off, BPF_SIZE(code)); + break; /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: diff --git a/arch/mips/net/bpf_jit_comp64.c b/arch/mips/net/bpf_jit_comp64.c index 22fb58f970223..14ef3f475c1c1 100644 --- a/arch/mips/net/bpf_jit_comp64.c +++ b/arch/mips/net/bpf_jit_comp64.c @@ -400,20 +400,30 @@ static void emit_trunc_r64(struct jit_context *ctx, u8 dst, u32 width) /* Narrow load operation: dst = *(size *)(src + off) */ static void emit_ldx_narrow(struct jit_context *ctx, - u8 dst, u8 src, s16 off, u8 size) + u8 dst, u8 src, s16 off, u8 size, + bool sign_extend) { switch (size) { /* Load a byte */ case BPF_B: - emit(ctx, lbu, dst, off, src); + if (sign_extend) + emit(ctx, lb, dst, off, src); + else + emit(ctx, lbu, dst, off, src); break; /* Load a half word */ case BPF_H: - emit(ctx, lhu, dst, off, src); + if (sign_extend) + emit(ctx, lh, dst, off, src); + else + emit(ctx, lhu, dst, off, src); break; /* Load a word */ case BPF_W: - emit(ctx, lwu, dst, off, src); + if (sign_extend) + emit(ctx, lw, dst, off, src); + else + emit(ctx, lwu, dst, off, src); break; } } @@ -426,7 +436,7 @@ static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) case BPF_B: case BPF_H: case BPF_W: - emit_ldx_narrow(ctx, dst, src, off, size); + emit_ldx_narrow(ctx, dst, src, off, size, false); break; /* Load a double word */ case BPF_DW: @@ -436,6 +446,13 @@ static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) clobber_reg(ctx, dst); } +/* Load operation with sign extension: dst = *(signed size *)(src + off) */ +static void emit_ldsx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) +{ + emit_ldx_narrow(ctx, dst, src, off, size, true); + clobber_reg(ctx, dst); +} + /* Store operation: *(size *)(dst + off) = src */ static void emit_stx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) { @@ -908,6 +925,12 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) case BPF_LDX | BPF_MEM | BPF_DW: emit_ldx(ctx, dst, src, off, BPF_SIZE(code)); break; + /* LDSX: dst = *(signed size *)(src + off) */ + case BPF_LDX | BPF_MEMSX | BPF_W: + case BPF_LDX | BPF_MEMSX | BPF_H: + case BPF_LDX | BPF_MEMSX | BPF_B: + emit_ldsx(ctx, dst, src, off, BPF_SIZE(code)); + break; /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: