]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
powerpc64/bpf: jit support for sign extended load
authorArtem Savkov <asavkov@redhat.com>
Fri, 17 May 2024 07:56:48 +0000 (09:56 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 11 Jul 2024 05:40:21 +0000 (15:40 +1000)
Add jit support for sign extended load. Tested using test_bpf module.

Signed-off-by: Artem Savkov <asavkov@redhat.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240517075650.248801-4-asavkov@redhat.com
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/net/bpf_jit_comp64.c

index 076ae60b4a55d71ad3fab2293f195d08a4976d07..76cc9a2d820659c7771bdcc9fcab7f2af716ce95 100644 (file)
 #define PPC_RAW_VCMPEQUB_RC(vrt, vra, vrb) \
        (0x10000006 | ___PPC_RT(vrt) | ___PPC_RA(vra) | ___PPC_RB(vrb) | __PPC_RC21)
 #define PPC_RAW_LD(r, base, i)         (0xe8000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_DS(i))
+#define PPC_RAW_LWA(r, base, i)                (0xe8000002 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_DS(i))
 #define PPC_RAW_LWZ(r, base, i)                (0x80000000 | ___PPC_RT(r) | ___PPC_RA(base) | IMM_L(i))
 #define PPC_RAW_LWZX(t, a, b)          (0x7c00002e | ___PPC_RT(t) | ___PPC_RA(a) | ___PPC_RB(b))
 #define PPC_RAW_STD(r, base, i)                (0xf8000000 | ___PPC_RS(r) | ___PPC_RA(base) | IMM_DS(i))
index 7de41e80c61fef7f5fa4bd005d939da273abadc0..ca3ca6e01db2d7fe46701412034ee22c6c667f68 100644 (file)
@@ -937,13 +937,19 @@ emit_clear:
                 */
                /* dst = *(u8 *)(ul) (src + off) */
                case BPF_LDX | BPF_MEM | BPF_B:
+               case BPF_LDX | BPF_MEMSX | BPF_B:
                case BPF_LDX | BPF_PROBE_MEM | BPF_B:
+               case BPF_LDX | BPF_PROBE_MEMSX | BPF_B:
                /* dst = *(u16 *)(ul) (src + off) */
                case BPF_LDX | BPF_MEM | BPF_H:
+               case BPF_LDX | BPF_MEMSX | BPF_H:
                case BPF_LDX | BPF_PROBE_MEM | BPF_H:
+               case BPF_LDX | BPF_PROBE_MEMSX | BPF_H:
                /* dst = *(u32 *)(ul) (src + off) */
                case BPF_LDX | BPF_MEM | BPF_W:
+               case BPF_LDX | BPF_MEMSX | BPF_W:
                case BPF_LDX | BPF_PROBE_MEM | BPF_W:
+               case BPF_LDX | BPF_PROBE_MEMSX | BPF_W:
                /* dst = *(u64 *)(ul) (src + off) */
                case BPF_LDX | BPF_MEM | BPF_DW:
                case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
@@ -953,7 +959,7 @@ emit_clear:
                         * load only if addr is kernel address (see is_kernel_addr()), otherwise
                         * set dst_reg=0 and move on.
                         */
-                       if (BPF_MODE(code) == BPF_PROBE_MEM) {
+                       if (BPF_MODE(code) == BPF_PROBE_MEM || BPF_MODE(code) == BPF_PROBE_MEMSX) {
                                EMIT(PPC_RAW_ADDI(tmp1_reg, src_reg, off));
                                if (IS_ENABLED(CONFIG_PPC_BOOK3E_64))
                                        PPC_LI64(tmp2_reg, 0x8000000000000000ul);
@@ -966,30 +972,47 @@ emit_clear:
                                 * Check if 'off' is word aligned for BPF_DW, because
                                 * we might generate two instructions.
                                 */
-                               if (BPF_SIZE(code) == BPF_DW && (off & 3))
+                               if ((BPF_SIZE(code) == BPF_DW ||
+                                   (BPF_SIZE(code) == BPF_B && BPF_MODE(code) == BPF_PROBE_MEMSX)) &&
+                                               (off & 3))
                                        PPC_JMP((ctx->idx + 3) * 4);
                                else
                                        PPC_JMP((ctx->idx + 2) * 4);
                        }
 
-                       switch (size) {
-                       case BPF_B:
-                               EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
-                               break;
-                       case BPF_H:
-                               EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
-                               break;
-                       case BPF_W:
-                               EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
-                               break;
-                       case BPF_DW:
-                               if (off % 4) {
-                                       EMIT(PPC_RAW_LI(tmp1_reg, off));
-                                       EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg));
-                               } else {
-                                       EMIT(PPC_RAW_LD(dst_reg, src_reg, off));
+                       if (BPF_MODE(code) == BPF_MEMSX || BPF_MODE(code) == BPF_PROBE_MEMSX) {
+                               switch (size) {
+                               case BPF_B:
+                                       EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+                                       EMIT(PPC_RAW_EXTSB(dst_reg, dst_reg));
+                                       break;
+                               case BPF_H:
+                                       EMIT(PPC_RAW_LHA(dst_reg, src_reg, off));
+                                       break;
+                               case BPF_W:
+                                       EMIT(PPC_RAW_LWA(dst_reg, src_reg, off));
+                                       break;
+                               }
+                       } else {
+                               switch (size) {
+                               case BPF_B:
+                                       EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+                                       break;
+                               case BPF_H:
+                                       EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+                                       break;
+                               case BPF_W:
+                                       EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+                                       break;
+                               case BPF_DW:
+                                       if (off % 4) {
+                                               EMIT(PPC_RAW_LI(tmp1_reg, off));
+                                               EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg));
+                                       } else {
+                                               EMIT(PPC_RAW_LD(dst_reg, src_reg, off));
+                                       }
+                                       break;
                                }
-                               break;
                        }
 
                        if (size != BPF_DW && insn_is_zext(&insn[i + 1]))