Logo Search packages:      
Sourcecode: nmap version File versions  Download package

time_calls.h

/*
 * Copyright (c) 2001
 *    Politecnico di Torino.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * distributions including binary code include the above copyright notice and
 * this paragraph in its entirety in the documentation or other materials
 * provided with the distribution, and (3) all advertising materials mentioning
 * features or use of this software display the following acknowledgement:
 * ``This product includes software developed by the Politecnico
 * di Torino, and its contributors.'' Neither the name of
 * the University nor the names of its contributors may be used to endorse
 * or promote products derived from this software without specific prior
 * written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef _time_calls
#define _time_calls

#ifdef WIN_NT_DRIVER

#include "debug.h"
#include "ndis.h"

#define     DEFAULT_TIMESTAMPMODE   0

#define TIMESTAMPMODE_SINGLE_SYNCHRONIZATION          0
#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP     1
#define TIMESTAMPMODE_QUERYSYSTEMTIME                 2
#define TIMESTAMPMODE_RDTSC                     3

#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP 99

#define TIMESTAMPMODE_REGKEY L"TimestampMode"

extern ULONG TimestampMode;

/*!
  \brief A microsecond precise timestamp.

  included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet. 
*/

struct timeval {
        long    tv_sec;         ///< seconds
        long    tv_usec;        ///< microseconds
};

#endif /*WIN_NT_DRIVER*/

00056 struct time_conv
{
      ULONGLONG reference;
      struct timeval start[32];
};

#ifdef WIN_NT_DRIVER

__inline void TIME_DESYNCHRONIZE(struct time_conv *data)
{
      data->reference = 0;
//    data->start.tv_sec = 0;
//    data->start.tv_usec = 0;
}


__inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath)
{
      ULONG NewLength;
      PWSTR NullTerminatedString;
      RTL_QUERY_REGISTRY_TABLE Queries[2];
      ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE;

      NewLength = RegistryPath->Length/2;
      
      NullTerminatedString = ExAllocatePool(PagedPool, (NewLength+1) *sizeof(WCHAR));
      
      if (NullTerminatedString != NULL)
      {
            RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length);
                        
            NullTerminatedString[NewLength]=0;

            RtlZeroMemory(Queries, sizeof(Queries));
            
            Queries[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
            Queries[0].Name = TIMESTAMPMODE_REGKEY;
            Queries[0].EntryContext = &TimestampMode;
            Queries[0].DefaultType = REG_DWORD;
            Queries[0].DefaultData = &DefaultTimestampMode;
            Queries[0].DefaultLength = sizeof(ULONG);

            if (RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS)
            {
                  TimestampMode = DEFAULT_TIMESTAMPMODE;
            }

            RtlWriteRegistryValue(  RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY,  REG_DWORD, &TimestampMode,sizeof(ULONG));     
            ExFreePool(NullTerminatedString);
      }     
      else
            TimestampMode = DEFAULT_TIMESTAMPMODE;
}

#pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 

/* KeQueryPerformanceCounter TimeStamps */
__inline void SynchronizeOnCpu(struct timeval *start)
{
//    struct timeval *start = (struct timeval*)Data;

      struct timeval tmp;
      LARGE_INTEGER SystemTime;
      LARGE_INTEGER i;
      ULONG tmp2;
      LARGE_INTEGER TimeFreq,PTime;

      // get the absolute value of the system boot time.   
      
      PTime = KeQueryPerformanceCounter(&TimeFreq);
      KeQuerySystemTime(&SystemTime);
      
      start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);

      start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);

      start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart);

      start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);

      if (start->tv_usec < 0)
      {
            start->tv_sec --;
            start->tv_usec += 1000000;
      }
}     

/*RDTSC timestamps                  */
/* callers must be at IRQL=PASSIVE_LEVEL*/
__inline VOID TimeSynchronizeRDTSC(struct time_conv *data)
{
      struct timeval tmp;
      LARGE_INTEGER system_time;
      ULONGLONG curr_ticks;
      KIRQL old;
      LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
      ULONGLONG start_ticks,stop_ticks;
      ULONGLONG delta,delta2;
      KEVENT event;
      LARGE_INTEGER i;
      ULONGLONG reference;

      if (data->reference!=0)
            return;
      
      KeInitializeEvent(&event,NotificationEvent,FALSE);

      i.QuadPart=-3500000;

      KeRaiseIrql(HIGH_LEVEL,&old);
      start_kqpc=KeQueryPerformanceCounter(&start_freq);
      __asm
      {
            push eax
            push edx
            push ecx
            rdtsc
            lea ecx, start_ticks
            mov [ecx+4], edx
            mov [ecx], eax
            pop ecx
            pop edx
            pop eax
      }

      KeLowerIrql(old);
      
      KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);

      KeRaiseIrql(HIGH_LEVEL,&old);
      stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
      __asm
      {
            push eax
            push edx
            push ecx
            rdtsc
            lea ecx, stop_ticks
            mov [ecx+4], edx
            mov [ecx], eax
            pop ecx
            pop edx
            pop eax
      }
      KeLowerIrql(old);

      delta=stop_ticks-start_ticks;
      delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
      if (delta>10000000000)
      {
            delta/=16;
            delta2/=16;
      }

      reference=delta*(start_freq.QuadPart)/delta2;
      
      data->reference=reference/1000;

      if (reference%1000>500) 
            data->reference++;

      data->reference*=1000;

      reference=data->reference;
            
      KeQuerySystemTime(&system_time);

      __asm
      {
            push eax
            push edx
            push ecx
            rdtsc
            lea ecx, curr_ticks
            mov [ecx+4], edx
            mov [ecx], eax
            pop ecx
            pop edx
            pop eax
      }
      
      tmp.tv_sec=-(LONG)(curr_ticks/reference);

      tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);

      system_time.QuadPart-=116444736000000000;
      
      tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
      tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
      
      if (tmp.tv_usec<0)
      {
            tmp.tv_sec--;
            tmp.tv_usec+=1000000;
      }

      data->start[0] = tmp;

      IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
}

#pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 

__inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
{
      ULONG NumberOfCpus, i;
      KAFFINITY AffinityMask;

      if (data->reference != 0)
            return;
            
      NumberOfCpus = NdisSystemProcessorCount();

      if ( TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
      {
            for (i = 0 ;  i < NumberOfCpus ; i++ )
            {
                  AffinityMask = (1 << i);
                  ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
                  SynchronizeOnCpu(&(data->start[i]));            
            }
            AffinityMask = 0xFFFFFFFF;
            ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
            data->reference = 1;
      }
      else
      if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
      {
            //do nothing
            data->reference = 1;
      }
      else
      if ( TimestampMode == TIMESTAMPMODE_RDTSC )
      {
            TimeSynchronizeRDTSC(data);
      }
      else
      {     //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
            SynchronizeOnCpu(data->start);
            data->reference = 1;
      }
      return;
}


#pragma optimize ("g",off)  //Due to some weird behaviour of the optimizer of DDK build 2600 

__inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data)
{
      LARGE_INTEGER PTime, TimeFreq;
      LONG tmp;
      ULONG CurrentCpu;
      static struct timeval old_ts={0,0};


      PTime = KeQueryPerformanceCounter(&TimeFreq);
      tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart);

      if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
      {
            //actually this code is ok only if we are guaranteed that no thread scheduling will take place. 
            CurrentCpu = KeGetCurrentProcessorNumber();     

            dst->tv_sec = data->start[CurrentCpu].tv_sec + tmp;
            dst->tv_usec = data->start[CurrentCpu].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
      
            if (dst->tv_usec >= 1000000)
            {
                  dst->tv_sec ++;
                  dst->tv_usec -= 1000000;
            }

            if (TimestampMode ==  TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP)
            {
                  if (old_ts.tv_sec > dst->tv_sec || (old_ts.tv_sec == dst->tv_sec &&  old_ts.tv_usec > dst->tv_usec) )
                        *dst = old_ts;
      
                  else
                        old_ts = *dst;
            }
      }
      else
      {     //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
            dst->tv_sec = data->start[0].tv_sec + tmp;
            dst->tv_usec = data->start[0].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
      
            if (dst->tv_usec >= 1000000)
            {
                  dst->tv_sec ++;
                  dst->tv_usec -= 1000000;
            }
      }
}

__inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data)
{

      ULONGLONG tmp;
      __asm
      {
            push eax
            push edx
            push ecx
            rdtsc
            lea ecx, tmp
            mov [ecx+4], edx
            mov [ecx], eax
            pop ecx
            pop edx
            pop eax
      }

      if (data->reference==0)
      {
            return;
      }
      dst->tv_sec=(LONG)(tmp/data->reference);

      dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
      
      dst->tv_sec+=data->start[0].tv_sec;

      dst->tv_usec+=data->start[0].tv_usec;

      if (dst->tv_usec>=1000000)
      {
            dst->tv_sec++;
            dst->tv_usec-=1000000;
      }


}

__inline void GetTimeQST(struct timeval *dst, struct time_conv *data)
{
      LARGE_INTEGER SystemTime;

      KeQuerySystemTime(&SystemTime);
      
      dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
      dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);

}

#pragma optimize ("g",on)  //Due to some weird behaviour of the optimizer of DDK build 2600 


__inline void GET_TIME(struct timeval *dst, struct time_conv *data)
{

      if ( TimestampMode == TIMESTAMPMODE_RDTSC )
      {
            GetTimeRDTSC(dst,data);
      }
      else
      if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
      {
            GetTimeQST(dst,data);
      }
      else
      {
            GetTimeKQPC(dst,data);
      }
}


#else /*WIN_NT_DRIVER*/

__inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
{
      dest->start[0]=*src;
}

__inline void GET_TIME(struct timeval *dst, struct time_conv *data)
{
      *dst=data->start[0];
}

#endif /*WIN_NT_DRIVER*/


#endif /*_time_calls*/

Generated by  Doxygen 1.6.0   Back to index