diff options
author | Philippe Bergheaud <felix@linux.vnet.ibm.com> | 2013-09-24 08:13:35 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-10-31 01:19:15 -0400 |
commit | 9c662cad2fb66ff3a44b1d4f545bf496bf67ab10 (patch) | |
tree | 631ffe0b18388dd7010c2ad36765307816e8ae22 /arch/powerpc/net | |
parent | 711b5138d54fcfd5e312cea895d6e706a46eff19 (diff) |
powerpc/bpf: BPF JIT compiler for 64-bit Little Endian
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>
Diffstat (limited to 'arch/powerpc/net')
-rw-r--r-- | arch/powerpc/net/bpf_jit.h | 10 | ||||
-rw-r--r-- | arch/powerpc/net/bpf_jit_64.S | 9 | ||||
-rw-r--r-- | arch/powerpc/net/bpf_jit_comp.c | 17 |
3 files changed, 20 insertions, 16 deletions
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h index 8a5dfaf5c6b7..0baf2b826e25 100644 --- a/arch/powerpc/net/bpf_jit.h +++ b/arch/powerpc/net/bpf_jit.h | |||
@@ -92,6 +92,8 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh); | |||
92 | ___PPC_RA(base) | IMM_L(i)) | 92 | ___PPC_RA(base) | IMM_L(i)) |
93 | #define PPC_LHZ(r, base, i) EMIT(PPC_INST_LHZ | ___PPC_RT(r) | \ | 93 | #define PPC_LHZ(r, base, i) EMIT(PPC_INST_LHZ | ___PPC_RT(r) | \ |
94 | ___PPC_RA(base) | IMM_L(i)) | 94 | ___PPC_RA(base) | IMM_L(i)) |
95 | #define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \ | ||
96 | ___PPC_RA(base) | ___PPC_RB(b)) | ||
95 | /* Convenience helpers for the above with 'far' offsets: */ | 97 | /* Convenience helpers for the above with 'far' offsets: */ |
96 | #define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \ | 98 | #define PPC_LD_OFFS(r, base, i) do { if ((i) < 32768) PPC_LD(r, base, i); \ |
97 | else { PPC_ADDIS(r, base, IMM_HA(i)); \ | 99 | else { PPC_ADDIS(r, base, IMM_HA(i)); \ |
@@ -186,6 +188,14 @@ DECLARE_LOAD_FUNC(sk_load_byte_msh); | |||
186 | PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \ | 188 | PPC_ORI(d, d, (uintptr_t)(i) & 0xffff); \ |
187 | } } while (0); | 189 | } } while (0); |
188 | 190 | ||
191 | #define PPC_LHBRX_OFFS(r, base, i) \ | ||
192 | do { PPC_LI32(r, i); PPC_LHBRX(r, r, base); } while(0) | ||
193 | #ifdef __LITTLE_ENDIAN__ | ||
194 | #define PPC_NTOHS_OFFS(r, base, i) PPC_LHBRX_OFFS(r, base, i) | ||
195 | #else | ||
196 | #define PPC_NTOHS_OFFS(r, base, i) PPC_LHZ_OFFS(r, base, i) | ||
197 | #endif | ||
198 | |||
189 | static inline bool is_nearbranch(int offset) | 199 | static inline bool is_nearbranch(int offset) |
190 | { | 200 | { |
191 | return (offset < 32768) && (offset >= -32768); | 201 | return (offset < 32768) && (offset >= -32768); |
diff --git a/arch/powerpc/net/bpf_jit_64.S b/arch/powerpc/net/bpf_jit_64.S index 7d3a3b5619a2..e76eba74d9da 100644 --- a/arch/powerpc/net/bpf_jit_64.S +++ b/arch/powerpc/net/bpf_jit_64.S | |||
@@ -43,8 +43,11 @@ sk_load_word_positive_offset: | |||
43 | cmpd r_scratch1, r_addr | 43 | cmpd r_scratch1, r_addr |
44 | blt bpf_slow_path_word | 44 | blt bpf_slow_path_word |
45 | /* Nope, just hitting the header. cr0 here is eq or gt! */ | 45 | /* Nope, just hitting the header. cr0 here is eq or gt! */ |
46 | #ifdef __LITTLE_ENDIAN__ | ||
47 | lwbrx r_A, r_D, r_addr | ||
48 | #else | ||
46 | lwzx r_A, r_D, r_addr | 49 | lwzx r_A, r_D, r_addr |
47 | /* When big endian we don't need to byteswap. */ | 50 | #endif |
48 | blr /* Return success, cr0 != LT */ | 51 | blr /* Return success, cr0 != LT */ |
49 | 52 | ||
50 | .globl sk_load_half | 53 | .globl sk_load_half |
@@ -56,7 +59,11 @@ sk_load_half_positive_offset: | |||
56 | subi r_scratch1, r_HL, 2 | 59 | subi r_scratch1, r_HL, 2 |
57 | cmpd r_scratch1, r_addr | 60 | cmpd r_scratch1, r_addr |
58 | blt bpf_slow_path_half | 61 | blt bpf_slow_path_half |
62 | #ifdef __LITTLE_ENDIAN__ | ||
63 | lhbrx r_A, r_D, r_addr | ||
64 | #else | ||
59 | lhzx r_A, r_D, r_addr | 65 | lhzx r_A, r_D, r_addr |
66 | #endif | ||
60 | blr | 67 | blr |
61 | 68 | ||
62 | .globl sk_load_byte | 69 | .globl sk_load_byte |
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index bf56e33f8257..81cd6c79babe 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c | |||
@@ -17,14 +17,8 @@ | |||
17 | 17 | ||
18 | #include "bpf_jit.h" | 18 | #include "bpf_jit.h" |
19 | 19 | ||
20 | #ifndef __BIG_ENDIAN | ||
21 | /* There are endianness assumptions herein. */ | ||
22 | #error "Little-endian PPC not supported in BPF compiler" | ||
23 | #endif | ||
24 | |||
25 | int bpf_jit_enable __read_mostly; | 20 | int bpf_jit_enable __read_mostly; |
26 | 21 | ||
27 | |||
28 | static inline void bpf_flush_icache(void *start, void *end) | 22 | static inline void bpf_flush_icache(void *start, void *end) |
29 | { | 23 | { |
30 | smp_wmb(); | 24 | smp_wmb(); |
@@ -346,18 +340,11 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image, | |||
346 | break; | 340 | break; |
347 | 341 | ||
348 | /*** Ancillary info loads ***/ | 342 | /*** Ancillary info loads ***/ |
349 | |||
350 | /* None of the BPF_S_ANC* codes appear to be passed by | ||
351 | * sk_chk_filter(). The interpreter and the x86 BPF | ||
352 | * compiler implement them so we do too -- they may be | ||
353 | * planted in future. | ||
354 | */ | ||
355 | case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ | 343 | case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */ |
356 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, | 344 | BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, |
357 | protocol) != 2); | 345 | protocol) != 2); |
358 | PPC_LHZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, | 346 | PPC_NTOHS_OFFS(r_A, r_skb, offsetof(struct sk_buff, |
359 | protocol)); | 347 | protocol)); |
360 | /* ntohs is a NOP with BE loads. */ | ||
361 | break; | 348 | break; |
362 | case BPF_S_ANC_IFINDEX: | 349 | case BPF_S_ANC_IFINDEX: |
363 | PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff, | 350 | PPC_LD_OFFS(r_scratch1, r_skb, offsetof(struct sk_buff, |