Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SoftEtherVPN/SoftEtherVPN_Stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
committerdnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
commit749497dde0a1dd08c434a73b9d4e93dc3e3326d9 (patch)
tree7c83a55919c0f1aa1267c4dbcd008f1644f961ee /src/See/time_calls.h
parentd433e567a561f8ae094a535025b02c7dc47026c6 (diff)
v4.03-9408-rtm
Diffstat (limited to 'src/See/time_calls.h')
-rw-r--r--src/See/time_calls.h486
1 files changed, 486 insertions, 0 deletions
diff --git a/src/See/time_calls.h b/src/See/time_calls.h
new file mode 100644
index 00000000..8f02f48f
--- /dev/null
+++ b/src/See/time_calls.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2001 - 2005 NetGroup, Politecnico di Torino (Italy)
+ * Copyright (c) 2005 CACE Technologies, Davis (California)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino, CACE Technologies
+ * 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#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;
+extern ULONG NCpu;
+
+/*!
+ \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*/
+
+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;
+
+ LARGE_INTEGER SystemTime;
+ 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;
+ }
+}
+
+//
+// inline assembler is not supported with the current AMD64 compilers
+// At the moment we simply disable this timestamping mode on AMD64.
+// A solution would be to allocate a small memory from the non-paged
+// pool, dump the instructions on that buffer, and then execute them.
+// The non paged pool is needed since it's the only area of kernel
+// data memory that is not subject to the NX protection.
+// Or use some lower level trick, like using an assembler to assemble
+// a small function for this.
+//
+
+#ifdef __NPF_x86__
+/*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);)
+}
+#endif //__NPF_x86__
+
+#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 = NCpu;
+
+ 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
+//
+// This timestamp mode is supported on x86 (32 bit) only
+//
+#ifdef __NPF_x86__
+ if ( TimestampMode == TIMESTAMPMODE_RDTSC )
+ {
+ TimeSynchronizeRDTSC(data);
+ }
+ else
+#endif // __NPF_x86__
+ { //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 assembler is not supported with the current AMD64 compilers
+// At the moment we simply disable this timestamping mode on AMD64.
+// A solution would be to allocate a small memory from the non-paged
+// pool, dump the instructions on that buffer, and then execute them.
+// The non paged pool is needed since it's the only area of kernel
+// data memory that is not subject to the NX protection.
+// Or use some lower level trick, like using an assembler to assemble
+// a small function for this.
+//
+
+#ifdef __NPF_x86__
+__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;
+ }
+
+
+}
+#endif //__NPF_x86__
+
+__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)
+{
+ return;
+
+#if 0
+//
+// This timestamp mode is supported on x86 (32 bit) only
+//
+#ifdef __NPF_x86__
+ if ( TimestampMode == TIMESTAMPMODE_RDTSC )
+ {
+ GetTimeRDTSC(dst,data);
+ }
+ else
+#endif
+ if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
+ {
+ GetTimeQST(dst,data);
+ }
+ else
+ {
+ GetTimeKQPC(dst,data);
+ }
+#endif
+}
+
+
+#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)
+{
+ return;
+ *dst=data->start[0];
+}
+
+#endif /*WIN_NT_DRIVER*/
+
+
+#endif /*_time_calls*/