reactos/ntoskrnl/ke/i386/systimer.S
Cameron Gutman 29fa274d6d - Create another branch for networking fixes
- TSVN choked repeatedly when attempting to merge ~9000 revs into the branch (tried 3 times on 2 different computers)
 - If someone wants to delete aicom-network-fixes, they are welcome to
 - Lesson learned: Letting a branch get thousands of revs out of date is a horrible idea

svn path=/branches/aicom-network-branch/; revision=44353
2009-12-02 03:23:19 +00:00

384 lines
9.7 KiB
ArmAsm

/*
* 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