[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:
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.