branch update for HEAD-2003021201
[reactos.git] / 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 }