* [PATCH bpf-next v2 1/2] bpf, mips: Factor register moves into helpers
2026-09-04 11:17 [PATCH bpf-next v2 0/2] bpf, mips: Add BPF_MOVSX support to the JITs Nicholas Dudar
@ 2026-09-04 11:17 ` Nicholas Dudar
2026-09-04 12:29 ` bot+bpf-ci
2026-09-04 11:17 ` [PATCH bpf-next v2 2/2] bpf, mips: Add support for BPF_MOVSX in the JITs Nicholas Dudar
1 sibling, 1 reply; 5+ messages in thread
From: Nicholas Dudar @ 2026-09-04 11:17 UTC (permalink / raw)
To: ast, daniel, andrii, eddyz87, memxor, johan.almbladh, paulburton,
tsbogend
Cc: martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, bpf,
linux-mips, linux-kernel
BPF_MOVSX carries its source width in insn->off. Both MIPS JITs
currently lower register MOV instructions directly in build_insn().
Keeping the forthcoming MOVSX width switch there would split the move
operation between dispatcher cases and backend emitters.
Factor ALU32 and ALU64 register moves into helpers for each backend and
route the existing MOV paths through them. The helpers own the complete
move operation, including MIPS32 register-pair handling and the ALU32
upper-half state. This keeps the following MOVSX width decoding inside
one per-backend, per-width-class move emitter rather than in dispatcher
case arms or generic primitives.
Keep the verifier-inserted zero-extension marker on its dedicated path.
No functional change is intended.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
---
arch/mips/net/bpf_jit_comp32.c | 22 ++++++++++++++++++----
arch/mips/net/bpf_jit_comp64.c | 18 +++++++++++++++---
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c
index 40a878b672f5..bfe73b023983 100644
--- a/arch/mips/net/bpf_jit_comp32.c
+++ b/arch/mips/net/bpf_jit_comp32.c
@@ -190,6 +190,22 @@ 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[])
+{
+ emit_mov_r(ctx, lo(dst), lo(src));
+ emit_zext_ver(ctx, dst);
+}
+
+/* Register move operation (64-bit) */
+static void emit_mov_r64(struct jit_context *ctx, const u8 dst[],
+ const u8 src[])
+{
+ emit_mov_r(ctx, lo(dst), lo(src));
+ emit_mov_r(ctx, hi(dst), hi(src));
+}
+
/* Load delay slot, if ISA mandates it */
static void emit_load_delay(struct jit_context *ctx)
{
@@ -1485,8 +1501,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_r(ctx, lo(dst), lo(src));
- emit_zext_ver(ctx, dst);
+ emit_mov_r32(ctx, dst, src);
}
break;
/* dst = -dst */
@@ -1555,8 +1570,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_r(ctx, lo(dst), lo(src));
- emit_mov_r(ctx, hi(dst), hi(src));
+ emit_mov_r64(ctx, dst, src);
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 fa7e9aa37f49..45fee6f6b87e 100644
--- a/arch/mips/net/bpf_jit_comp64.c
+++ b/arch/mips/net/bpf_jit_comp64.c
@@ -120,6 +120,19 @@ 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)
+{
+ emit_mov_r(ctx, dst, src);
+ emit_zext_ver(ctx, dst);
+}
+
+/* Register move operation (64-bit) */
+static void emit_mov_r64(struct jit_context *ctx, u8 dst, u8 src)
+{
+ emit_mov_r(ctx, dst, src);
+}
+
/* dst = imm (64-bit) */
static void emit_mov_i64(struct jit_context *ctx, u8 dst, u64 imm64)
{
@@ -656,8 +669,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
/* Special mov32 for zext */
emit_zext(ctx, dst);
} else {
- emit_mov_r(ctx, dst, src);
- emit_zext_ver(ctx, dst);
+ emit_mov_r32(ctx, dst, src);
}
break;
/* dst = -dst */
@@ -742,7 +754,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_r(ctx, dst, src);
+ emit_mov_r64(ctx, dst, src);
break;
/* dst = -dst (64-bit) */
case BPF_ALU64 | BPF_NEG:
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH bpf-next v2 2/2] bpf, mips: Add support for BPF_MOVSX in the JITs
2026-09-04 11:17 [PATCH bpf-next v2 0/2] bpf, mips: Add BPF_MOVSX support to the JITs Nicholas Dudar
2026-09-04 11:17 ` [PATCH bpf-next v2 1/2] bpf, mips: Factor register moves into helpers Nicholas Dudar
@ 2026-09-04 11:17 ` Nicholas Dudar
1 sibling, 0 replies; 5+ messages in thread
From: Nicholas Dudar @ 2026-09-04 11:17 UTC (permalink / raw)
To: ast, daniel, andrii, eddyz87, memxor, johan.almbladh, paulburton,
tsbogend
Cc: martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, bpf,
linux-mips, linux-kernel
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 insn->off in the register-move helpers and sign-extend 8- and
16-bit ALU32 operands and 8-, 16-, and 32-bit ALU64 operands. On
MIPS32, propagate the sign into the high word for ALU64 while
preserving the existing ALU32 zero-extension handling.
Use shift pairs rather than seb/seh so the lowering works on every CPU
supported by these JITs. seb/seh would save one instruction on
R2-or-newer CPUs but would require adding those opcodes to uasm.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
---
arch/mips/net/bpf_jit_comp32.c | 56 ++++++++++++++++++++++++++++------
arch/mips/net/bpf_jit_comp64.c | 54 +++++++++++++++++++++++++++-----
2 files changed, 93 insertions(+), 17 deletions(-)
diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c
index bfe73b023983..885da0d0d74b 100644
--- a/arch/mips/net/bpf_jit_comp32.c
+++ b/arch/mips/net/bpf_jit_comp32.c
@@ -190,20 +190,58 @@ 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));
+ int shift;
+
+ switch (off) {
+ case 8:
+ case 16:
+ shift = 32 - off;
+ emit(ctx, sll, lo(dst), lo(src), shift);
+ emit(ctx, sra, lo(dst), lo(dst), shift);
+ 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));
+ int shift;
+
+ switch (off) {
+ case 8:
+ case 16:
+ shift = 32 - off;
+ emit(ctx, sll, lo(dst), lo(src), shift);
+ emit(ctx, sra, lo(dst), lo(dst), shift);
+ 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 */
@@ -1501,7 +1539,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 +1608,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 45fee6f6b87e..a1dfb7492a9c 100644
--- a/arch/mips/net/bpf_jit_comp64.c
+++ b/arch/mips/net/bpf_jit_comp64.c
@@ -120,17 +120,55 @@ 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);
+ int shift;
+
+ switch (off) {
+ case 8:
+ case 16:
+ shift = 32 - off;
+ /* dsll32 and dsra32 add 32 to the shift argument. */
+ emit(ctx, dsll32, dst, src, shift);
+ emit(ctx, dsra32, dst, dst, shift);
+ 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);
+ int shift;
+
+ switch (off) {
+ case 8:
+ case 16:
+ shift = 32 - off;
+ /* dsll32 and dsra32 add 32 to the shift argument. */
+ emit(ctx, dsll32, dst, src, shift);
+ emit(ctx, dsra32, dst, dst, shift);
+ 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) */
@@ -669,7 +707,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 +792,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:
^ permalink raw reply related [flat|nested] 5+ messages in thread