]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
arm32, bpf: add support for sign-extension mov instruction
authorPuranjay Mohan <puranjay12@gmail.com>
Thu, 7 Sep 2023 23:05:44 +0000 (23:05 +0000)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 16 Sep 2023 00:16:56 +0000 (17:16 -0700)
The cpuv4 added a new BPF_MOVSX instruction that sign extends the src
before moving it to the destination.

BPF_ALU | BPF_MOVSX sign extends 8-bit and 16-bit operands into 32-bit
operands, and zeroes the remaining upper 32 bits.

BPF_ALU64 | BPF_MOVSX sign extends 8-bit, 16-bit, and 32-bit  operands
into 64-bit operands.

The offset field of the instruction is used to tell the number of bit to
use for sign-extension. BPF_MOV and BPF_MOVSX have the same code but the
former sets offset to 0 and the later one sets the offset to 8, 16 or 32

The behaviour of this instruction is dst = (s8,s16,s32)src

On ARM32 the implementation uses LSH and ARSH to extend the 8/16 bits to
a 32-bit register and then it is sign extended to the upper 32-bit
register using ARSH. For 32-bit we just move it to the destination
register and use ARSH to extend it to the upper 32-bit register.

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://lore.kernel.org/r/20230907230550.1417590-4-puranjay12@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
arch/arm/net/bpf_jit_32.c

index 1b3bd05878ab98112933cc86994daebaa72aeacf..29a1ccf761fd88130f578bb49e102661e8b9c422 100644 (file)
@@ -747,12 +747,16 @@ static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
 }
 
 /* dst = src (4 bytes)*/
-static inline void emit_a32_mov_r(const s8 dst, const s8 src,
+static inline void emit_a32_mov_r(const s8 dst, const s8 src, const u8 off,
                                  struct jit_ctx *ctx) {
        const s8 *tmp = bpf2a32[TMP_REG_1];
        s8 rt;
 
        rt = arm_bpf_get_reg32(src, tmp[0], ctx);
+       if (off && off != 32) {
+               emit(ARM_LSL_I(rt, rt, 32 - off), ctx);
+               emit(ARM_ASR_I(rt, rt, 32 - off), ctx);
+       }
        arm_bpf_put_reg32(dst, rt, ctx);
 }
 
@@ -761,15 +765,15 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
                                  const s8 src[],
                                  struct jit_ctx *ctx) {
        if (!is64) {
-               emit_a32_mov_r(dst_lo, src_lo, ctx);
+               emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
                if (!ctx->prog->aux->verifier_zext)
                        /* Zero out high 4 bytes */
                        emit_a32_mov_i(dst_hi, 0, ctx);
        } else if (__LINUX_ARM_ARCH__ < 6 &&
                   ctx->cpu_architecture < CPU_ARCH_ARMv5TE) {
                /* complete 8 byte move */
-               emit_a32_mov_r(dst_lo, src_lo, ctx);
-               emit_a32_mov_r(dst_hi, src_hi, ctx);
+               emit_a32_mov_r(dst_lo, src_lo, 0, ctx);
+               emit_a32_mov_r(dst_hi, src_hi, 0, ctx);
        } else if (is_stacked(src_lo) && is_stacked(dst_lo)) {
                const u8 *tmp = bpf2a32[TMP_REG_1];
 
@@ -785,6 +789,24 @@ static inline void emit_a32_mov_r64(const bool is64, const s8 dst[],
        }
 }
 
+/* dst = (signed)src */
+static inline void emit_a32_movsx_r64(const bool is64, const u8 off, const s8 dst[], const s8 src[],
+                                     struct jit_ctx *ctx) {
+       const s8 *tmp = bpf2a32[TMP_REG_1];
+       const s8 *rt;
+
+       rt = arm_bpf_get_reg64(dst, tmp, ctx);
+
+       emit_a32_mov_r(dst_lo, src_lo, off, ctx);
+       if (!is64) {
+               if (!ctx->prog->aux->verifier_zext)
+                       /* Zero out high 4 bytes */
+                       emit_a32_mov_i(dst_hi, 0, ctx);
+       } else {
+               emit(ARM_ASR_I(rt[0], rt[1], 31), ctx);
+       }
+}
+
 /* Shift operations */
 static inline void emit_a32_alu_i(const s8 dst, const u32 val,
                                struct jit_ctx *ctx, const u8 op) {
@@ -1450,7 +1472,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
                                emit_a32_mov_i(dst_hi, 0, ctx);
                                break;
                        }
-                       emit_a32_mov_r64(is64, dst, src, ctx);
+                       if (insn->off)
+                               emit_a32_movsx_r64(is64, insn->off, dst, src, ctx);
+                       else
+                               emit_a32_mov_r64(is64, dst, src, ctx);
                        break;
                case BPF_K:
                        /* Sign-extend immediate value to destination reg */