aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>2016-09-23 16:35:01 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-10-04 05:33:19 -0400
commitce0761419faefbe9e450749ccc879ff88843af12 (patch)
treee11d3ae238cd82b7d59274f0491c9ca5f47e8e63
parent7b847f523fe07b4ad73a01cec49a4da86a9be412 (diff)
powerpc/bpf: Implement support for tail calls
Tail calls allow JIT'ed eBPF programs to call into other JIT'ed eBPF programs. This can be achieved either by: (1) retaining the stack setup by the first eBPF program and having all subsequent eBPF programs re-using it, or, (2) by unwinding/tearing down the stack and having each eBPF program deal with its own stack as it sees fit. To ensure that this does not create loops, there is a limit to how many tail calls can be done (currently 32). This requires the JIT'ed code to maintain a count of the number of tail calls done so far. Approach (1) is simple, but requires every eBPF program to have (almost) the same prologue/epilogue, regardless of whether they need it. This is inefficient for small eBPF programs which may not sometimes need a prologue at all. As such, to minimize impact of tail call implementation, we use approach (2) here which needs each eBPF program in the chain to use its own prologue/epilogue. This is not ideal when many tail calls are involved and when all the eBPF programs in the chain have similar prologue/epilogue. However, the impact is restricted to programs that do tail calls. Individual eBPF programs are not affected. We maintain the tail call count in a fixed location on the stack and updated tail call count values are passed in through this. The very first eBPF program in a chain sets this up to 0 (the first 2 instructions). Subsequent tail calls skip the first two eBPF JIT instructions to maintain the count. For programs that don't do tail calls themselves, the first two instructions are NOPs. Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h2
-rw-r--r--arch/powerpc/net/bpf_jit.h2
-rw-r--r--arch/powerpc/net/bpf_jit64.h1
-rw-r--r--arch/powerpc/net/bpf_jit_comp64.c149
4 files changed, 126 insertions, 28 deletions
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 127ebf5862b4..54ff8ce7fa96 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -236,6 +236,7 @@
236#define PPC_INST_STWU 0x94000000 236#define PPC_INST_STWU 0x94000000
237#define PPC_INST_MFLR 0x7c0802a6 237#define PPC_INST_MFLR 0x7c0802a6
238#define PPC_INST_MTLR 0x7c0803a6 238#define PPC_INST_MTLR 0x7c0803a6
239#define PPC_INST_MTCTR 0x7c0903a6
239#define PPC_INST_CMPWI 0x2c000000 240#define PPC_INST_CMPWI 0x2c000000
240#define PPC_INST_CMPDI 0x2c200000 241#define PPC_INST_CMPDI 0x2c200000
241#define PPC_INST_CMPW 0x7c000000 242#define PPC_INST_CMPW 0x7c000000
@@ -250,6 +251,7 @@
250#define PPC_INST_SUB 0x7c000050 251#define PPC_INST_SUB 0x7c000050
251#define PPC_INST_BLR 0x4e800020 252#define PPC_INST_BLR 0x4e800020
252#define PPC_INST_BLRL 0x4e800021 253#define PPC_INST_BLRL 0x4e800021
254#define PPC_INST_BCTR 0x4e800420
253#define PPC_INST_MULLD 0x7c0001d2 255#define PPC_INST_MULLD 0x7c0001d2
254#define PPC_INST_MULLW 0x7c0001d6 256#define PPC_INST_MULLW 0x7c0001d6
255#define PPC_INST_MULHWU 0x7c000016 257#define PPC_INST_MULHWU 0x7c000016
diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h
index d5301b6f20d0..89f70073dec8 100644
--- a/arch/powerpc/net/bpf_jit.h
+++ b/arch/powerpc/net/bpf_jit.h
@@ -40,6 +40,8 @@
40#define PPC_BLR() EMIT(PPC_INST_BLR) 40#define PPC_BLR() EMIT(PPC_INST_BLR)
41#define PPC_BLRL() EMIT(PPC_INST_BLRL) 41#define PPC_BLRL() EMIT(PPC_INST_BLRL)
42#define PPC_MTLR(r) EMIT(PPC_INST_MTLR | ___PPC_RT(r)) 42#define PPC_MTLR(r) EMIT(PPC_INST_MTLR | ___PPC_RT(r))
43#define PPC_BCTR() EMIT(PPC_INST_BCTR)
44#define PPC_MTCTR(r) EMIT(PPC_INST_MTCTR | ___PPC_RT(r))
43#define PPC_ADDI(d, a, i) EMIT(PPC_INST_ADDI | ___PPC_RT(d) | \ 45#define PPC_ADDI(d, a, i) EMIT(PPC_INST_ADDI | ___PPC_RT(d) | \
44 ___PPC_RA(a) | IMM_L(i)) 46 ___PPC_RA(a) | IMM_L(i))
45#define PPC_MR(d, a) PPC_OR(d, a, a) 47#define PPC_MR(d, a) PPC_OR(d, a, a)
diff --git a/arch/powerpc/net/bpf_jit64.h b/arch/powerpc/net/bpf_jit64.h
index a1645d7a4033..038e00bf2b77 100644
--- a/arch/powerpc/net/bpf_jit64.h
+++ b/arch/powerpc/net/bpf_jit64.h
@@ -88,6 +88,7 @@ DECLARE_LOAD_FUNC(sk_load_byte);
88#define SEEN_FUNC 0x1000 /* might call external helpers */ 88#define SEEN_FUNC 0x1000 /* might call external helpers */
89#define SEEN_STACK 0x2000 /* uses BPF stack */ 89#define SEEN_STACK 0x2000 /* uses BPF stack */
90#define SEEN_SKB 0x4000 /* uses sk_buff */ 90#define SEEN_SKB 0x4000 /* uses sk_buff */
91#define SEEN_TAILCALL 0x8000 /* uses tail calls */
91 92
92struct codegen_context { 93struct codegen_context {
93 /* 94 /*
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index 5f8c91fa612e..3ec29d6fba60 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -17,6 +17,7 @@
17#include <linux/filter.h> 17#include <linux/filter.h>
18#include <linux/if_vlan.h> 18#include <linux/if_vlan.h>
19#include <asm/kprobes.h> 19#include <asm/kprobes.h>
20#include <linux/bpf.h>
20 21
21#include "bpf_jit64.h" 22#include "bpf_jit64.h"
22 23
@@ -77,6 +78,11 @@ static int bpf_jit_stack_local(struct codegen_context *ctx)
77 return -(BPF_PPC_STACK_SAVE + 16); 78 return -(BPF_PPC_STACK_SAVE + 16);
78} 79}
79 80
81static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx)
82{
83 return bpf_jit_stack_local(ctx) + 8;
84}
85
80static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg) 86static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg)
81{ 87{
82 if (reg >= BPF_PPC_NVR_MIN && reg < 32) 88 if (reg >= BPF_PPC_NVR_MIN && reg < 32)
@@ -102,33 +108,25 @@ static void bpf_jit_emit_skb_loads(u32 *image, struct codegen_context *ctx)
102 PPC_BPF_LL(b2p[SKB_DATA_REG], 3, offsetof(struct sk_buff, data)); 108 PPC_BPF_LL(b2p[SKB_DATA_REG], 3, offsetof(struct sk_buff, data));
103} 109}
104 110
105static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) 111static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
106{ 112{
107#ifdef PPC64_ELF_ABI_v1 113 int i;
108 /* func points to the function descriptor */ 114
109 PPC_LI64(b2p[TMP_REG_2], func);
110 /* Load actual entry point from function descriptor */
111 PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
112 /* ... and move it to LR */
113 PPC_MTLR(b2p[TMP_REG_1]);
114 /* 115 /*
115 * Load TOC from function descriptor at offset 8. 116 * Initialize tail_call_cnt if we do tail calls.
116 * We can clobber r2 since we get called through a 117 * Otherwise, put in NOPs so that it can be skipped when we are
117 * function pointer (so caller will save/restore r2) 118 * invoked through a tail call.
118 * and since we don't use a TOC ourself.
119 */ 119 */
120 PPC_BPF_LL(2, b2p[TMP_REG_2], 8); 120 if (ctx->seen & SEEN_TAILCALL) {
121#else 121 PPC_LI(b2p[TMP_REG_1], 0);
122 /* We can clobber r12 */ 122 /* this goes in the redzone */
123 PPC_FUNC_ADDR(12, func); 123 PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8));
124 PPC_MTLR(12); 124 } else {
125#endif 125 PPC_NOP();
126 PPC_BLRL(); 126 PPC_NOP();
127} 127 }
128 128
129static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) 129#define BPF_TAILCALL_PROLOGUE_SIZE 8
130{
131 int i;
132 130
133 if (bpf_has_stack_frame(ctx)) { 131 if (bpf_has_stack_frame(ctx)) {
134 /* 132 /*
@@ -170,13 +168,10 @@ static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx)
170 STACK_FRAME_MIN_SIZE + MAX_BPF_STACK); 168 STACK_FRAME_MIN_SIZE + MAX_BPF_STACK);
171} 169}
172 170
173static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) 171static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx)
174{ 172{
175 int i; 173 int i;
176 174
177 /* Move result to r3 */
178 PPC_MR(3, b2p[BPF_REG_0]);
179
180 /* Restore NVRs */ 175 /* Restore NVRs */
181 for (i = BPF_REG_6; i <= BPF_REG_10; i++) 176 for (i = BPF_REG_6; i <= BPF_REG_10; i++)
182 if (bpf_is_seen_register(ctx, i)) 177 if (bpf_is_seen_register(ctx, i))
@@ -198,10 +193,105 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
198 PPC_MTLR(0); 193 PPC_MTLR(0);
199 } 194 }
200 } 195 }
196}
197
198static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
199{
200 bpf_jit_emit_common_epilogue(image, ctx);
201
202 /* Move result to r3 */
203 PPC_MR(3, b2p[BPF_REG_0]);
201 204
202 PPC_BLR(); 205 PPC_BLR();
203} 206}
204 207
208static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func)
209{
210#ifdef PPC64_ELF_ABI_v1
211 /* func points to the function descriptor */
212 PPC_LI64(b2p[TMP_REG_2], func);
213 /* Load actual entry point from function descriptor */
214 PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
215 /* ... and move it to LR */
216 PPC_MTLR(b2p[TMP_REG_1]);
217 /*
218 * Load TOC from function descriptor at offset 8.
219 * We can clobber r2 since we get called through a
220 * function pointer (so caller will save/restore r2)
221 * and since we don't use a TOC ourself.
222 */
223 PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
224#else
225 /* We can clobber r12 */
226 PPC_FUNC_ADDR(12, func);
227 PPC_MTLR(12);
228#endif
229 PPC_BLRL();
230}
231
232static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out)
233{
234 /*
235 * By now, the eBPF program has already setup parameters in r3, r4 and r5
236 * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program
237 * r4/BPF_REG_2 - pointer to bpf_array
238 * r5/BPF_REG_3 - index in bpf_array
239 */
240 int b2p_bpf_array = b2p[BPF_REG_2];
241 int b2p_index = b2p[BPF_REG_3];
242
243 /*
244 * if (index >= array->map.max_entries)
245 * goto out;
246 */
247 PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries));
248 PPC_CMPLW(b2p_index, b2p[TMP_REG_1]);
249 PPC_BCC(COND_GE, out);
250
251 /*
252 * if (tail_call_cnt > MAX_TAIL_CALL_CNT)
253 * goto out;
254 */
255 PPC_LD(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx));
256 PPC_CMPLWI(b2p[TMP_REG_1], MAX_TAIL_CALL_CNT);
257 PPC_BCC(COND_GT, out);
258
259 /*
260 * tail_call_cnt++;
261 */
262 PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1);
263 PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx));
264
265 /* prog = array->ptrs[index]; */
266 PPC_MULI(b2p[TMP_REG_1], b2p_index, 8);
267 PPC_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array);
268 PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs));
269
270 /*
271 * if (prog == NULL)
272 * goto out;
273 */
274 PPC_CMPLDI(b2p[TMP_REG_1], 0);
275 PPC_BCC(COND_EQ, out);
276
277 /* goto *(prog->bpf_func + prologue_size); */
278 PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func));
279#ifdef PPC64_ELF_ABI_v1
280 /* skip past the function descriptor */
281 PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1],
282 FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE);
283#else
284 PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE);
285#endif
286 PPC_MTCTR(b2p[TMP_REG_1]);
287
288 /* tear down stack, restore NVRs, ... */
289 bpf_jit_emit_common_epilogue(image, ctx);
290
291 PPC_BCTR();
292 /* out: */
293}
294
205/* Assemble the body code between the prologue & epilogue */ 295/* Assemble the body code between the prologue & epilogue */
206static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, 296static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
207 struct codegen_context *ctx, 297 struct codegen_context *ctx,
@@ -846,9 +936,12 @@ common_load:
846 break; 936 break;
847 937
848 /* 938 /*
849 * TODO: Tail call 939 * Tail call
850 */ 940 */
851 case BPF_JMP | BPF_CALL | BPF_X: 941 case BPF_JMP | BPF_CALL | BPF_X:
942 ctx->seen |= SEEN_TAILCALL;
943 bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]);
944 break;
852 945
853 default: 946 default:
854 /* 947 /*