- Implement KeUpdateSystemTime properly, it now saves and returns the old time, supports HAL time, as well as loops the timer list to fixup relative timers and expired timers after the time has changed.

- Replace mm failure detection code by dprint + while loop to avoid bugchecks which might make the error worse to see.
- Remove some deprecated code/functions and cleanup clock.c entirely.

svn path=/trunk/; revision=25626
This commit is contained in:
Alex Ionescu 2007-01-25 05:14:55 +00:00
parent 2691e0994a
commit 92208d72a8
8 changed files with 242 additions and 142 deletions

View file

@ -15,9 +15,6 @@
/* DATA **********************************************************************/
/* HACK */
extern BOOLEAN KiClockSetupComplete;
#define BUILD_OSCSDVERSION(major, minor) (((major & 0xFF) << 8) | (minor & 0xFF))
/* NT Version Info */
@ -1127,9 +1124,6 @@ Phase1InitializationDiscard(PVOID Context)
KeBootTimeBias = 0;
}
/* The clock is ready now (FIXME: HACK FOR OLD HAL) */
KiClockSetupComplete = TRUE;
/* Initialize all processors */
if (!HalAllProcessorsStarted()) KeBugCheck(HAL1_INITIALIZATION_FAILED);

View file

@ -82,7 +82,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
NTSTATUS
ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
{
LARGE_INTEGER LocalTime, SystemTime;
LARGE_INTEGER LocalTime, SystemTime, OldTime;
TIME_FIELDS TimeFields;
DPRINT("ExpSetTimeZoneInformation() called\n");
@ -123,7 +123,7 @@ ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
/* Set the new system time */
KeSetSystemTime(&SystemTime, NULL, FALSE, NULL);
KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL);
/* Return success */
DPRINT("ExpSetTimeZoneInformation() done\n");
@ -184,16 +184,13 @@ NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
return STATUS_PRIVILEGE_NOT_HELD;
}
/* Check if caller wants the old time */
if(PreviousTime) KeQuerySystemTime(&OldSystemTime);
/* Convert the time and set it in HAL */
ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
RtlTimeToTimeFields(&LocalTime, &TimeFields);
HalSetRealTimeClock(&TimeFields);
/* Now set system time */
KeSetSystemTime(&NewSystemTime, NULL, FALSE, NULL);
KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
/* Check if caller wanted previous time */
if(PreviousTime)

View file

@ -85,7 +85,8 @@ extern PVOID KeUserCallbackDispatcher;
extern PVOID KeUserExceptionDispatcher;
extern PVOID KeRaiseUserExceptionDispatcher;
extern LARGE_INTEGER KeBootTime;
extern ULONG KeBootTimeBias;
extern ULONGLONG KeBootTimeBias;
extern BOOLEAN ExCmosClockIsSane;
extern ULONG KeI386NpxPresent;
extern ULONG KeI386XMMIPresent;
extern ULONG KeI386FxsrPresent;

View file

@ -1,118 +1,182 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/clock.c
* PURPOSE: Handle System Clock
*
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created
* David Welch & Phillip Susi - Implementation (?)
* PURPOSE: System Clock Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* NOTES ******************************************************************/
/*
* System time units are 100-nanosecond intervals
*/
/* INCLUDES ***************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, KiInitializeSystemClock)
#endif
/* GLOBALS ****************************************************************/
/* GLOBALS *******************************************************************/
LARGE_INTEGER KeBootTime;
ULONG KeBootTimeBias;
KDPC KiTimerExpireDpc;
BOOLEAN KiClockSetupComplete = FALSE;
ULONG KiTimeLimitIsrMicroseconds;
/*
* Number of timer interrupts since initialisation
*/
ULONGLONG KeBootTimeBias;
volatile KSYSTEM_TIME KeTickCount = {0};
volatile ULONG KiRawTicks = 0;
ULONG KeMaximumIncrement;
ULONG KeMinimumIncrement;
ULONG KeTimeAdjustment;
ULONG KeTimeIncrement;
LONG KiTickOffset = 0;
/*
* The increment in the system clock every timer tick (in system time units)
*
* = (1/18.2)*10^9
*
* RJJ was 54945055
*/
#define CLOCK_INCREMENT (100000)
ULONG KeMaximumIncrement = 100000;
ULONG KeMinimumIncrement = 100000;
ULONG KeTimeAdjustment = 100000;
#define MICROSECONDS_PER_TICK (10000)
#define TICKS_TO_CALIBRATE (1)
#define CALIBRATE_PERIOD (MICROSECONDS_PER_TICK * TICKS_TO_CALIBRATE)
/* FUNCTIONS **************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
KeSetSystemTime(IN PLARGE_INTEGER NewSystemTime,
KeSetSystemTime(IN PLARGE_INTEGER NewTime,
OUT PLARGE_INTEGER OldTime,
IN BOOLEAN FixInterruptTime,
IN PLARGE_INTEGER HalTime)
IN PLARGE_INTEGER HalTime OPTIONAL)
{
LARGE_INTEGER OldSystemTime;
LARGE_INTEGER DeltaTime;
KIRQL OldIrql;
TIME_FIELDS TimeFields;
KIRQL OldIrql, OldIrql2;
LARGE_INTEGER DeltaTime;
PLIST_ENTRY ListHead, NextEntry;
PKTIMER Timer;
PKSPIN_LOCK_QUEUE LockQueue;
LIST_ENTRY TempList, TempList2;
ULONG Hand, i;
PKTIMER_TABLE_ENTRY TimerEntry;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
/* Sanity checks */
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
OldIrql = KiAcquireDispatcherLock();
/* Check if this is for the HAL */
if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
do
/* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
KeSetSystemAffinityThread(1);
OldIrql = KiAcquireDispatcherLock();
KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
/* Query the system time now */
KeQuerySystemTime(OldTime);
/* Set the new system time */
SharedUserData->SystemTime.LowPart = NewTime->LowPart;
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
/* Check if this was for the HAL and set the RTC time */
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
/* Calculate the difference between the new and the old time */
DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
/* Update system boot time */
KeBootTime.QuadPart += DeltaTime.QuadPart;
KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
/* Lower IRQL back */
KeLowerIrql(OldIrql2);
/* Check if we need to adjust interrupt time */
if (FixInterruptTime) KEBUGCHECK(0);
/* Setup a temporary list of absolute timers */
InitializeListHead(&TempList);
/* Loop current timers */
for (i = 0; i < TIMER_TABLE_SIZE; i++)
{
OldSystemTime.u.HighPart = SharedUserData->SystemTime.High1Time;
OldSystemTime.u.LowPart = SharedUserData->SystemTime.LowPart;
/* Loop the entries in this table and lock the timers */
ListHead = &KiTimerTableListHead[i].Entry;
LockQueue = KiAcquireTimerLock(i);
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the timer */
Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
NextEntry = NextEntry->Flink;
/* Is is absolute? */
if (Timer->Header.Absolute)
{
/* Remove it from the timer list */
if (RemoveEntryList(&Timer->TimerListEntry))
{
/* Get the entry and check if it's empty */
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
if (IsListEmpty(&TimerEntry->Entry))
{
/* Clear the time then */
TimerEntry->Time.HighPart = 0xFFFFFFFF;
}
}
/* Insert it into our temporary list */
DPRINT1("Adding a timer!\n");
InsertTailList(&TempList, &Timer->TimerListEntry);
}
}
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
while (OldSystemTime.u.HighPart != SharedUserData->SystemTime.High2Time);
/* Set the new system time */
SharedUserData->SystemTime.LowPart = NewSystemTime->u.LowPart;
SharedUserData->SystemTime.High1Time = NewSystemTime->u.HighPart;
SharedUserData->SystemTime.High2Time = NewSystemTime->u.HighPart;
/* Setup a temporary list of expired timers */
InitializeListHead(&TempList2);
/* Calculate the difference between the new and the old time */
DeltaTime.QuadPart = NewSystemTime->QuadPart - OldSystemTime.QuadPart;
/* Loop absolute timers */
while (TempList.Flink != &TempList)
{
/* Get the timer */
Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
RemoveEntryList(&Timer->TimerListEntry);
/* Update system boot time */
KeBootTime.QuadPart += DeltaTime.QuadPart;
/* Update the due time and handle */
Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
Timer->Header.Hand = (UCHAR)Hand;
/* Update absolute timers */
DPRINT1("FIXME: TIMER UPDATE NOT DONE!!!\n");
/* Lock the timer and re-insert it */
LockQueue = KiAcquireTimerLock(Hand);
if (KiInsertTimerTable(Timer, Hand))
{
/* Remove it from the timer list */
if (RemoveEntryList(&Timer->TimerListEntry))
{
/* Get the entry and check if it's empty */
TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
if (IsListEmpty(&TimerEntry->Entry))
{
/* Clear the time then */
TimerEntry->Time.HighPart = 0xFFFFFFFF;
}
}
KiReleaseDispatcherLock(OldIrql);
/* Insert it into our temporary list */
DPRINT1("Adding a timer 2!\n");
InsertTailList(&TempList2, &Timer->TimerListEntry);
}
/*
* NOTE: Expired timers will be processed at the next clock tick!
*/
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
/* FIXME: Process expired timers! */
KiReleaseDispatcherLock(OldIrql);
/* Revert affinity */
KeRevertToUserAffinityThread();
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
ULONG
STDCALL
NTAPI
KeQueryTimeIncrement(VOID)
/*
* FUNCTION: Gets the increment (in 100-nanosecond units) that is added to
* the system clock every time the clock interrupts
* RETURNS: The increment
*/
{
/* Return the increment */
return KeMaximumIncrement;
}
@ -121,47 +185,60 @@ KeQueryTimeIncrement(VOID)
*/
#undef KeQueryTickCount
VOID
STDCALL
KeQueryTickCount(PLARGE_INTEGER TickCount)
/*
* FUNCTION: Returns the number of ticks since the system was booted
* ARGUMENTS:
* TickCount (OUT) = Points to storage for the number of ticks
*/
NTAPI
KeQueryTickCount(IN PLARGE_INTEGER TickCount)
{
TickCount->QuadPart = *(PULONGLONG)&KeTickCount;
/* Loop until we get a perfect match */
for (;;)
{
/* Read the tick count value */
TickCount->HighPart = KeTickCount.High1Time;
TickCount->LowPart = KeTickCount.LowPart;
if (TickCount->HighPart == KeTickCount.High2Time) break;
YieldProcessor();
}
}
/*
* FUNCTION: Gets the current system time
* ARGUMENTS:
* CurrentTime (OUT) = The routine stores the current time here
* NOTE: The time is the number of 100-nanosecond intervals since the
* 1st of January, 1601.
*
* @implemented
*/
VOID
STDCALL
KeQuerySystemTime(PLARGE_INTEGER CurrentTime)
NTAPI
KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
{
do {
CurrentTime->u.HighPart = SharedUserData->SystemTime.High1Time;
CurrentTime->u.LowPart = SharedUserData->SystemTime.LowPart;
} while (CurrentTime->u.HighPart != SharedUserData->SystemTime.High2Time);
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
if (CurrentTime->HighPart ==
SharedUserData->SystemTime.High2Time) break;
YieldProcessor();
}
}
/*
* @implemented
*/
ULONGLONG
STDCALL
NTAPI
KeQueryInterruptTime(VOID)
{
LARGE_INTEGER CurrentTime;
do {
CurrentTime.u.HighPart = SharedUserData->InterruptTime.High1Time;
CurrentTime.u.LowPart = SharedUserData->InterruptTime.LowPart;
} while (CurrentTime.u.HighPart != SharedUserData->InterruptTime.High2Time);
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
if (CurrentTime.HighPart ==
SharedUserData->InterruptTime.High2Time) break;
YieldProcessor();
}
/* Return the time value */
return CurrentTime.QuadPart;
}
@ -169,32 +246,20 @@ KeQueryInterruptTime(VOID)
* @implemented
*/
VOID
STDCALL
KeSetTimeIncrement(
IN ULONG MaxIncrement,
IN ULONG MinIncrement)
NTAPI
KeSetTimeIncrement(IN ULONG MaxIncrement,
IN ULONG MinIncrement)
{
/* Set some Internal Variables */
/* FIXME: We use a harcoded CLOCK_INCREMENT. That *must* be changed */
KeMaximumIncrement = MaxIncrement;
KeMinimumIncrement = MinIncrement;
}
/*
* @implemented
*/
ULONG
STDCALL
NtGetTickCount(VOID)
{
LARGE_INTEGER TickCount;
KeQueryTickCount(&TickCount);
return TickCount.u.LowPart;
KeMinimumIncrement = max(MinIncrement, 10000);
KeTimeAdjustment = MaxIncrement;
KeTimeIncrement = MaxIncrement;
KiTickOffset = MaxIncrement;
}
NTSTATUS
STDCALL
NTAPI
NtQueryTimerResolution(OUT PULONG MinimumResolution,
OUT PULONG MaximumResolution,
OUT PULONG ActualResolution)
@ -204,7 +269,7 @@ NtQueryTimerResolution(OUT PULONG MinimumResolution,
}
NTSTATUS
STDCALL
NTAPI
NtSetTimerResolution(IN ULONG DesiredResolution,
IN BOOLEAN SetResolution,
OUT PULONG CurrentResolution)

View file

@ -22,6 +22,8 @@ ULONG KiAdjustDpcThreshold = 20;
ULONG KiIdealDpcRate = 20;
BOOLEAN KeThreadDpcEnable;
FAST_MUTEX KiGenericCallDpcMutex;
KDPC KiTimerExpireDpc;
ULONG KiTimeLimitIsrMicroseconds;
/* PRIVATE FUNCTIONS *********************************************************/

View file

@ -363,7 +363,11 @@ MmReserveSwapPages(ULONG Nr)
KIRQL oldIrql;
ULONG MiAvailSwapPages;
if (!PagingReady) KEBUGCHECK(0);
if (!PagingReady)
{
DPRINT1("PAGING USED TOO SOON!!!\n");
while (TRUE);
}
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
MiAvailSwapPages =
(MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
@ -383,7 +387,11 @@ MmDereserveSwapPages(ULONG Nr)
{
KIRQL oldIrql;
if (!PagingReady) KEBUGCHECK(0);
if (!PagingReady)
{
DPRINT1("PAGING USED TOO SOON!!!\n");
while (TRUE);
}
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
MiReservedSwapPages = MiReservedSwapPages - Nr;
KeReleaseSpinLock(&PagingFileListLock, oldIrql);
@ -395,7 +403,11 @@ MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
KIRQL oldIrql;
ULONG i, j;
if (!PagingReady) KEBUGCHECK(0);
if (!PagingReady)
{
DPRINT1("PAGING USED TOO SOON!!!\n");
while (TRUE);
}
KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
for (i = 0; i < PagingFile->AllocMapSize; i++)
@ -425,7 +437,11 @@ MmFreeSwapPage(SWAPENTRY Entry)
ULONG off;
KIRQL oldIrql;
if (!PagingReady) KEBUGCHECK(0);
if (!PagingReady)
{
DPRINT1("PAGING USED TOO SOON!!!\n");
while (TRUE);
}
i = FILE_FROM_ENTRY(Entry);
off = OFFSET_FROM_ENTRY(Entry);
@ -470,7 +486,11 @@ MmAllocSwapPage(VOID)
ULONG off;
SWAPENTRY entry;
if (!PagingReady) KEBUGCHECK(0);
if (!PagingReady)
{
DPRINT1("PAGING USED TOO SOON!!!\n");
while (TRUE);
}
KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
if (MiFreeSwapPages == 0)

View file

@ -149,7 +149,11 @@ MmGetPageOp(PMEMORY_AREA MArea, HANDLE Pid, PVOID Address,
KIRQL oldIrql;
PMM_PAGEOP PageOp;
if (!PageOpReady) KEBUGCHECK(0);
if (!PageOpReady)
{
DPRINT1("PAGEOPS USED TOO SOON!!!\n");
while (TRUE);
}
/*
* Calcuate the hash value for pageop structure
@ -269,3 +273,4 @@ MmInitializePageOp(VOID)

View file

@ -390,7 +390,11 @@ MmInsertRmap(PFN_TYPE Page, PEPROCESS Process,
PMM_RMAP_ENTRY new_entry;
ULONG PrevSize;
if (!RmapReady) KEBUGCHECK(0);
if (!RmapReady)
{
DPRINT1("RMAPS USED TOO SOON!!!\n");
while (TRUE);
}
Address = (PVOID)PAGE_ROUND_DOWN(Address);
@ -459,6 +463,12 @@ MmDeleteAllRmaps(PFN_TYPE Page, PVOID Context,
PMM_RMAP_ENTRY previous_entry;
PEPROCESS Process;
if (!RmapReady)
{
DPRINT1("RMAPS USED TOO SOON!!!\n");
while (TRUE);
}
ExAcquireFastMutex(&RmapListLock);
current_entry = MmGetRmapListHeadPage(Page);
if (current_entry == NULL)
@ -497,6 +507,12 @@ MmDeleteRmap(PFN_TYPE Page, PEPROCESS Process,
{
PMM_RMAP_ENTRY current_entry, previous_entry;
if (!RmapReady)
{
DPRINT1("RMAPS USED TOO SOON!!!\n");
while (TRUE);
}
ExAcquireFastMutex(&RmapListLock);
previous_entry = NULL;
current_entry = MmGetRmapListHeadPage(Page);