os/boardsupport/emulator/emulatorbsp/wpdpack/include/time_calls.h
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2  * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy)
     3  * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
     4  * All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions
     8  * are met:
     9  *
    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.
    19  *
    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.
    31  *
    32  */
    33 
    34 #ifndef _time_calls
    35 #define _time_calls
    36 
    37 #ifdef WIN_NT_DRIVER
    38 
    39 #include "debug.h"
    40 #include "ndis.h"
    41 
    42 #define	DEFAULT_TIMESTAMPMODE								0
    43 
    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
    48 
    49 #define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP		99
    50 
    51 #define TIMESTAMPMODE_REGKEY L"TimestampMode"
    52 
    53 extern ULONG TimestampMode;
    54 
    55 /*!
    56   \brief A microsecond precise timestamp.
    57 
    58   included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet. 
    59 */
    60 
    61 struct timeval {
    62         long    tv_sec;         ///< seconds
    63         long    tv_usec;        ///< microseconds
    64 };
    65 
    66 #endif /*WIN_NT_DRIVER*/
    67 
    68 struct time_conv
    69 {
    70 	ULONGLONG reference;
    71 	struct timeval start[32];
    72 };
    73 
    74 #ifdef WIN_NT_DRIVER
    75 
    76 __inline void TIME_DESYNCHRONIZE(struct time_conv *data)
    77 {
    78 	data->reference = 0;
    79 //	data->start.tv_sec = 0;
    80 //	data->start.tv_usec = 0;
    81 }
    82 
    83 
    84 __inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath)
    85 {
    86 	ULONG NewLength;
    87 	PWSTR NullTerminatedString;
    88 	RTL_QUERY_REGISTRY_TABLE Queries[2];
    89 	ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE;
    90 
    91 	NewLength = RegistryPath->Length/2;
    92 	
    93 	NullTerminatedString = ExAllocatePoolWithTag(PagedPool, (NewLength+1) *sizeof(WCHAR), '2TWA');
    94 	
    95 	if (NullTerminatedString != NULL)
    96 	{
    97 		RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length);
    98 				
    99 		NullTerminatedString[NewLength]=0;
   100 
   101 		RtlZeroMemory(Queries, sizeof(Queries));
   102 		
   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);
   109 
   110 		if(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS)
   111 		{
   112 			TimestampMode = DEFAULT_TIMESTAMPMODE;
   113 		}
   114 
   115 		RtlWriteRegistryValue(	RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY,  REG_DWORD, &TimestampMode,sizeof(ULONG));	
   116 		ExFreePool(NullTerminatedString);
   117 	}	
   118 	else
   119 		TimestampMode = DEFAULT_TIMESTAMPMODE;
   120 }
   121 
   122 #pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 
   123 
   124 /* KeQueryPerformanceCounter TimeStamps */
   125 __inline void SynchronizeOnCpu(struct timeval *start)
   126 {
   127 //	struct timeval *start = (struct timeval*)Data;
   128 
   129 	struct timeval tmp;
   130 	LARGE_INTEGER SystemTime;
   131 	LARGE_INTEGER i;
   132 	ULONG tmp2;
   133 	LARGE_INTEGER TimeFreq,PTime;
   134 
   135 	// get the absolute value of the system boot time.   
   136 	
   137 	PTime = KeQueryPerformanceCounter(&TimeFreq);
   138 	KeQuerySystemTime(&SystemTime);
   139 	
   140 	start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
   141 
   142 	start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
   143 
   144 	start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
   145 
   146 	start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
   147 
   148 	if (start->tv_usec < 0)
   149 	{
   150 		start->tv_sec --;
   151 		start->tv_usec += 1000000;
   152 	}
   153 }	
   154 
   155 //
   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. 
   164 //
   165 
   166 #ifdef __NPF_x86__
   167 /*RDTSC timestamps			*/
   168 /* callers must be at IRQL=PASSIVE_LEVEL*/
   169 __inline VOID TimeSynchronizeRDTSC(struct time_conv *data)
   170 {
   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;
   181 
   182    	if (data->reference!=0)
   183 		return;
   184 	
   185 	KeInitializeEvent(&event,NotificationEvent,FALSE);
   186 
   187 	i.QuadPart=-3500000;
   188 
   189 	KeRaiseIrql(HIGH_LEVEL,&old);
   190 	start_kqpc=KeQueryPerformanceCounter(&start_freq);
   191 	__asm
   192 	{
   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
   203 	}
   204 
   205 	KeLowerIrql(old);
   206 	
   207     	KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
   208 
   209 	KeRaiseIrql(HIGH_LEVEL,&old);
   210 	stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
   211 	__asm
   212 	{
   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
   223 	}
   224 	KeLowerIrql(old);
   225 
   226 	delta=stop_ticks-start_ticks;
   227 	delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
   228 	if (delta>10000000000)
   229 	{
   230 		delta/=16;
   231 		delta2/=16;
   232 	}
   233 
   234 	reference=delta*(start_freq.QuadPart)/delta2;
   235 	
   236 	data->reference=reference/1000;
   237 
   238 	if (reference%1000>500) 
   239 		data->reference++;
   240 
   241 	data->reference*=1000;
   242 
   243 	reference=data->reference;
   244 		
   245 	KeQuerySystemTime(&system_time);
   246 
   247 	__asm
   248 	{
   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
   259 	}
   260 	
   261 	tmp.tv_sec=-(LONG)(curr_ticks/reference);
   262 
   263 	tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
   264 
   265 	system_time.QuadPart-=116444736000000000;
   266 	
   267 	tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
   268 	tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
   269 	
   270 	if (tmp.tv_usec<0)
   271 	{
   272 		tmp.tv_sec--;
   273 		tmp.tv_usec+=1000000;
   274 	}
   275 
   276 	data->start[0] = tmp;
   277 
   278 	IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
   279 }
   280 #endif //__NPF_x86__
   281 
   282 #pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 
   283 
   284 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
   285 {
   286 	ULONG NumberOfCpus, i;
   287 	KAFFINITY AffinityMask;
   288 
   289 	if (data->reference != 0)
   290 		return;
   291 		
   292 	NumberOfCpus = NdisSystemProcessorCount();
   293 
   294 	if ( TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
   295 	{
   296 		for (i = 0 ;  i < NumberOfCpus ; i++ )
   297 		{
   298 			AffinityMask = (1 << i);
   299 			ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
   300 			SynchronizeOnCpu(&(data->start[i]));		
   301 		}
   302 		AffinityMask = 0xFFFFFFFF;
   303 		ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
   304 		data->reference = 1;
   305  	}
   306 	else
   307 	if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
   308 	{
   309 		//do nothing
   310 		data->reference = 1;
   311 	}
   312 	else
   313 //
   314 // This timestamp mode is supported on x86 (32 bit) only
   315 //
   316 #ifdef __NPF_x86__
   317 	if ( TimestampMode == TIMESTAMPMODE_RDTSC )
   318 	{
   319 		TimeSynchronizeRDTSC(data);
   320 	}
   321 	else
   322 #endif // __NPF_x86__
   323 	{	//it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
   324 		SynchronizeOnCpu(data->start);
   325 		data->reference = 1;
   326 	}
   327 	return;
   328 }
   329 
   330 
   331 #pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 
   332 
   333 __inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data)
   334 {
   335 	LARGE_INTEGER PTime, TimeFreq;
   336 	LONG tmp;
   337 	ULONG CurrentCpu;
   338 	static struct timeval old_ts={0,0};
   339 
   340 
   341 	PTime = KeQueryPerformanceCounter(&TimeFreq);
   342 	tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart);
   343 
   344 	if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
   345 	{
   346 		//actually this code is ok only if we are guaranteed that no thread scheduling will take place. 
   347 		CurrentCpu = KeGetCurrentProcessorNumber();	
   348 
   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);
   351 	
   352 		if (dst->tv_usec >= 1000000)
   353 		{
   354 			dst->tv_sec ++;
   355 			dst->tv_usec -= 1000000;
   356 		}
   357 
   358 		if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP)
   359 		{
   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;
   362 	
   363 			else
   364 				old_ts = *dst;
   365 		}
   366 	}
   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);
   371 	
   372 		if (dst->tv_usec >= 1000000)
   373 		{
   374 			dst->tv_sec ++;
   375 			dst->tv_usec -= 1000000;
   376 		}
   377 	}
   378 }
   379 
   380 //
   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. 
   389 //
   390 
   391 #ifdef __NPF_x86__
   392 __inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data)
   393 {
   394 
   395 	ULONGLONG tmp = 0;
   396 	__asm
   397 	{
   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
   408 	}
   409 
   410 	if (data->reference==0)
   411 	{
   412 		return;
   413 	}
   414 	dst->tv_sec=(LONG)(tmp/data->reference);
   415 
   416 	dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
   417 	
   418 	dst->tv_sec+=data->start[0].tv_sec;
   419 
   420 	dst->tv_usec+=data->start[0].tv_usec;
   421 
   422 	if (dst->tv_usec>=1000000)
   423 	{
   424 		dst->tv_sec++;
   425 		dst->tv_usec-=1000000;
   426 	}
   427 
   428 
   429 }
   430 #endif //__NPF_x86__
   431 
   432 __inline void GetTimeQST(struct timeval *dst, struct time_conv *data)
   433 {
   434 	LARGE_INTEGER SystemTime;
   435 
   436 	KeQuerySystemTime(&SystemTime);
   437 	
   438 	dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
   439 	dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
   440 
   441 }
   442 
   443 #pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 
   444 
   445 
   446 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
   447 {
   448 
   449 //
   450 // This timestamp mode is supported on x86 (32 bit) only
   451 //
   452 #ifdef __NPF_x86__
   453 	if ( TimestampMode == TIMESTAMPMODE_RDTSC )
   454 	{
   455 		GetTimeRDTSC(dst,data);
   456 	}
   457 	else
   458 #endif
   459 	if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
   460 	{
   461 		GetTimeQST(dst,data);
   462 	}
   463 	else
   464 	{
   465 		GetTimeKQPC(dst,data);
   466 	}
   467 }
   468 
   469 
   470 #else /*WIN_NT_DRIVER*/
   471 
   472 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
   473 {
   474 	dest->start[0]=*src;
   475 }
   476 
   477 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
   478 {
   479 	*dst=data->start[0];
   480 }
   481 
   482 #endif /*WIN_NT_DRIVER*/
   483 
   484 
   485 #endif /*_time_calls*/