Skip to content

Commit 156d0e2

Browse files
rnavmpe
authored andcommitted
powerpc/ebpf/jit: Implement JIT compiler for extended BPF
PPC64 eBPF JIT compiler. Enable with: echo 1 > /proc/sys/net/core/bpf_jit_enable or echo 2 > /proc/sys/net/core/bpf_jit_enable ... to see the generated JIT code. This can further be processed with tools/net/bpf_jit_disasm. With CONFIG_TEST_BPF=m and 'modprobe test_bpf': test_bpf: Summary: 305 PASSED, 0 FAILED, [297/297 JIT'ed] ... on both ppc64 BE and LE. The details of the approach are documented through various comments in the code. Acked-by: Alexei Starovoitov <[email protected]> Signed-off-by: Naveen N. Rao <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 6ac0ba5 commit 156d0e2

File tree

8 files changed

+1315
-3
lines changed

8 files changed

+1315
-3
lines changed

Diff for: arch/powerpc/Kconfig

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ config PPC
128128
select IRQ_FORCED_THREADING
129129
select HAVE_RCU_TABLE_FREE if SMP
130130
select HAVE_SYSCALL_TRACEPOINTS
131-
select HAVE_CBPF_JIT
131+
select HAVE_CBPF_JIT if !PPC64
132+
select HAVE_EBPF_JIT if PPC64
132133
select HAVE_ARCH_JUMP_LABEL
133134
select ARCH_HAVE_NMI_SAFE_CMPXCHG
134135
select ARCH_HAS_GCOV_PROFILE_ALL

Diff for: arch/powerpc/include/asm/asm-compat.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@
3636
#define PPC_MIN_STKFRM 112
3737

3838
#ifdef __BIG_ENDIAN__
39+
#define LHZX_BE stringify_in_c(lhzx)
3940
#define LWZX_BE stringify_in_c(lwzx)
4041
#define LDX_BE stringify_in_c(ldx)
4142
#define STWX_BE stringify_in_c(stwx)
4243
#define STDX_BE stringify_in_c(stdx)
4344
#else
45+
#define LHZX_BE stringify_in_c(lhbrx)
4446
#define LWZX_BE stringify_in_c(lwbrx)
4547
#define LDX_BE stringify_in_c(ldbrx)
4648
#define STWX_BE stringify_in_c(stwbrx)

Diff for: arch/powerpc/include/asm/ppc-opcode.h

+19-1
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,11 @@
142142
#define PPC_INST_ISEL 0x7c00001e
143143
#define PPC_INST_ISEL_MASK 0xfc00003e
144144
#define PPC_INST_LDARX 0x7c0000a8
145+
#define PPC_INST_STDCX 0x7c0001ad
145146
#define PPC_INST_LSWI 0x7c0004aa
146147
#define PPC_INST_LSWX 0x7c00042a
147148
#define PPC_INST_LWARX 0x7c000028
149+
#define PPC_INST_STWCX 0x7c00012d
148150
#define PPC_INST_LWSYNC 0x7c2004ac
149151
#define PPC_INST_SYNC 0x7c0004ac
150152
#define PPC_INST_SYNC_MASK 0xfc0007fe
@@ -211,8 +213,11 @@
211213
#define PPC_INST_LBZ 0x88000000
212214
#define PPC_INST_LD 0xe8000000
213215
#define PPC_INST_LHZ 0xa0000000
214-
#define PPC_INST_LHBRX 0x7c00062c
215216
#define PPC_INST_LWZ 0x80000000
217+
#define PPC_INST_LHBRX 0x7c00062c
218+
#define PPC_INST_LDBRX 0x7c000428
219+
#define PPC_INST_STB 0x98000000
220+
#define PPC_INST_STH 0xb0000000
216221
#define PPC_INST_STD 0xf8000000
217222
#define PPC_INST_STDU 0xf8000001
218223
#define PPC_INST_STW 0x90000000
@@ -221,22 +226,34 @@
221226
#define PPC_INST_MTLR 0x7c0803a6
222227
#define PPC_INST_CMPWI 0x2c000000
223228
#define PPC_INST_CMPDI 0x2c200000
229+
#define PPC_INST_CMPW 0x7c000000
230+
#define PPC_INST_CMPD 0x7c200000
224231
#define PPC_INST_CMPLW 0x7c000040
232+
#define PPC_INST_CMPLD 0x7c200040
225233
#define PPC_INST_CMPLWI 0x28000000
234+
#define PPC_INST_CMPLDI 0x28200000
226235
#define PPC_INST_ADDI 0x38000000
227236
#define PPC_INST_ADDIS 0x3c000000
228237
#define PPC_INST_ADD 0x7c000214
229238
#define PPC_INST_SUB 0x7c000050
230239
#define PPC_INST_BLR 0x4e800020
231240
#define PPC_INST_BLRL 0x4e800021
241+
#define PPC_INST_MULLD 0x7c0001d2
232242
#define PPC_INST_MULLW 0x7c0001d6
233243
#define PPC_INST_MULHWU 0x7c000016
234244
#define PPC_INST_MULLI 0x1c000000
235245
#define PPC_INST_DIVWU 0x7c000396
246+
#define PPC_INST_DIVD 0x7c0003d2
236247
#define PPC_INST_RLWINM 0x54000000
248+
#define PPC_INST_RLWIMI 0x50000000
249+
#define PPC_INST_RLDICL 0x78000000
237250
#define PPC_INST_RLDICR 0x78000004
238251
#define PPC_INST_SLW 0x7c000030
252+
#define PPC_INST_SLD 0x7c000036
239253
#define PPC_INST_SRW 0x7c000430
254+
#define PPC_INST_SRD 0x7c000436
255+
#define PPC_INST_SRAD 0x7c000634
256+
#define PPC_INST_SRADI 0x7c000674
240257
#define PPC_INST_AND 0x7c000038
241258
#define PPC_INST_ANDDOT 0x7c000039
242259
#define PPC_INST_OR 0x7c000378
@@ -247,6 +264,7 @@
247264
#define PPC_INST_XORI 0x68000000
248265
#define PPC_INST_XORIS 0x6c000000
249266
#define PPC_INST_NEG 0x7c0000d0
267+
#define PPC_INST_EXTSW 0x7c0007b4
250268
#define PPC_INST_BRANCH 0x48000000
251269
#define PPC_INST_BRANCH_COND 0x40800000
252270
#define PPC_INST_LBZCIX 0x7c0006aa

Diff for: arch/powerpc/net/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
#
22
# Arch-specific network modules
33
#
4+
ifeq ($(CONFIG_PPC64),y)
5+
obj-$(CONFIG_BPF_JIT) += bpf_jit_asm64.o bpf_jit_comp64.o
6+
else
47
obj-$(CONFIG_BPF_JIT) += bpf_jit_asm.o bpf_jit_comp.o
8+
endif

Diff for: arch/powerpc/net/bpf_jit.h

+52-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* bpf_jit.h: BPF JIT compiler for PPC
33
*
44
* Copyright 2011 Matt Evans <[email protected]>, IBM Corporation
5+
* 2016 Naveen N. Rao <[email protected]>
56
*
67
* This program is free software; you can redistribute it and/or
78
* modify it under the terms of the GNU General Public License
@@ -13,7 +14,9 @@
1314

1415
#ifndef __ASSEMBLY__
1516

16-
#ifdef CONFIG_PPC64
17+
#include <asm/types.h>
18+
19+
#ifdef PPC64_ELF_ABI_v1
1720
#define FUNCTION_DESCR_SIZE 24
1821
#else
1922
#define FUNCTION_DESCR_SIZE 0
@@ -52,6 +55,10 @@
5255
___PPC_RA(base) | IMM_L(i))
5356
#define PPC_STWU(r, base, i) EMIT(PPC_INST_STWU | ___PPC_RS(r) | \
5457
___PPC_RA(base) | IMM_L(i))
58+
#define PPC_STH(r, base, i) EMIT(PPC_INST_STH | ___PPC_RS(r) | \
59+
___PPC_RA(base) | IMM_L(i))
60+
#define PPC_STB(r, base, i) EMIT(PPC_INST_STB | ___PPC_RS(r) | \
61+
___PPC_RA(base) | IMM_L(i))
5562

5663
#define PPC_LBZ(r, base, i) EMIT(PPC_INST_LBZ | ___PPC_RT(r) | \
5764
___PPC_RA(base) | IMM_L(i))
@@ -63,6 +70,19 @@
6370
___PPC_RA(base) | IMM_L(i))
6471
#define PPC_LHBRX(r, base, b) EMIT(PPC_INST_LHBRX | ___PPC_RT(r) | \
6572
___PPC_RA(base) | ___PPC_RB(b))
73+
#define PPC_LDBRX(r, base, b) EMIT(PPC_INST_LDBRX | ___PPC_RT(r) | \
74+
___PPC_RA(base) | ___PPC_RB(b))
75+
76+
#define PPC_BPF_LDARX(t, a, b, eh) EMIT(PPC_INST_LDARX | ___PPC_RT(t) | \
77+
___PPC_RA(a) | ___PPC_RB(b) | \
78+
__PPC_EH(eh))
79+
#define PPC_BPF_LWARX(t, a, b, eh) EMIT(PPC_INST_LWARX | ___PPC_RT(t) | \
80+
___PPC_RA(a) | ___PPC_RB(b) | \
81+
__PPC_EH(eh))
82+
#define PPC_BPF_STWCX(s, a, b) EMIT(PPC_INST_STWCX | ___PPC_RS(s) | \
83+
___PPC_RA(a) | ___PPC_RB(b))
84+
#define PPC_BPF_STDCX(s, a, b) EMIT(PPC_INST_STDCX | ___PPC_RS(s) | \
85+
___PPC_RA(a) | ___PPC_RB(b))
6686

6787
#ifdef CONFIG_PPC64
6888
#define PPC_BPF_LL(r, base, i) do { PPC_LD(r, base, i); } while(0)
@@ -76,14 +96,23 @@
7696

7797
#define PPC_CMPWI(a, i) EMIT(PPC_INST_CMPWI | ___PPC_RA(a) | IMM_L(i))
7898
#define PPC_CMPDI(a, i) EMIT(PPC_INST_CMPDI | ___PPC_RA(a) | IMM_L(i))
99+
#define PPC_CMPW(a, b) EMIT(PPC_INST_CMPW | ___PPC_RA(a) | \
100+
___PPC_RB(b))
101+
#define PPC_CMPD(a, b) EMIT(PPC_INST_CMPD | ___PPC_RA(a) | \
102+
___PPC_RB(b))
79103
#define PPC_CMPLWI(a, i) EMIT(PPC_INST_CMPLWI | ___PPC_RA(a) | IMM_L(i))
104+
#define PPC_CMPLDI(a, i) EMIT(PPC_INST_CMPLDI | ___PPC_RA(a) | IMM_L(i))
80105
#define PPC_CMPLW(a, b) EMIT(PPC_INST_CMPLW | ___PPC_RA(a) | \
81106
___PPC_RB(b))
107+
#define PPC_CMPLD(a, b) EMIT(PPC_INST_CMPLD | ___PPC_RA(a) | \
108+
___PPC_RB(b))
82109

83110
#define PPC_SUB(d, a, b) EMIT(PPC_INST_SUB | ___PPC_RT(d) | \
84111
___PPC_RB(a) | ___PPC_RA(b))
85112
#define PPC_ADD(d, a, b) EMIT(PPC_INST_ADD | ___PPC_RT(d) | \
86113
___PPC_RA(a) | ___PPC_RB(b))
114+
#define PPC_MULD(d, a, b) EMIT(PPC_INST_MULLD | ___PPC_RT(d) | \
115+
___PPC_RA(a) | ___PPC_RB(b))
87116
#define PPC_MULW(d, a, b) EMIT(PPC_INST_MULLW | ___PPC_RT(d) | \
88117
___PPC_RA(a) | ___PPC_RB(b))
89118
#define PPC_MULHWU(d, a, b) EMIT(PPC_INST_MULHWU | ___PPC_RT(d) | \
@@ -92,6 +121,8 @@
92121
___PPC_RA(a) | IMM_L(i))
93122
#define PPC_DIVWU(d, a, b) EMIT(PPC_INST_DIVWU | ___PPC_RT(d) | \
94123
___PPC_RA(a) | ___PPC_RB(b))
124+
#define PPC_DIVD(d, a, b) EMIT(PPC_INST_DIVD | ___PPC_RT(d) | \
125+
___PPC_RA(a) | ___PPC_RB(b))
95126
#define PPC_AND(d, a, b) EMIT(PPC_INST_AND | ___PPC_RA(d) | \
96127
___PPC_RS(a) | ___PPC_RB(b))
97128
#define PPC_ANDI(d, a, i) EMIT(PPC_INST_ANDI | ___PPC_RA(d) | \
@@ -100,6 +131,7 @@
100131
___PPC_RS(a) | ___PPC_RB(b))
101132
#define PPC_OR(d, a, b) EMIT(PPC_INST_OR | ___PPC_RA(d) | \
102133
___PPC_RS(a) | ___PPC_RB(b))
134+
#define PPC_MR(d, a) PPC_OR(d, a, a)
103135
#define PPC_ORI(d, a, i) EMIT(PPC_INST_ORI | ___PPC_RA(d) | \
104136
___PPC_RS(a) | IMM_L(i))
105137
#define PPC_ORIS(d, a, i) EMIT(PPC_INST_ORIS | ___PPC_RA(d) | \
@@ -110,13 +142,30 @@
110142
___PPC_RS(a) | IMM_L(i))
111143
#define PPC_XORIS(d, a, i) EMIT(PPC_INST_XORIS | ___PPC_RA(d) | \
112144
___PPC_RS(a) | IMM_L(i))
145+
#define PPC_EXTSW(d, a) EMIT(PPC_INST_EXTSW | ___PPC_RA(d) | \
146+
___PPC_RS(a))
113147
#define PPC_SLW(d, a, s) EMIT(PPC_INST_SLW | ___PPC_RA(d) | \
114148
___PPC_RS(a) | ___PPC_RB(s))
149+
#define PPC_SLD(d, a, s) EMIT(PPC_INST_SLD | ___PPC_RA(d) | \
150+
___PPC_RS(a) | ___PPC_RB(s))
115151
#define PPC_SRW(d, a, s) EMIT(PPC_INST_SRW | ___PPC_RA(d) | \
116152
___PPC_RS(a) | ___PPC_RB(s))
153+
#define PPC_SRD(d, a, s) EMIT(PPC_INST_SRD | ___PPC_RA(d) | \
154+
___PPC_RS(a) | ___PPC_RB(s))
155+
#define PPC_SRAD(d, a, s) EMIT(PPC_INST_SRAD | ___PPC_RA(d) | \
156+
___PPC_RS(a) | ___PPC_RB(s))
157+
#define PPC_SRADI(d, a, i) EMIT(PPC_INST_SRADI | ___PPC_RA(d) | \
158+
___PPC_RS(a) | __PPC_SH(i) | \
159+
(((i) & 0x20) >> 4))
117160
#define PPC_RLWINM(d, a, i, mb, me) EMIT(PPC_INST_RLWINM | ___PPC_RA(d) | \
118161
___PPC_RS(a) | __PPC_SH(i) | \
119162
__PPC_MB(mb) | __PPC_ME(me))
163+
#define PPC_RLWIMI(d, a, i, mb, me) EMIT(PPC_INST_RLWIMI | ___PPC_RA(d) | \
164+
___PPC_RS(a) | __PPC_SH(i) | \
165+
__PPC_MB(mb) | __PPC_ME(me))
166+
#define PPC_RLDICL(d, a, i, mb) EMIT(PPC_INST_RLDICL | ___PPC_RA(d) | \
167+
___PPC_RS(a) | __PPC_SH(i) | \
168+
__PPC_MB64(mb) | (((i) & 0x20) >> 4))
120169
#define PPC_RLDICR(d, a, i, me) EMIT(PPC_INST_RLDICR | ___PPC_RA(d) | \
121170
___PPC_RS(a) | __PPC_SH(i) | \
122171
__PPC_ME64(me) | (((i) & 0x20) >> 4))
@@ -127,6 +176,8 @@
127176
#define PPC_SRWI(d, a, i) PPC_RLWINM(d, a, 32-(i), i, 31)
128177
/* sldi = rldicr Rx, Ry, n, 63-n */
129178
#define PPC_SLDI(d, a, i) PPC_RLDICR(d, a, i, 63-(i))
179+
/* sldi = rldicl Rx, Ry, 64-n, n */
180+
#define PPC_SRDI(d, a, i) PPC_RLDICL(d, a, 64-(i), i)
130181

131182
#define PPC_NEG(d, a) EMIT(PPC_INST_NEG | ___PPC_RT(d) | ___PPC_RA(a))
132183

Diff for: arch/powerpc/net/bpf_jit64.h

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* bpf_jit64.h: BPF JIT compiler for PPC64
3+
*
4+
* Copyright 2016 Naveen N. Rao <[email protected]>
5+
* IBM Corporation
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation; version 2
10+
* of the License.
11+
*/
12+
#ifndef _BPF_JIT64_H
13+
#define _BPF_JIT64_H
14+
15+
#include "bpf_jit.h"
16+
17+
/*
18+
* Stack layout:
19+
*
20+
* [ prev sp ] <-------------
21+
* [ nv gpr save area ] 8*8 |
22+
* fp (r31) --> [ ebpf stack space ] 512 |
23+
* [ local/tmp var space ] 16 |
24+
* [ frame header ] 32/112 |
25+
* sp (r1) ---> [ stack pointer ] --------------
26+
*/
27+
28+
/* for bpf JIT code internal usage */
29+
#define BPF_PPC_STACK_LOCALS 16
30+
/* for gpr non volatile registers BPG_REG_6 to 10, plus skb cache registers */
31+
#define BPF_PPC_STACK_SAVE (8*8)
32+
/* Ensure this is quadword aligned */
33+
#define BPF_PPC_STACKFRAME (STACK_FRAME_MIN_SIZE + BPF_PPC_STACK_LOCALS + \
34+
MAX_BPF_STACK + BPF_PPC_STACK_SAVE)
35+
36+
#ifndef __ASSEMBLY__
37+
38+
/* BPF register usage */
39+
#define SKB_HLEN_REG (MAX_BPF_REG + 0)
40+
#define SKB_DATA_REG (MAX_BPF_REG + 1)
41+
#define TMP_REG_1 (MAX_BPF_REG + 2)
42+
#define TMP_REG_2 (MAX_BPF_REG + 3)
43+
44+
/* BPF to ppc register mappings */
45+
static const int b2p[] = {
46+
/* function return value */
47+
[BPF_REG_0] = 8,
48+
/* function arguments */
49+
[BPF_REG_1] = 3,
50+
[BPF_REG_2] = 4,
51+
[BPF_REG_3] = 5,
52+
[BPF_REG_4] = 6,
53+
[BPF_REG_5] = 7,
54+
/* non volatile registers */
55+
[BPF_REG_6] = 27,
56+
[BPF_REG_7] = 28,
57+
[BPF_REG_8] = 29,
58+
[BPF_REG_9] = 30,
59+
/* frame pointer aka BPF_REG_10 */
60+
[BPF_REG_FP] = 31,
61+
/* eBPF jit internal registers */
62+
[SKB_HLEN_REG] = 25,
63+
[SKB_DATA_REG] = 26,
64+
[TMP_REG_1] = 9,
65+
[TMP_REG_2] = 10
66+
};
67+
68+
/* Assembly helpers */
69+
#define DECLARE_LOAD_FUNC(func) u64 func(u64 r3, u64 r4); \
70+
u64 func##_negative_offset(u64 r3, u64 r4); \
71+
u64 func##_positive_offset(u64 r3, u64 r4);
72+
73+
DECLARE_LOAD_FUNC(sk_load_word);
74+
DECLARE_LOAD_FUNC(sk_load_half);
75+
DECLARE_LOAD_FUNC(sk_load_byte);
76+
77+
#define CHOOSE_LOAD_FUNC(imm, func) \
78+
(imm < 0 ? \
79+
(imm >= SKF_LL_OFF ? func##_negative_offset : func) : \
80+
func##_positive_offset)
81+
82+
#define SEEN_FUNC 0x1000 /* might call external helpers */
83+
#define SEEN_STACK 0x2000 /* uses BPF stack */
84+
#define SEEN_SKB 0x4000 /* uses sk_buff */
85+
86+
struct codegen_context {
87+
/*
88+
* This is used to track register usage as well
89+
* as calls to external helpers.
90+
* - register usage is tracked with corresponding
91+
* bits (r3-r10 and r25-r31)
92+
* - rest of the bits can be used to track other
93+
* things -- for now, we use bits 16 to 23
94+
* encoded in SEEN_* macros above
95+
*/
96+
unsigned int seen;
97+
unsigned int idx;
98+
};
99+
100+
#endif /* !__ASSEMBLY__ */
101+
102+
#endif

0 commit comments

Comments
 (0)