From bf8b9467dc905845c8042b5469b500ad2b092a0c Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Tue, 19 Jan 2010 06:16:47 +0000 Subject: [PATCH] [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 --- reactos/ntoskrnl/include/internal/ke.h | 6 - reactos/ntoskrnl/include/internal/ke_x.h | 7 + reactos/ntoskrnl/ke/arm/time.c | 322 ------------------- reactos/ntoskrnl/ke/i386/systimer.S | 383 ----------------------- reactos/ntoskrnl/ke/i386/trap.s | 35 +++ reactos/ntoskrnl/ke/time.c | 212 +++++++++++++ reactos/ntoskrnl/ntoskrnl-generic.rbuild | 3 +- 7 files changed, 255 insertions(+), 713 deletions(-) delete mode 100644 reactos/ntoskrnl/ke/arm/time.c delete mode 100644 reactos/ntoskrnl/ke/i386/systimer.S create mode 100644 reactos/ntoskrnl/ke/time.c diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index e5785a5ccab..f25bc92de44 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -728,12 +728,6 @@ KiTimerExpiration( IN PVOID SystemArgument2 ); -ULONG -NTAPI -KiComputeTimerTableIndex( - IN LONGLONG TimeValue -); - ULONG NTAPI KeSetProcess( diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index d649559f8d0..d7861839be5 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -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 diff --git a/reactos/ntoskrnl/ke/arm/time.c b/reactos/ntoskrnl/ke/arm/time.c deleted file mode 100644 index 988c4aff92a..00000000000 --- a/reactos/ntoskrnl/ke/arm/time.c +++ /dev/null @@ -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 -#define NDEBUG -#include - -/* 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); - } -} diff --git a/reactos/ntoskrnl/ke/i386/systimer.S b/reactos/ntoskrnl/ke/i386/systimer.S deleted file mode 100644 index 8790f88795d..00000000000 --- a/reactos/ntoskrnl/ke/i386/systimer.S +++ /dev/null @@ -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 -#include -.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 diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index 2161dee6553..4d725cc7888 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -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: diff --git a/reactos/ntoskrnl/ke/time.c b/reactos/ntoskrnl/ke/time.c new file mode 100644 index 00000000000..e33c45995d3 --- /dev/null +++ b/reactos/ntoskrnl/ke/time.c @@ -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 +#define NDEBUG +#include + +/* 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); + } +} diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index b6b5d014e46..d136727dea8 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -48,7 +48,6 @@ ldt.c mtrr.c patpge.c - systimer.S thrdini.c trap.s traphdlr.c @@ -66,7 +65,6 @@ kiinit.c stubs_asm.s thrdini.c - time.c trap.s trapc.c usercall.c @@ -107,6 +105,7 @@ queue.c semphobj.c spinlock.c + time.c thrdschd.c thrdobj.c timerobj.c