Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentime.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS Kernel 00004 * FILE: ntoskrnl/ex/time.c 00005 * PURPOSE: Time and Timezone Management 00006 * PROGRAMMERS: Eric Kohl 00007 * Thomas Weidenmueller 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define TICKSPERMINUTE 600000000 00017 00018 /* GLOBALS ******************************************************************/ 00019 00020 /* Note: Bias[minutes] = UTC - local time */ 00021 TIME_ZONE_INFORMATION ExpTimeZoneInfo; 00022 ULONG ExpLastTimeZoneBias = -1; 00023 LARGE_INTEGER ExpTimeZoneBias; 00024 ULONG ExpAltTimeZoneBias; 00025 ULONG ExpTimeZoneId; 00026 ULONG ExpTickCountMultiplier; 00027 ERESOURCE ExpTimeRefreshLock; 00028 ULONG ExpKernelResolutionCount = 0; 00029 ULONG ExpTimerResolutionCount = 0; 00030 00031 /* FUNCTIONS ****************************************************************/ 00032 00033 /*++ 00034 * @name ExAcquireTimeRefreshLock 00035 * 00036 * The ExReleaseTimeRefreshLock routine acquires the system-wide lock used 00037 * to synchronize clock interrupt frequency changes. 00038 * 00039 * @param Wait 00040 * If TRUE, the system will block the caller thread waiting for the lock 00041 * to become available. If FALSE, the routine will fail if the lock has 00042 * already been acquired. 00043 * 00044 * @return Boolean value indicating success or failure of the lock acquisition. 00045 * 00046 * @remarks None. 00047 * 00048 *--*/ 00049 BOOLEAN 00050 NTAPI 00051 ExAcquireTimeRefreshLock( 00052 IN BOOLEAN Wait 00053 ) 00054 { 00055 /* Block APCs */ 00056 KeEnterCriticalRegion(); 00057 00058 /* Attempt lock acquisition */ 00059 if (!(ExAcquireResourceExclusiveLite(&ExpTimeRefreshLock, Wait))) 00060 { 00061 /* Lock was not acquired, enable APCs and fail */ 00062 KeLeaveCriticalRegion(); 00063 return FALSE; 00064 } 00065 00066 /* Lock has been acquired */ 00067 return TRUE; 00068 } 00069 00070 /*++ 00071 * @name ExReleaseTimeRefreshLock 00072 * 00073 * The ExReleaseTimeRefreshLock routine releases the system-wide lock used 00074 * to synchronize clock interrupt frequency changes. 00075 * 00076 * @param None. 00077 * 00078 * @return None. 00079 * 00080 * @remarks None. 00081 * 00082 *--*/ 00083 VOID 00084 NTAPI 00085 ExReleaseTimeRefreshLock( 00086 VOID 00087 ) 00088 { 00089 /* Release the lock and re-enable APCs */ 00090 ExReleaseResourceLite(&ExpTimeRefreshLock); 00091 KeLeaveCriticalRegion(); 00092 } 00093 00094 /*++ 00095 * @name ExSetTimerResolution 00096 * @exported 00097 * 00098 * The KiInsertQueueApc routine modifies the frequency at which the system 00099 * clock interrupts. 00100 * 00101 * @param DesiredTime 00102 * Specifies the amount of time that should elapse between each timer 00103 * interrupt, in 100-nanosecond units. 00104 * 00105 * This parameter is ignored if SetResolution is FALSE. 00106 * 00107 * @param SetResolution 00108 * If TRUE, the call is a request to set the clock interrupt frequency to 00109 * the value specified by DesiredTime. If FALSE, the call is a request to 00110 * restore the clock interrupt frequency to the system's default value. 00111 * 00112 * @return New timer resolution, in 100-nanosecond ticks. 00113 * 00114 * @remarks (1) The clock frequency is changed only if the DesiredTime value is 00115 * less than the current setting. 00116 * 00117 * (2) The routine just returns the current setting if the DesiredTime 00118 * value is greater than what is currently set. 00119 * 00120 * (3) If the DesiredTime value is less than the system clock can 00121 * support, the routine uses the smallest resolution the system can 00122 * support, and returns that value. 00123 * 00124 * (4) If multiple drivers have attempted to change the clock interrupt 00125 * frequency, the system will only restore the default frequency 00126 * once ALL drivers have called the routine with SetResolution set 00127 * to FALSE. 00128 * 00129 * NB. This routine synchronizes with IRP_MJ_POWER requests through the 00130 * TimeRefreshLock. 00131 * 00132 *--*/ 00133 ULONG 00134 NTAPI 00135 ExSetTimerResolution(IN ULONG DesiredTime, 00136 IN BOOLEAN SetResolution) 00137 { 00138 ULONG CurrentIncrement; 00139 00140 /* Wait for clock interrupt frequency and power requests to synchronize */ 00141 ExAcquireTimeRefreshLock(TRUE); 00142 00143 /* Obey remark 2*/ 00144 CurrentIncrement = KeTimeIncrement; 00145 00146 /* Check the type of operation this is */ 00147 if (SetResolution) 00148 { 00149 /* 00150 * If this is the first kernel change, bump the timer resolution change 00151 * count, then bump the kernel change count as well. 00152 * 00153 * These two variables are tracked differently since user-mode processes 00154 * can also change the timer resolution through the NtSetTimerResolution 00155 * system call. A per-process flag in the EPROCESS then stores the per- 00156 * process change state. 00157 * 00158 */ 00159 if (!ExpKernelResolutionCount++) ExpTimerResolutionCount++; 00160 00161 /* Obey remark 3 */ 00162 if (DesiredTime < KeMinimumIncrement) DesiredTime = KeMinimumIncrement; 00163 00164 /* Obey remark 1 */ 00165 if (DesiredTime < KeTimeIncrement) 00166 { 00167 /* Force this thread on CPU zero, since we don't want it to drift */ 00168 KeSetSystemAffinityThread(1); 00169 00170 /* Now call the platform driver (HAL) to make the change */ 00171 CurrentIncrement = HalSetTimeIncrement(DesiredTime); 00172 00173 /* Put the thread back to its original affinity */ 00174 KeRevertToUserAffinityThread(); 00175 00176 /* Finally, keep track of the new value in the kernel */ 00177 KeTimeIncrement = CurrentIncrement; 00178 } 00179 } 00180 else 00181 { 00182 /* First, make sure that a driver has actually changed the resolution */ 00183 if (ExpKernelResolutionCount) 00184 { 00185 /* Obey remark 4 */ 00186 if (--ExpKernelResolutionCount) 00187 { 00188 /* 00189 * All kernel drivers have requested the original frequency to 00190 * be restored, but there might still be user processes with an 00191 * ongoing clock interrupt frequency change, so make sure that 00192 * this isn't the case. 00193 */ 00194 if (--ExpTimerResolutionCount) 00195 { 00196 /* Force this thread on one CPU so that it doesn't drift */ 00197 KeSetSystemAffinityThread(1); 00198 00199 /* Call the HAL to restore the frequency to its default */ 00200 CurrentIncrement = HalSetTimeIncrement(KeMaximumIncrement); 00201 00202 /* Put the thread back to its original affinity */ 00203 KeRevertToUserAffinityThread(); 00204 00205 /* Finally, keep track of the new value in the kernel */ 00206 KeTimeIncrement = CurrentIncrement; 00207 } 00208 } 00209 } 00210 } 00211 00212 /* Release the clock interrupt frequency lock since changes are done */ 00213 ExReleaseTimeRefreshLock(); 00214 00215 /* And return the current value -- which could reflect the new frequency */ 00216 return CurrentIncrement; 00217 } 00218 00219 VOID 00220 NTAPI 00221 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime, 00222 IN ULONG MaxSepInSeconds) 00223 { 00224 /* FIXME: TODO */ 00225 return; 00226 } 00227 00228 BOOLEAN 00229 NTAPI 00230 ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime) 00231 { 00232 LARGE_INTEGER CurrentTime; 00233 NTSTATUS Status; 00234 00235 /* Read time zone information from the registry */ 00236 Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo); 00237 if (!NT_SUCCESS(Status)) 00238 { 00239 /* Failed, clear all data */ 00240 RtlZeroMemory(&ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION)); 00241 ExpTimeZoneBias.QuadPart = (LONGLONG)0; 00242 ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN; 00243 } 00244 else 00245 { 00246 /* FIXME: Calculate transition dates */ 00247 00248 /* Set bias and ID */ 00249 ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias + 00250 ExpTimeZoneInfo.StandardBias)) * 00251 TICKSPERMINUTE; 00252 ExpTimeZoneId = TIME_ZONE_ID_STANDARD; 00253 } 00254 00255 /* Change it for user-mode applications */ 00256 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart; 00257 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart; 00258 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart; 00259 SharedUserData->TimeZoneId = ExpTimeZoneId; 00260 00261 /* Convert boot time from local time to UTC */ 00262 KeBootTime.QuadPart += ExpTimeZoneBias.QuadPart; 00263 00264 /* Convert system time from local time to UTC */ 00265 do 00266 { 00267 CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time; 00268 CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart; 00269 } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time); 00270 00271 /* Change it for user-mode applications */ 00272 CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart; 00273 SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart; 00274 SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart; 00275 SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart; 00276 00277 /* Return success */ 00278 return TRUE; 00279 } 00280 00281 NTSTATUS 00282 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation) 00283 { 00284 LARGE_INTEGER LocalTime, SystemTime, OldTime; 00285 TIME_FIELDS TimeFields; 00286 DPRINT("ExpSetTimeZoneInformation() called\n"); 00287 00288 DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias); 00289 DPRINT("Old time zone standard bias: %d minutes\n", 00290 ExpTimeZoneInfo.StandardBias); 00291 DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation->Bias); 00292 DPRINT("New time zone standard bias: %d minutes\n", 00293 TimeZoneInformation->StandardBias); 00294 00295 /* Get the local time */ 00296 HalQueryRealTimeClock(&TimeFields); 00297 RtlTimeFieldsToTime(&TimeFields, &LocalTime); 00298 00299 /* FIXME: Calculate transition dates */ 00300 00301 /* Calculate the bias and set the ID */ 00302 ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias + 00303 TimeZoneInformation->StandardBias)) * 00304 TICKSPERMINUTE; 00305 ExpTimeZoneId = TIME_ZONE_ID_STANDARD; 00306 00307 /* Copy the timezone information */ 00308 RtlCopyMemory(&ExpTimeZoneInfo, 00309 TimeZoneInformation, 00310 sizeof(TIME_ZONE_INFORMATION)); 00311 00312 /* Set the new time zone information */ 00313 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart; 00314 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart; 00315 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart; 00316 SharedUserData->TimeZoneId = ExpTimeZoneId; 00317 00318 DPRINT("New time zone bias: %I64d minutes\n", 00319 ExpTimeZoneBias.QuadPart / TICKSPERMINUTE); 00320 00321 /* Calculate the new system time */ 00322 ExLocalTimeToSystemTime(&LocalTime, &SystemTime); 00323 00324 /* Set the new system time */ 00325 KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL); 00326 00327 /* Return success */ 00328 DPRINT("ExpSetTimeZoneInformation() done\n"); 00329 return STATUS_SUCCESS; 00330 } 00331 00332 /* 00333 * FUNCTION: Sets the system time. 00334 * PARAMETERS: 00335 * NewTime - Points to a variable that specified the new time 00336 * of day in the standard time format. 00337 * OldTime - Optionally points to a variable that receives the 00338 * old time of day in the standard time format. 00339 * RETURNS: Status 00340 */ 00341 NTSTATUS 00342 NTAPI 00343 NtSetSystemTime(IN PLARGE_INTEGER SystemTime, 00344 OUT PLARGE_INTEGER PreviousTime OPTIONAL) 00345 { 00346 LARGE_INTEGER OldSystemTime; 00347 LARGE_INTEGER NewSystemTime; 00348 LARGE_INTEGER LocalTime; 00349 TIME_FIELDS TimeFields; 00350 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00351 NTSTATUS Status = STATUS_SUCCESS; 00352 PAGED_CODE(); 00353 00354 /* Check if we were called from user-mode */ 00355 if (PreviousMode != KernelMode) 00356 { 00357 _SEH2_TRY 00358 { 00359 /* Verify the time pointers */ 00360 NewSystemTime = ProbeForReadLargeInteger(SystemTime); 00361 if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime); 00362 } 00363 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00364 { 00365 /* Return the exception code */ 00366 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00367 } 00368 _SEH2_END; 00369 } 00370 else 00371 { 00372 /* Reuse the pointer */ 00373 NewSystemTime = *SystemTime; 00374 } 00375 00376 /* Make sure we have permission to change the time */ 00377 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode)) 00378 { 00379 DPRINT1("NtSetSystemTime: Caller requires the " 00380 "SeSystemtimePrivilege privilege!\n"); 00381 return STATUS_PRIVILEGE_NOT_HELD; 00382 } 00383 00384 /* Convert the time and set it in HAL */ 00385 ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime); 00386 RtlTimeToTimeFields(&LocalTime, &TimeFields); 00387 HalSetRealTimeClock(&TimeFields); 00388 00389 /* Now set system time */ 00390 KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL); 00391 00392 /* Check if caller wanted previous time */ 00393 if (PreviousTime) 00394 { 00395 /* Enter SEH Block for return */ 00396 _SEH2_TRY 00397 { 00398 /* Return the previous time */ 00399 *PreviousTime = OldSystemTime; 00400 } 00401 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00402 { 00403 /* Get the exception code */ 00404 Status = _SEH2_GetExceptionCode(); 00405 } 00406 _SEH2_END; 00407 } 00408 00409 /* Return status */ 00410 return Status; 00411 } 00412 00413 /* 00414 * FUNCTION: Retrieves the system time. 00415 * PARAMETERS: 00416 * CurrentTime - Points to a variable that receives the current 00417 * time of day in the standard time format. 00418 */ 00419 NTSTATUS 00420 NTAPI 00421 NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime) 00422 { 00423 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00424 NTSTATUS Status = STATUS_SUCCESS; 00425 PAGED_CODE(); 00426 00427 /* Check if we were called from user-mode */ 00428 if (PreviousMode != KernelMode) 00429 { 00430 _SEH2_TRY 00431 { 00432 /* Verify the time pointer */ 00433 ProbeForWriteLargeInteger(SystemTime); 00434 00435 /* 00436 * It's safe to pass the pointer directly to KeQuerySystemTime as 00437 * it's just a basic copy to this pointer. If it raises an 00438 * exception nothing dangerous can happen! 00439 */ 00440 KeQuerySystemTime(SystemTime); 00441 } 00442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00443 { 00444 /* Get the exception code */ 00445 Status = _SEH2_GetExceptionCode(); 00446 } 00447 _SEH2_END; 00448 } 00449 else 00450 { 00451 /* Query the time directly */ 00452 KeQuerySystemTime(SystemTime); 00453 } 00454 00455 /* Return status to caller */ 00456 return Status; 00457 } 00458 00459 /* 00460 * @implemented 00461 */ 00462 VOID 00463 NTAPI 00464 ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime, 00465 PLARGE_INTEGER SystemTime) 00466 { 00467 SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart; 00468 } 00469 00470 /* 00471 * @implemented 00472 */ 00473 VOID 00474 NTAPI 00475 ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime, 00476 PLARGE_INTEGER LocalTime) 00477 { 00478 LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart; 00479 } 00480 00481 /* EOF */ Generated on Mon May 28 2012 04:18:04 for ReactOS by
1.7.6.1
|