Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

time_calls.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001
00003  *      Politecnico di Torino.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that: (1) source code distributions
00007  * retain the above copyright notice and this paragraph in its entirety, (2)
00008  * distributions including binary code include the above copyright notice and
00009  * this paragraph in its entirety in the documentation or other materials
00010  * provided with the distribution, and (3) all advertising materials mentioning
00011  * features or use of this software display the following acknowledgement:
00012  * ``This product includes software developed by the Politecnico
00013  * di Torino, and its contributors.'' Neither the name of
00014  * the University nor the names of its contributors may be used to endorse
00015  * or promote products derived from this software without specific prior
00016  * written permission.
00017  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
00018  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00020  */
00021 
00022 #ifndef _time_calls
00023 #define _time_calls
00024 
00025 #ifdef WIN_NT_DRIVER
00026 
00027 #include "debug.h"
00028 #include "ndis.h"
00029 
00030 #define DEFAULT_TIMESTAMPMODE   0
00031 
00032 #define TIMESTAMPMODE_SINGLE_SYNCHRONIZATION            0
00033 #define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP 1
00034 #define TIMESTAMPMODE_QUERYSYSTEMTIME                   2
00035 #define TIMESTAMPMODE_RDTSC                             3
00036 
00037 #define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP   99
00038 
00039 #define TIMESTAMPMODE_REGKEY L"TimestampMode"
00040 
00041 extern ULONG TimestampMode;
00042 
00043 /*!
00044   \brief A microsecond precise timestamp.
00045 
00046   included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet. 
00047 */
00048 
00049 struct timeval {
00050         long    tv_sec;         ///< seconds
00051         long    tv_usec;        ///< microseconds
00052 };
00053 
00054 #endif /*WIN_NT_DRIVER*/
00055 
00056 struct time_conv
00057 {
00058         ULONGLONG reference;
00059         struct timeval start[32];
00060 };
00061 
00062 #ifdef WIN_NT_DRIVER
00063 
00064 __inline void TIME_DESYNCHRONIZE(struct time_conv *data)
00065 {
00066         data->reference = 0;
00067 //      data->start.tv_sec = 0;
00068 //      data->start.tv_usec = 0;
00069 }
00070 
00071 
00072 __inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath)
00073 {
00074         ULONG NewLength;
00075         PWSTR NullTerminatedString;
00076         RTL_QUERY_REGISTRY_TABLE Queries[2];
00077         ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE;
00078 
00079         NewLength = RegistryPath->Length/2;
00080         
00081         NullTerminatedString = ExAllocatePool(PagedPool, (NewLength+1) *sizeof(WCHAR));
00082         
00083         if (NullTerminatedString != NULL)
00084         {
00085                 RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length);
00086                                 
00087                 NullTerminatedString[NewLength]=0;
00088 
00089                 RtlZeroMemory(Queries, sizeof(Queries));
00090                 
00091                 Queries[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
00092                 Queries[0].Name = TIMESTAMPMODE_REGKEY;
00093                 Queries[0].EntryContext = &TimestampMode;
00094                 Queries[0].DefaultType = REG_DWORD;
00095                 Queries[0].DefaultData = &DefaultTimestampMode;
00096                 Queries[0].DefaultLength = sizeof(ULONG);
00097 
00098                 if (RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS)
00099                 {
00100                         TimestampMode = DEFAULT_TIMESTAMPMODE;
00101                 }
00102 
00103                 RtlWriteRegistryValue(  RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY,  REG_DWORD, &TimestampMode,sizeof(ULONG));   
00104                 ExFreePool(NullTerminatedString);
00105         }       
00106         else
00107                 TimestampMode = DEFAULT_TIMESTAMPMODE;
00108 }
00109 
00110 #pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 
00111 
00112 /* KeQueryPerformanceCounter TimeStamps */
00113 __inline void SynchronizeOnCpu(struct timeval *start)
00114 {
00115 //      struct timeval *start = (struct timeval*)Data;
00116 
00117         struct timeval tmp;
00118         LARGE_INTEGER SystemTime;
00119         LARGE_INTEGER i;
00120         ULONG tmp2;
00121         LARGE_INTEGER TimeFreq,PTime;
00122 
00123         // get the absolute value of the system boot time.   
00124         
00125         PTime = KeQueryPerformanceCounter(&TimeFreq);
00126         KeQuerySystemTime(&SystemTime);
00127         
00128         start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
00129 
00130         start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
00131 
00132         start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
00133 
00134         start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
00135 
00136         if (start->tv_usec < 0)
00137         {
00138                 start->tv_sec --;
00139                 start->tv_usec += 1000000;
00140         }
00141 }       
00142 
00143 /*RDTSC timestamps                      */
00144 /* callers must be at IRQL=PASSIVE_LEVEL*/
00145 __inline VOID TimeSynchronizeRDTSC(struct time_conv *data)
00146 {
00147         struct timeval tmp;
00148         LARGE_INTEGER system_time;
00149         ULONGLONG curr_ticks;
00150         KIRQL old;
00151         LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
00152         ULONGLONG start_ticks,stop_ticks;
00153         ULONGLONG delta,delta2;
00154         KEVENT event;
00155         LARGE_INTEGER i;
00156         ULONGLONG reference;
00157 
00158         if (data->reference!=0)
00159                 return;
00160         
00161         KeInitializeEvent(&event,NotificationEvent,FALSE);
00162 
00163         i.QuadPart=-3500000;
00164 
00165         KeRaiseIrql(HIGH_LEVEL,&old);
00166         start_kqpc=KeQueryPerformanceCounter(&start_freq);
00167         __asm
00168         {
00169                 push eax
00170                 push edx
00171                 push ecx
00172                 rdtsc
00173                 lea ecx, start_ticks
00174                 mov [ecx+4], edx
00175                 mov [ecx], eax
00176                 pop ecx
00177                 pop edx
00178                 pop eax
00179         }
00180 
00181         KeLowerIrql(old);
00182         
00183         KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
00184 
00185         KeRaiseIrql(HIGH_LEVEL,&old);
00186         stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
00187         __asm
00188         {
00189                 push eax
00190                 push edx
00191                 push ecx
00192                 rdtsc
00193                 lea ecx, stop_ticks
00194                 mov [ecx+4], edx
00195                 mov [ecx], eax
00196                 pop ecx
00197                 pop edx
00198                 pop eax
00199         }
00200         KeLowerIrql(old);
00201 
00202         delta=stop_ticks-start_ticks;
00203         delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
00204         if (delta>10000000000)
00205         {
00206                 delta/=16;
00207                 delta2/=16;
00208         }
00209 
00210         reference=delta*(start_freq.QuadPart)/delta2;
00211         
00212         data->reference=reference/1000;
00213 
00214         if (reference%1000>500) 
00215                 data->reference++;
00216 
00217         data->reference*=1000;
00218 
00219         reference=data->reference;
00220                 
00221         KeQuerySystemTime(&system_time);
00222 
00223         __asm
00224         {
00225                 push eax
00226                 push edx
00227                 push ecx
00228                 rdtsc
00229                 lea ecx, curr_ticks
00230                 mov [ecx+4], edx
00231                 mov [ecx], eax
00232                 pop ecx
00233                 pop edx
00234                 pop eax
00235         }
00236         
00237         tmp.tv_sec=-(LONG)(curr_ticks/reference);
00238 
00239         tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
00240 
00241         system_time.QuadPart-=116444736000000000;
00242         
00243         tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
00244         tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
00245         
00246         if (tmp.tv_usec<0)
00247         {
00248                 tmp.tv_sec--;
00249                 tmp.tv_usec+=1000000;
00250         }
00251 
00252         data->start[0] = tmp;
00253 
00254         IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
00255 }
00256 
00257 #pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 
00258 
00259 __inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
00260 {
00261         ULONG NumberOfCpus, i;
00262         KAFFINITY AffinityMask;
00263 
00264         if (data->reference != 0)
00265                 return;
00266                 
00267         NumberOfCpus = NdisSystemProcessorCount();
00268 
00269         if ( TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
00270         {
00271                 for (i = 0 ;  i < NumberOfCpus ; i++ )
00272                 {
00273                         AffinityMask = (1 << i);
00274                         ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
00275                         SynchronizeOnCpu(&(data->start[i]));            
00276                 }
00277                 AffinityMask = 0xFFFFFFFF;
00278                 ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
00279                 data->reference = 1;
00280         }
00281         else
00282         if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
00283         {
00284                 //do nothing
00285                 data->reference = 1;
00286         }
00287         else
00288         if ( TimestampMode == TIMESTAMPMODE_RDTSC )
00289         {
00290                 TimeSynchronizeRDTSC(data);
00291         }
00292         else
00293         {       //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
00294                 SynchronizeOnCpu(data->start);
00295                 data->reference = 1;
00296         }
00297         return;
00298 }
00299 
00300 
00301 #pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 
00302 
00303 __inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data)
00304 {
00305         LARGE_INTEGER PTime, TimeFreq;
00306         LONG tmp;
00307         ULONG CurrentCpu;
00308         static struct timeval old_ts={0,0};
00309 
00310 
00311         PTime = KeQueryPerformanceCounter(&TimeFreq);
00312         tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart);
00313 
00314         if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
00315         {
00316                 //actually this code is ok only if we are guaranteed that no thread scheduling will take place. 
00317                 CurrentCpu = KeGetCurrentProcessorNumber();     
00318 
00319                 dst->tv_sec = data->start[CurrentCpu].tv_sec + tmp;
00320                 dst->tv_usec = data->start[CurrentCpu].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
00321         
00322                 if (dst->tv_usec >= 1000000)
00323                 {
00324                         dst->tv_sec ++;
00325                         dst->tv_usec -= 1000000;
00326                 }
00327 
00328                 if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP)
00329                 {
00330                         if (old_ts.tv_sec > dst->tv_sec || (old_ts.tv_sec == dst->tv_sec &&  old_ts.tv_usec > dst->tv_usec) )
00331                                 *dst = old_ts;
00332         
00333                         else
00334                                 old_ts = *dst;
00335                 }
00336         }
00337         else
00338         {       //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
00339                 dst->tv_sec = data->start[0].tv_sec + tmp;
00340                 dst->tv_usec = data->start[0].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
00341         
00342                 if (dst->tv_usec >= 1000000)
00343                 {
00344                         dst->tv_sec ++;
00345                         dst->tv_usec -= 1000000;
00346                 }
00347         }
00348 }
00349 
00350 __inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data)
00351 {
00352 
00353         ULONGLONG tmp;
00354         __asm
00355         {
00356                 push eax
00357                 push edx
00358                 push ecx
00359                 rdtsc
00360                 lea ecx, tmp
00361                 mov [ecx+4], edx
00362                 mov [ecx], eax
00363                 pop ecx
00364                 pop edx
00365                 pop eax
00366         }
00367 
00368         if (data->reference==0)
00369         {
00370                 return;
00371         }
00372         dst->tv_sec=(LONG)(tmp/data->reference);
00373 
00374         dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
00375         
00376         dst->tv_sec+=data->start[0].tv_sec;
00377 
00378         dst->tv_usec+=data->start[0].tv_usec;
00379 
00380         if (dst->tv_usec>=1000000)
00381         {
00382                 dst->tv_sec++;
00383                 dst->tv_usec-=1000000;
00384         }
00385 
00386 
00387 }
00388 
00389 __inline void GetTimeQST(struct timeval *dst, struct time_conv *data)
00390 {
00391         LARGE_INTEGER SystemTime;
00392 
00393         KeQuerySystemTime(&SystemTime);
00394         
00395         dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
00396         dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
00397 
00398 }
00399 
00400 #pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 
00401 
00402 
00403 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
00404 {
00405 
00406         if ( TimestampMode == TIMESTAMPMODE_RDTSC )
00407         {
00408                 GetTimeRDTSC(dst,data);
00409         }
00410         else
00411         if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
00412         {
00413                 GetTimeQST(dst,data);
00414         }
00415         else
00416         {
00417                 GetTimeKQPC(dst,data);
00418         }
00419 }
00420 
00421 
00422 #else /*WIN_NT_DRIVER*/
00423 
00424 __inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
00425 {
00426         dest->start[0]=*src;
00427 }
00428 
00429 __inline void GET_TIME(struct timeval *dst, struct time_conv *data)
00430 {
00431         *dst=data->start[0];
00432 }
00433 
00434 #endif /*WIN_NT_DRIVER*/
00435 
00436 
00437 #endif /*_time_calls*/

Generated on Sun May 14 14:51:20 2006 by  doxygen 1.4.2