powerpc/bpf: BPF JIT compiler for 64-bit Little Endian
authorPhilippe Bergheaud <felix@linux.vnet.ibm.com>
Tue, 24 Sep 2013 12:13:35 +0000 (14:13 +0200)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 31 Oct 2013 05:19:15 +0000 (16:19 +1100)
This enables the Berkeley Packet Filter JIT compiler
for the PowerPC running in 64bit Little Endian.

Signed-off-by: Philippe Bergheaud <felix@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/net/bpf_jit.h
arch/powerpc/net/bpf_jit_64.S
arch/powerpc/net/bpf_jit_comp.c

index 442edee4b6aa5cba5306fddf2c84e82c890844d9..99f87906de1740022c7ee1d6f479740949bead19 100644 (file)
 /* Misc instructions for BPF compiler */
 #define PPC_INST_LD                    0xe8000000
 #define PPC_INST_LHZ                   0xa0000000
+#define PPC_INST_LHBRX                 0x7c00062c
 #define PPC_INST_LWZ                   0x80000000
 #define PPC_INST_STD                   0xf8000000
 #define PPC_INST_STDU                  0xf8000001
index 8a5dfaf5c6b73fc94c7ceab634d1bf679a4f06b1..0baf2b826e25cf1345a6f950ad861f6274895dc3 100644 (file)
@@ -92,6 +92,8 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
                                     ___PPC_RA(base) | IMM_L(i))
 #define PPC_LHZ(r, base, i)    EMIT(PPC_INST_LHZ | ___PPC_RT(r) |            \
                                     ___PPC_RA(base) | IMM_L(i))
+#define PPC_LHBRX(r, base, b)  EMIT(PPC_INST_LHBRX | ___PPC_RT(r) |          \
+                                    ___PPC_RA(base) | ___PPC_RB(b))
 /* Convenience helpers for the above with 'far' offsets: */
 #define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i);     \
                else {  PPC_ADDIS(r, base, IMM_HA(i));                        \
@@ -186,6 +188,14 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh);
                                PPC_ORI(d, d, (uintptr_t)(i) & 0xffff);       \
                } } while (0);
 
+#define PPC_LHBRX_OFFS(r, base, i) \
+               do { PPC_LI32(r, i); PPC_LHBRX(r, r, base); } while(0)
+#ifdef __LITTLE_ENDIAN__
+#define PPC_NTOHS_OFFS(r, base, i)     PPC_LHBRX_OFFS(r, base, i)
+#else
+#define PPC_NTOHS_OFFS(r, base, i)     PPC_LHZ_OFFS(r, base, i)
+#endif
+
 static inline bool is_nearbranch(int offset)
 {
        return (offset < 32768) && (offset >= -32768);
index 7d3a3b5619a2b8f2528b61dc7077b4dd84c594d2..e76eba74d9da8972afeed2525c755959c304dd6f 100644 (file)
@@ -43,8 +43,11 @@ sk_load_word_positive_offset:
        cmpd    r_scratch1, r_addr
        blt     bpf_slow_path_word
        /* Nope, just hitting the header.  cr0 here is eq or gt! */
+#ifdef __LITTLE_ENDIAN__
+       lwbrx   r_A, r_D, r_addr
+#else
        lwzx    r_A, r_D, r_addr
-       /* When big endian we don't need to byteswap. */
+#endif
        blr     /* Return success, cr0 != LT */
 
        .globl  sk_load_half
@@ -56,7 +59,11 @@ sk_load_half_positive_offset:
        subi    r_scratch1, r_HL, 2
        cmpd    r_scratch1, r_addr
        blt     bpf_slow_path_half
+#ifdef __LITTLE_ENDIAN__
+       lhbrx   r_A, r_D, r_addr
+#else
        lhzx    r_A, r_D, r_addr
+#endif
        blr
 
        .globl  sk_load_byte
index bf56e33f8257f68717b241c98abefb2f925f2858..81cd6c79babeb79c8d3904f12a890bfb6e99aa64 100644 (file)
 
 #include "bpf_jit.h"
 
-#ifndef __BIG_ENDIAN
-/* There are endianness assumptions herein. */
-#error "Little-endian PPC not supported in BPF compiler"
-#endif
-
 int bpf_jit_enable __read_mostly;
 
-
 static inline void bpf_flush_icache(void *start, void *end)
 {
        smp_wmb();
@@ -346,18 +340,11 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
                        break;
 
                        /*** Ancillary info loads ***/
-
-                       /* None of the BPF_S_ANC* codes appear to be passed by
-                        * sk_chk_filter().  The interpreter and the x86 BPF
-                        * compiler implement them so we do too -- they may be
-                        * planted in future.
-                        */
                case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
                        BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
                                                  protocol) != 2);
-                       PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
-                                                         protocol));
-                       /* ntohs is a NOP with BE loads. */
+                       PPC_NTOHS_OFFS(r_A, r_skb, offsetof(struct sk_buff,
+                                                           protocol));
                        break;
                case BPF_S_ANC_IFINDEX:
                        PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff,