remove whitespace from end of lines
[reactos.git] / reactos / drivers / net / packet / jitter.c
1 /*
2 * Copyright (c) 2002
3 * Politecnico di Torino. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 #ifdef _MSC_VER
23 #include "stdarg.h"
24 #include "ntddk.h"
25 #include "ntiologc.h"
26 #include "ndis.h"
27 #else
28 #include <ddk/ntddk.h>
29 #include <net/ndis.h>
30 #endif
31
32 #include "packet.h"
33 #include "win_bpf.h"
34
35 emit_func emitm;
36
37 //
38 // emit routine to update the jump table
39 //
40 void emit_lenght(binary_stream *stream, ULONG value, UINT len)
41 {
42 (stream->refs)[stream->bpf_pc]+=len;
43 stream->cur_ip+=len;
44 }
45
46 //
47 // emit routine to output the actual binary code
48 //
49 void emit_code(binary_stream *stream, ULONG value, UINT len)
50 {
51
52 switch (len){
53
54 case 1:
55 stream->ibuf[stream->cur_ip]=(UCHAR)value;
56 stream->cur_ip++;
57 break;
58
59 case 2:
60 *((USHORT*)(stream->ibuf+stream->cur_ip))=(USHORT)value;
61 stream->cur_ip+=2;
62 break;
63
64 case 4:
65 *((ULONG*)(stream->ibuf+stream->cur_ip))=value;
66 stream->cur_ip+=4;
67 break;
68
69 default:;
70
71 }
72
73 return;
74
75 }
76
77 //
78 // Function that does the real stuff
79 //
80 BPF_filter_function BPFtoX86(struct bpf_insn *prog, UINT nins, INT *mem)
81 {
82 struct bpf_insn *ins;
83 UINT i, pass;
84 binary_stream stream;
85
86
87 // Allocate the reference table for the jumps
88 #ifdef NTKERNEL
89 #define NPF_TAG_REFTABLE TAG('0', 'J', 'W', 'A')
90 stream.refs=(UINT *)ExAllocatePoolWithTag(NonPagedPool, (nins + 1)*sizeof(UINT), NPF_TAG_REFTABLE);
91 #else
92 stream.refs=(UINT *)malloc((nins + 1)*sizeof(UINT));
93 #endif
94 if(stream.refs==NULL)
95 {
96 return NULL;
97 }
98
99 // Reset the reference table
100 for(i=0; i< nins + 1; i++)
101 stream.refs[i]=0;
102
103 stream.cur_ip=0;
104 stream.bpf_pc=0;
105
106 // the first pass will emit the lengths of the instructions
107 // to create the reference table
108 emitm=emit_lenght;
109
110 for(pass=0;;){
111
112 ins = prog;
113
114 /* create the procedure header */
115 PUSH(EBP)
116 MOVrd(EBP,ESP)
117 PUSH(EBX)
118 PUSH(ECX)
119 PUSH(EDX)
120 PUSH(ESI)
121 PUSH(EDI)
122 MOVodd(EBX, EBP, 8)
123
124 for(i=0;i<nins;i++){
125
126 stream.bpf_pc++;
127
128 switch (ins->code) {
129
130 default:
131
132 return NULL;
133
134 case BPF_RET|BPF_K:
135
136 MOVid(EAX,ins->k)
137 POP(EDI)
138 POP(ESI)
139 POP(EDX)
140 POP(ECX)
141 POP(EBX)
142 POP(EBP)
143 RET()
144
145 break;
146
147
148 case BPF_RET|BPF_A:
149
150 POP(EDI)
151 POP(ESI)
152 POP(EDX)
153 POP(ECX)
154 POP(EBX)
155 POP(EBP)
156 RET()
157
158 break;
159
160
161 case BPF_LD|BPF_W|BPF_ABS:
162
163 MOVid(ECX,ins->k)
164 MOVrd(ESI,ECX)
165 ADDib(ECX,sizeof(INT))
166 CMPodd(ECX, EBP, 0x10)
167 JLEb(12)
168 POP(EDI)
169 POP(ESI)
170 POP(EDX)
171 POP(ECX)
172 POP(EBX)
173 POP(EBP)
174 MOVid(EAX,0) //this can be optimized with xor eax,eax
175 RET()
176 MOVobd(EAX, EBX, ESI)
177 BSWAP(EAX)
178
179 break;
180
181 case BPF_LD|BPF_H|BPF_ABS:
182
183 MOVid(ECX,ins->k)
184 MOVrd(ESI,ECX)
185 ADDib(ECX,sizeof(SHORT))
186 CMPodd(ECX, EBP, 0x10)
187 JLEb(12)
188 POP(EDI)
189 POP(ESI)
190 POP(EDX)
191 POP(ECX)
192 POP(EBX)
193 POP(EBP)
194 MOVid(EAX,0)
195 RET()
196 MOVid(EAX,0)
197 MOVobw(AX, EBX, ESI)
198 SWAP_AX()
199
200 break;
201
202 case BPF_LD|BPF_B|BPF_ABS:
203
204 MOVid(ECX,ins->k)
205 CMPodd(ECX, EBP, 0x10)
206 JLEb(12)
207 POP(EDI)
208 POP(ESI)
209 POP(EDX)
210 POP(ECX)
211 POP(EBX)
212 POP(EBP)
213 MOVid(EAX,0)
214 RET()
215 MOVid(EAX,0)
216 MOVobb(AL,EBX,ECX)
217
218 break;
219
220 case BPF_LD|BPF_W|BPF_LEN:
221
222 MOVodd(EAX, EBP, 0xc)
223
224 break;
225
226 case BPF_LDX|BPF_W|BPF_LEN:
227
228 MOVodd(EDX, EBP, 0xc)
229
230 break;
231
232 case BPF_LD|BPF_W|BPF_IND:
233
234 MOVid(ECX,ins->k)
235 ADDrd(ECX,EDX)
236 MOVrd(ESI,ECX)
237 ADDib(ECX,sizeof(INT))
238 CMPodd(ECX, EBP, 0x10)
239 JLEb(12)
240 POP(EDI)
241 POP(ESI)
242 POP(EDX)
243 POP(ECX)
244 POP(EBX)
245 POP(EBP)
246 MOVid(EAX,0)
247 RET()
248 MOVobd(EAX, EBX, ESI)
249 BSWAP(EAX)
250
251 break;
252
253 case BPF_LD|BPF_H|BPF_IND:
254
255 MOVid(ECX,ins->k)
256 ADDrd(ECX,EDX)
257 MOVrd(ESI,ECX)
258 ADDib(ECX,sizeof(SHORT))
259 CMPodd(ECX, EBP, 0x10)
260 JLEb(12)
261 POP(EDI)
262 POP(ESI)
263 POP(EDX)
264 POP(ECX)
265 POP(EBX)
266 POP(EBP)
267 MOVid(EAX,0)
268 RET()
269 MOVid(EAX,0)
270 MOVobw(AX, EBX, ESI)
271 SWAP_AX()
272
273 break;
274
275 case BPF_LD|BPF_B|BPF_IND:
276
277 MOVid(ECX,ins->k)
278 ADDrd(ECX,EDX)
279 CMPodd(ECX, EBP, 0x10)
280 JLEb(12)
281 POP(EDI)
282 POP(ESI)
283 POP(EDX)
284 POP(ECX)
285 POP(EBX)
286 POP(EBP)
287 MOVid(EAX,0)
288 RET()
289 MOVid(EAX,0)
290 MOVobb(AL,EBX,ECX)
291
292 break;
293
294 case BPF_LDX|BPF_MSH|BPF_B:
295
296 MOVid(ECX,ins->k)
297 CMPodd(ECX, EBP, 0x10)
298 JLEb(12)
299 POP(EDI)
300 POP(ESI)
301 POP(EDX)
302 POP(ECX)
303 POP(EBX)
304 POP(EBP)
305 MOVid(EAX,0)
306 RET()
307 MOVid(EDX,0)
308 MOVobb(DL,EBX,ECX)
309 ANDib(DL, 0xf)
310 SHLib(EDX, 2)
311
312 break;
313
314 case BPF_LD|BPF_IMM:
315
316 MOVid(EAX,ins->k)
317
318 break;
319
320 case BPF_LDX|BPF_IMM:
321
322 MOVid(EDX,ins->k)
323
324 break;
325
326 case BPF_LD|BPF_MEM:
327
328 MOVid(ECX,(INT)mem)
329 MOVid(ESI,ins->k*4)
330 MOVobd(EAX, ECX, ESI)
331
332 break;
333
334 case BPF_LDX|BPF_MEM:
335
336 MOVid(ECX,(INT)mem)
337 MOVid(ESI,ins->k*4)
338 MOVobd(EDX, ECX, ESI)
339
340 break;
341
342 case BPF_ST:
343
344 // XXX: this command and the following could be optimized if the previous
345 // instruction was already of this type
346 MOVid(ECX,(INT)mem)
347 MOVid(ESI,ins->k*4)
348 MOVomd(ECX, ESI, EAX)
349
350 break;
351
352 case BPF_STX:
353
354 MOVid(ECX,(INT)mem)
355 MOVid(ESI,ins->k*4)
356 MOVomd(ECX, ESI, EDX)
357 break;
358
359 case BPF_JMP|BPF_JA:
360
361 JMP(stream.refs[stream.bpf_pc+ins->k]-stream.refs[stream.bpf_pc])
362
363 break;
364
365 case BPF_JMP|BPF_JGT|BPF_K:
366
367 CMPid(EAX, ins->k)
368 JG(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5) // 5 is the size of the following JMP
369 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
370 break;
371
372 case BPF_JMP|BPF_JGE|BPF_K:
373
374 CMPid(EAX, ins->k)
375 JGE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
376 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
377
378 break;
379
380 case BPF_JMP|BPF_JEQ|BPF_K:
381
382 CMPid(EAX, ins->k)
383 JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
384 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
385
386 break;
387
388 case BPF_JMP|BPF_JSET|BPF_K:
389
390 MOVrd(ECX,EAX)
391 ANDid(ECX,ins->k)
392 JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5)
393 JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc])
394
395 break;
396
397 case BPF_JMP|BPF_JGT|BPF_X:
398
399 CMPrd(EAX, EDX)
400 JA(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
401 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
402 break;
403
404 case BPF_JMP|BPF_JGE|BPF_X:
405
406 CMPrd(EAX, EDX)
407 JAE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
408 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
409
410 break;
411
412 case BPF_JMP|BPF_JEQ|BPF_X:
413
414 CMPrd(EAX, EDX)
415 JE(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc]+5)
416 JMP(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc])
417
418 break;
419
420 case BPF_JMP|BPF_JSET|BPF_X:
421
422 MOVrd(ECX,EAX)
423 ANDrd(ECX,EDX)
424 JE(stream.refs[stream.bpf_pc+ins->jf]-stream.refs[stream.bpf_pc]+5)
425 JMP(stream.refs[stream.bpf_pc+ins->jt]-stream.refs[stream.bpf_pc])
426
427 break;
428
429 case BPF_ALU|BPF_ADD|BPF_X:
430
431 ADDrd(EAX,EDX)
432
433 break;
434
435 case BPF_ALU|BPF_SUB|BPF_X:
436
437 SUBrd(EAX,EDX)
438
439 break;
440
441 case BPF_ALU|BPF_MUL|BPF_X:
442
443 MOVrd(ECX,EDX)
444 MULrd(EDX)
445 MOVrd(EDX,ECX)
446 break;
447
448 case BPF_ALU|BPF_DIV|BPF_X:
449
450 CMPid(EDX, 0)
451 JNEb(12)
452 POP(EDI)
453 POP(ESI)
454 POP(EDX)
455 POP(ECX)
456 POP(EBX)
457 POP(EBP)
458 MOVid(EAX,0)
459 RET()
460 MOVrd(ECX,EDX)
461 MOVid(EDX,0)
462 DIVrd(ECX)
463 MOVrd(EDX,ECX)
464
465 break;
466
467 case BPF_ALU|BPF_AND|BPF_X:
468
469 ANDrd(EAX,EDX)
470
471 break;
472
473 case BPF_ALU|BPF_OR|BPF_X:
474
475 ORrd(EAX,EDX)
476
477 break;
478
479 case BPF_ALU|BPF_LSH|BPF_X:
480
481 MOVrd(ECX,EDX)
482 SHL_CLrb(EAX)
483
484 break;
485
486 case BPF_ALU|BPF_RSH|BPF_X:
487
488 MOVrd(ECX,EDX)
489 SHR_CLrb(EAX)
490
491 break;
492
493 case BPF_ALU|BPF_ADD|BPF_K:
494
495 ADD_EAXi(ins->k)
496
497 break;
498
499 case BPF_ALU|BPF_SUB|BPF_K:
500
501 SUB_EAXi(ins->k)
502
503 break;
504
505 case BPF_ALU|BPF_MUL|BPF_K:
506
507 MOVrd(ECX,EDX)
508 MOVid(EDX,ins->k)
509 MULrd(EDX)
510 MOVrd(EDX,ECX)
511
512 break;
513
514 case BPF_ALU|BPF_DIV|BPF_K:
515
516 MOVrd(ECX,EDX)
517 MOVid(EDX,0)
518 MOVid(ESI,ins->k)
519 DIVrd(ESI)
520 MOVrd(EDX,ECX)
521
522 break;
523
524 case BPF_ALU|BPF_AND|BPF_K:
525
526 ANDid(EAX, ins->k)
527
528 break;
529
530 case BPF_ALU|BPF_OR|BPF_K:
531
532 ORid(EAX, ins->k)
533
534 break;
535
536 case BPF_ALU|BPF_LSH|BPF_K:
537
538 SHLib(EAX, (ins->k) & 255)
539
540 break;
541
542 case BPF_ALU|BPF_RSH|BPF_K:
543
544 SHRib(EAX, (ins->k) & 255)
545
546 break;
547
548 case BPF_ALU|BPF_NEG:
549
550 NEGd(EAX)
551
552 break;
553
554 case BPF_MISC|BPF_TAX:
555
556 MOVrd(EDX,EAX)
557
558 break;
559
560 case BPF_MISC|BPF_TXA:
561
562 MOVrd(EAX,EDX)
563
564 break;
565
566
567
568 }
569
570 ins++;
571 }
572
573 pass++;
574 if(pass == 2) break;
575
576 #ifdef NTKERNEL
577 #define NPF_TAG_STREAMBUF TAG('1', 'J', 'W', 'A')
578 stream.ibuf=(CHAR*)ExAllocatePoolWithTag(NonPagedPool, stream.cur_ip, NPF_TAG_STREAMBUF);
579 #else
580 stream.ibuf=(CHAR*)malloc(stream.cur_ip);
581 #endif
582 if(stream.ibuf==NULL)
583 {
584 #ifdef NTKERNEL
585 ExFreePool(stream.refs);
586 #else
587 free(stream.refs);
588 #endif
589 return NULL;
590 }
591
592 // modify the reference table to contain the offsets and not the lengths of the instructions
593 for(i=1; i< nins + 1; i++)
594 stream.refs[i]+=stream.refs[i-1];
595
596 // Reset the counters
597 stream.cur_ip=0;
598 stream.bpf_pc=0;
599 // the second pass creates the actual code
600 emitm=emit_code;
601
602 }
603
604 // the reference table is needed only during compilation, now we can free it
605 #ifdef NTKERNEL
606 ExFreePool(stream.refs);
607 #else
608 free(stream.refs);
609 #endif
610 return (BPF_filter_function)stream.ibuf;
611
612 }
613
614
615 JIT_BPF_Filter* BPF_jitter(struct bpf_insn *fp, INT nins)
616 {
617 JIT_BPF_Filter *Filter;
618
619
620 // Allocate the filter structure
621 #ifdef NTKERNEL
622 #define NPF_TAG_FILTSTRUCT TAG('2', 'J', 'W', 'A')
623 Filter=(struct JIT_BPF_Filter*)ExAllocatePoolWithTag(NonPagedPool, sizeof(struct JIT_BPF_Filter), NPF_TAG_FILTSTRUCT);
624 #else
625 Filter=(struct JIT_BPF_Filter*)malloc(sizeof(struct JIT_BPF_Filter));
626 #endif
627 if(Filter==NULL)
628 {
629 return NULL;
630 }
631
632 // Allocate the filter's memory
633 #ifdef NTKERNEL
634 #define NPF_TAG_FILTMEM TAG('3', 'J', 'W', 'A')
635 Filter->mem=(INT*)ExAllocatePoolWithTag(NonPagedPool, BPF_MEMWORDS*sizeof(INT), NPF_TAG_FILTMEM);
636 #else
637 Filter->mem=(INT*)malloc(BPF_MEMWORDS*sizeof(INT));
638 #endif
639 if(Filter->mem==NULL)
640 {
641 #ifdef NTKERNEL
642 ExFreePool(Filter);
643 #else
644 free(Filter);
645 #endif
646 return NULL;
647 }
648
649 // Create the binary
650 if((Filter->Function = BPFtoX86(fp, nins, Filter->mem))==NULL)
651 {
652 #ifdef NTKERNEL
653 ExFreePool(Filter->mem);
654 ExFreePool(Filter);
655 #else
656 free(Filter->mem);
657 free(Filter);
658
659 return NULL;
660 #endif
661 }
662
663 return Filter;
664
665 }
666
667 //////////////////////////////////////////////////////////////
668
669 void BPF_Destroy_JIT_Filter(JIT_BPF_Filter *Filter){
670
671 #ifdef NTKERNEL
672 ExFreePool(Filter->mem);
673 ExFreePool(Filter->Function);
674 ExFreePool(Filter);
675 #else
676 free(Filter->mem);
677 free(Filter->Function);
678 free(Filter);
679 #endif
680
681 }