mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[NTOS]: Implement KeUpdateSystemTime and KeUpdateRunTime in C instead of ASM. Based off eVb's ARM implementation, with multiple bugs fixed (incorrect update of system counters, incorrect expiration of timers, remove non-used debug features, use locks when needed).
[NTOS]: Implement KiComputeTimerTableIndex in C instead of ASM. Based off eVb's ARM implementation, bugfixed to do correct math instead. As a side effect, this should fix timers on ARM ;-) svn path=/trunk/; revision=45140
This commit is contained in:
parent
d6b8e75c83
commit
bf8b9467dc
7 changed files with 255 additions and 713 deletions
|
@ -728,12 +728,6 @@ KiTimerExpiration(
|
|||
IN PVOID SystemArgument2
|
||||
);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
KiComputeTimerTableIndex(
|
||||
IN LONGLONG TimeValue
|
||||
);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
KeSetProcess(
|
||||
|
|
|
@ -972,6 +972,13 @@ KiCheckAlertability(IN PKTHREAD Thread,
|
|||
return STATUS_WAIT_0;
|
||||
}
|
||||
|
||||
ULONG
|
||||
FORCEINLINE
|
||||
KiComputeTimerTableIndex(IN ULONGLONG DueTime)
|
||||
{
|
||||
return (DueTime / KeMaximumIncrement) & (TIMER_TABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Called from KiCompleteTimer, KiInsertTreeTimer, KeSetSystemTime
|
||||
// to remove timer entries
|
||||
|
|
|
@ -1,322 +0,0 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: ntoskrnl/ke/arm/time.c
|
||||
* PURPOSE: Implements timebase functionality on ARM processors
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
LONG KiTickOffset;
|
||||
ULONG KeTimeAdjustment;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
ULONG
|
||||
KiComputeTimerTableIndex(IN LONGLONG DueTime)
|
||||
{
|
||||
ULONG Hand;
|
||||
|
||||
//
|
||||
// Compute the timer table index
|
||||
//
|
||||
Hand = (DueTime / KeMaximumIncrement);
|
||||
Hand %= TIMER_TABLE_SIZE;
|
||||
return Hand;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KIRQL Irql,
|
||||
IN ULONG Increment)
|
||||
{
|
||||
PKPRCB Prcb = KeGetPcr()->Prcb;
|
||||
ULARGE_INTEGER SystemTime, InterruptTime;
|
||||
ULONG Hand;
|
||||
|
||||
//
|
||||
// Do nothing if this tick is being skipped
|
||||
//
|
||||
if (Prcb->SkipTick)
|
||||
{
|
||||
//
|
||||
// Handle it next time
|
||||
//
|
||||
Prcb->SkipTick = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Add the increment time to the shared data
|
||||
//
|
||||
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
|
||||
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
|
||||
InterruptTime.QuadPart += Increment;
|
||||
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
|
||||
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
|
||||
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
|
||||
|
||||
//
|
||||
// Update tick count
|
||||
//
|
||||
KiTickOffset -= Increment;
|
||||
|
||||
//
|
||||
// Check for incomplete tick
|
||||
//
|
||||
if (KiTickOffset <= 0)
|
||||
{
|
||||
//
|
||||
// Update the system time
|
||||
//
|
||||
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
|
||||
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
|
||||
SystemTime.QuadPart += KeTimeAdjustment;
|
||||
SharedUserData->SystemTime.High1Time = SystemTime.HighPart;
|
||||
SharedUserData->SystemTime.LowPart = SystemTime.LowPart;
|
||||
SharedUserData->SystemTime.High2Time = SystemTime.HighPart;
|
||||
|
||||
//
|
||||
// Update the tick count
|
||||
//
|
||||
SystemTime.HighPart = KeTickCount.High1Time;
|
||||
SystemTime.LowPart = KeTickCount.LowPart;
|
||||
SystemTime.QuadPart += 1;
|
||||
KeTickCount.High1Time = SystemTime.HighPart;
|
||||
KeTickCount.LowPart = SystemTime.LowPart;
|
||||
KeTickCount.High2Time = SystemTime.HighPart;
|
||||
|
||||
//
|
||||
// Update it in the shared user data
|
||||
//
|
||||
SharedUserData->TickCount.High1Time = SystemTime.HighPart;
|
||||
SharedUserData->TickCount.LowPart = SystemTime.LowPart;
|
||||
SharedUserData->TickCount.High2Time = SystemTime.HighPart;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for timer expiration
|
||||
//
|
||||
Hand = KeTickCount.LowPart % TIMER_TABLE_SIZE;
|
||||
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
|
||||
{
|
||||
//
|
||||
// Check if we are already doing expiration
|
||||
//
|
||||
if (!Prcb->TimerRequest)
|
||||
{
|
||||
//
|
||||
// Request a DPC to handle this
|
||||
//
|
||||
Prcb->TimerRequest = TrapFrame->SvcSp;
|
||||
Prcb->TimerHand = Hand;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check if we should request a debugger break
|
||||
//
|
||||
if (KdDebuggerEnabled)
|
||||
{
|
||||
//
|
||||
// Check if we should break
|
||||
//
|
||||
if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
|
||||
}
|
||||
|
||||
//
|
||||
// Check if this was a full tick
|
||||
//
|
||||
if (KiTickOffset <= 0)
|
||||
{
|
||||
//
|
||||
// Updare the tick offset
|
||||
//
|
||||
KiTickOffset += KeMaximumIncrement;
|
||||
|
||||
//
|
||||
// Update system runtime
|
||||
//
|
||||
KeUpdateRunTime(TrapFrame, CLOCK2_LEVEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Increase interrupt count and exit
|
||||
//
|
||||
Prcb->InterruptCount++;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KIRQL Irql)
|
||||
{
|
||||
PKTHREAD Thread = KeGetCurrentThread();
|
||||
PKPROCESS Process = Thread->ApcState.Process;
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
|
||||
//
|
||||
// Do nothing if this tick is being skipped
|
||||
//
|
||||
if (Prcb->SkipTick)
|
||||
{
|
||||
//
|
||||
// Handle it next time
|
||||
//
|
||||
Prcb->SkipTick = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Increase interrupt count
|
||||
//
|
||||
Prcb->InterruptCount++;
|
||||
|
||||
//
|
||||
// Check if we came from user mode
|
||||
//
|
||||
if (TrapFrame->PreviousMode != KernelMode)
|
||||
{
|
||||
//
|
||||
// Increase process user time
|
||||
//
|
||||
InterlockedIncrement((PLONG)&Process->UserTime);
|
||||
Prcb->UserTime++;
|
||||
Thread->UserTime++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// See if we were in an ISR
|
||||
//
|
||||
if (TrapFrame->OldIrql > DISPATCH_LEVEL)
|
||||
{
|
||||
//
|
||||
// Handle that
|
||||
//
|
||||
Prcb->InterruptTime++;
|
||||
}
|
||||
else if ((TrapFrame->OldIrql < DISPATCH_LEVEL) ||
|
||||
!(Prcb->DpcRoutineActive))
|
||||
{
|
||||
//
|
||||
// Handle being in kernel mode
|
||||
//
|
||||
Thread->KernelTime++;
|
||||
InterlockedIncrement((PLONG)&Process->KernelTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Handle being in a DPC
|
||||
//
|
||||
Prcb->DpcTime++;
|
||||
|
||||
//
|
||||
// Update Debug DPC time
|
||||
//
|
||||
Prcb->DebugDpcTime++;
|
||||
|
||||
//
|
||||
// Check if we've timed out
|
||||
//
|
||||
if (Prcb->DebugDpcTime >= KiDPCTimeout)
|
||||
{
|
||||
//
|
||||
// Print a message
|
||||
//
|
||||
DbgPrint("\n*** DPC routine > 1 sec --- This is not a break in "
|
||||
"KeUpdateSystemTime\n");
|
||||
|
||||
//
|
||||
// Break if a debugger is attached
|
||||
//
|
||||
if (KdDebuggerEnabled) DbgBreakPoint();
|
||||
|
||||
//
|
||||
// Restore the debug DPC time
|
||||
//
|
||||
Prcb->DebugDpcTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update DPC rates
|
||||
//
|
||||
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
|
||||
Prcb->DpcRequestRate) >> 1;
|
||||
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
|
||||
|
||||
//
|
||||
// Check if the queue is large enough
|
||||
//
|
||||
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
|
||||
{
|
||||
//
|
||||
// Request a DPC
|
||||
//
|
||||
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
|
||||
//
|
||||
// Fix the maximum queue depth
|
||||
//
|
||||
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
|
||||
(Prcb->MaximumDpcQueueDepth > 1))
|
||||
{
|
||||
//
|
||||
// Make it smaller
|
||||
//
|
||||
Prcb->MaximumDpcQueueDepth--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Check if we've reached the adjustment limit
|
||||
//
|
||||
if (!(--Prcb->AdjustDpcThreshold))
|
||||
{
|
||||
//
|
||||
// Reset it, and check the queue maximum
|
||||
//
|
||||
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
||||
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
|
||||
{
|
||||
//
|
||||
// Increase it
|
||||
//
|
||||
Prcb->MaximumDpcQueueDepth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Decrement the thread quantum
|
||||
//
|
||||
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
|
||||
|
||||
//
|
||||
// Check if the time expired
|
||||
//
|
||||
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
|
||||
{
|
||||
//
|
||||
// Schedule a quantum end
|
||||
//
|
||||
Prcb->QuantumEnd = 1;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
|
@ -1,383 +0,0 @@
|
|||
/*
|
||||
* FILE: ntoskrnl/ke/i386/clock.S
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PURPOSE: System Clock Management
|
||||
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <asm.h>
|
||||
#include <internal/i386/asmmacro.S>
|
||||
.intel_syntax noprefix
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
_DpcTimeoutMsg:
|
||||
.asciz "\n*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n"
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
.globl _KiComputeTimerTableIndex@8
|
||||
.func KiComputeTimerTableIndex@8
|
||||
_KiComputeTimerTableIndex@8:
|
||||
|
||||
/* Save registers */
|
||||
push ebx
|
||||
|
||||
/* Make the first multiplication */
|
||||
mov eax, [esp+8]
|
||||
mul dword ptr [_KiTimeIncrementReciprocal+4]
|
||||
mov ebx, eax
|
||||
mov ecx, edx
|
||||
|
||||
/* Make the second multiplication */
|
||||
mov eax, [esp+12]
|
||||
mul dword ptr [_KiTimeIncrementReciprocal]
|
||||
add ebx, eax
|
||||
adc ecx, edx
|
||||
|
||||
/* Multiply by the reciprocal */
|
||||
mov eax, [esp+8]
|
||||
mul dword ptr [_KiTimeIncrementReciprocal]
|
||||
mov eax, [esp+12]
|
||||
push edx
|
||||
mul dword ptr [_KiTimeIncrementReciprocal+4]
|
||||
pop edx
|
||||
add edx, ebx
|
||||
adc eax, ecx
|
||||
|
||||
/* Shift the result and generate the index */
|
||||
mov cl, [_KiTimeIncrementShiftCount]
|
||||
shr eax, cl
|
||||
and eax, TIMER_TABLE_SIZE - 1
|
||||
|
||||
/* Return */
|
||||
pop ebx
|
||||
ret 8
|
||||
.endfunc
|
||||
|
||||
.globl _KeUpdateRunTime@8
|
||||
.func KeUpdateRunTime@8
|
||||
_KeUpdateRunTime@8:
|
||||
|
||||
/* Get KPCR */
|
||||
mov eax, [fs:KPCR_SELF]
|
||||
|
||||
/* Check if this tick is getting skipped */
|
||||
cmp byte ptr [eax+KPCR_PRCB_SKIP_TICK], 0
|
||||
jnz SkipTick
|
||||
|
||||
/* Save EBX */
|
||||
push ebx
|
||||
|
||||
/* Increase interrupt count */
|
||||
inc dword ptr [eax+KPCR_PRCB_INTERRUPT_COUNT]
|
||||
|
||||
/* Get the current thread and process */
|
||||
mov ebx, [eax+KPCR_CURRENT_THREAD]
|
||||
mov ecx, [ebx+KTHREAD_APCSTATE_PROCESS]
|
||||
|
||||
/* Check if this was V86 or user mode */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz NotKern
|
||||
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
||||
jnz NotKern
|
||||
|
||||
/* Increase kernel time */
|
||||
inc dword ptr [eax+KPCR_PRCB_KERNEL_TIME]
|
||||
|
||||
/* Check if IRQL was DISPATCH_LEVEL */
|
||||
cmp byte ptr [esp+8], DISPATCH_LEVEL
|
||||
jb BelowDispatch
|
||||
ja AboveDispatch
|
||||
|
||||
/* Check if the DPC routine is active */
|
||||
cmp byte ptr fs:[KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
|
||||
jz BelowDispatch
|
||||
|
||||
/* At dispatch, increase DPC time */
|
||||
inc dword ptr [eax+KPCR_PRCB_DPC_TIME]
|
||||
#if DBG
|
||||
/* Update the DPC time */
|
||||
inc dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME]
|
||||
|
||||
/* Check if we've timed out */
|
||||
mov edx, _KiDPCTimeout
|
||||
cmp dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME], edx
|
||||
jc AfterSet
|
||||
|
||||
/* We did, print out a message */
|
||||
push offset _DpcTimeoutMsg
|
||||
call _DbgPrint
|
||||
add esp, 4
|
||||
|
||||
/* Check if the debugger is enabled */
|
||||
cmp byte ptr __KdDebuggerEnabled, 0
|
||||
jz ResetDpcTime
|
||||
|
||||
/* Breakpoint */
|
||||
call _DbgBreakPoint@0
|
||||
|
||||
ResetDpcTime:
|
||||
/* Restore state */
|
||||
mov eax, PCR[KPCR_SELF]
|
||||
mov dword ptr [eax+KPCR_PRCB_DEBUG_DPC_TIME], 0
|
||||
#endif
|
||||
jmp AfterSet
|
||||
|
||||
AboveDispatch:
|
||||
/* Update interrupt time */
|
||||
inc dword ptr [eax+KPCR_PRCB_INTERRUPT_TIME]
|
||||
jmp AfterSet
|
||||
|
||||
BelowDispatch:
|
||||
/* Update kernel time */
|
||||
inc dword ptr [ebx+KTHREAD_KERNEL_TIME]
|
||||
jmp AfterSet
|
||||
|
||||
NotKern:
|
||||
/* Update user time */
|
||||
inc dword ptr [eax+KPCR_PRCB_USER_TIME]
|
||||
inc dword ptr [ebx+KTHREAD_USER_TIME]
|
||||
|
||||
AfterSet:
|
||||
/* Get the DPC Count and last count, and set the ne wone */
|
||||
mov ecx, [eax+KPCR_PRCB_DPC_COUNT]
|
||||
mov edx, [eax+KPCR_PRCB_DPC_LAST_COUNT]
|
||||
mov [eax+KPCR_PRCB_DPC_LAST_COUNT], ecx
|
||||
|
||||
/* Substract counts and add request rate, divide by two to get average */
|
||||
sub ecx, edx
|
||||
add ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
|
||||
shr ecx, 1
|
||||
|
||||
/* Set this as the new request rate */
|
||||
mov [eax+KPCR_PRCB_DPC_REQUEST_RATE], ecx
|
||||
|
||||
/* Check for depth > 0, DPCs to be inactive, and no other pending request */
|
||||
cmp dword ptr [eax+KPCR_PRCB_DPC_QUEUE_DEPTH], 0
|
||||
je DontRequest
|
||||
cmp byte ptr [eax+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
|
||||
jnz DontRequest
|
||||
cmp byte ptr [eax+KPCR_PRCB_DPC_INTERRUPT_REQUESTED], 0
|
||||
jnz DontRequest
|
||||
|
||||
/* Request a DPC */
|
||||
mov ecx, DISPATCH_LEVEL
|
||||
call @HalRequestSoftwareInterrupt@4
|
||||
|
||||
/* Restore PCR address */
|
||||
mov eax, [fs:KPCR_SELF]
|
||||
|
||||
/* Get the DPC request rate and threshold adjust, and set it */
|
||||
mov ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
|
||||
mov edx, _KiAdjustDpcThreshold
|
||||
mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], edx
|
||||
|
||||
/* Check if the rate now is not ideal */
|
||||
cmp ecx, _KiIdealDpcRate
|
||||
jge RateOk
|
||||
cmp dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH], 1
|
||||
je RateOk
|
||||
|
||||
/* Fix the depth */
|
||||
dec dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
|
||||
jmp RateOk
|
||||
|
||||
DontRequest:
|
||||
/* We didn't request a DPC, decrease the threshold */
|
||||
dec dword ptr [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD]
|
||||
jnz RateOk
|
||||
|
||||
/* We're at 0 now, reset it */
|
||||
mov ecx, _KiAdjustDpcThreshold
|
||||
mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], ecx
|
||||
|
||||
/* Get maximum depth and check it */
|
||||
mov ecx, _KiMaximumDpcQueueDepth
|
||||
cmp ecx, [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
|
||||
je RateOk
|
||||
|
||||
/* Increase it, it's below maximum */
|
||||
inc dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
|
||||
|
||||
RateOk:
|
||||
/* Decrement quantum and verify it */
|
||||
sub byte ptr [ebx+KTHREAD_QUANTUM], CLOCK_QUANTUM_DECREMENT
|
||||
jg QuantumNotEmpty
|
||||
|
||||
/* Make sure this isn't the idle thread */
|
||||
cmp ebx, [eax+KPCR_PRCB_IDLE_THREAD]
|
||||
jz QuantumNotEmpty
|
||||
|
||||
/* Set quantum end */
|
||||
mov byte ptr [eax+KPCR_PRCB_QUANTUM_END], 1
|
||||
mov ecx, DISPATCH_LEVEL
|
||||
call @HalRequestSoftwareInterrupt@4
|
||||
|
||||
QuantumNotEmpty:
|
||||
/* Restore ebx and return */
|
||||
pop ebx
|
||||
ret 4
|
||||
|
||||
SkipTick:
|
||||
/* Disable skipping the next tick and return */
|
||||
mov byte ptr [eax+KPCR_PRCB_SKIP_TICK], 0
|
||||
ret 4
|
||||
.endfunc
|
||||
|
||||
.globl _KeUpdateSystemTime@0
|
||||
.func KeUpdateSystemTime@0
|
||||
_KeUpdateSystemTime@0:
|
||||
|
||||
/* Check if this tick is getting skipped */
|
||||
cmp byte ptr fs:[KPCR_PRCB_SKIP_TICK], 0
|
||||
jnz SkipTickSys
|
||||
|
||||
/* Get shared data in ECX */
|
||||
mov ecx, USER_SHARED_DATA
|
||||
|
||||
/* Get interrupt time */
|
||||
mov edi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME]
|
||||
mov esi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4]
|
||||
|
||||
/* Add the increment and get the carry */
|
||||
add edi, eax
|
||||
adc esi, 0
|
||||
|
||||
/* Now store the updated times */
|
||||
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+8], esi
|
||||
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME], edi
|
||||
mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4], esi
|
||||
|
||||
/* Substract tick count and get the low count */
|
||||
LOCK sub _KiTickOffset, eax
|
||||
mov eax, _KeTickCount
|
||||
mov ebx, eax
|
||||
jg IncompleteTick
|
||||
|
||||
/* Get shared data in ECX */
|
||||
mov ebx, USER_SHARED_DATA
|
||||
|
||||
/* Get system time */
|
||||
mov ecx, [ebx+USER_SHARED_DATA_SYSTEM_TIME]
|
||||
mov edx, [ebx+USER_SHARED_DATA_SYSTEM_TIME+4]
|
||||
|
||||
/* Add the increment and get the carry */
|
||||
add ecx, _KeTimeAdjustment
|
||||
adc edx, 0
|
||||
|
||||
/* Now store the updated times */
|
||||
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+8], edx
|
||||
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME], ecx
|
||||
mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+4], edx
|
||||
|
||||
/* Put tick count back in EBX */
|
||||
mov ebx, eax
|
||||
|
||||
/* Copy it in ECX and get high count */
|
||||
mov ecx, eax
|
||||
mov edx, _KeTickCount + 4
|
||||
|
||||
/* Add the increment and get the carry */
|
||||
add ecx, 1
|
||||
adc edx, 0
|
||||
|
||||
/* Now store the updated tick */
|
||||
mov [_KeTickCount+8], edx
|
||||
mov [_KeTickCount], ecx
|
||||
mov [_KeTickCount+4], edx
|
||||
|
||||
/* Store in in shared data too */
|
||||
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+8], edx
|
||||
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT], ecx
|
||||
mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+4], edx
|
||||
|
||||
/* Get hand index and entry into the table */
|
||||
and eax, TIMER_TABLE_SIZE - 1
|
||||
shl eax, 4
|
||||
|
||||
/* Compare the due time */
|
||||
cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
|
||||
jb NextHand
|
||||
ja TimerExpired
|
||||
cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
|
||||
jnb TimerExpired
|
||||
|
||||
NextHand:
|
||||
/* Move to the next hand */
|
||||
inc ebx
|
||||
mov eax, ebx
|
||||
|
||||
IncompleteTick:
|
||||
|
||||
/* Get hand index and entry into the table */
|
||||
and eax, TIMER_TABLE_SIZE - 1
|
||||
shl eax, 4
|
||||
|
||||
/* Compare the due time */
|
||||
cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
|
||||
jb DebugCheck
|
||||
ja TimerExpired
|
||||
cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
|
||||
jb DebugCheck
|
||||
|
||||
TimerExpired:
|
||||
|
||||
/* Check if expiration is active */
|
||||
mov ecx, [fs:KPCR_PRCB]
|
||||
cmp dword ptr [ecx+KPRCB_TIMER_REQUEST], 0
|
||||
jne DebugCheck
|
||||
|
||||
/* It's not, register it */
|
||||
mov [ecx+KPRCB_TIMER_REQUEST], esp
|
||||
mov [ecx+KPRCB_TIMER_HAND], ebx
|
||||
mov ecx, DISPATCH_LEVEL
|
||||
call @HalRequestSoftwareInterrupt@4
|
||||
|
||||
DebugCheck:
|
||||
/* Check if the debugger is enabled */
|
||||
cmp byte ptr __KdDebuggerEnabled, 0
|
||||
jnz DebuggerEnabled
|
||||
|
||||
/* Check if this was a full tick */
|
||||
NoDebug:
|
||||
cmp dword ptr _KiTickOffset, 0
|
||||
jg IncompleteTick2
|
||||
|
||||
/* Increase tick offset */
|
||||
mov eax, _KeMaximumIncrement
|
||||
add _KiTickOffset, eax
|
||||
|
||||
/* Update system run time */
|
||||
push [esp]
|
||||
call _KeUpdateRunTime@8
|
||||
jmp Done
|
||||
|
||||
IncompleteTick2:
|
||||
/* Increase interrupt count */
|
||||
inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
|
||||
|
||||
Done:
|
||||
/* Exit the interrupt */
|
||||
cli
|
||||
call _HalEndSystemInterrupt@8
|
||||
jmp _Kei386EoiHelper@0
|
||||
|
||||
DebuggerEnabled:
|
||||
/* Check for break-in request */
|
||||
call _KdPollBreakIn@0
|
||||
or al, al
|
||||
jz NoDebug
|
||||
|
||||
/* Break-in requested! */
|
||||
push DBG_STATUS_CONTROL_C
|
||||
call _DbgBreakPointWithStatus@4
|
||||
jmp NoDebug
|
||||
|
||||
SkipTickSys:
|
||||
/* Disable skipping the next tick and return */
|
||||
mov byte ptr fs:[KPCR_PRCB_SKIP_TICK], 0
|
||||
jmp IncompleteTick2
|
||||
.endfunc
|
|
@ -656,6 +656,41 @@ _KiUnexpectedInterrupt:
|
|||
|
||||
/* INTERRUPT HANDLERS ********************************************************/
|
||||
|
||||
.globl _KeUpdateSystemTime@0
|
||||
.func KeUpdateSystemTime@0
|
||||
_KeUpdateSystemTime@0:
|
||||
|
||||
/*
|
||||
* When we enter here, the ASM HAL has:
|
||||
* - Entered here with a JMP, not a CALL
|
||||
* - Put increment in EAX
|
||||
* - Pushed OldIRQL on the stack earlier [ESP]
|
||||
* - Pushed Vector on the stack earlier [ESP + 4]
|
||||
* - The trap frame at ESP + 8
|
||||
*
|
||||
* When the HAL moves to C, this shit needs to die!!!
|
||||
*
|
||||
*/
|
||||
|
||||
/* Call the regparm with Increment, OldIrql, TrapFrame */
|
||||
mov edx, [esp]
|
||||
mov ecx, ebp
|
||||
call _KeUpdateSystemTimeHandler
|
||||
|
||||
/*
|
||||
* The code below cannot be done in C because HalEndSystemInterrupt will
|
||||
* fuck with your stack sideways when it decides to handle a pending APC or
|
||||
* DPC!
|
||||
*/
|
||||
|
||||
/* Stack is back where it was, HalEndSystemInterrupt will clean it up */
|
||||
cli
|
||||
call _HalEndSystemInterrupt@8
|
||||
|
||||
/* Now the stack has become the trap frame */
|
||||
jmp _Kei386EoiHelper@0
|
||||
.endfunc
|
||||
|
||||
.func KiDispatchInterrupt@0
|
||||
_KiDispatchInterrupt@0:
|
||||
|
||||
|
|
212
reactos/ntoskrnl/ke/time.c
Normal file
212
reactos/ntoskrnl/ke/time.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
||||
* FILE: ntoskrnl/ke/time.c
|
||||
* PURPOSE: Implements timebase functionality
|
||||
* PROGRAMMERS: ReactOS Portable Systems Group
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
LONG KiTickOffset;
|
||||
ULONG KeTimeAdjustment;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
#ifndef _M_ARM
|
||||
VOID
|
||||
__attribute__((regparm(3)))
|
||||
KeUpdateSystemTimeHandler(IN ULONG Increment,
|
||||
IN KIRQL Irql,
|
||||
IN PKTRAP_FRAME TrapFrame)
|
||||
#else
|
||||
VOID
|
||||
NTAPI
|
||||
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
|
||||
IN ULONG Increment,
|
||||
IN KIRQL Irql)
|
||||
#endif
|
||||
{
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
ULARGE_INTEGER CurrentTime, InterruptTime;
|
||||
ULONG Hand, OldTickCount;
|
||||
|
||||
/* Add the increment time to the shared data */
|
||||
InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
|
||||
InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
|
||||
InterruptTime.QuadPart += Increment;
|
||||
SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
|
||||
SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
|
||||
SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
|
||||
|
||||
/* Update tick count */
|
||||
InterlockedExchangeAdd(&KiTickOffset, -(LONG)Increment);
|
||||
|
||||
/* Check for incomplete tick */
|
||||
OldTickCount = KeTickCount.LowPart;
|
||||
if (KiTickOffset <= 0)
|
||||
{
|
||||
/* Update the system time */
|
||||
CurrentTime.HighPart = SharedUserData->SystemTime.High1Time;
|
||||
CurrentTime.LowPart = SharedUserData->SystemTime.LowPart;
|
||||
CurrentTime.QuadPart += KeTimeAdjustment;
|
||||
SharedUserData->SystemTime.High2Time = CurrentTime.HighPart;
|
||||
SharedUserData->SystemTime.LowPart = CurrentTime.LowPart;
|
||||
SharedUserData->SystemTime.High1Time = CurrentTime.HighPart;
|
||||
|
||||
/* Update the tick count */
|
||||
CurrentTime.HighPart = KeTickCount.High1Time;
|
||||
CurrentTime.LowPart = OldTickCount;
|
||||
CurrentTime.QuadPart += 1;
|
||||
KeTickCount.High2Time = CurrentTime.HighPart;
|
||||
KeTickCount.LowPart = CurrentTime.LowPart;
|
||||
KeTickCount.High1Time = CurrentTime.HighPart;
|
||||
|
||||
/* Update it in the shared user data */
|
||||
SharedUserData->TickCount.High2Time = CurrentTime.HighPart;
|
||||
SharedUserData->TickCount.LowPart = CurrentTime.LowPart;
|
||||
SharedUserData->TickCount.High1Time = CurrentTime.HighPart;
|
||||
|
||||
/* Check for timer expiration */
|
||||
Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
|
||||
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
|
||||
{
|
||||
/* Check if we are already doing expiration */
|
||||
if (!Prcb->TimerRequest)
|
||||
{
|
||||
/* Request a DPC to handle this */
|
||||
Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
|
||||
Prcb->TimerHand = Hand;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for expiration with the new tick count as well */
|
||||
OldTickCount++;
|
||||
}
|
||||
|
||||
/* Check for timer expiration */
|
||||
Hand = OldTickCount & (TIMER_TABLE_SIZE - 1);
|
||||
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
|
||||
{
|
||||
/* Check if we are already doing expiration */
|
||||
if (!Prcb->TimerRequest)
|
||||
{
|
||||
/* Request a DPC to handle this */
|
||||
Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
|
||||
Prcb->TimerHand = Hand;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if this was a full tick */
|
||||
if (KiTickOffset <= 0)
|
||||
{
|
||||
/* Update the tick offset */
|
||||
KiTickOffset += KeMaximumIncrement;
|
||||
|
||||
/* Update system runtime */
|
||||
KeUpdateRunTime(TrapFrame, Irql);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increase interrupt count and exit */
|
||||
Prcb->InterruptCount++;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KIRQL Irql)
|
||||
{
|
||||
PKTHREAD Thread = KeGetCurrentThread();
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
|
||||
/* Increase interrupt count */
|
||||
Prcb->InterruptCount++;
|
||||
|
||||
/* Check if we came from user mode */
|
||||
#ifndef _M_ARM
|
||||
if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
|
||||
#else
|
||||
if (TrapFrame->PreviousMode == UserMode)
|
||||
#endif
|
||||
{
|
||||
/* Increase thread user time */
|
||||
Prcb->UserTime++;
|
||||
Thread->UserTime++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* See if we were in an ISR */
|
||||
Prcb->KernelTime++;
|
||||
if (Irql > DISPATCH_LEVEL)
|
||||
{
|
||||
/* Handle that */
|
||||
Prcb->InterruptTime++;
|
||||
}
|
||||
else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
|
||||
{
|
||||
/* Handle being in kernel mode */
|
||||
Thread->KernelTime++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle being in a DPC */
|
||||
Prcb->DpcTime++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update DPC rates */
|
||||
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
|
||||
Prcb->DpcRequestRate) >> 1;
|
||||
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
|
||||
|
||||
/* Check if the queue is large enough */
|
||||
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
|
||||
{
|
||||
/* Request a DPC */
|
||||
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
|
||||
/* Fix the maximum queue depth */
|
||||
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
|
||||
(Prcb->MaximumDpcQueueDepth > 1))
|
||||
{
|
||||
/* Make it smaller */
|
||||
Prcb->MaximumDpcQueueDepth--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if we've reached the adjustment limit */
|
||||
if (!(--Prcb->AdjustDpcThreshold))
|
||||
{
|
||||
/* Reset it, and check the queue maximum */
|
||||
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
||||
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
|
||||
{
|
||||
/* Increase it */
|
||||
Prcb->MaximumDpcQueueDepth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement the thread quantum */
|
||||
Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
|
||||
|
||||
/* Check if the time expired */
|
||||
if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
|
||||
{
|
||||
/* Schedule a quantum end */
|
||||
Prcb->QuantumEnd = 1;
|
||||
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
||||
}
|
||||
}
|
|
@ -48,7 +48,6 @@
|
|||
<file>ldt.c</file>
|
||||
<file>mtrr.c</file>
|
||||
<file>patpge.c</file>
|
||||
<file>systimer.S</file>
|
||||
<file>thrdini.c</file>
|
||||
<file>trap.s</file>
|
||||
<file>traphdlr.c</file>
|
||||
|
@ -66,7 +65,6 @@
|
|||
<file>kiinit.c</file>
|
||||
<file>stubs_asm.s</file>
|
||||
<file>thrdini.c</file>
|
||||
<file>time.c</file>
|
||||
<file>trap.s</file>
|
||||
<file>trapc.c</file>
|
||||
<file>usercall.c</file>
|
||||
|
@ -107,6 +105,7 @@
|
|||
<file>queue.c</file>
|
||||
<file>semphobj.c</file>
|
||||
<file>spinlock.c</file>
|
||||
<file>time.c</file>
|
||||
<file>thrdschd.c</file>
|
||||
<file>thrdobj.c</file>
|
||||
<file>timerobj.c</file>
|
||||
|
|
Loading…
Reference in a new issue