1ae275efcSJung-uk Kim /*-
251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni *
4095130bfSJung-uk Kim * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy)
5af197328SJung-uk Kim * Copyright (C) 2005-2017 Jung-uk Kim <jkim@FreeBSD.org>
6ae275efcSJung-uk Kim * All rights reserved.
7ae275efcSJung-uk Kim *
8ae275efcSJung-uk Kim * Redistribution and use in source and binary forms, with or without
9ae275efcSJung-uk Kim * modification, are permitted provided that the following conditions
10ae275efcSJung-uk Kim * are met:
11ae275efcSJung-uk Kim *
12ae275efcSJung-uk Kim * 1. Redistributions of source code must retain the above copyright
13ae275efcSJung-uk Kim * notice, this list of conditions and the following disclaimer.
14ae275efcSJung-uk Kim * 2. Redistributions in binary form must reproduce the above copyright
15ae275efcSJung-uk Kim * notice, this list of conditions and the following disclaimer in the
16ae275efcSJung-uk Kim * documentation and/or other materials provided with the distribution.
17ae275efcSJung-uk Kim * 3. Neither the name of the Politecnico di Torino nor the names of its
18ae275efcSJung-uk Kim * contributors may be used to endorse or promote products derived from
19ae275efcSJung-uk Kim * this software without specific prior written permission.
20ae275efcSJung-uk Kim *
21ae275efcSJung-uk Kim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22ae275efcSJung-uk Kim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23ae275efcSJung-uk Kim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24ae275efcSJung-uk Kim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25ae275efcSJung-uk Kim * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26ae275efcSJung-uk Kim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27ae275efcSJung-uk Kim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28f471e569SJung-uk Kim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29ae275efcSJung-uk Kim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30ae275efcSJung-uk Kim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31ae275efcSJung-uk Kim * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32ae275efcSJung-uk Kim */
33ae275efcSJung-uk Kim
34ae275efcSJung-uk Kim #include <sys/cdefs.h>
353bfea868SJung-uk Kim #ifdef _KERNEL
36ae275efcSJung-uk Kim #include "opt_bpf.h"
37ae275efcSJung-uk Kim #include <sys/param.h>
38ae275efcSJung-uk Kim #include <sys/systm.h>
39ae275efcSJung-uk Kim #include <sys/kernel.h>
40ae275efcSJung-uk Kim #include <sys/malloc.h>
41eedc7fd9SGleb Smirnoff #include <sys/mbuf.h>
42af197328SJung-uk Kim #include <sys/socket.h>
43af197328SJung-uk Kim
44ae275efcSJung-uk Kim #include <net/if.h>
453bfea868SJung-uk Kim #else
463bfea868SJung-uk Kim #include <stdlib.h>
47c12b965fSJung-uk Kim #include <string.h>
48366652f9SJung-uk Kim #include <sys/mman.h>
49366652f9SJung-uk Kim #include <sys/param.h>
503bfea868SJung-uk Kim #endif
513bfea868SJung-uk Kim
523bfea868SJung-uk Kim #include <sys/types.h>
533bfea868SJung-uk Kim
54ae275efcSJung-uk Kim #include <net/bpf.h>
55ae275efcSJung-uk Kim #include <net/bpf_jitter.h>
56ae275efcSJung-uk Kim
57ae275efcSJung-uk Kim #include <amd64/amd64/bpf_jit_machdep.h>
58ae275efcSJung-uk Kim
59ae275efcSJung-uk Kim /*
6035012a1eSJung-uk Kim * Emit routine to update the jump table.
61ae275efcSJung-uk Kim */
62ae275efcSJung-uk Kim static void
emit_length(bpf_bin_stream * stream,__unused u_int value,u_int len)633bfea868SJung-uk Kim emit_length(bpf_bin_stream *stream, __unused u_int value, u_int len)
64ae275efcSJung-uk Kim {
65ae275efcSJung-uk Kim
6635012a1eSJung-uk Kim if (stream->refs != NULL)
67ae275efcSJung-uk Kim (stream->refs)[stream->bpf_pc] += len;
68ae275efcSJung-uk Kim stream->cur_ip += len;
69ae275efcSJung-uk Kim }
70ae275efcSJung-uk Kim
71ae275efcSJung-uk Kim /*
7235012a1eSJung-uk Kim * Emit routine to output the actual binary code.
73ae275efcSJung-uk Kim */
74ae275efcSJung-uk Kim static void
emit_code(bpf_bin_stream * stream,u_int value,u_int len)75ae275efcSJung-uk Kim emit_code(bpf_bin_stream *stream, u_int value, u_int len)
76ae275efcSJung-uk Kim {
77ae275efcSJung-uk Kim
78ae275efcSJung-uk Kim switch (len) {
79ae275efcSJung-uk Kim case 1:
80ae275efcSJung-uk Kim stream->ibuf[stream->cur_ip] = (u_char)value;
81ae275efcSJung-uk Kim stream->cur_ip++;
82ae275efcSJung-uk Kim break;
83ae275efcSJung-uk Kim
84ae275efcSJung-uk Kim case 2:
8599e3ae68SJung-uk Kim *((u_short *)(void *)(stream->ibuf + stream->cur_ip)) =
8699e3ae68SJung-uk Kim (u_short)value;
87ae275efcSJung-uk Kim stream->cur_ip += 2;
88ae275efcSJung-uk Kim break;
89ae275efcSJung-uk Kim
90ae275efcSJung-uk Kim case 4:
9199e3ae68SJung-uk Kim *((u_int *)(void *)(stream->ibuf + stream->cur_ip)) = value;
92ae275efcSJung-uk Kim stream->cur_ip += 4;
93ae275efcSJung-uk Kim break;
94ae275efcSJung-uk Kim }
95ae275efcSJung-uk Kim
96ae275efcSJung-uk Kim return;
97ae275efcSJung-uk Kim }
98ae275efcSJung-uk Kim
99ae275efcSJung-uk Kim /*
10035012a1eSJung-uk Kim * Scan the filter program and find possible optimization.
10135012a1eSJung-uk Kim */
10235012a1eSJung-uk Kim static int
bpf_jit_optimize(struct bpf_insn * prog,u_int nins)10335012a1eSJung-uk Kim bpf_jit_optimize(struct bpf_insn *prog, u_int nins)
10435012a1eSJung-uk Kim {
10535012a1eSJung-uk Kim int flags;
10635012a1eSJung-uk Kim u_int i;
10735012a1eSJung-uk Kim
10835012a1eSJung-uk Kim /* Do we return immediately? */
10935012a1eSJung-uk Kim if (BPF_CLASS(prog[0].code) == BPF_RET)
11026b8a1c9SJung-uk Kim return (BPF_JIT_FRET);
11135012a1eSJung-uk Kim
11235012a1eSJung-uk Kim for (flags = 0, i = 0; i < nins; i++) {
11326b8a1c9SJung-uk Kim switch (prog[i].code) {
11426b8a1c9SJung-uk Kim case BPF_LD|BPF_W|BPF_ABS:
11526b8a1c9SJung-uk Kim case BPF_LD|BPF_H|BPF_ABS:
11626b8a1c9SJung-uk Kim case BPF_LD|BPF_B|BPF_ABS:
11726b8a1c9SJung-uk Kim case BPF_LD|BPF_W|BPF_IND:
11826b8a1c9SJung-uk Kim case BPF_LD|BPF_H|BPF_IND:
11926b8a1c9SJung-uk Kim case BPF_LD|BPF_B|BPF_IND:
12026b8a1c9SJung-uk Kim case BPF_LDX|BPF_MSH|BPF_B:
12126b8a1c9SJung-uk Kim flags |= BPF_JIT_FPKT;
12226b8a1c9SJung-uk Kim break;
12326b8a1c9SJung-uk Kim case BPF_LD|BPF_MEM:
12426b8a1c9SJung-uk Kim case BPF_LDX|BPF_MEM:
12526b8a1c9SJung-uk Kim case BPF_ST:
12626b8a1c9SJung-uk Kim case BPF_STX:
12726b8a1c9SJung-uk Kim flags |= BPF_JIT_FMEM;
12826b8a1c9SJung-uk Kim break;
12926b8a1c9SJung-uk Kim case BPF_LD|BPF_W|BPF_LEN:
13026b8a1c9SJung-uk Kim case BPF_LDX|BPF_W|BPF_LEN:
13126b8a1c9SJung-uk Kim flags |= BPF_JIT_FLEN;
13226b8a1c9SJung-uk Kim break;
13326b8a1c9SJung-uk Kim case BPF_JMP|BPF_JA:
13426b8a1c9SJung-uk Kim case BPF_JMP|BPF_JGT|BPF_K:
13526b8a1c9SJung-uk Kim case BPF_JMP|BPF_JGE|BPF_K:
13626b8a1c9SJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_K:
13726b8a1c9SJung-uk Kim case BPF_JMP|BPF_JSET|BPF_K:
13826b8a1c9SJung-uk Kim case BPF_JMP|BPF_JGT|BPF_X:
13926b8a1c9SJung-uk Kim case BPF_JMP|BPF_JGE|BPF_X:
14026b8a1c9SJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_X:
14126b8a1c9SJung-uk Kim case BPF_JMP|BPF_JSET|BPF_X:
14226b8a1c9SJung-uk Kim flags |= BPF_JIT_FJMP;
14326b8a1c9SJung-uk Kim break;
14426b8a1c9SJung-uk Kim }
14535012a1eSJung-uk Kim if (flags == BPF_JIT_FLAG_ALL)
14635012a1eSJung-uk Kim break;
14735012a1eSJung-uk Kim }
14835012a1eSJung-uk Kim
14935012a1eSJung-uk Kim return (flags);
15035012a1eSJung-uk Kim }
15135012a1eSJung-uk Kim
15235012a1eSJung-uk Kim /*
15335012a1eSJung-uk Kim * Function that does the real stuff.
154ae275efcSJung-uk Kim */
155ae275efcSJung-uk Kim bpf_filter_func
bpf_jit_compile(struct bpf_insn * prog,u_int nins,size_t * size)1565ecf7736SJung-uk Kim bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size)
157ae275efcSJung-uk Kim {
158366652f9SJung-uk Kim bpf_bin_stream stream;
159ae275efcSJung-uk Kim struct bpf_insn *ins;
16026b8a1c9SJung-uk Kim int flags, fret, fpkt, fmem, fjmp, flen;
161ae275efcSJung-uk Kim u_int i, pass;
162ae275efcSJung-uk Kim
163ae275efcSJung-uk Kim /*
164c12b965fSJung-uk Kim * NOTE: Do not modify the name of this variable, as it's used by
165ae275efcSJung-uk Kim * the macros to emit code.
166ae275efcSJung-uk Kim */
167ae275efcSJung-uk Kim emit_func emitm;
168ae275efcSJung-uk Kim
16926b8a1c9SJung-uk Kim flags = bpf_jit_optimize(prog, nins);
17026b8a1c9SJung-uk Kim fret = (flags & BPF_JIT_FRET) != 0;
17126b8a1c9SJung-uk Kim fpkt = (flags & BPF_JIT_FPKT) != 0;
17226b8a1c9SJung-uk Kim fmem = (flags & BPF_JIT_FMEM) != 0;
17326b8a1c9SJung-uk Kim fjmp = (flags & BPF_JIT_FJMP) != 0;
17426b8a1c9SJung-uk Kim flen = (flags & BPF_JIT_FLEN) != 0;
17526b8a1c9SJung-uk Kim
17626b8a1c9SJung-uk Kim if (fret)
17726b8a1c9SJung-uk Kim nins = 1;
17826b8a1c9SJung-uk Kim
17935012a1eSJung-uk Kim memset(&stream, 0, sizeof(stream));
18035012a1eSJung-uk Kim
181c12b965fSJung-uk Kim /* Allocate the reference table for the jumps. */
18226b8a1c9SJung-uk Kim if (fjmp) {
1833bfea868SJung-uk Kim #ifdef _KERNEL
184ac2fffa4SPedro F. Giffuni stream.refs = malloc((nins + 1) * sizeof(u_int), M_BPFJIT,
185c12b965fSJung-uk Kim M_NOWAIT | M_ZERO);
1863bfea868SJung-uk Kim #else
18726b8a1c9SJung-uk Kim stream.refs = calloc(nins + 1, sizeof(u_int));
1883bfea868SJung-uk Kim #endif
189ae275efcSJung-uk Kim if (stream.refs == NULL)
190095130bfSJung-uk Kim return (NULL);
19135012a1eSJung-uk Kim }
192ae275efcSJung-uk Kim
193ae275efcSJung-uk Kim /*
194c12b965fSJung-uk Kim * The first pass will emit the lengths of the instructions
195c12b965fSJung-uk Kim * to create the reference table.
196ae275efcSJung-uk Kim */
197ae275efcSJung-uk Kim emitm = emit_length;
198ae275efcSJung-uk Kim
199c12b965fSJung-uk Kim for (pass = 0; pass < 2; pass++) {
200ae275efcSJung-uk Kim ins = prog;
201ae275efcSJung-uk Kim
202c12b965fSJung-uk Kim /* Create the procedure header. */
20326b8a1c9SJung-uk Kim if (fmem) {
2045ecf7736SJung-uk Kim PUSH(RBP);
2055ecf7736SJung-uk Kim MOVrq(RSP, RBP);
2065ecf7736SJung-uk Kim SUBib(BPF_MEMWORDS * sizeof(uint32_t), RSP);
20735012a1eSJung-uk Kim }
20826b8a1c9SJung-uk Kim if (flen)
209059485d0SJung-uk Kim MOVrd2(ESI, R9D);
21026b8a1c9SJung-uk Kim if (fpkt) {
21126b8a1c9SJung-uk Kim MOVrq2(RDI, R8);
212059485d0SJung-uk Kim MOVrd(EDX, EDI);
21335012a1eSJung-uk Kim }
214ae275efcSJung-uk Kim
215ae275efcSJung-uk Kim for (i = 0; i < nins; i++) {
216ae275efcSJung-uk Kim stream.bpf_pc++;
217ae275efcSJung-uk Kim
218ae275efcSJung-uk Kim switch (ins->code) {
219ae275efcSJung-uk Kim default:
2203bfea868SJung-uk Kim #ifdef _KERNEL
221095130bfSJung-uk Kim return (NULL);
2223bfea868SJung-uk Kim #else
2233bfea868SJung-uk Kim abort();
2243bfea868SJung-uk Kim #endif
225ae275efcSJung-uk Kim
226ae275efcSJung-uk Kim case BPF_RET|BPF_K:
227292f013cSJung-uk Kim MOVid(ins->k, EAX);
22826b8a1c9SJung-uk Kim if (fmem)
22935012a1eSJung-uk Kim LEAVE();
23035012a1eSJung-uk Kim RET();
231ae275efcSJung-uk Kim break;
232ae275efcSJung-uk Kim
233ae275efcSJung-uk Kim case BPF_RET|BPF_A:
23426b8a1c9SJung-uk Kim if (fmem)
23535012a1eSJung-uk Kim LEAVE();
23635012a1eSJung-uk Kim RET();
237ae275efcSJung-uk Kim break;
238ae275efcSJung-uk Kim
239ae275efcSJung-uk Kim case BPF_LD|BPF_W|BPF_ABS:
24069e08c86SJung-uk Kim MOVid(ins->k, ESI);
24169e08c86SJung-uk Kim CMPrd(EDI, ESI);
24269e08c86SJung-uk Kim JAb(12);
24369e08c86SJung-uk Kim MOVrd(EDI, ECX);
24469e08c86SJung-uk Kim SUBrd(ESI, ECX);
24569e08c86SJung-uk Kim CMPid(sizeof(int32_t), ECX);
24626b8a1c9SJung-uk Kim if (fmem) {
2475ecf7736SJung-uk Kim JAEb(4);
248b86977a5SJung-uk Kim ZEROrd(EAX);
24935012a1eSJung-uk Kim LEAVE();
25035012a1eSJung-uk Kim } else {
25135012a1eSJung-uk Kim JAEb(3);
25235012a1eSJung-uk Kim ZEROrd(EAX);
25335012a1eSJung-uk Kim }
25435012a1eSJung-uk Kim RET();
2555ecf7736SJung-uk Kim MOVrq3(R8, RCX);
2565ecf7736SJung-uk Kim MOVobd(RCX, RSI, EAX);
257ae275efcSJung-uk Kim BSWAP(EAX);
258ae275efcSJung-uk Kim break;
259ae275efcSJung-uk Kim
260ae275efcSJung-uk Kim case BPF_LD|BPF_H|BPF_ABS:
261b86977a5SJung-uk Kim ZEROrd(EAX);
26269e08c86SJung-uk Kim MOVid(ins->k, ESI);
26369e08c86SJung-uk Kim CMPrd(EDI, ESI);
26469e08c86SJung-uk Kim JAb(12);
26569e08c86SJung-uk Kim MOVrd(EDI, ECX);
26669e08c86SJung-uk Kim SUBrd(ESI, ECX);
26769e08c86SJung-uk Kim CMPid(sizeof(int16_t), ECX);
26826b8a1c9SJung-uk Kim if (fmem) {
2695ecf7736SJung-uk Kim JAEb(2);
27035012a1eSJung-uk Kim LEAVE();
27135012a1eSJung-uk Kim } else
27235012a1eSJung-uk Kim JAEb(1);
27335012a1eSJung-uk Kim RET();
2745ecf7736SJung-uk Kim MOVrq3(R8, RCX);
2755ecf7736SJung-uk Kim MOVobw(RCX, RSI, AX);
276ae275efcSJung-uk Kim SWAP_AX();
277ae275efcSJung-uk Kim break;
278ae275efcSJung-uk Kim
279ae275efcSJung-uk Kim case BPF_LD|BPF_B|BPF_ABS:
280b86977a5SJung-uk Kim ZEROrd(EAX);
28169e08c86SJung-uk Kim MOVid(ins->k, ESI);
28269e08c86SJung-uk Kim CMPrd(EDI, ESI);
28326b8a1c9SJung-uk Kim if (fmem) {
2845ecf7736SJung-uk Kim JBb(2);
28535012a1eSJung-uk Kim LEAVE();
28635012a1eSJung-uk Kim } else
28735012a1eSJung-uk Kim JBb(1);
28835012a1eSJung-uk Kim RET();
2895ecf7736SJung-uk Kim MOVrq3(R8, RCX);
2905ecf7736SJung-uk Kim MOVobb(RCX, RSI, AL);
291ae275efcSJung-uk Kim break;
292ae275efcSJung-uk Kim
293ae275efcSJung-uk Kim case BPF_LD|BPF_W|BPF_LEN:
294059485d0SJung-uk Kim MOVrd3(R9D, EAX);
295ae275efcSJung-uk Kim break;
296ae275efcSJung-uk Kim
297ae275efcSJung-uk Kim case BPF_LDX|BPF_W|BPF_LEN:
298059485d0SJung-uk Kim MOVrd3(R9D, EDX);
299ae275efcSJung-uk Kim break;
300ae275efcSJung-uk Kim
301ae275efcSJung-uk Kim case BPF_LD|BPF_W|BPF_IND:
30269e08c86SJung-uk Kim CMPrd(EDI, EDX);
30369e08c86SJung-uk Kim JAb(27);
30469e08c86SJung-uk Kim MOVid(ins->k, ESI);
30569e08c86SJung-uk Kim MOVrd(EDI, ECX);
30669e08c86SJung-uk Kim SUBrd(EDX, ECX);
30769e08c86SJung-uk Kim CMPrd(ESI, ECX);
30869e08c86SJung-uk Kim JBb(14);
30969e08c86SJung-uk Kim ADDrd(EDX, ESI);
31069e08c86SJung-uk Kim MOVrd(EDI, ECX);
31169e08c86SJung-uk Kim SUBrd(ESI, ECX);
31269e08c86SJung-uk Kim CMPid(sizeof(int32_t), ECX);
31326b8a1c9SJung-uk Kim if (fmem) {
3145ecf7736SJung-uk Kim JAEb(4);
315b86977a5SJung-uk Kim ZEROrd(EAX);
31635012a1eSJung-uk Kim LEAVE();
31735012a1eSJung-uk Kim } else {
31835012a1eSJung-uk Kim JAEb(3);
31935012a1eSJung-uk Kim ZEROrd(EAX);
32035012a1eSJung-uk Kim }
32135012a1eSJung-uk Kim RET();
3225ecf7736SJung-uk Kim MOVrq3(R8, RCX);
3235ecf7736SJung-uk Kim MOVobd(RCX, RSI, EAX);
324ae275efcSJung-uk Kim BSWAP(EAX);
325ae275efcSJung-uk Kim break;
326ae275efcSJung-uk Kim
327ae275efcSJung-uk Kim case BPF_LD|BPF_H|BPF_IND:
328b86977a5SJung-uk Kim ZEROrd(EAX);
32969e08c86SJung-uk Kim CMPrd(EDI, EDX);
33069e08c86SJung-uk Kim JAb(27);
33169e08c86SJung-uk Kim MOVid(ins->k, ESI);
33269e08c86SJung-uk Kim MOVrd(EDI, ECX);
33369e08c86SJung-uk Kim SUBrd(EDX, ECX);
33469e08c86SJung-uk Kim CMPrd(ESI, ECX);
33569e08c86SJung-uk Kim JBb(14);
33669e08c86SJung-uk Kim ADDrd(EDX, ESI);
33769e08c86SJung-uk Kim MOVrd(EDI, ECX);
33869e08c86SJung-uk Kim SUBrd(ESI, ECX);
33969e08c86SJung-uk Kim CMPid(sizeof(int16_t), ECX);
34026b8a1c9SJung-uk Kim if (fmem) {
3415ecf7736SJung-uk Kim JAEb(2);
34235012a1eSJung-uk Kim LEAVE();
34335012a1eSJung-uk Kim } else
34435012a1eSJung-uk Kim JAEb(1);
34535012a1eSJung-uk Kim RET();
3465ecf7736SJung-uk Kim MOVrq3(R8, RCX);
3475ecf7736SJung-uk Kim MOVobw(RCX, RSI, AX);
348ae275efcSJung-uk Kim SWAP_AX();
349ae275efcSJung-uk Kim break;
350ae275efcSJung-uk Kim
351ae275efcSJung-uk Kim case BPF_LD|BPF_B|BPF_IND:
352b86977a5SJung-uk Kim ZEROrd(EAX);
35369e08c86SJung-uk Kim CMPrd(EDI, EDX);
35469e08c86SJung-uk Kim JAEb(13);
35569e08c86SJung-uk Kim MOVid(ins->k, ESI);
35669e08c86SJung-uk Kim MOVrd(EDI, ECX);
35769e08c86SJung-uk Kim SUBrd(EDX, ECX);
35869e08c86SJung-uk Kim CMPrd(ESI, ECX);
35926b8a1c9SJung-uk Kim if (fmem) {
3605ecf7736SJung-uk Kim JAb(2);
36135012a1eSJung-uk Kim LEAVE();
36235012a1eSJung-uk Kim } else
36335012a1eSJung-uk Kim JAb(1);
36435012a1eSJung-uk Kim RET();
3655ecf7736SJung-uk Kim MOVrq3(R8, RCX);
36669e08c86SJung-uk Kim ADDrd(EDX, ESI);
3675ecf7736SJung-uk Kim MOVobb(RCX, RSI, AL);
368ae275efcSJung-uk Kim break;
369ae275efcSJung-uk Kim
370ae275efcSJung-uk Kim case BPF_LDX|BPF_MSH|BPF_B:
37169e08c86SJung-uk Kim MOVid(ins->k, ESI);
37269e08c86SJung-uk Kim CMPrd(EDI, ESI);
37326b8a1c9SJung-uk Kim if (fmem) {
3745ecf7736SJung-uk Kim JBb(4);
375b86977a5SJung-uk Kim ZEROrd(EAX);
37635012a1eSJung-uk Kim LEAVE();
37735012a1eSJung-uk Kim } else {
37835012a1eSJung-uk Kim JBb(3);
37935012a1eSJung-uk Kim ZEROrd(EAX);
38035012a1eSJung-uk Kim }
38135012a1eSJung-uk Kim RET();
382b86977a5SJung-uk Kim ZEROrd(EDX);
3835ecf7736SJung-uk Kim MOVrq3(R8, RCX);
3845ecf7736SJung-uk Kim MOVobb(RCX, RSI, DL);
385095130bfSJung-uk Kim ANDib(0x0f, DL);
386292f013cSJung-uk Kim SHLib(2, EDX);
387ae275efcSJung-uk Kim break;
388ae275efcSJung-uk Kim
389ae275efcSJung-uk Kim case BPF_LD|BPF_IMM:
390292f013cSJung-uk Kim MOVid(ins->k, EAX);
391ae275efcSJung-uk Kim break;
392ae275efcSJung-uk Kim
393ae275efcSJung-uk Kim case BPF_LDX|BPF_IMM:
394292f013cSJung-uk Kim MOVid(ins->k, EDX);
395ae275efcSJung-uk Kim break;
396ae275efcSJung-uk Kim
397ae275efcSJung-uk Kim case BPF_LD|BPF_MEM:
3985ecf7736SJung-uk Kim MOVid(ins->k * sizeof(uint32_t), ESI);
3995ecf7736SJung-uk Kim MOVobd(RSP, RSI, EAX);
400ae275efcSJung-uk Kim break;
401ae275efcSJung-uk Kim
402ae275efcSJung-uk Kim case BPF_LDX|BPF_MEM:
4035ecf7736SJung-uk Kim MOVid(ins->k * sizeof(uint32_t), ESI);
4045ecf7736SJung-uk Kim MOVobd(RSP, RSI, EDX);
405ae275efcSJung-uk Kim break;
406ae275efcSJung-uk Kim
407ae275efcSJung-uk Kim case BPF_ST:
408ae275efcSJung-uk Kim /*
409ae275efcSJung-uk Kim * XXX this command and the following could
410ae275efcSJung-uk Kim * be optimized if the previous instruction
411ae275efcSJung-uk Kim * was already of this type
412ae275efcSJung-uk Kim */
4135ecf7736SJung-uk Kim MOVid(ins->k * sizeof(uint32_t), ESI);
4145ecf7736SJung-uk Kim MOVomd(EAX, RSP, RSI);
415ae275efcSJung-uk Kim break;
416ae275efcSJung-uk Kim
417ae275efcSJung-uk Kim case BPF_STX:
4185ecf7736SJung-uk Kim MOVid(ins->k * sizeof(uint32_t), ESI);
4195ecf7736SJung-uk Kim MOVomd(EDX, RSP, RSI);
420ae275efcSJung-uk Kim break;
421ae275efcSJung-uk Kim
422ae275efcSJung-uk Kim case BPF_JMP|BPF_JA:
423b8341230SJung-uk Kim JUMP(ins->k);
424ae275efcSJung-uk Kim break;
425ae275efcSJung-uk Kim
426ae275efcSJung-uk Kim case BPF_JMP|BPF_JGT|BPF_K:
427ae275efcSJung-uk Kim case BPF_JMP|BPF_JGE|BPF_K:
428ae275efcSJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_K:
429ae275efcSJung-uk Kim case BPF_JMP|BPF_JSET|BPF_K:
430ae275efcSJung-uk Kim case BPF_JMP|BPF_JGT|BPF_X:
431ae275efcSJung-uk Kim case BPF_JMP|BPF_JGE|BPF_X:
432ae275efcSJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_X:
433ae275efcSJung-uk Kim case BPF_JMP|BPF_JSET|BPF_X:
434b8341230SJung-uk Kim if (ins->jt == ins->jf) {
435b8341230SJung-uk Kim JUMP(ins->jt);
436f40611e2SJung-uk Kim break;
437b8341230SJung-uk Kim }
438730b3be3SJung-uk Kim switch (ins->code) {
439730b3be3SJung-uk Kim case BPF_JMP|BPF_JGT|BPF_K:
440730b3be3SJung-uk Kim CMPid(ins->k, EAX);
441730b3be3SJung-uk Kim JCC(JA, JBE);
442730b3be3SJung-uk Kim break;
443730b3be3SJung-uk Kim
444730b3be3SJung-uk Kim case BPF_JMP|BPF_JGE|BPF_K:
445730b3be3SJung-uk Kim CMPid(ins->k, EAX);
446730b3be3SJung-uk Kim JCC(JAE, JB);
447730b3be3SJung-uk Kim break;
448730b3be3SJung-uk Kim
449730b3be3SJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_K:
450730b3be3SJung-uk Kim CMPid(ins->k, EAX);
451730b3be3SJung-uk Kim JCC(JE, JNE);
452730b3be3SJung-uk Kim break;
453730b3be3SJung-uk Kim
454730b3be3SJung-uk Kim case BPF_JMP|BPF_JSET|BPF_K:
455730b3be3SJung-uk Kim TESTid(ins->k, EAX);
456730b3be3SJung-uk Kim JCC(JNE, JE);
457730b3be3SJung-uk Kim break;
458730b3be3SJung-uk Kim
459730b3be3SJung-uk Kim case BPF_JMP|BPF_JGT|BPF_X:
460730b3be3SJung-uk Kim CMPrd(EDX, EAX);
461730b3be3SJung-uk Kim JCC(JA, JBE);
462730b3be3SJung-uk Kim break;
463730b3be3SJung-uk Kim
464730b3be3SJung-uk Kim case BPF_JMP|BPF_JGE|BPF_X:
465730b3be3SJung-uk Kim CMPrd(EDX, EAX);
466730b3be3SJung-uk Kim JCC(JAE, JB);
467730b3be3SJung-uk Kim break;
468730b3be3SJung-uk Kim
469730b3be3SJung-uk Kim case BPF_JMP|BPF_JEQ|BPF_X:
470730b3be3SJung-uk Kim CMPrd(EDX, EAX);
471730b3be3SJung-uk Kim JCC(JE, JNE);
472730b3be3SJung-uk Kim break;
473730b3be3SJung-uk Kim
474730b3be3SJung-uk Kim case BPF_JMP|BPF_JSET|BPF_X:
475f40611e2SJung-uk Kim TESTrd(EDX, EAX);
476f40611e2SJung-uk Kim JCC(JNE, JE);
477ae275efcSJung-uk Kim break;
478730b3be3SJung-uk Kim }
479730b3be3SJung-uk Kim break;
480ae275efcSJung-uk Kim
481ae275efcSJung-uk Kim case BPF_ALU|BPF_ADD|BPF_X:
482292f013cSJung-uk Kim ADDrd(EDX, EAX);
483ae275efcSJung-uk Kim break;
484ae275efcSJung-uk Kim
485ae275efcSJung-uk Kim case BPF_ALU|BPF_SUB|BPF_X:
486292f013cSJung-uk Kim SUBrd(EDX, EAX);
487ae275efcSJung-uk Kim break;
488ae275efcSJung-uk Kim
489ae275efcSJung-uk Kim case BPF_ALU|BPF_MUL|BPF_X:
490ae275efcSJung-uk Kim MOVrd(EDX, ECX);
491292f013cSJung-uk Kim MULrd(EDX);
492292f013cSJung-uk Kim MOVrd(ECX, EDX);
493ae275efcSJung-uk Kim break;
494ae275efcSJung-uk Kim
495ae275efcSJung-uk Kim case BPF_ALU|BPF_DIV|BPF_X:
49669d410eeSJung-uk Kim case BPF_ALU|BPF_MOD|BPF_X:
497f40611e2SJung-uk Kim TESTrd(EDX, EDX);
49826b8a1c9SJung-uk Kim if (fmem) {
4995ecf7736SJung-uk Kim JNEb(4);
500b86977a5SJung-uk Kim ZEROrd(EAX);
50135012a1eSJung-uk Kim LEAVE();
50235012a1eSJung-uk Kim } else {
50335012a1eSJung-uk Kim JNEb(3);
50435012a1eSJung-uk Kim ZEROrd(EAX);
50535012a1eSJung-uk Kim }
50635012a1eSJung-uk Kim RET();
507292f013cSJung-uk Kim MOVrd(EDX, ECX);
508b86977a5SJung-uk Kim ZEROrd(EDX);
509ae275efcSJung-uk Kim DIVrd(ECX);
51069d410eeSJung-uk Kim if (BPF_OP(ins->code) == BPF_MOD)
51169d410eeSJung-uk Kim MOVrd(EDX, EAX);
512292f013cSJung-uk Kim MOVrd(ECX, EDX);
513ae275efcSJung-uk Kim break;
514ae275efcSJung-uk Kim
515ae275efcSJung-uk Kim case BPF_ALU|BPF_AND|BPF_X:
516292f013cSJung-uk Kim ANDrd(EDX, EAX);
517ae275efcSJung-uk Kim break;
518ae275efcSJung-uk Kim
519ae275efcSJung-uk Kim case BPF_ALU|BPF_OR|BPF_X:
520292f013cSJung-uk Kim ORrd(EDX, EAX);
521ae275efcSJung-uk Kim break;
522ae275efcSJung-uk Kim
52369d410eeSJung-uk Kim case BPF_ALU|BPF_XOR|BPF_X:
52469d410eeSJung-uk Kim XORrd(EDX, EAX);
52569d410eeSJung-uk Kim break;
52669d410eeSJung-uk Kim
527ae275efcSJung-uk Kim case BPF_ALU|BPF_LSH|BPF_X:
528292f013cSJung-uk Kim MOVrd(EDX, ECX);
529ae275efcSJung-uk Kim SHL_CLrb(EAX);
530ae275efcSJung-uk Kim break;
531ae275efcSJung-uk Kim
532ae275efcSJung-uk Kim case BPF_ALU|BPF_RSH|BPF_X:
533292f013cSJung-uk Kim MOVrd(EDX, ECX);
534ae275efcSJung-uk Kim SHR_CLrb(EAX);
535ae275efcSJung-uk Kim break;
536ae275efcSJung-uk Kim
537ae275efcSJung-uk Kim case BPF_ALU|BPF_ADD|BPF_K:
538ae275efcSJung-uk Kim ADD_EAXi(ins->k);
539ae275efcSJung-uk Kim break;
540ae275efcSJung-uk Kim
541ae275efcSJung-uk Kim case BPF_ALU|BPF_SUB|BPF_K:
542ae275efcSJung-uk Kim SUB_EAXi(ins->k);
543ae275efcSJung-uk Kim break;
544ae275efcSJung-uk Kim
545ae275efcSJung-uk Kim case BPF_ALU|BPF_MUL|BPF_K:
546ae275efcSJung-uk Kim MOVrd(EDX, ECX);
547292f013cSJung-uk Kim MOVid(ins->k, EDX);
548292f013cSJung-uk Kim MULrd(EDX);
549292f013cSJung-uk Kim MOVrd(ECX, EDX);
550ae275efcSJung-uk Kim break;
551ae275efcSJung-uk Kim
552ae275efcSJung-uk Kim case BPF_ALU|BPF_DIV|BPF_K:
55369d410eeSJung-uk Kim case BPF_ALU|BPF_MOD|BPF_K:
554ae275efcSJung-uk Kim MOVrd(EDX, ECX);
555b86977a5SJung-uk Kim ZEROrd(EDX);
556292f013cSJung-uk Kim MOVid(ins->k, ESI);
557292f013cSJung-uk Kim DIVrd(ESI);
55869d410eeSJung-uk Kim if (BPF_OP(ins->code) == BPF_MOD)
55969d410eeSJung-uk Kim MOVrd(EDX, EAX);
560292f013cSJung-uk Kim MOVrd(ECX, EDX);
561ae275efcSJung-uk Kim break;
562ae275efcSJung-uk Kim
563ae275efcSJung-uk Kim case BPF_ALU|BPF_AND|BPF_K:
564292f013cSJung-uk Kim ANDid(ins->k, EAX);
565ae275efcSJung-uk Kim break;
566ae275efcSJung-uk Kim
567ae275efcSJung-uk Kim case BPF_ALU|BPF_OR|BPF_K:
568292f013cSJung-uk Kim ORid(ins->k, EAX);
569ae275efcSJung-uk Kim break;
570ae275efcSJung-uk Kim
57169d410eeSJung-uk Kim case BPF_ALU|BPF_XOR|BPF_K:
57269d410eeSJung-uk Kim XORid(ins->k, EAX);
57369d410eeSJung-uk Kim break;
57469d410eeSJung-uk Kim
575ae275efcSJung-uk Kim case BPF_ALU|BPF_LSH|BPF_K:
576292f013cSJung-uk Kim SHLib((ins->k) & 0xff, EAX);
577ae275efcSJung-uk Kim break;
578ae275efcSJung-uk Kim
579ae275efcSJung-uk Kim case BPF_ALU|BPF_RSH|BPF_K:
580292f013cSJung-uk Kim SHRib((ins->k) & 0xff, EAX);
581ae275efcSJung-uk Kim break;
582ae275efcSJung-uk Kim
583ae275efcSJung-uk Kim case BPF_ALU|BPF_NEG:
584ae275efcSJung-uk Kim NEGd(EAX);
585ae275efcSJung-uk Kim break;
586ae275efcSJung-uk Kim
587ae275efcSJung-uk Kim case BPF_MISC|BPF_TAX:
588292f013cSJung-uk Kim MOVrd(EAX, EDX);
589ae275efcSJung-uk Kim break;
590ae275efcSJung-uk Kim
591ae275efcSJung-uk Kim case BPF_MISC|BPF_TXA:
592292f013cSJung-uk Kim MOVrd(EDX, EAX);
593ae275efcSJung-uk Kim break;
594ae275efcSJung-uk Kim }
595ae275efcSJung-uk Kim ins++;
596ae275efcSJung-uk Kim }
597ae275efcSJung-uk Kim
598c12b965fSJung-uk Kim if (pass > 0)
599c12b965fSJung-uk Kim continue;
600ae275efcSJung-uk Kim
601c12b965fSJung-uk Kim *size = stream.cur_ip;
6023bfea868SJung-uk Kim #ifdef _KERNEL
603*82c174a3SMateusz Guzik stream.ibuf = malloc_exec(*size, M_BPFJIT, M_NOWAIT);
604366652f9SJung-uk Kim if (stream.ibuf == NULL)
605366652f9SJung-uk Kim break;
6063bfea868SJung-uk Kim #else
607c12b965fSJung-uk Kim stream.ibuf = mmap(NULL, *size, PROT_READ | PROT_WRITE,
6085ecf7736SJung-uk Kim MAP_ANON, -1, 0);
609366652f9SJung-uk Kim if (stream.ibuf == MAP_FAILED) {
610366652f9SJung-uk Kim stream.ibuf = NULL;
611366652f9SJung-uk Kim break;
6123bfea868SJung-uk Kim }
6133bfea868SJung-uk Kim #endif
614ae275efcSJung-uk Kim
615ae275efcSJung-uk Kim /*
616c12b965fSJung-uk Kim * Modify the reference table to contain the offsets and
617c12b965fSJung-uk Kim * not the lengths of the instructions.
618ae275efcSJung-uk Kim */
61926b8a1c9SJung-uk Kim if (fjmp)
620ae275efcSJung-uk Kim for (i = 1; i < nins + 1; i++)
621ae275efcSJung-uk Kim stream.refs[i] += stream.refs[i - 1];
622ae275efcSJung-uk Kim
623c12b965fSJung-uk Kim /* Reset the counters. */
624ae275efcSJung-uk Kim stream.cur_ip = 0;
625ae275efcSJung-uk Kim stream.bpf_pc = 0;
626ae275efcSJung-uk Kim
627c12b965fSJung-uk Kim /* The second pass creates the actual code. */
628ae275efcSJung-uk Kim emitm = emit_code;
629ae275efcSJung-uk Kim }
630ae275efcSJung-uk Kim
631ae275efcSJung-uk Kim /*
632c12b965fSJung-uk Kim * The reference table is needed only during compilation,
633c12b965fSJung-uk Kim * now we can free it.
634ae275efcSJung-uk Kim */
63526b8a1c9SJung-uk Kim if (fjmp)
6363bfea868SJung-uk Kim #ifdef _KERNEL
637ae275efcSJung-uk Kim free(stream.refs, M_BPFJIT);
6383bfea868SJung-uk Kim #else
6393bfea868SJung-uk Kim free(stream.refs);
64035012a1eSJung-uk Kim #endif
64135012a1eSJung-uk Kim
64235012a1eSJung-uk Kim #ifndef _KERNEL
643c12b965fSJung-uk Kim if (stream.ibuf != NULL &&
644c12b965fSJung-uk Kim mprotect(stream.ibuf, *size, PROT_READ | PROT_EXEC) != 0) {
645c12b965fSJung-uk Kim munmap(stream.ibuf, *size);
646c12b965fSJung-uk Kim stream.ibuf = NULL;
647c12b965fSJung-uk Kim }
6483bfea868SJung-uk Kim #endif
649ae275efcSJung-uk Kim
65099e3ae68SJung-uk Kim return ((bpf_filter_func)(void *)stream.ibuf);
651ae275efcSJung-uk Kim }
652