mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf, mips: Add support for BPF_MOVSX in the JITs
Both MIPS JITs ignore insn->off when lowering register MOV instructions, so BPF_MOVSX is emitted as an ordinary move. Since build_insn() accepts it, affected programs are silently miscompiled instead of falling back to the interpreter. Decode the MOVSX width from insn->off in the register-move helpers. On MIPS32, propagate the sign into the high word for ALU64 while preserving the existing ALU32 zero-extension handling. Use seb/seh on MIPS32 R2-or-newer CPUs and shift pairs otherwise. On MIPS64, seb/seh require a sign-extended 32-bit source. Normalizing an arbitrary BPF register first would cost another instruction, so retain the doubleword shift pairs. Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20260912041220.444715-3-main.kalliope@gmail.com
This commit is contained in:
parent
86187bd3cd
commit
07ebb8c386
|
|
@ -190,20 +190,67 @@ static void emit_zext_ver(struct jit_context *ctx, const u8 dst[])
|
|||
}
|
||||
}
|
||||
|
||||
/* Register move operation (32-bit) */
|
||||
static void emit_mov_r32(struct jit_context *ctx, const u8 dst[],
|
||||
const u8 src[])
|
||||
/* Sign-extend an 8- or 16-bit field into a native register. */
|
||||
static void emit_movsx_r(struct jit_context *ctx, u8 dst, u8 src, s16 off)
|
||||
{
|
||||
emit_mov_r(ctx, lo(dst), lo(src));
|
||||
int shift;
|
||||
|
||||
if (cpu_has_mips32r2 || cpu_has_mips32r6) {
|
||||
if (off == 8)
|
||||
emit(ctx, seb, dst, src);
|
||||
else
|
||||
emit(ctx, seh, dst, src);
|
||||
} else {
|
||||
shift = 32 - off;
|
||||
emit(ctx, sll, dst, src, shift);
|
||||
emit(ctx, sra, dst, dst, shift);
|
||||
}
|
||||
}
|
||||
|
||||
/* Register move operation (32-bit), optionally with sign extension */
|
||||
static void emit_mov_r32(struct jit_context *ctx, const u8 dst[],
|
||||
const u8 src[], s16 off)
|
||||
{
|
||||
switch (off) {
|
||||
case 8:
|
||||
case 16:
|
||||
emit_movsx_r(ctx, lo(dst), lo(src), off);
|
||||
break;
|
||||
default:
|
||||
/* off == 0 is MOV; the verifier rejects other offsets. */
|
||||
emit_mov_r(ctx, lo(dst), lo(src));
|
||||
break;
|
||||
}
|
||||
clobber_reg(ctx, lo(dst));
|
||||
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:
|
||||
case 16:
|
||||
emit_movsx_r(ctx, lo(dst), lo(src), off);
|
||||
emit(ctx, sra, hi(dst), lo(dst), 31);
|
||||
break;
|
||||
case 32:
|
||||
emit(ctx, move, lo(dst), lo(src));
|
||||
emit(ctx, sra, hi(dst), lo(dst), 31);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* off == 0 is ordinary MOV. The verifier rejects other
|
||||
* offsets; defined exceptions require
|
||||
* bpf_jit_supports_percpu_insn() or bpf_jit_supports_arena(),
|
||||
* neither implemented by MIPS.
|
||||
*/
|
||||
emit_mov_r(ctx, lo(dst), lo(src));
|
||||
emit_mov_r(ctx, hi(dst), hi(src));
|
||||
break;
|
||||
}
|
||||
clobber_reg64(ctx, dst);
|
||||
}
|
||||
|
||||
/* Load delay slot, if ISA mandates it */
|
||||
|
|
@ -1510,7 +1557,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 */
|
||||
|
|
@ -1579,7 +1626,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:
|
||||
|
|
|
|||
|
|
@ -120,17 +120,56 @@ 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)
|
||||
/* Sign-extend an 8- or 16-bit field into a native register. */
|
||||
static void emit_movsx_r(struct jit_context *ctx, u8 dst, u8 src, s16 off)
|
||||
{
|
||||
emit_mov_r(ctx, dst, src);
|
||||
/* seb/seh would need a sign-extended 32-bit source first. */
|
||||
int shift = 32 - off;
|
||||
|
||||
/* dsll32 and dsra32 add 32 to the shift argument. */
|
||||
emit(ctx, dsll32, dst, src, shift);
|
||||
emit(ctx, dsra32, dst, dst, shift);
|
||||
}
|
||||
|
||||
/* Register move operation (32-bit), optionally with sign extension */
|
||||
static void emit_mov_r32(struct jit_context *ctx, u8 dst, u8 src, s16 off)
|
||||
{
|
||||
switch (off) {
|
||||
case 8:
|
||||
case 16:
|
||||
emit_movsx_r(ctx, dst, src, off);
|
||||
break;
|
||||
default:
|
||||
/* off == 0 is MOV; the verifier rejects other offsets. */
|
||||
emit_mov_r(ctx, dst, src);
|
||||
break;
|
||||
}
|
||||
clobber_reg(ctx, dst);
|
||||
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:
|
||||
case 16:
|
||||
emit_movsx_r(ctx, dst, src, off);
|
||||
break;
|
||||
case 32:
|
||||
emit_sext(ctx, dst, src);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* off == 0 is ordinary MOV. The verifier rejects other
|
||||
* offsets; defined exceptions require
|
||||
* bpf_jit_supports_percpu_insn() or bpf_jit_supports_arena(),
|
||||
* neither implemented by MIPS.
|
||||
*/
|
||||
emit_mov_r(ctx, dst, src);
|
||||
break;
|
||||
}
|
||||
clobber_reg(ctx, dst);
|
||||
}
|
||||
|
||||
/* dst = imm (64-bit) */
|
||||
|
|
@ -694,7 +733,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 */
|
||||
|
|
@ -779,7 +818,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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user