bpf_jit_machdep.c revision 153995
154359Sroberto/*- 2182007Sroberto * Copyright (c) 2002 - 2003 NetGroup, Politecnico di Torino (Italy) 354359Sroberto * Copyright (c) 2005 Jung-uk Kim <jkim@FreeBSD.org> 4182007Sroberto * All rights reserved. 5182007Sroberto * 654359Sroberto * Redistribution and use in source and binary forms, with or without 754359Sroberto * modification, are permitted provided that the following conditions 8182007Sroberto * are met: 9182007Sroberto * 10182007Sroberto * 1. Redistributions of source code must retain the above copyright 11182007Sroberto * notice, this list of conditions and the following disclaimer. 12182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright 13182007Sroberto * notice, this list of conditions and the following disclaimer in the 14182007Sroberto * documentation and/or other materials provided with the distribution. 15182007Sroberto * 3. Neither the name of the Politecnico di Torino nor the names of its 16182007Sroberto * contributors may be used to endorse or promote products derived from 17182007Sroberto * this software without specific prior written permission. 18182007Sroberto * 19182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20182007Sroberto * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21182007Sroberto * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22182007Sroberto * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23182007Sroberto * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24182007Sroberto * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25182007Sroberto * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26182007Sroberto * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY 27182007Sroberto * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28182007Sroberto * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29182007Sroberto * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30182007Sroberto */ 31182007Sroberto 32182007Sroberto#include <sys/cdefs.h> 33182007Sroberto__FBSDID("$FreeBSD: head/sys/i386/i386/bpf_jit_machdep.c 153995 2006-01-03 20:26:03Z jkim $"); 3454359Sroberto 3554359Sroberto#include "opt_bpf.h" 3654359Sroberto 3754359Sroberto#include <sys/param.h> 3854359Sroberto#include <sys/systm.h> 3954359Sroberto#include <sys/kernel.h> 4054359Sroberto#include <sys/types.h> 4154359Sroberto#include <sys/socket.h> 4254359Sroberto#include <sys/malloc.h> 4354359Sroberto 4454359Sroberto#include <net/if.h> 4554359Sroberto#include <net/bpf.h> 4654359Sroberto#include <net/bpf_jitter.h> 4754359Sroberto 4854359Sroberto#include <i386/i386/bpf_jit_machdep.h> 4954359Sroberto 5054359Srobertobpf_filter_func bpf_jit_compile(struct bpf_insn *, u_int, int *); 5154359Sroberto 5254359Sroberto/* 5354359Sroberto * emit routine to update the jump table 5454359Sroberto */ 5554359Srobertostatic void 5654359Srobertoemit_length(bpf_bin_stream *stream, u_int value, u_int len) 5754359Sroberto{ 5854359Sroberto 5954359Sroberto (stream->refs)[stream->bpf_pc] += len; 6054359Sroberto stream->cur_ip += len; 6154359Sroberto} 6254359Sroberto 6354359Sroberto/* 6454359Sroberto * emit routine to output the actual binary code 6554359Sroberto */ 6654359Srobertostatic void 6754359Srobertoemit_code(bpf_bin_stream *stream, u_int value, u_int len) 6854359Sroberto{ 6954359Sroberto 7054359Sroberto switch (len) { 7154359Sroberto case 1: 7254359Sroberto stream->ibuf[stream->cur_ip] = (u_char)value; 7354359Sroberto stream->cur_ip++; 7454359Sroberto break; 7554359Sroberto 7654359Sroberto case 2: 7754359Sroberto *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; 78182007Sroberto stream->cur_ip += 2; 79182007Sroberto break; 8054359Sroberto 81182007Sroberto case 4: 82182007Sroberto *((u_int *)(stream->ibuf + stream->cur_ip)) = value; 83182007Sroberto stream->cur_ip += 4; 84182007Sroberto break; 85182007Sroberto } 86182007Sroberto 8754359Sroberto return; 8854359Sroberto} 8954359Sroberto 9054359Sroberto/* 9154359Sroberto * Function that does the real stuff 9254359Sroberto */ 9354359Srobertobpf_filter_func 9454359Srobertobpf_jit_compile(struct bpf_insn *prog, u_int nins, int *mem) 9554359Sroberto{ 9654359Sroberto struct bpf_insn *ins; 97 u_int i, pass; 98 bpf_bin_stream stream; 99 100 /* 101 * NOTE: do not modify the name of this variable, as it's used by 102 * the macros to emit code. 103 */ 104 emit_func emitm; 105 106 /* Do not compile an empty filter. */ 107 if (nins == 0) 108 return NULL; 109 110 /* Allocate the reference table for the jumps */ 111 stream.refs = (u_int *)malloc((nins + 1) * sizeof(u_int), 112 M_BPFJIT, M_NOWAIT); 113 if (stream.refs == NULL) 114 return NULL; 115 116 /* Reset the reference table */ 117 for (i = 0; i < nins + 1; i++) 118 stream.refs[i] = 0; 119 120 stream.cur_ip = 0; 121 stream.bpf_pc = 0; 122 123 /* 124 * the first pass will emit the lengths of the instructions 125 * to create the reference table 126 */ 127 emitm = emit_length; 128 129 pass = 0; 130 for (;;) { 131 ins = prog; 132 133 /* create the procedure header */ 134 PUSH(EBP); 135 MOVrd(EBP, ESP); 136 PUSH(EDI); 137 PUSH(ESI); 138 PUSH(EBX); 139 MOVodd(EBX, EBP, 8); 140 141 for (i = 0; i < nins; i++) { 142 stream.bpf_pc++; 143 144 switch (ins->code) { 145 default: 146 return NULL; 147 148 case BPF_RET|BPF_K: 149 MOVid(EAX, ins->k); 150 POP(EBX); 151 POP(ESI); 152 POP(EDI); 153 LEAVE_RET(); 154 break; 155 156 case BPF_RET|BPF_A: 157 POP(EBX); 158 POP(ESI); 159 POP(EDI); 160 LEAVE_RET(); 161 break; 162 163 case BPF_LD|BPF_W|BPF_ABS: 164 MOVid(ECX, ins->k); 165 MOVrd(ESI, ECX); 166 ADDib(ECX, sizeof(int)); 167 CMPodd(ECX, EBP, 0x10); 168 JLEb(7); 169 ZERO_EAX(); 170 POP(EBX); 171 POP(ESI); 172 POP(EDI); 173 LEAVE_RET(); 174 MOVobd(EAX, EBX, ESI); 175 BSWAP(EAX); 176 break; 177 178 case BPF_LD|BPF_H|BPF_ABS: 179 ZERO_EAX(); 180 MOVid(ECX, ins->k); 181 MOVrd(ESI, ECX); 182 ADDib(ECX, sizeof(short)); 183 CMPodd(ECX, EBP, 0x10); 184 JLEb(5); 185 POP(EBX); 186 POP(ESI); 187 POP(EDI); 188 LEAVE_RET(); 189 MOVobw(AX, EBX, ESI); 190 SWAP_AX(); 191 break; 192 193 case BPF_LD|BPF_B|BPF_ABS: 194 ZERO_EAX(); 195 MOVid(ECX, ins->k); 196 CMPodd(ECX, EBP, 0x10); 197 JLEb(5); 198 POP(EBX); 199 POP(ESI); 200 POP(EDI); 201 LEAVE_RET(); 202 MOVobb(AL, EBX, ECX); 203 break; 204 205 case BPF_LD|BPF_W|BPF_LEN: 206 MOVodd(EAX, EBP, 0xc); 207 break; 208 209 case BPF_LDX|BPF_W|BPF_LEN: 210 MOVodd(EDX, EBP, 0xc); 211 break; 212 213 case BPF_LD|BPF_W|BPF_IND: 214 MOVid(ECX, ins->k); 215 ADDrd(ECX, EDX); 216 MOVrd(ESI, ECX); 217 ADDib(ECX, sizeof(int)); 218 CMPodd(ECX, EBP, 0x10); 219 JLEb(7); 220 ZERO_EAX(); 221 POP(EBX); 222 POP(ESI); 223 POP(EDI); 224 LEAVE_RET(); 225 MOVobd(EAX, EBX, ESI); 226 BSWAP(EAX); 227 break; 228 229 case BPF_LD|BPF_H|BPF_IND: 230 ZERO_EAX(); 231 MOVid(ECX, ins->k); 232 ADDrd(ECX, EDX); 233 MOVrd(ESI, ECX); 234 ADDib(ECX, sizeof(short)); 235 CMPodd(ECX, EBP, 0x10); 236 JLEb(5); 237 POP(EBX); 238 POP(ESI); 239 POP(EDI); 240 LEAVE_RET(); 241 MOVobw(AX, EBX, ESI); 242 SWAP_AX(); 243 break; 244 245 case BPF_LD|BPF_B|BPF_IND: 246 ZERO_EAX(); 247 MOVid(ECX, ins->k); 248 ADDrd(ECX, EDX); 249 CMPodd(ECX, EBP, 0x10); 250 JLEb(5); 251 POP(EBX); 252 POP(ESI); 253 POP(EDI); 254 LEAVE_RET(); 255 MOVobb(AL, EBX, ECX); 256 break; 257 258 case BPF_LDX|BPF_MSH|BPF_B: 259 MOVid(ECX, ins->k); 260 CMPodd(ECX, EBP, 0x10); 261 JLEb(7); 262 ZERO_EAX(); 263 POP(EBX); 264 POP(ESI); 265 POP(EDI); 266 LEAVE_RET(); 267 ZERO_EDX(); 268 MOVobb(DL, EBX, ECX); 269 ANDib(DL, 0xf); 270 SHLib(EDX, 2); 271 break; 272 273 case BPF_LD|BPF_IMM: 274 MOVid(EAX, ins->k); 275 break; 276 277 case BPF_LDX|BPF_IMM: 278 MOVid(EDX, ins->k); 279 break; 280 281 case BPF_LD|BPF_MEM: 282 MOVid(ECX, (uintptr_t)mem); 283 MOVid(ESI, ins->k * 4); 284 MOVobd(EAX, ECX, ESI); 285 break; 286 287 case BPF_LDX|BPF_MEM: 288 MOVid(ECX, (uintptr_t)mem); 289 MOVid(ESI, ins->k * 4); 290 MOVobd(EDX, ECX, ESI); 291 break; 292 293 case BPF_ST: 294 /* 295 * XXX this command and the following could 296 * be optimized if the previous instruction 297 * was already of this type 298 */ 299 MOVid(ECX, (uintptr_t)mem); 300 MOVid(ESI, ins->k * 4); 301 MOVomd(ECX, ESI, EAX); 302 break; 303 304 case BPF_STX: 305 MOVid(ECX, (uintptr_t)mem); 306 MOVid(ESI, ins->k * 4); 307 MOVomd(ECX, ESI, EDX); 308 break; 309 310 case BPF_JMP|BPF_JA: 311 JMP(stream.refs[stream.bpf_pc + ins->k] - 312 stream.refs[stream.bpf_pc]); 313 break; 314 315 case BPF_JMP|BPF_JGT|BPF_K: 316 CMPid(EAX, ins->k); 317 /* 5 is the size of the following JMP */ 318 JG(stream.refs[stream.bpf_pc + ins->jt] - 319 stream.refs[stream.bpf_pc] + 5 ); 320 JMP(stream.refs[stream.bpf_pc + ins->jf] - 321 stream.refs[stream.bpf_pc]); 322 break; 323 324 case BPF_JMP|BPF_JGE|BPF_K: 325 CMPid(EAX, ins->k); 326 JGE(stream.refs[stream.bpf_pc + ins->jt] - 327 stream.refs[stream.bpf_pc] + 5); 328 JMP(stream.refs[stream.bpf_pc + ins->jf] - 329 stream.refs[stream.bpf_pc]); 330 break; 331 332 case BPF_JMP|BPF_JEQ|BPF_K: 333 CMPid(EAX, ins->k); 334 JE(stream.refs[stream.bpf_pc + ins->jt] - 335 stream.refs[stream.bpf_pc] + 5); 336 JMP(stream.refs[stream.bpf_pc + ins->jf] - 337 stream.refs[stream.bpf_pc]); 338 break; 339 340 case BPF_JMP|BPF_JSET|BPF_K: 341 MOVrd(ECX, EAX); 342 ANDid(ECX, ins->k); 343 JE(stream.refs[stream.bpf_pc + ins->jf] - 344 stream.refs[stream.bpf_pc] + 5); 345 JMP(stream.refs[stream.bpf_pc + ins->jt] - 346 stream.refs[stream.bpf_pc]); 347 break; 348 349 case BPF_JMP|BPF_JGT|BPF_X: 350 CMPrd(EAX, EDX); 351 JA(stream.refs[stream.bpf_pc + ins->jt] - 352 stream.refs[stream.bpf_pc] + 5); 353 JMP(stream.refs[stream.bpf_pc + ins->jf] - 354 stream.refs[stream.bpf_pc]); 355 break; 356 357 case BPF_JMP|BPF_JGE|BPF_X: 358 CMPrd(EAX, EDX); 359 JAE(stream.refs[stream.bpf_pc + ins->jt] - 360 stream.refs[stream.bpf_pc] + 5); 361 JMP(stream.refs[stream.bpf_pc + ins->jf] - 362 stream.refs[stream.bpf_pc]); 363 break; 364 365 case BPF_JMP|BPF_JEQ|BPF_X: 366 CMPrd(EAX, EDX); 367 JE(stream.refs[stream.bpf_pc + ins->jt] - 368 stream.refs[stream.bpf_pc] + 5); 369 JMP(stream.refs[stream.bpf_pc + ins->jf] - 370 stream.refs[stream.bpf_pc]); 371 break; 372 373 case BPF_JMP|BPF_JSET|BPF_X: 374 MOVrd(ECX, EAX); 375 ANDrd(ECX, EDX); 376 JE(stream.refs[stream.bpf_pc + ins->jf] - 377 stream.refs[stream.bpf_pc] + 5); 378 JMP(stream.refs[stream.bpf_pc + ins->jt] - 379 stream.refs[stream.bpf_pc]); 380 break; 381 382 case BPF_ALU|BPF_ADD|BPF_X: 383 ADDrd(EAX, EDX); 384 break; 385 386 case BPF_ALU|BPF_SUB|BPF_X: 387 SUBrd(EAX, EDX); 388 break; 389 390 case BPF_ALU|BPF_MUL|BPF_X: 391 MOVrd(ECX, EDX); 392 MULrd(EDX); 393 MOVrd(EDX, ECX); 394 break; 395 396 case BPF_ALU|BPF_DIV|BPF_X: 397 CMPid(EDX, 0); 398 JNEb(7); 399 ZERO_EAX(); 400 POP(EBX); 401 POP(ESI); 402 POP(EDI); 403 LEAVE_RET(); 404 MOVrd(ECX, EDX); 405 ZERO_EDX(); 406 DIVrd(ECX); 407 MOVrd(EDX, ECX); 408 break; 409 410 case BPF_ALU|BPF_AND|BPF_X: 411 ANDrd(EAX, EDX); 412 break; 413 414 case BPF_ALU|BPF_OR|BPF_X: 415 ORrd(EAX, EDX); 416 break; 417 418 case BPF_ALU|BPF_LSH|BPF_X: 419 MOVrd(ECX, EDX); 420 SHL_CLrb(EAX); 421 break; 422 423 case BPF_ALU|BPF_RSH|BPF_X: 424 MOVrd(ECX, EDX); 425 SHR_CLrb(EAX); 426 break; 427 428 case BPF_ALU|BPF_ADD|BPF_K: 429 ADD_EAXi(ins->k); 430 break; 431 432 case BPF_ALU|BPF_SUB|BPF_K: 433 SUB_EAXi(ins->k); 434 break; 435 436 case BPF_ALU|BPF_MUL|BPF_K: 437 MOVrd(ECX, EDX); 438 MOVid(EDX, ins->k); 439 MULrd(EDX); 440 MOVrd(EDX, ECX); 441 break; 442 443 case BPF_ALU|BPF_DIV|BPF_K: 444 MOVrd(ECX, EDX); 445 ZERO_EDX(); 446 MOVid(ESI, ins->k); 447 DIVrd(ESI); 448 MOVrd(EDX, ECX); 449 break; 450 451 case BPF_ALU|BPF_AND|BPF_K: 452 ANDid(EAX, ins->k); 453 break; 454 455 case BPF_ALU|BPF_OR|BPF_K: 456 ORid(EAX, ins->k); 457 break; 458 459 case BPF_ALU|BPF_LSH|BPF_K: 460 SHLib(EAX, (ins->k) & 255); 461 break; 462 463 case BPF_ALU|BPF_RSH|BPF_K: 464 SHRib(EAX, (ins->k) & 255); 465 break; 466 467 case BPF_ALU|BPF_NEG: 468 NEGd(EAX); 469 break; 470 471 case BPF_MISC|BPF_TAX: 472 MOVrd(EDX, EAX); 473 break; 474 475 case BPF_MISC|BPF_TXA: 476 MOVrd(EAX, EDX); 477 break; 478 } 479 ins++; 480 } 481 482 pass++; 483 if (pass == 2) 484 break; 485 486 stream.ibuf = (char *)malloc(stream.cur_ip, M_BPFJIT, M_NOWAIT); 487 if (stream.ibuf == NULL) { 488 free(stream.refs, M_BPFJIT); 489 return NULL; 490 } 491 492 /* 493 * modify the reference table to contain the offsets and 494 * not the lengths of the instructions 495 */ 496 for (i = 1; i < nins + 1; i++) 497 stream.refs[i] += stream.refs[i - 1]; 498 499 /* Reset the counters */ 500 stream.cur_ip = 0; 501 stream.bpf_pc = 0; 502 503 /* the second pass creates the actual code */ 504 emitm = emit_code; 505 } 506 507 /* 508 * the reference table is needed only during compilation, 509 * now we can free it 510 */ 511 free(stream.refs, M_BPFJIT); 512 513 return (bpf_filter_func)stream.ibuf; 514} 515