2 * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
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
;
56 \brief A microsecond precise timestamp.
58 included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet.
62 long tv_sec
; ///< seconds
63 long tv_usec
; ///< microseconds
66 #endif /*WIN_NT_DRIVER*/
71 struct timeval start
[32];
76 __inline
void TIME_DESYNCHRONIZE(struct time_conv
*data
)
79 // data->start.tv_sec = 0;
80 // data->start.tv_usec = 0;
84 __inline
void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath
)
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
);
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;
130 LARGE_INTEGER SystemTime
;
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)
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.
167 /*RDTSC timestamps */
168 /* callers must be at IRQL=PASSIVE_LEVEL*/
169 __inline VOID
TimeSynchronizeRDTSC(struct time_conv
*data
)
172 LARGE_INTEGER system_time
;
173 ULONGLONG curr_ticks
;
175 LARGE_INTEGER start_kqpc
,stop_kqpc
,start_freq
,stop_freq
;
176 ULONGLONG start_ticks
,stop_ticks
;
177 ULONGLONG delta
,delta2
;
182 if (data
->reference
!=0)
185 KeInitializeEvent(&event
,NotificationEvent
,FALSE
);
189 KeRaiseIrql(HIGH_LEVEL
,&old
);
190 start_kqpc
=KeQueryPerformanceCounter(&start_freq
);
207 KeWaitForSingleObject(&event
,UserRequest
,KernelMode
,TRUE
,&i
);
209 KeRaiseIrql(HIGH_LEVEL
,&old
);
210 stop_kqpc
=KeQueryPerformanceCounter(&stop_freq
);
226 delta
=stop_ticks
-start_ticks
;
227 delta2
=stop_kqpc
.QuadPart
-start_kqpc
.QuadPart
;
228 if (delta
>10000000000)
234 reference
=delta
*(start_freq
.QuadPart
)/delta2
;
236 data
->reference
=reference
/1000;
238 if (reference
%1000>500)
241 data
->reference
*=1000;
243 reference
=data
->reference
;
245 KeQuerySystemTime(&system_time
);
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);
273 tmp
.tv_usec
+=1000000;
276 data
->start
[0] = tmp
;
278 IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data
->reference
);)
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)
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
));
307 if ( TimestampMode
== TIMESTAMPMODE_QUERYSYSTEMTIME
)
314 // This timestamp mode is supported on x86 (32 bit) only
317 if ( TimestampMode
== TIMESTAMPMODE_RDTSC
)
319 TimeSynchronizeRDTSC(data
);
323 { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
324 SynchronizeOnCpu(data
->start
);
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
;
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)
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
) )
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)
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.
392 __inline
void GetTimeRDTSC(struct timeval
*dst
, struct time_conv
*data
)
410 if (data
->reference
==0)
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)
425 dst
->tv_usec
-=1000000;
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
453 if ( TimestampMode
== TIMESTAMPMODE_RDTSC
)
455 GetTimeRDTSC(dst
,data
);
459 if ( TimestampMode
== TIMESTAMPMODE_QUERYSYSTEMTIME
)
461 GetTimeQST(dst
,data
);
465 GetTimeKQPC(dst
,data
);
470 #else /*WIN_NT_DRIVER*/
472 __inline
void FORCE_TIME(struct timeval
*src
, struct time_conv
*dest
)
477 __inline
void GET_TIME(struct timeval
*dst
, struct time_conv
*data
)
482 #endif /*WIN_NT_DRIVER*/
485 #endif /*_time_calls*/