[RFC bpf-next 2/2] bpf, mips: Add support for BPF_MOVSX in 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]> |
The MIPS32 and MIPS64 JITs lower register BPF_MOVSX instructions as ordinary moves because their register-move paths do not interpret insn->off. Negative low-width values therefore retain incorrect upper bits. Teach the register-move helpers to sign-extend the BPF-defined MOVSX widths: 8 and 16 for ALU32, and 8, 16, and 32 for ALU64. Propagate the sign into the MIPS32 high word for ALU64, while retaining the existing verifier-managed zero extension for ALU32. Keep the verifier-inserted zero-extension move on its dedicated path and interpret the raw offset within the MOV helpers. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Nicholas Dudar <[email protected]> --- arch/mips/net/bpf_jit_comp32.c | 50 ++++++++++++++++++++++++++++------ arch/mips/net/bpf_jit_comp64.c | 46 +++++++++++++++++++++++++------ 2 files changed, 79 insertions(+), 17 deletions(-) diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c index bfe73b023983e..66ade9d77638d 100644 --- a/arch/mips/net/bpf_jit_comp32.c +++ b/arch/mips/net/bpf_jit_comp32.c @@ -190,20 +190,52 @@ static void emit_zext_ver(struct jit_context *ctx, const u8 dst[]) } } -/* Register move operation (32-bit) */ +/* Register move operation (32-bit), optionally with sign extension */ static void emit_mov_r32(struct jit_context *ctx, const u8 dst[], - const u8 src[]) + const u8 src[], s16 off) { - emit_mov_r(ctx, lo(dst), lo(src)); + switch (off) { + case 8: + emit(ctx, sll, lo(dst), lo(src), 24); + emit(ctx, sra, lo(dst), lo(dst), 24); + clobber_reg(ctx, lo(dst)); + break; + case 16: + emit(ctx, sll, lo(dst), lo(src), 16); + emit(ctx, sra, lo(dst), lo(dst), 16); + clobber_reg(ctx, lo(dst)); + break; + default: + emit_mov_r(ctx, lo(dst), lo(src)); + break; + } emit_zext_ver(ctx, dst); } -/* Register move operation (64-bit) */ +/* Register move operation (64-bit), optionally with sign extension */ static void emit_mov_r64(struct jit_context *ctx, const u8 dst[], - const u8 src[]) + const u8 src[], s16 off) { - emit_mov_r(ctx, lo(dst), lo(src)); - emit_mov_r(ctx, hi(dst), hi(src)); + switch (off) { + case 8: + emit(ctx, sll, lo(dst), lo(src), 24); + emit(ctx, sra, lo(dst), lo(dst), 24); + break; + case 16: + emit(ctx, sll, lo(dst), lo(src), 16); + emit(ctx, sra, lo(dst), lo(dst), 16); + break; + case 32: + emit(ctx, move, lo(dst), lo(src)); + break; + default: + emit_mov_r(ctx, lo(dst), lo(src)); + emit_mov_r(ctx, hi(dst), hi(src)); + return; + } + clobber_reg(ctx, lo(dst)); + emit(ctx, sra, hi(dst), lo(dst), 31); + clobber_reg(ctx, hi(dst)); } /* Load delay slot, if ISA mandates it */ @@ -1501,7 +1533,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) /* Special mov32 for zext */ emit_mov_i(ctx, hi(dst), 0); } else { - emit_mov_r32(ctx, dst, src); + emit_mov_r32(ctx, dst, src, off); } break; /* dst = -dst */ @@ -1570,7 +1602,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) break; /* dst = src (64-bit) */ case BPF_ALU64 | BPF_MOV | BPF_X: - emit_mov_r64(ctx, dst, src); + emit_mov_r64(ctx, dst, src, off); break; /* dst = -dst (64-bit) */ case BPF_ALU64 | BPF_NEG: diff --git a/arch/mips/net/bpf_jit_comp64.c b/arch/mips/net/bpf_jit_comp64.c index 45fee6f6b87e9..31f73f50caf5d 100644 --- a/arch/mips/net/bpf_jit_comp64.c +++ b/arch/mips/net/bpf_jit_comp64.c @@ -120,17 +120,47 @@ static void emit_zext_ver(struct jit_context *ctx, u8 dst) emit_zext(ctx, dst); } -/* Register move operation (32-bit) */ -static void emit_mov_r32(struct jit_context *ctx, u8 dst, u8 src) +/* Register move operation (32-bit), optionally with sign extension */ +static void emit_mov_r32(struct jit_context *ctx, u8 dst, u8 src, s16 off) { - emit_mov_r(ctx, dst, src); + switch (off) { + case 8: + emit(ctx, dsll32, dst, src, 24); + emit(ctx, dsra32, dst, dst, 24); + clobber_reg(ctx, dst); + break; + case 16: + emit(ctx, dsll32, dst, src, 16); + emit(ctx, dsra32, dst, dst, 16); + clobber_reg(ctx, dst); + break; + default: + emit_mov_r(ctx, dst, src); + break; + } emit_zext_ver(ctx, dst); } -/* Register move operation (64-bit) */ -static void emit_mov_r64(struct jit_context *ctx, u8 dst, u8 src) +/* Register move operation (64-bit), optionally with sign extension */ +static void emit_mov_r64(struct jit_context *ctx, u8 dst, u8 src, s16 off) { - emit_mov_r(ctx, dst, src); + switch (off) { + case 8: + emit(ctx, dsll32, dst, src, 24); + emit(ctx, dsra32, dst, dst, 24); + break; + case 16: + emit(ctx, dsll32, dst, src, 16); + emit(ctx, dsra32, dst, dst, 16); + break; + case 32: + emit(ctx, sll, dst, src, 0); + break; + default: + emit_mov_r(ctx, dst, src); + return; + } + clobber_reg(ctx, dst); } /* dst = imm (64-bit) */ @@ -669,7 +699,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) /* Special mov32 for zext */ emit_zext(ctx, dst); } else { - emit_mov_r32(ctx, dst, src); + emit_mov_r32(ctx, dst, src, off); } break; /* dst = -dst */ @@ -754,7 +784,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) break; /* dst = src (64-bit) */ case BPF_ALU64 | BPF_MOV | BPF_X: - emit_mov_r64(ctx, dst, src); + emit_mov_r64(ctx, dst, src, off); break; /* dst = -dst (64-bit) */ case BPF_ALU64 | BPF_NEG: