aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2014-05-13 22:50:45 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-15 16:31:30 -0400
commitf3c2af7ba17a83809806880062c9ad541744fb95 (patch)
tree883522e429e6268a4b79e3bb7f15046c87d5eda7
parent9509b1c150ebbffce0a0480ff21f43e3cd3b2c32 (diff)
net: filter: x86: split bpf_jit_compile()
Split bpf_jit_compile() into two functions to improve readability of for(pass++) loop. The change follows similar style of JIT compilers for arm, powerpc, s390 The body of new do_jit() was not reformatted to reduce noise in this patch, since the following patch replaces most of it. Tested with BPF testsuite. Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/x86/net/bpf_jit_comp.c157
1 files changed, 92 insertions, 65 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index dc017735bb91..c5fa7c9cb665 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -178,41 +178,26 @@ static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
178 return header; 178 return header;
179} 179}
180 180
181void bpf_jit_compile(struct sk_filter *fp) 181struct jit_context {
182 unsigned int cleanup_addr; /* epilogue code offset */
183 int pc_ret0; /* bpf index of first RET #0 instruction (if any) */
184 u8 seen;
185};
186
187static int do_jit(struct sk_filter *bpf_prog, int *addrs, u8 *image,
188 int oldproglen, struct jit_context *ctx)
182{ 189{
190 const struct sock_filter *filter = bpf_prog->insns;
191 int flen = bpf_prog->len;
183 u8 temp[64]; 192 u8 temp[64];
184 u8 *prog; 193 u8 *prog;
185 unsigned int proglen, oldproglen = 0; 194 int ilen, i, proglen;
186 int ilen, i;
187 int t_offset, f_offset; 195 int t_offset, f_offset;
188 u8 t_op, f_op, seen = 0, pass; 196 u8 t_op, f_op, seen = 0;
189 u8 *image = NULL;
190 struct bpf_binary_header *header = NULL;
191 u8 *func; 197 u8 *func;
192 int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */ 198 unsigned int cleanup_addr = ctx->cleanup_addr;
193 unsigned int cleanup_addr; /* epilogue code offset */ 199 u8 seen_or_pass0 = ctx->seen;
194 unsigned int *addrs;
195 const struct sock_filter *filter = fp->insns;
196 int flen = fp->len;
197
198 if (!bpf_jit_enable)
199 return;
200
201 addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
202 if (addrs == NULL)
203 return;
204
205 /* Before first pass, make a rough estimation of addrs[]
206 * each bpf instruction is translated to less than 64 bytes
207 */
208 for (proglen = 0, i = 0; i < flen; i++) {
209 proglen += 64;
210 addrs[i] = proglen;
211 }
212 cleanup_addr = proglen; /* epilogue address */
213 200
214 for (pass = 0; pass < 10; pass++) {
215 u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen;
216 /* no prologue/epilogue for trivial filters (RET something) */ 201 /* no prologue/epilogue for trivial filters (RET something) */
217 proglen = 0; 202 proglen = 0;
218 prog = temp; 203 prog = temp;
@@ -325,12 +310,12 @@ void bpf_jit_compile(struct sk_filter *fp)
325 case BPF_S_ALU_DIV_X: /* A /= X; */ 310 case BPF_S_ALU_DIV_X: /* A /= X; */
326 seen |= SEEN_XREG; 311 seen |= SEEN_XREG;
327 EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ 312 EMIT2(0x85, 0xdb); /* test %ebx,%ebx */
328 if (pc_ret0 > 0) { 313 if (ctx->pc_ret0 > 0) {
329 /* addrs[pc_ret0 - 1] is start address of target 314 /* addrs[pc_ret0 - 1] is start address of target
330 * (addrs[i] - 4) is the address following this jmp 315 * (addrs[i] - 4) is the address following this jmp
331 * ("xor %edx,%edx; div %ebx" being 4 bytes long) 316 * ("xor %edx,%edx; div %ebx" being 4 bytes long)
332 */ 317 */
333 EMIT_COND_JMP(X86_JE, addrs[pc_ret0 - 1] - 318 EMIT_COND_JMP(X86_JE, addrs[ctx->pc_ret0 - 1] -
334 (addrs[i] - 4)); 319 (addrs[i] - 4));
335 } else { 320 } else {
336 EMIT_COND_JMP(X86_JNE, 2 + 5); 321 EMIT_COND_JMP(X86_JNE, 2 + 5);
@@ -342,12 +327,12 @@ void bpf_jit_compile(struct sk_filter *fp)
342 case BPF_S_ALU_MOD_X: /* A %= X; */ 327 case BPF_S_ALU_MOD_X: /* A %= X; */
343 seen |= SEEN_XREG; 328 seen |= SEEN_XREG;
344 EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ 329 EMIT2(0x85, 0xdb); /* test %ebx,%ebx */
345 if (pc_ret0 > 0) { 330 if (ctx->pc_ret0 > 0) {
346 /* addrs[pc_ret0 - 1] is start address of target 331 /* addrs[pc_ret0 - 1] is start address of target
347 * (addrs[i] - 6) is the address following this jmp 332 * (addrs[i] - 6) is the address following this jmp
348 * ("xor %edx,%edx; div %ebx;mov %edx,%eax" being 6 bytes long) 333 * ("xor %edx,%edx; div %ebx;mov %edx,%eax" being 6 bytes long)
349 */ 334 */
350 EMIT_COND_JMP(X86_JE, addrs[pc_ret0 - 1] - 335 EMIT_COND_JMP(X86_JE, addrs[ctx->pc_ret0 - 1] -
351 (addrs[i] - 6)); 336 (addrs[i] - 6));
352 } else { 337 } else {
353 EMIT_COND_JMP(X86_JNE, 2 + 5); 338 EMIT_COND_JMP(X86_JNE, 2 + 5);
@@ -441,8 +426,8 @@ void bpf_jit_compile(struct sk_filter *fp)
441 break; 426 break;
442 case BPF_S_RET_K: 427 case BPF_S_RET_K:
443 if (!K) { 428 if (!K) {
444 if (pc_ret0 == -1) 429 if (ctx->pc_ret0 == -1)
445 pc_ret0 = i; 430 ctx->pc_ret0 = i;
446 CLEAR_A(); 431 CLEAR_A();
447 } else { 432 } else {
448 EMIT1_off32(0xb8, K); /* mov $imm32,%eax */ 433 EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
@@ -603,7 +588,7 @@ void bpf_jit_compile(struct sk_filter *fp)
603 int off = pkt_type_offset(); 588 int off = pkt_type_offset();
604 589
605 if (off < 0) 590 if (off < 0)
606 goto out; 591 return -EINVAL;
607 if (is_imm8(off)) { 592 if (is_imm8(off)) {
608 /* movzbl off8(%rdi),%eax */ 593 /* movzbl off8(%rdi),%eax */
609 EMIT4(0x0f, 0xb6, 0x47, off); 594 EMIT4(0x0f, 0xb6, 0x47, off);
@@ -725,36 +710,79 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
725 } 710 }
726 EMIT_COND_JMP(f_op, f_offset); 711 EMIT_COND_JMP(f_op, f_offset);
727 break; 712 break;
728 default: 713 default:
729 /* hmm, too complex filter, give up with jit compiler */ 714 /* hmm, too complex filter, give up with jit compiler */
730 goto out; 715 return -EINVAL;
731 } 716 }
732 ilen = prog - temp; 717 ilen = prog - temp;
733 if (image) { 718 if (image) {
734 if (unlikely(proglen + ilen > oldproglen)) { 719 if (unlikely(proglen + ilen > oldproglen)) {
735 pr_err("bpb_jit_compile fatal error\n"); 720 pr_err("bpb_jit_compile fatal error\n");
736 kfree(addrs); 721 return -EFAULT;
737 module_free(NULL, header);
738 return;
739 }
740 memcpy(image + proglen, temp, ilen);
741 } 722 }
742 proglen += ilen; 723 memcpy(image + proglen, temp, ilen);
743 addrs[i] = proglen;
744 prog = temp;
745 } 724 }
746 /* last bpf instruction is always a RET : 725 proglen += ilen;
747 * use it to give the cleanup instruction(s) addr 726 addrs[i] = proglen;
748 */ 727 prog = temp;
749 cleanup_addr = proglen - 1; /* ret */ 728 }
750 if (seen_or_pass0) 729 /* last bpf instruction is always a RET :
751 cleanup_addr -= 1; /* leaveq */ 730 * use it to give the cleanup instruction(s) addr
752 if (seen_or_pass0 & SEEN_XREG) 731 */
753 cleanup_addr -= 4; /* mov -8(%rbp),%rbx */ 732 ctx->cleanup_addr = proglen - 1; /* ret */
733 if (seen_or_pass0)
734 ctx->cleanup_addr -= 1; /* leaveq */
735 if (seen_or_pass0 & SEEN_XREG)
736 ctx->cleanup_addr -= 4; /* mov -8(%rbp),%rbx */
737
738 ctx->seen = seen;
739
740 return proglen;
741}
742
743void bpf_jit_compile(struct sk_filter *prog)
744{
745 struct bpf_binary_header *header = NULL;
746 int proglen, oldproglen = 0;
747 struct jit_context ctx = {};
748 u8 *image = NULL;
749 int *addrs;
750 int pass;
751 int i;
752
753 if (!bpf_jit_enable)
754 return;
754 755
756 if (!prog || !prog->len)
757 return;
758
759 addrs = kmalloc(prog->len * sizeof(*addrs), GFP_KERNEL);
760 if (!addrs)
761 return;
762
763 /* Before first pass, make a rough estimation of addrs[]
764 * each bpf instruction is translated to less than 64 bytes
765 */
766 for (proglen = 0, i = 0; i < prog->len; i++) {
767 proglen += 64;
768 addrs[i] = proglen;
769 }
770 ctx.cleanup_addr = proglen;
771 ctx.seen = SEEN_XREG | SEEN_DATAREF | SEEN_MEM;
772 ctx.pc_ret0 = -1;
773
774 for (pass = 0; pass < 10; pass++) {
775 proglen = do_jit(prog, addrs, image, oldproglen, &ctx);
776 if (proglen <= 0) {
777 image = NULL;
778 if (header)
779 module_free(NULL, header);
780 goto out;
781 }
755 if (image) { 782 if (image) {
756 if (proglen != oldproglen) 783 if (proglen != oldproglen)
757 pr_err("bpb_jit_compile proglen=%u != oldproglen=%u\n", proglen, oldproglen); 784 pr_err("bpf_jit: proglen=%d != oldproglen=%d\n",
785 proglen, oldproglen);
758 break; 786 break;
759 } 787 }
760 if (proglen == oldproglen) { 788 if (proglen == oldproglen) {
@@ -766,17 +794,16 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
766 } 794 }
767 795
768 if (bpf_jit_enable > 1) 796 if (bpf_jit_enable > 1)
769 bpf_jit_dump(flen, proglen, pass, image); 797 bpf_jit_dump(prog->len, proglen, 0, image);
770 798
771 if (image) { 799 if (image) {
772 bpf_flush_icache(header, image + proglen); 800 bpf_flush_icache(header, image + proglen);
773 set_memory_ro((unsigned long)header, header->pages); 801 set_memory_ro((unsigned long)header, header->pages);
774 fp->bpf_func = (void *)image; 802 prog->bpf_func = (void *)image;
775 fp->jited = 1; 803 prog->jited = 1;
776 } 804 }
777out: 805out:
778 kfree(addrs); 806 kfree(addrs);
779 return;
780} 807}
781 808
782static void bpf_jit_free_deferred(struct work_struct *work) 809static void bpf_jit_free_deferred(struct work_struct *work)