#define KI_USER_SHARED_DATA 0x7FFE0000
#define SharedUserData ((KUSER_SHARED_DATA * CONST)
KI_USER_SHARED_DATA)
typedef struct _KSYSTEM_TIME
{
ULONG LowPart;
LONG High1Time;
LONG High2Time;
} KSYSTEM_TIME, *PKSYSTEM_TIME;
typedef enum _NT_PRODUCT_TYPE
{
NtProductWinNt = 1,
NtProductLanManNt,
NtProductServer
} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
//
// Maximum Processor Features supported in KUSER_SHARED_DATA
//
#define PROCESSOR_FEATURE_MAX 64
typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
{
StandardDesign,
NEC98x86,
EndAlternatives
} ALTERNATIVE_ARCHITECTURE_TYPE;
#define MAX_WOW64_SHARED_ENTRIES 16
typedef struct _KUSER_SHARED_DATA
{
ULONG TickCountLowDeprecated;
ULONG TickCountMultiplier;
volatile KSYSTEM_TIME InterruptTime;
volatile KSYSTEM_TIME SystemTime;
volatile KSYSTEM_TIME TimeZoneBias;
USHORT ImageNumberLow;
USHORT ImageNumberHigh;
WCHAR NtSystemRoot[260];
ULONG MaxStackTraceDepth;
ULONG CryptoExponent;
ULONG TimeZoneId;
ULONG LargePageMinimum;
ULONG Reserved2[7];
NT_PRODUCT_TYPE NtProductType;
BOOLEAN ProductTypeIsValid;
ULONG NtMajorVersion;
ULONG NtMinorVersion;
BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
ULONG Reserved1;
ULONG Reserved3;
volatile ULONG TimeSlip;
ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
LARGE_INTEGER SystemExpirationDate;
ULONG SuiteMask;
BOOLEAN KdDebuggerEnabled;
volatile ULONG ActiveConsoleId;
volatile ULONG DismountCount;
ULONG ComPlusPackage;
ULONG LastSystemRITEventTickCount;
ULONG NumberOfPhysicalPages;
BOOLEAN SafeBootMode;
ULONG TraceLogging;
ULONG Fill0;
ULONGLONG TestRetInstruction;
ULONG SystemCall;
ULONG SystemCallReturn;
ULONGLONG SystemCallPad[3];
union {
volatile KSYSTEM_TIME TickCount;
volatile ULONG64 TickCountQuad;
};
ULONG Cookie;
LONGLONG ConsoleSessionForegroundProcessId;
ULONG Wow64SharedInformation[MAX_WOW64_SHARED_ENTRIES];
ULONG UserModeGlobalLogging;
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
DWORD MyGetTickCount()
{
return (DWORD)((ULONGLONG)SharedUserData->TickCountLowDeprecated *
SharedUserData->TickCountMultiplier / 16777216);
}
int main(int argc,char *argv[])
{
DWORD u1=GetTickCount();
DWORD u2=MyGetTickCount();
return 0;
}
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
KiRawTicks++;
if (KiClockSetupComplete == FALSE) return;
/*
* Increment the number of timers ticks
*/
KeTickCount++;
SharedUserData->TickCountLowDeprecated++;
Time.u.LowPart = SharedUserData->InterruptTime.LowPart;
Time.u.HighPart = SharedUserData->InterruptTime.High1Time;
Time.QuadPart += CLOCK_INCREMENT;
SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
Time.u.LowPart = SharedUserData->SystemTime.LowPart;
Time.u.HighPart = SharedUserData->SystemTime.High1Time;
Time.QuadPart += CLOCK_INCREMENT;
SharedUserData->SystemTime.High2Time = Time.u.HighPart;
SharedUserData->SystemTime.LowPart = Time.u.LowPart;
SharedUserData->SystemTime.High1Time = Time.u.HighPart;
/* FIXME: Here we should check for remote debugger break-ins */
/* Update process and thread times */
KeUpdateRunTime(TrapFrame, Irql);
/*
* Queue a DPC that will expire timers
*/
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
}
汇编代码的注释:
; VOID
; KeUpdateSystemTime (
; IN KIRQL PreviousIrql,
; IN KTRAP_FRAME TrapFrame
; )
;
; Routine Description:
;
; This routine is entered as the result of an interrupt generated by
CLOCK2.
; Its function is to update the system time and check to determine
if a timer
; has expired.
;
; N.B. This routine is executed on a single processor in a
multiprocess
; system. The remainder of the processors only execute the
quantum end
; and runtime update code.
;
; N.B. This routine is not called, but directly jumped to. Thus,
there
; is no return address. It returns via the INTERRUPT_EXIT macro.
.FPO (2, 0, 0, 0, 0, 1) ; treat params as locals since functions is
JMPed too
if DBG
cmp byte ptr PCR[PcPrcbData+PbSkipTick], 0
jnz kust_skiptick
endif
;
; Update interrupt time.
;
; N.B. The interrupt time is updated in a very strict manner so that an
; interlock does not have to be used in an MP system to read time.
;
mov ecx,USER_SHARED_DATA ; set address of user shared
data
mov edi,[ecx].UsInterruptTime+0 ; get low interrupt time
mov esi,[ecx].UsInterruptTime+4 ; get high interrupt time
add edi,eax ; add time increment
adc esi,0 ; propagate carry
mov [ecx].UsInterruptTime+8,esi ; store high 2 interrupt
time
mov [ecx].UsInterruptTime+0,edi ; store low interrupt time
mov [ecx].UsInterruptTime+4,esi ; store high 1 interrupt
time
sub _KiTickOffset,eax ; subtract time increment
mov eax,_KeTickCount+0 ; get low tick count
mov ebx,eax ; copy low tick count
jg kust10 ; if greater, not complete tick
;
; Update system time.
;
; N.B. The system time is updated in a very strict manner so that an
; interlock does not have to be used in an MP system to read time.
;
mov ebx,USER_SHARED_DATA ; set address of user shared
data
mov ecx,[ebx].UsSystemTime+0 ; get low interrupt time
mov edx,[ebx].UsSystemTime+4 ; get high interrupt time
add ecx,_KeTimeAdjustment ; add time increment
adc edx,0 ; propagate carry
mov [ebx].UsSystemTime+8,edx ; store high 2 interrupt time
mov [ebx].UsSystemTime+0,ecx ; store low interrupt time
mov [ebx].UsSystemTime+4,edx ; store high 1 interrupt time
mov ebx,eax ; restore low tick count
;
; Update tick count.
;
; N.B. The tick count is updated in a very strict manner so that an
; interlock does not have to be used in an MP system to read
count.
;
mov ecx,eax ; copy low tick count
mov edx,_KeTickCount+4 ; get high tick count
add ecx,1 ; increment tick count
adc edx,0 ; propagate carry
mov _KeTickCount+8,edx ; store high 2 tick count
mov _KeTickCount+0,ecx ; store low tick count
mov _KeTickCount+4,edx ; store high 1 tick count
mov USERDATA[UsTickCountLow], ecx
if 0
; debug code
push eax
mov edx, esi
mov eax, edi ; (eax:edx) = InterruptTime
mov ecx, _KeMaximumIncrement
div ecx
cmp al, bl ; same bucket?
je short @f
int 3 ; no - stop
@@:
pop eax
endif
;
; Check to determine if a timer has expired.
; (edi:esi) = KiInterruptTime
; (eax) = KeTickCount.LowPart
; (ebx) = KeTickCount.LowPart
;
and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value
lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees
mov edx,[ecx] ; get first entry address
cmp ecx,edx ; check if list is empry
je short kust5 ; if equal, list is empty
cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ;
compare high
jb short kust5 ; if below, timer has not
expired
ja short kust15 ; if above, timer has expired
cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ;
compare low
jae short kust15 ; if above or equal, time has
expired
kust5: inc eax ; advance hand value to next
entry
inc ebx
;
; Check to determine if a timer has expired.
; (edi:esi) = KiInterruptTime
; (eax) = bucket
; (ebx) = KeTickCount.LowPart
;
kust10: and eax,TIMER_TABLE_SIZE-1 ; isolate current hand value
lea ecx,_KiTimerTableListHead[eax*8] ; get listhead addrees
mov edx,[ecx] ; get first entry address
cmp ecx,edx ; check if list is empry
je kustxx ; if equal, list is empty
cmp esi,[edx].TiDueTime.TmHighTime-TiTimerListEntry ;
compare high
jb kustxx ; if below, timer has not
expired
ja short kust15 ; if above, timer has expired
cmp edi,[edx].TiDueTime.TmLowTime-TiTimerListEntry ;
compare low
jb kustxx ; if below, timer has not
expired
kust15:
;
; Timer has expired, put timer expiration DPC in the current
processor's DPC
; queue.
;
; (ebx) = KeTickCount.LowPart
;
mov ecx,PCR[PcPrcb] ; get processor control block
address
lea eax,_KiTimerExpireDpc+DpDpcListEntry ; get list entry
address
lea edx,[ecx]+PbDpcLock ; get DPC lock address
cmp dword ptr [eax]+(DpLock-DpDpcListEntry), 0H ; check if
inserted
jnz kustxx ; if nz, DPC already inserted
kust20: cli
ACQUIRE_SPINLOCK edx, kust60
inc dword ptr [ecx].PbDpcQueueDepth ; increment DPC queue
depth
mov dword ptr [eax]+(DpLock-DpDpcListEntry), edx ; set lock
address
mov [eax]+(DpSystemArgument1-DpDpcListEntry),ebx ; pass
tick count
add ecx,PbDpcListHead ; compute DPC listhead address
mov ebx,[ecx]+LsBlink ; get address of last entry in
list
mov [ecx]+LsBlink, eax ; set new address of last entry
mov [ebx]+LsFlink, eax ; set forward link in old last
entry
mov [eax]+LsFlink, ecx ; set forward link in new last
entry
mov [eax]+LsBlink, ebx ; set backward link in new last
entry
RELEASE_SPINLOCK edx
sti ; enable interrupt
; request dispatch interrupt
mov ecx, DISPATCH_LEVEL
fstCall HalRequestSoftwareInterrupt
kustxx:
if DEVL
cmp _KdDebuggerEnabled, 0
jnz short kust45
kust30:
endif
cmp _KiTickOffset,0 ; check if full tick
jg short Kust40 ; if not less, not a full tick
mov eax,_KeMaximumIncrement ; get maximum time incrmeent
add _KiTickOffset,eax ; add maximum tine to residue
;
; call KeUpdateRunTime to do the acutal work
;
; TOS const PreviousIrql
push [esp]
call _KeUpdateRunTime@4
;
; Do interrupt exit processing
;
INTERRUPT_EXIT
kust40:
inc dword ptr PCR[PcPrcbData+PbInterruptCount]
INTERRUPT_EXIT
if DEVL
kust45:
stdCall _KdPollBreakIn
or al,al
jz short kust30
stdCall _DbgBreakPointWithStatus,<DBG_STATUS_CONTROL_C>
jmp short kust30
endif
if DBG
kust_skiptick:
mov byte ptr PCR[PcPrcbData+PbSkipTick], 0
jmp short kust40
endif
;
; Lock is currently owned; spin until free and then attempt to acquire
; lock again.
;
ALIGN 4
kust60: sti ; spin with interrupts enabled
SPIN_ON_SPINLOCK edx, kust20,,DbgMp
stdENDP _KeUpdateSystemTime
page ,132
subttl "Update Thread and Process Runtime"
mail list就你我两人,真冷清
--
Sincerely,
Ghost Cheng
Email : ghost...@gmail.com
Web : http://www.GhostSoft.net