add winpcap 4.0.2 from url http://www.winpcap.org/
[natblaster.git] / winpcap / packetNtx / driver / time_calls.h
blob09a6d6959520c4bcc4f1595663f00d1bec655ef0
1 /*
2 * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #ifndef _time_calls
35 #define _time_calls
37 #ifdef WIN_NT_DRIVER
39 #include "debug.h"
40 #include "ndis.h"
42 #define DEFAULT_TIMESTAMPMODE 0
44 #define TIMESTAMPMODE_SINGLE_SYNCHRONIZATION 0
45 #define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP 1
46 #define TIMESTAMPMODE_QUERYSYSTEMTIME 2
47 #define TIMESTAMPMODE_RDTSC 3
49 #define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP 99
51 #define TIMESTAMPMODE_REGKEY L"TimestampMode"
53 extern ULONG TimestampMode;
55 /*!
56 \brief A microsecond precise timestamp.
58 included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet.
61 struct timeval {
62 long tv_sec; ///< seconds
63 long tv_usec; ///< microseconds
66 #endif /*WIN_NT_DRIVER*/
68 struct time_conv
70 ULONGLONG reference;
71 struct timeval start[32];
74 #ifdef WIN_NT_DRIVER
76 __inline void TIME_DESYNCHRONIZE(struct time_conv *data)
78 data->reference = 0;
79 // data->start.tv_sec = 0;
80 // data->start.tv_usec = 0;
84 __inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath)
86 ULONG NewLength;
87 PWSTR NullTerminatedString;
88 RTL_QUERY_REGISTRY_TABLE Queries[2];
89 ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE;
91 NewLength = RegistryPath->Length/2;
93 NullTerminatedString = ExAllocatePoolWithTag(PagedPool, (NewLength+1) *sizeof(WCHAR), '2TWA');
95 if (NullTerminatedString != NULL)
97 RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length);
99 NullTerminatedString[NewLength]=0;
101 RtlZeroMemory(Queries, sizeof(Queries));
103 Queries[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
104 Queries[0].Name = TIMESTAMPMODE_REGKEY;
105 Queries[0].EntryContext = &TimestampMode;
106 Queries[0].DefaultType = REG_DWORD;
107 Queries[0].DefaultData = &DefaultTimestampMode;
108 Queries[0].DefaultLength = sizeof(ULONG);
110 if(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS)
112 TimestampMode = DEFAULT_TIMESTAMPMODE;
115 RtlWriteRegistryValue( RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY, REG_DWORD, &TimestampMode,sizeof(ULONG));
116 ExFreePool(NullTerminatedString);
118 else
119 TimestampMode = DEFAULT_TIMESTAMPMODE;
122 #pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600
124 /* KeQueryPerformanceCounter TimeStamps */
125 __inline void SynchronizeOnCpu(struct timeval *start)
127 // struct timeval *start = (struct timeval*)Data;
129 struct timeval tmp;
130 LARGE_INTEGER SystemTime;
131 LARGE_INTEGER i;
132 ULONG tmp2;
133 LARGE_INTEGER TimeFreq,PTime;
135 // get the absolute value of the system boot time.
137 PTime = KeQueryPerformanceCounter(&TimeFreq);
138 KeQuerySystemTime(&SystemTime);
140 start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
142 start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
144 start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
146 start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
148 if (start->tv_usec < 0)
150 start->tv_sec --;
151 start->tv_usec += 1000000;
156 // inline assembler is not supported with the current AMD64 compilers
157 // At the moment we simply disable this timestamping mode on AMD64.
158 // A solution would be to allocate a small memory from the non-paged
159 // pool, dump the instructions on that buffer, and then execute them.
160 // The non paged pool is needed since it's the only area of kernel
161 // data memory that is not subject to the NX protection.
162 // Or use some lower level trick, like using an assembler to assemble
163 // a small function for this.
166 #ifdef _X86_
167 /*RDTSC timestamps */
168 /* callers must be at IRQL=PASSIVE_LEVEL*/
169 __inline VOID TimeSynchronizeRDTSC(struct time_conv *data)
171 struct timeval tmp;
172 LARGE_INTEGER system_time;
173 ULONGLONG curr_ticks;
174 KIRQL old;
175 LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
176 ULONGLONG start_ticks,stop_ticks;
177 ULONGLONG delta,delta2;
178 KEVENT event;
179 LARGE_INTEGER i;
180 ULONGLONG reference;
182 if (data->reference!=0)
183 return;
185 KeInitializeEvent(&event,NotificationEvent,FALSE);
187 i.QuadPart=-3500000;
189 KeRaiseIrql(HIGH_LEVEL,&old);
190 start_kqpc=KeQueryPerformanceCounter(&start_freq);
191 __asm
193 push eax
194 push edx
195 push ecx
196 rdtsc
197 lea ecx, start_ticks
198 mov [ecx+4], edx
199 mov [ecx], eax
200 pop ecx
201 pop edx
202 pop eax
205 KeLowerIrql(old);
207 KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
209 KeRaiseIrql(HIGH_LEVEL,&old);
210 stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
211 __asm
213 push eax
214 push edx
215 push ecx
216 rdtsc
217 lea ecx, stop_ticks
218 mov [ecx+4], edx
219 mov [ecx], eax
220 pop ecx
221 pop edx
222 pop eax
224 KeLowerIrql(old);
226 delta=stop_ticks-start_ticks;
227 delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
228 if (delta>10000000000)
230 delta/=16;
231 delta2/=16;
234 reference=delta*(start_freq.QuadPart)/delta2;
236 data->reference=reference/1000;
238 if (reference%1000>500)
239 data->reference++;
241 data->reference*=1000;
243 reference=data->reference;
245 KeQuerySystemTime(&system_time);
247 __asm
249 push eax
250 push edx
251 push ecx
252 rdtsc
253 lea ecx, curr_ticks
254 mov [ecx+4], edx
255 mov [ecx], eax
256 pop ecx
257 pop edx
258 pop eax
261 tmp.tv_sec=-(LONG)(curr_ticks/reference);
263 tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
265 system_time.QuadPart-=116444736000000000;
267 tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
268 tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
270 if (tmp.tv_usec<0)
272 tmp.tv_sec--;
273 tmp.tv_usec+=1000000;
276 data->start[0] = tmp;
278 IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
280 #endif //_X86_
282 #pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600
284 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
286 ULONG NumberOfCpus, i;
287 KAFFINITY AffinityMask;
289 if (data->reference != 0)
290 return;
292 NumberOfCpus = NdisSystemProcessorCount();
294 if ( TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
296 for (i = 0 ; i < NumberOfCpus ; i++ )
298 AffinityMask = (1 << i);
299 ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
300 SynchronizeOnCpu(&(data->start[i]));
302 AffinityMask = 0xFFFFFFFF;
303 ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
304 data->reference = 1;
306 else
307 if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
309 //do nothing
310 data->reference = 1;
312 else
314 // This timestamp mode is supported on x86 (32 bit) only
316 #ifdef _X86_
317 if ( TimestampMode == TIMESTAMPMODE_RDTSC )
319 TimeSynchronizeRDTSC(data);
321 else
322 #endif // _X86_
323 { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
324 SynchronizeOnCpu(data->start);
325 data->reference = 1;
327 return;
331 #pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600
333 __inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data)
335 LARGE_INTEGER PTime, TimeFreq;
336 LONG tmp;
337 ULONG CurrentCpu;
338 static struct timeval old_ts={0,0};
341 PTime = KeQueryPerformanceCounter(&TimeFreq);
342 tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart);
344 if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
346 //actually this code is ok only if we are guaranteed that no thread scheduling will take place.
347 CurrentCpu = KeGetCurrentProcessorNumber();
349 dst->tv_sec = data->start[CurrentCpu].tv_sec + tmp;
350 dst->tv_usec = data->start[CurrentCpu].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
352 if (dst->tv_usec >= 1000000)
354 dst->tv_sec ++;
355 dst->tv_usec -= 1000000;
358 if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP)
360 if (old_ts.tv_sec > dst->tv_sec || (old_ts.tv_sec == dst->tv_sec && old_ts.tv_usec > dst->tv_usec) )
361 *dst = old_ts;
363 else
364 old_ts = *dst;
367 else
368 { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
369 dst->tv_sec = data->start[0].tv_sec + tmp;
370 dst->tv_usec = data->start[0].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
372 if (dst->tv_usec >= 1000000)
374 dst->tv_sec ++;
375 dst->tv_usec -= 1000000;
381 // inline assembler is not supported with the current AMD64 compilers
382 // At the moment we simply disable this timestamping mode on AMD64.
383 // A solution would be to allocate a small memory from the non-paged
384 // pool, dump the instructions on that buffer, and then execute them.
385 // The non paged pool is needed since it's the only area of kernel
386 // data memory that is not subject to the NX protection.
387 // Or use some lower level trick, like using an assembler to assemble
388 // a small function for this.
391 #ifdef _X86_
392 __inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data)
395 ULONGLONG tmp = 0;
396 __asm
398 push eax
399 push edx
400 push ecx
401 rdtsc
402 lea ecx, tmp
403 mov [ecx+4], edx
404 mov [ecx], eax
405 pop ecx
406 pop edx
407 pop eax
410 if (data->reference==0)
412 return;
414 dst->tv_sec=(LONG)(tmp/data->reference);
416 dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
418 dst->tv_sec+=data->start[0].tv_sec;
420 dst->tv_usec+=data->start[0].tv_usec;
422 if (dst->tv_usec>=1000000)
424 dst->tv_sec++;
425 dst->tv_usec-=1000000;
430 #endif //_X86_
432 __inline void GetTimeQST(struct timeval *dst, struct time_conv *data)
434 LARGE_INTEGER SystemTime;
436 KeQuerySystemTime(&SystemTime);
438 dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
439 dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
443 #pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600
446 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
450 // This timestamp mode is supported on x86 (32 bit) only
452 #ifdef _X86_
453 if ( TimestampMode == TIMESTAMPMODE_RDTSC )
455 GetTimeRDTSC(dst,data);
457 else
458 #endif // _X86_
459 if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
461 GetTimeQST(dst,data);
463 else
465 GetTimeKQPC(dst,data);
470 #else /*WIN_NT_DRIVER*/
472 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
474 dest->start[0]=*src;
477 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
479 *dst=data->start[0];
482 #endif /*WIN_NT_DRIVER*/
485 #endif /*_time_calls*/