Linux MIPS Architecture development
 help / color / mirror / Atom feed
* [RFC bpf-next 0/2] bpf, mips: Add BPF_MEMSX support to the JITs
@ 2026-08-21  2:46 Nicholas Dudar
  2026-08-21  2:46 ` [RFC bpf-next 1/2] bpf, mips: Factor narrow loads out of emit_ldx() Nicholas Dudar
  2026-08-21  2:46 ` [RFC bpf-next 2/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar
  0 siblings, 2 replies; 3+ messages in thread
From: Nicholas Dudar @ 2026-08-21  2:46 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-next is closed for the merge window, so I am sending this for
review. I plan to post this series after it reopens.

The MIPS32 and MIPS64 JITs reject BPF_MEMSX byte, half-word, and word
instructions, so a program containing one cannot run when JIT execution
is required.

First factor ordinary narrow-load selection into backend-local helpers.
Then extend those helpers to select signed native loads for BPF_MEMSX.
MIPS32 observes the load-delay rule and propagates the low-word sign into
the high half; MIPS64 obtains the full result from the native load.
Ordinary loads remain unsigned, and BPF_MEMSX with BPF_DW remains
unsupported.

This series must be applied after the in-review MIPS MOVSX and SDIV/SMOD
series:

MOVSX: https://lore.kernel.org/bpf/20260819010523.1057789-1-main.kalliope@gmail.com/
SDIV/SMOD: https://lore.kernel.org/bpf/20260810194215.3754591-1-main.kalliope@gmail.com/

Applying MEMSX removes a whole-program JIT fallback that otherwise keeps
mixed programs containing unsupported MOVSX or signed DIV/MOD out of the
JIT.

The ordering discussion is here:

https://lore.kernel.org/bpf/CAJZwKkis=3NGw9At0WfiZaRYEoMPbQfqJKN0e+vtRDvp4VY5Ng@mail.gmail.com/

On four little-endian profiles, patch 1 leaves the complete test_bpf
results with 1031 passed/31 failed on MIPS32 and 1030/31 on MIPS64.
Patch 2 changes the three MEMSX cases, yielding 1034/28 and 1033/28,
respectively. Ordinary unsigned-load controls passed at each boundary.

Selector-focused QEMU testing covered MIPS32 base, R2, and R6 plus
pre-R6 MIPS64, each in big- and little-endian configurations. The focused
mixed-operation matrix reproduced the unsafe MEMSX-first ordering and the
correct fully composed result on MIPS32 and MIPS64, both big- and
little-endian. No physical MIPS hardware was tested.

Nicholas Dudar (2):
  bpf, mips: Factor narrow loads out of emit_ldx()
  bpf, mips: Add BPF_MEMSX support to the JITs

 arch/mips/net/bpf_jit_comp32.c | 51 ++++++++++++++++++++++++++++------
 arch/mips/net/bpf_jit_comp64.c | 47 +++++++++++++++++++++++++++----
 2 files changed, 85 insertions(+), 13 deletions(-)


base-commit: 91ec2035134982b98fab0609a9fd8480e8217dc1
prerequisite-patch-id: aa8ca3f50fc4b0160c5fdba43a92e4b7ec3f2e07
prerequisite-patch-id: bda4c3f3d59b48d784ed98bd8558d9591399bc86
prerequisite-patch-id: 35236f563c0536859077709d52b345b696e5c26e
prerequisite-patch-id: c0f282b0e57ecd60e9582fb1e89e4b3112ae7893
prerequisite-patch-id: 4e93eed38f6585e21fc13931c314907b4e437ef5

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC bpf-next 1/2] bpf, mips: Factor narrow loads out of emit_ldx()
  2026-08-21  2:46 [RFC bpf-next 0/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar
@ 2026-08-21  2:46 ` Nicholas Dudar
  2026-08-21  2:46 ` [RFC bpf-next 2/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar
  1 sibling, 0 replies; 3+ messages in thread
From: Nicholas Dudar @ 2026-08-21  2:46 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

Factor the byte, half-word, and word load selection out of emit_ldx()
in both MIPS JIT backends. The existing unsigned LDX paths remain the
only callers and retain the same native instructions, upper-half
handling, and clobber accounting. The double-word paths remain
unchanged.

This gives narrow loads one width dispatcher that can be extended
without duplicating the BPF size switch. No functional change
intended.

Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
---
 arch/mips/net/bpf_jit_comp32.c | 28 ++++++++++++++++++++--------
 arch/mips/net/bpf_jit_comp64.c | 18 ++++++++++++++++--
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c
index b3f6b92ac34ed..48a3c834453f2 100644
--- a/arch/mips/net/bpf_jit_comp32.c
+++ b/arch/mips/net/bpf_jit_comp32.c
@@ -707,24 +707,36 @@ static void emit_trunc_r64(struct jit_context *ctx, const u8 dst[], u32 width)
 	}
 }
 
-/* Load operation: dst = *(size*)(src + off) */
-static void emit_ldx(struct jit_context *ctx,
-		     const u8 dst[], u8 src, s16 off, u8 size)
+/* Narrow load operation: dst = *(size *)(src + off) */
+static void emit_ldx_narrow(struct jit_context *ctx,
+			    u8 dst, u8 src, s16 off, u8 size)
 {
 	switch (size) {
 	/* Load a byte */
 	case BPF_B:
-		emit(ctx, lbu, lo(dst), off, src);
-		emit(ctx, move, hi(dst), MIPS_R_ZERO);
+		emit(ctx, lbu, dst, off, src);
 		break;
 	/* Load a half word */
 	case BPF_H:
-		emit(ctx, lhu, lo(dst), off, src);
-		emit(ctx, move, hi(dst), MIPS_R_ZERO);
+		emit(ctx, lhu, dst, off, src);
 		break;
 	/* Load a word */
 	case BPF_W:
-		emit(ctx, lw, lo(dst), off, src);
+		emit(ctx, lw, dst, off, src);
+		break;
+	}
+}
+
+/* Load operation: dst = *(size *)(src + off) */
+static void emit_ldx(struct jit_context *ctx,
+		     const u8 dst[], u8 src, s16 off, u8 size)
+{
+	switch (size) {
+	/* Load a byte, half word or word */
+	case BPF_B:
+	case BPF_H:
+	case BPF_W:
+		emit_ldx_narrow(ctx, lo(dst), src, off, size);
 		emit(ctx, move, hi(dst), MIPS_R_ZERO);
 		break;
 	/* Load a double word */
diff --git a/arch/mips/net/bpf_jit_comp64.c b/arch/mips/net/bpf_jit_comp64.c
index ee99f46828c86..22fb58f970223 100644
--- a/arch/mips/net/bpf_jit_comp64.c
+++ b/arch/mips/net/bpf_jit_comp64.c
@@ -398,8 +398,9 @@ static void emit_trunc_r64(struct jit_context *ctx, u8 dst, u32 width)
 	clobber_reg(ctx, dst);
 }
 
-/* Load operation: dst = *(size*)(src + off) */
-static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size)
+/* Narrow load operation: dst = *(size *)(src + off) */
+static void emit_ldx_narrow(struct jit_context *ctx,
+			    u8 dst, u8 src, s16 off, u8 size)
 {
 	switch (size) {
 	/* Load a byte */
@@ -414,6 +415,19 @@ static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size)
 	case BPF_W:
 		emit(ctx, lwu, dst, off, src);
 		break;
+	}
+}
+
+/* Load operation: dst = *(size *)(src + off) */
+static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size)
+{
+	switch (size) {
+	/* Load a byte, half word or word */
+	case BPF_B:
+	case BPF_H:
+	case BPF_W:
+		emit_ldx_narrow(ctx, dst, src, off, size);
+		break;
 	/* Load a double word */
 	case BPF_DW:
 		emit(ctx, ld, dst, off, src);

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC bpf-next 2/2] bpf, mips: Add BPF_MEMSX support to the JITs
  2026-08-21  2:46 [RFC bpf-next 0/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar
  2026-08-21  2:46 ` [RFC bpf-next 1/2] bpf, mips: Factor narrow loads out of emit_ldx() Nicholas Dudar
@ 2026-08-21  2:46 ` Nicholas Dudar
  1 sibling, 0 replies; 3+ messages in thread
From: Nicholas Dudar @ 2026-08-21  2:46 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_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 <main.kalliope@gmail.com>
---
 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:

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-21  2:50 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21  2:46 [RFC bpf-next 0/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar
2026-08-21  2:46 ` [RFC bpf-next 1/2] bpf, mips: Factor narrow loads out of emit_ldx() Nicholas Dudar
2026-08-21  2:46 ` [RFC bpf-next 2/2] bpf, mips: Add BPF_MEMSX support to the JITs Nicholas Dudar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox