]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/bpf_jit_machdep.c
Upgrade NetBSD tests to 01.11.2017_23.20 snapshot
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / bpf_jit_machdep.c
1 /*-
2  * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
3  * Copyright (C) 2005-2016 Jung-uk Kim <jkim@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the Politecnico di Torino nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #ifdef _KERNEL
36 #include "opt_bpf.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <net/if.h>
44 #else
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/mman.h>
48 #include <sys/param.h>
49 #endif
50
51 #include <sys/types.h>
52
53 #include <net/bpf.h>
54 #include <net/bpf_jitter.h>
55
56 #include <amd64/amd64/bpf_jit_machdep.h>
57
58 bpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, size_t *);
59
60 /*
61  * Emit routine to update the jump table.
62  */
63 static void
64 emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
65 {
66
67         if (stream->refs != NULL)
68                 (stream->refs)[stream->bpf_pc] += len;
69         stream->cur_ip += len;
70 }
71
72 /*
73  * Emit routine to output the actual binary code.
74  */
75 static void
76 emit_code(bpf_bin_stream *stream, u_int value, u_int len)
77 {
78
79         switch (len) {
80         case 1:
81                 stream->ibuf[stream->cur_ip] = (u_char)value;
82                 stream->cur_ip++;
83                 break;
84
85         case 2:
86                 *((u_short *)(void *)(stream->ibuf + stream->cur_ip)) =
87                     (u_short)value;
88                 stream->cur_ip += 2;
89                 break;
90
91         case 4:
92                 *((u_int *)(void *)(stream->ibuf + stream->cur_ip)) = value;
93                 stream->cur_ip += 4;
94                 break;
95         }
96
97         return;
98 }
99
100 /*
101  * Scan the filter program and find possible optimization.
102  */
103 static int
104 bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
105 {
106         int flags;
107         u_int i;
108
109         /* Do we return immediately? */
110         if (BPF_CLASS(prog[0].code) == BPF_RET)
111                 return (BPF_JIT_FRET);
112
113         for (flags = 0, i = 0; i < nins; i++) {
114                 switch (prog[i].code) {
115                 case BPF_LD|BPF_W|BPF_ABS:
116                 case BPF_LD|BPF_H|BPF_ABS:
117                 case BPF_LD|BPF_B|BPF_ABS:
118                 case BPF_LD|BPF_W|BPF_IND:
119                 case BPF_LD|BPF_H|BPF_IND:
120                 case BPF_LD|BPF_B|BPF_IND:
121                 case BPF_LDX|BPF_MSH|BPF_B:
122                         flags |= BPF_JIT_FPKT;
123                         break;
124                 case BPF_LD|BPF_MEM:
125                 case BPF_LDX|BPF_MEM:
126                 case BPF_ST:
127                 case BPF_STX:
128                         flags |= BPF_JIT_FMEM;
129                         break;
130                 case BPF_LD|BPF_W|BPF_LEN:
131                 case BPF_LDX|BPF_W|BPF_LEN:
132                         flags |= BPF_JIT_FLEN;
133                         break;
134                 case BPF_JMP|BPF_JA:
135                 case BPF_JMP|BPF_JGT|BPF_K:
136                 case BPF_JMP|BPF_JGE|BPF_K:
137                 case BPF_JMP|BPF_JEQ|BPF_K:
138                 case BPF_JMP|BPF_JSET|BPF_K:
139                 case BPF_JMP|BPF_JGT|BPF_X:
140                 case BPF_JMP|BPF_JGE|BPF_X:
141                 case BPF_JMP|BPF_JEQ|BPF_X:
142                 case BPF_JMP|BPF_JSET|BPF_X:
143                         flags |= BPF_JIT_FJMP;
144                         break;
145                 }
146                 if (flags == BPF_JIT_FLAG_ALL)
147                         break;
148         }
149
150         return (flags);
151 }
152
153 /*
154  * Function that does the real stuff.
155  */
156 bpf_filter_func
157 bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
158 {
159         bpf_bin_stream stream;
160         struct bpf_insn *ins;
161         int flags, fret, fpkt, fmem, fjmp, flen;
162         u_int i, pass;
163
164         /*
165          * NOTE: Do not modify the name of this variable, as it's used by
166          * the macros to emit code.
167          */
168         emit_func emitm;
169
170         flags = bpf_jit_optimize(prog, nins);
171         fret = (flags & BPF_JIT_FRET) != 0;
172         fpkt = (flags & BPF_JIT_FPKT) != 0;
173         fmem = (flags & BPF_JIT_FMEM) != 0;
174         fjmp = (flags & BPF_JIT_FJMP) != 0;
175         flen = (flags & BPF_JIT_FLEN) != 0;
176
177         if (fret)
178                 nins = 1;
179
180         memset(&stream, 0, sizeof(stream));
181
182         /* Allocate the reference table for the jumps. */
183         if (fjmp) {
184 #ifdef _KERNEL
185                 stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
186                     M_NOWAIT | M_ZERO);
187 #else
188                 stream.refs = calloc(nins + 1, sizeof(u_int));
189 #endif
190                 if (stream.refs == NULL)
191                         return (NULL);
192         }
193
194         /*
195          * The first pass will emit the lengths of the instructions
196          * to create the reference table.
197          */
198         emitm = emit_length;
199
200         for (pass = 0; pass < 2; pass++) {
201                 ins = prog;
202
203                 /* Create the procedure header. */
204                 if (fmem) {
205                         PUSH(RBP);
206                         MOVrq(RSP, RBP);
207                         SUBib(BPF_MEMWORDS * sizeof(uint32_t), RSP);
208                 }
209                 if (flen)
210                         MOVrd2(ESI, R9D);
211                 if (fpkt) {
212                         MOVrq2(RDI, R8);
213                         MOVrd(EDX, EDI);
214                 }
215
216                 for (i = 0; i < nins; i++) {
217                         stream.bpf_pc++;
218
219                         switch (ins->code) {
220                         default:
221 #ifdef _KERNEL
222                                 return (NULL);
223 #else
224                                 abort();
225 #endif
226
227                         case BPF_RET|BPF_K:
228                                 MOVid(ins->k, EAX);
229                                 if (fmem)
230                                         LEAVE();
231                                 RET();
232                                 break;
233
234                         case BPF_RET|BPF_A:
235                                 if (fmem)
236                                         LEAVE();
237                                 RET();
238                                 break;
239
240                         case BPF_LD|BPF_W|BPF_ABS:
241                                 MOVid(ins->k, ESI);
242                                 CMPrd(EDI, ESI);
243                                 JAb(12);
244                                 MOVrd(EDI, ECX);
245                                 SUBrd(ESI, ECX);
246                                 CMPid(sizeof(int32_t), ECX);
247                                 if (fmem) {
248                                         JAEb(4);
249                                         ZEROrd(EAX);
250                                         LEAVE();
251                                 } else {
252                                         JAEb(3);
253                                         ZEROrd(EAX);
254                                 }
255                                 RET();
256                                 MOVrq3(R8, RCX);
257                                 MOVobd(RCX, RSI, EAX);
258                                 BSWAP(EAX);
259                                 break;
260
261                         case BPF_LD|BPF_H|BPF_ABS:
262                                 ZEROrd(EAX);
263                                 MOVid(ins->k, ESI);
264                                 CMPrd(EDI, ESI);
265                                 JAb(12);
266                                 MOVrd(EDI, ECX);
267                                 SUBrd(ESI, ECX);
268                                 CMPid(sizeof(int16_t), ECX);
269                                 if (fmem) {
270                                         JAEb(2);
271                                         LEAVE();
272                                 } else
273                                         JAEb(1);
274                                 RET();
275                                 MOVrq3(R8, RCX);
276                                 MOVobw(RCX, RSI, AX);
277                                 SWAP_AX();
278                                 break;
279
280                         case BPF_LD|BPF_B|BPF_ABS:
281                                 ZEROrd(EAX);
282                                 MOVid(ins->k, ESI);
283                                 CMPrd(EDI, ESI);
284                                 if (fmem) {
285                                         JBb(2);
286                                         LEAVE();
287                                 } else
288                                         JBb(1);
289                                 RET();
290                                 MOVrq3(R8, RCX);
291                                 MOVobb(RCX, RSI, AL);
292                                 break;
293
294                         case BPF_LD|BPF_W|BPF_LEN:
295                                 MOVrd3(R9D, EAX);
296                                 break;
297
298                         case BPF_LDX|BPF_W|BPF_LEN:
299                                 MOVrd3(R9D, EDX);
300                                 break;
301
302                         case BPF_LD|BPF_W|BPF_IND:
303                                 CMPrd(EDI, EDX);
304                                 JAb(27);
305                                 MOVid(ins->k, ESI);
306                                 MOVrd(EDI, ECX);
307                                 SUBrd(EDX, ECX);
308                                 CMPrd(ESI, ECX);
309                                 JBb(14);
310                                 ADDrd(EDX, ESI);
311                                 MOVrd(EDI, ECX);
312                                 SUBrd(ESI, ECX);
313                                 CMPid(sizeof(int32_t), ECX);
314                                 if (fmem) {
315                                         JAEb(4);
316                                         ZEROrd(EAX);
317                                         LEAVE();
318                                 } else {
319                                         JAEb(3);
320                                         ZEROrd(EAX);
321                                 }
322                                 RET();
323                                 MOVrq3(R8, RCX);
324                                 MOVobd(RCX, RSI, EAX);
325                                 BSWAP(EAX);
326                                 break;
327
328                         case BPF_LD|BPF_H|BPF_IND:
329                                 ZEROrd(EAX);
330                                 CMPrd(EDI, EDX);
331                                 JAb(27);
332                                 MOVid(ins->k, ESI);
333                                 MOVrd(EDI, ECX);
334                                 SUBrd(EDX, ECX);
335                                 CMPrd(ESI, ECX);
336                                 JBb(14);
337                                 ADDrd(EDX, ESI);
338                                 MOVrd(EDI, ECX);
339                                 SUBrd(ESI, ECX);
340                                 CMPid(sizeof(int16_t), ECX);
341                                 if (fmem) {
342                                         JAEb(2);
343                                         LEAVE();
344                                 } else
345                                         JAEb(1);
346                                 RET();
347                                 MOVrq3(R8, RCX);
348                                 MOVobw(RCX, RSI, AX);
349                                 SWAP_AX();
350                                 break;
351
352                         case BPF_LD|BPF_B|BPF_IND:
353                                 ZEROrd(EAX);
354                                 CMPrd(EDI, EDX);
355                                 JAEb(13);
356                                 MOVid(ins->k, ESI);
357                                 MOVrd(EDI, ECX);
358                                 SUBrd(EDX, ECX);
359                                 CMPrd(ESI, ECX);
360                                 if (fmem) {
361                                         JAb(2);
362                                         LEAVE();
363                                 } else
364                                         JAb(1);
365                                 RET();
366                                 MOVrq3(R8, RCX);
367                                 ADDrd(EDX, ESI);
368                                 MOVobb(RCX, RSI, AL);
369                                 break;
370
371                         case BPF_LDX|BPF_MSH|BPF_B:
372                                 MOVid(ins->k, ESI);
373                                 CMPrd(EDI, ESI);
374                                 if (fmem) {
375                                         JBb(4);
376                                         ZEROrd(EAX);
377                                         LEAVE();
378                                 } else {
379                                         JBb(3);
380                                         ZEROrd(EAX);
381                                 }
382                                 RET();
383                                 ZEROrd(EDX);
384                                 MOVrq3(R8, RCX);
385                                 MOVobb(RCX, RSI, DL);
386                                 ANDib(0x0f, DL);
387                                 SHLib(2, EDX);
388                                 break;
389
390                         case BPF_LD|BPF_IMM:
391                                 MOVid(ins->k, EAX);
392                                 break;
393
394                         case BPF_LDX|BPF_IMM:
395                                 MOVid(ins->k, EDX);
396                                 break;
397
398                         case BPF_LD|BPF_MEM:
399                                 MOVid(ins->k * sizeof(uint32_t), ESI);
400                                 MOVobd(RSP, RSI, EAX);
401                                 break;
402
403                         case BPF_LDX|BPF_MEM:
404                                 MOVid(ins->k * sizeof(uint32_t), ESI);
405                                 MOVobd(RSP, RSI, EDX);
406                                 break;
407
408                         case BPF_ST:
409                                 /*
410                                  * XXX this command and the following could
411                                  * be optimized if the previous instruction
412                                  * was already of this type
413                                  */
414                                 MOVid(ins->k * sizeof(uint32_t), ESI);
415                                 MOVomd(EAX, RSP, RSI);
416                                 break;
417
418                         case BPF_STX:
419                                 MOVid(ins->k * sizeof(uint32_t), ESI);
420                                 MOVomd(EDX, RSP, RSI);
421                                 break;
422
423                         case BPF_JMP|BPF_JA:
424                                 JUMP(ins->k);
425                                 break;
426
427                         case BPF_JMP|BPF_JGT|BPF_K:
428                         case BPF_JMP|BPF_JGE|BPF_K:
429                         case BPF_JMP|BPF_JEQ|BPF_K:
430                         case BPF_JMP|BPF_JSET|BPF_K:
431                         case BPF_JMP|BPF_JGT|BPF_X:
432                         case BPF_JMP|BPF_JGE|BPF_X:
433                         case BPF_JMP|BPF_JEQ|BPF_X:
434                         case BPF_JMP|BPF_JSET|BPF_X:
435                                 if (ins->jt == ins->jf) {
436                                         JUMP(ins->jt);
437                                         break;
438                                 }
439                                 switch (ins->code) {
440                                 case BPF_JMP|BPF_JGT|BPF_K:
441                                         CMPid(ins->k, EAX);
442                                         JCC(JA, JBE);
443                                         break;
444
445                                 case BPF_JMP|BPF_JGE|BPF_K:
446                                         CMPid(ins->k, EAX);
447                                         JCC(JAE, JB);
448                                         break;
449
450                                 case BPF_JMP|BPF_JEQ|BPF_K:
451                                         CMPid(ins->k, EAX);
452                                         JCC(JE, JNE);
453                                         break;
454
455                                 case BPF_JMP|BPF_JSET|BPF_K:
456                                         TESTid(ins->k, EAX);
457                                         JCC(JNE, JE);
458                                         break;
459
460                                 case BPF_JMP|BPF_JGT|BPF_X:
461                                         CMPrd(EDX, EAX);
462                                         JCC(JA, JBE);
463                                         break;
464
465                                 case BPF_JMP|BPF_JGE|BPF_X:
466                                         CMPrd(EDX, EAX);
467                                         JCC(JAE, JB);
468                                         break;
469
470                                 case BPF_JMP|BPF_JEQ|BPF_X:
471                                         CMPrd(EDX, EAX);
472                                         JCC(JE, JNE);
473                                         break;
474
475                                 case BPF_JMP|BPF_JSET|BPF_X:
476                                         TESTrd(EDX, EAX);
477                                         JCC(JNE, JE);
478                                         break;
479                                 }
480                                 break;
481
482                         case BPF_ALU|BPF_ADD|BPF_X:
483                                 ADDrd(EDX, EAX);
484                                 break;
485
486                         case BPF_ALU|BPF_SUB|BPF_X:
487                                 SUBrd(EDX, EAX);
488                                 break;
489
490                         case BPF_ALU|BPF_MUL|BPF_X:
491                                 MOVrd(EDX, ECX);
492                                 MULrd(EDX);
493                                 MOVrd(ECX, EDX);
494                                 break;
495
496                         case BPF_ALU|BPF_DIV|BPF_X:
497                         case BPF_ALU|BPF_MOD|BPF_X:
498                                 TESTrd(EDX, EDX);
499                                 if (fmem) {
500                                         JNEb(4);
501                                         ZEROrd(EAX);
502                                         LEAVE();
503                                 } else {
504                                         JNEb(3);
505                                         ZEROrd(EAX);
506                                 }
507                                 RET();
508                                 MOVrd(EDX, ECX);
509                                 ZEROrd(EDX);
510                                 DIVrd(ECX);
511                                 if (BPF_OP(ins->code) == BPF_MOD)
512                                         MOVrd(EDX, EAX);
513                                 MOVrd(ECX, EDX);
514                                 break;
515
516                         case BPF_ALU|BPF_AND|BPF_X:
517                                 ANDrd(EDX, EAX);
518                                 break;
519
520                         case BPF_ALU|BPF_OR|BPF_X:
521                                 ORrd(EDX, EAX);
522                                 break;
523
524                         case BPF_ALU|BPF_XOR|BPF_X:
525                                 XORrd(EDX, EAX);
526                                 break;
527
528                         case BPF_ALU|BPF_LSH|BPF_X:
529                                 MOVrd(EDX, ECX);
530                                 SHL_CLrb(EAX);
531                                 break;
532
533                         case BPF_ALU|BPF_RSH|BPF_X:
534                                 MOVrd(EDX, ECX);
535                                 SHR_CLrb(EAX);
536                                 break;
537
538                         case BPF_ALU|BPF_ADD|BPF_K:
539                                 ADD_EAXi(ins->k);
540                                 break;
541
542                         case BPF_ALU|BPF_SUB|BPF_K:
543                                 SUB_EAXi(ins->k);
544                                 break;
545
546                         case BPF_ALU|BPF_MUL|BPF_K:
547                                 MOVrd(EDX, ECX);
548                                 MOVid(ins->k, EDX);
549                                 MULrd(EDX);
550                                 MOVrd(ECX, EDX);
551                                 break;
552
553                         case BPF_ALU|BPF_DIV|BPF_K:
554                         case BPF_ALU|BPF_MOD|BPF_K:
555                                 MOVrd(EDX, ECX);
556                                 ZEROrd(EDX);
557                                 MOVid(ins->k, ESI);
558                                 DIVrd(ESI);
559                                 if (BPF_OP(ins->code) == BPF_MOD)
560                                         MOVrd(EDX, EAX);
561                                 MOVrd(ECX, EDX);
562                                 break;
563
564                         case BPF_ALU|BPF_AND|BPF_K:
565                                 ANDid(ins->k, EAX);
566                                 break;
567
568                         case BPF_ALU|BPF_OR|BPF_K:
569                                 ORid(ins->k, EAX);
570                                 break;
571
572                         case BPF_ALU|BPF_XOR|BPF_K:
573                                 XORid(ins->k, EAX);
574                                 break;
575
576                         case BPF_ALU|BPF_LSH|BPF_K:
577                                 SHLib((ins->k) & 0xff, EAX);
578                                 break;
579
580                         case BPF_ALU|BPF_RSH|BPF_K:
581                                 SHRib((ins->k) & 0xff, EAX);
582                                 break;
583
584                         case BPF_ALU|BPF_NEG:
585                                 NEGd(EAX);
586                                 break;
587
588                         case BPF_MISC|BPF_TAX:
589                                 MOVrd(EAX, EDX);
590                                 break;
591
592                         case BPF_MISC|BPF_TXA:
593                                 MOVrd(EDX, EAX);
594                                 break;
595                         }
596                         ins++;
597                 }
598
599                 if (pass > 0)
600                         continue;
601
602                 *size = stream.cur_ip;
603 #ifdef _KERNEL
604                 stream.ibuf = malloc(*size, M_BPFJIT, M_NOWAIT);
605                 if (stream.ibuf == NULL)
606                         break;
607 #else
608                 stream.ibuf = mmap(NULL, *size, PROT_READ | PROT_WRITE,
609                     MAP_ANON, -1, 0);
610                 if (stream.ibuf == MAP_FAILED) {
611                         stream.ibuf = NULL;
612                         break;
613                 }
614 #endif
615
616                 /*
617                  * Modify the reference table to contain the offsets and
618                  * not the lengths of the instructions.
619                  */
620                 if (fjmp)
621                         for (i = 1; i < nins + 1; i++)
622                                 stream.refs[i] += stream.refs[i - 1];
623
624                 /* Reset the counters. */
625                 stream.cur_ip = 0;
626                 stream.bpf_pc = 0;
627
628                 /* The second pass creates the actual code. */
629                 emitm = emit_code;
630         }
631
632         /*
633          * The reference table is needed only during compilation,
634          * now we can free it.
635          */
636         if (fjmp)
637 #ifdef _KERNEL
638                 free(stream.refs, M_BPFJIT);
639 #else
640                 free(stream.refs);
641 #endif
642
643 #ifndef _KERNEL
644         if (stream.ibuf != NULL &&
645             mprotect(stream.ibuf, *size, PROT_READ | PROT_EXEC) != 0) {
646                 munmap(stream.ibuf, *size);
647                 stream.ibuf = NULL;
648         }
649 #endif
650
651         return ((bpf_filter_func)(void *)stream.ibuf);
652 }