[PATCH bpf-next 2/2] bpf, parisc: Add support for BPF_MOVSX in the parisc32 JIT
From: Nicholas Dudar
Date: Fri Nov 13 2026 - 16:42:36 EST
RFC9669 defines BPF_MOV | BPF_X with an offset of 8, 16 or 32 as a
sign-extending move, dst = (s8,s16,s32)src. The parisc32 JIT handles it
like an ordinary register move, so r0 = (s8)r0 with 0x80 gives 128
instead of -128.
Add emit_movsx_r(). It sign-extends the low 8 or 16 bits of the source
low word with extrw,s, or copies the low word for a 32-bit extension,
and fills the high word with the sign for ALU64. For ALU32,
bpf_put_reg32() zeroes the high word unless the verifier inserts the
zero extension.
Under QEMU on a 32-bit kernel, with test_progs built as a static 32-bit
binary with jit_insns only:
# ./test_progs -t jit_insns -w 0
[...]
#201/33 jit_insns/movsx:OK
[...]
Summary: 0/40 PASSED, 0 SKIPPED, 2/12 FAILED
Without this change jit_insns/movsx fails as well. The 12 failures left
fail without this change too.
Signed-off-by: Nicholas Dudar <main.kalliope@xxxxxxxxx>
---
arch/parisc/net/bpf_jit_comp32.c | 41 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/arch/parisc/net/bpf_jit_comp32.c b/arch/parisc/net/bpf_jit_comp32.c
index eea0a34a3bfe..9cfbff3e58bb 100644
--- a/arch/parisc/net/bpf_jit_comp32.c
+++ b/arch/parisc/net/bpf_jit_comp32.c
@@ -705,6 +705,35 @@ static void emit_alu_r32(const s8 *dst, const s8 *src,
bpf_put_reg32(dst, rd, ctx);
}
+/* dst = sign_extend(src, width) */
+static void emit_movsx_r(const s8 *dst, const s8 *src,
+ struct hppa_jit_context *ctx, u8 width, bool is64)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+ const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
+ const s8 *rd;
+
+ if (is64)
+ rd = bpf_get_reg64_ref(dst, tmp1, false, ctx);
+ else
+ rd = bpf_get_reg32_ref(dst, tmp1, ctx);
+
+ /* Low word: sign-extend the field, or copy it for a 32-bit extension */
+ if (width == 32)
+ emit_hppa_copy(lo(rs), lo(rd), ctx);
+ else
+ emit(hppa_extrws(lo(rs), 31, 32 - width, lo(rd)), ctx);
+
+ if (is64) {
+ /* High word: copies of the sign bit */
+ emit(hppa_extrws(lo(rd), 0, 31, hi(rd)), ctx);
+ bpf_put_reg64(dst, rd, ctx);
+ } else {
+ bpf_put_reg32(dst, rd, ctx);
+ }
+}
+
static int emit_branch_r64(const s8 *src1, const s8 *src2, s32 paoff,
struct hppa_jit_context *ctx, const u8 op)
{
@@ -1145,7 +1174,12 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
switch (code) {
/* dst = src */
case BPF_ALU64 | BPF_MOV | BPF_X:
-
+ if (off == 8 || off == 16 || off == 32) {
+ /* Sign-extending mov: dst = (s8,s16,s32)src */
+ emit_movsx_r(dst, src, ctx, off, true);
+ break;
+ }
+ fallthrough;
case BPF_ALU64 | BPF_ADD | BPF_X:
case BPF_ALU64 | BPF_ADD | BPF_K:
@@ -1196,6 +1230,11 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
emit_zext64(dst, ctx);
break;
}
+ if (off == 8 || off == 16) {
+ /* Sign-extending mov32: dst = (s8,s16)src */
+ emit_movsx_r(dst, src, ctx, off, false);
+ break;
+ }
fallthrough;
/* dst = dst OP src */
case BPF_ALU | BPF_ADD | BPF_X:
--
2.53.0