ReactOS 0.4.15-dev-5672-gf73ac17
time.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/time.c
5 * PURPOSE: Time and Timezone Management
6 * PROGRAMMERS: Eric Kohl
7 * Thomas Weidenmueller
8 */
9
10/* INCLUDES *****************************************************************/
11
12#include <ntoskrnl.h>
13#define NDEBUG
14#include <debug.h>
15
16#define TICKSPERMINUTE 600000000
17
18/* GLOBALS ******************************************************************/
19
20/* Note: Bias[minutes] = UTC - local time */
30
31/* FUNCTIONS ****************************************************************/
32
33/*++
34 * @name ExAcquireTimeRefreshLock
35 *
36 * The ExReleaseTimeRefreshLock routine acquires the system-wide lock used
37 * to synchronize clock interrupt frequency changes.
38 *
39 * @param Wait
40 * If TRUE, the system will block the caller thread waiting for the lock
41 * to become available. If FALSE, the routine will fail if the lock has
42 * already been acquired.
43 *
44 * @return Boolean value indicating success or failure of the lock acquisition.
45 *
46 * @remarks None.
47 *
48 *--*/
52{
53 /* Block APCs */
55
56 /* Attempt lock acquisition */
58 {
59 /* Lock was not acquired, enable APCs and fail */
61 return FALSE;
62 }
63
64 /* Lock has been acquired */
65 return TRUE;
66}
67
68/*++
69 * @name ExReleaseTimeRefreshLock
70 *
71 * The ExReleaseTimeRefreshLock routine releases the system-wide lock used
72 * to synchronize clock interrupt frequency changes.
73 *
74 * @param None.
75 *
76 * @return None.
77 *
78 * @remarks None.
79 *
80 *--*/
81VOID
84{
85 /* Release the lock and re-enable APCs */
88}
89
90/*++
91 * @name ExSetTimerResolution
92 * @exported
93 *
94 * The KiInsertQueueApc routine modifies the frequency at which the system
95 * clock interrupts.
96 *
97 * @param DesiredTime
98 * Specifies the amount of time that should elapse between each timer
99 * interrupt, in 100-nanosecond units.
100 *
101 * This parameter is ignored if SetResolution is FALSE.
102 *
103 * @param SetResolution
104 * If TRUE, the call is a request to set the clock interrupt frequency to
105 * the value specified by DesiredTime. If FALSE, the call is a request to
106 * restore the clock interrupt frequency to the system's default value.
107 *
108 * @return New timer resolution, in 100-nanosecond ticks.
109 *
110 * @remarks (1) The clock frequency is changed only if the DesiredTime value is
111 * less than the current setting.
112 *
113 * (2) The routine just returns the current setting if the DesiredTime
114 * value is greater than what is currently set.
115 *
116 * (3) If the DesiredTime value is less than the system clock can
117 * support, the routine uses the smallest resolution the system can
118 * support, and returns that value.
119 *
120 * (4) If multiple drivers have attempted to change the clock interrupt
121 * frequency, the system will only restore the default frequency
122 * once ALL drivers have called the routine with SetResolution set
123 * to FALSE.
124 *
125 * NB. This routine synchronizes with IRP_MJ_POWER requests through the
126 * TimeRefreshLock.
127 *
128 *--*/
129ULONG
130NTAPI
133{
134 ULONG CurrentIncrement;
135
136 /* Wait for clock interrupt frequency and power requests to synchronize */
138
139 /* Obey remark 2*/
140 CurrentIncrement = KeTimeIncrement;
141
142 /* Check the type of operation this is */
143 if (SetResolution)
144 {
145 /*
146 * If this is the first kernel change, bump the timer resolution change
147 * count, then bump the kernel change count as well.
148 *
149 * These two variables are tracked differently since user-mode processes
150 * can also change the timer resolution through the NtSetTimerResolution
151 * system call. A per-process flag in the EPROCESS then stores the per-
152 * process change state.
153 *
154 */
156
157 /* Obey remark 3 */
158 if (DesiredTime < KeMinimumIncrement) DesiredTime = KeMinimumIncrement;
159
160 /* Obey remark 1 */
161 if (DesiredTime < KeTimeIncrement)
162 {
163 /* Force this thread on CPU zero, since we don't want it to drift */
165
166 /* Now call the platform driver (HAL) to make the change */
167 CurrentIncrement = HalSetTimeIncrement(DesiredTime);
168
169 /* Put the thread back to its original affinity */
171
172 /* Finally, keep track of the new value in the kernel */
173 KeTimeIncrement = CurrentIncrement;
174 }
175 }
176 else
177 {
178 /* First, make sure that a driver has actually changed the resolution */
180 {
181 /* Obey remark 4 */
183 {
184 /*
185 * All kernel drivers have requested the original frequency to
186 * be restored, but there might still be user processes with an
187 * ongoing clock interrupt frequency change, so make sure that
188 * this isn't the case.
189 */
191 {
192 /* Force this thread on one CPU so that it doesn't drift */
194
195 /* Call the HAL to restore the frequency to its default */
196 CurrentIncrement = HalSetTimeIncrement(KeMaximumIncrement);
197
198 /* Put the thread back to its original affinity */
200
201 /* Finally, keep track of the new value in the kernel */
202 KeTimeIncrement = CurrentIncrement;
203 }
204 }
205 }
206 }
207
208 /* Release the clock interrupt frequency lock since changes are done */
210
211 /* And return the current value -- which could reflect the new frequency */
212 return CurrentIncrement;
213}
214
215VOID
216NTAPI
218 IN ULONG MaxSepInSeconds)
219{
220 /* FIXME: TODO */
221 return;
222}
223
225NTAPI
227{
228 LARGE_INTEGER StandardTime;
229 LARGE_INTEGER DaylightTime;
230 LARGE_INTEGER CurrentTime;
232
233 /* Read time zone information from the registry */
235 if (!NT_SUCCESS(Status))
236 {
237 DPRINT1("RtlQueryTimeZoneInformation() failed (Status 0x%08lx)\n", Status);
238 return FALSE;
239 }
240
241 /* Get the default bias */
243
246 {
247 /* Get this years standard start time */
249 &StandardTime,
250 CurrentBootTime,
251 TRUE))
252 {
253 DPRINT1("RtlCutoverTimeToSystemTime() for StandardDate failed!\n");
254 return FALSE;
255 }
256
257 /* Get this years daylight start time */
259 &DaylightTime,
260 CurrentBootTime,
261 TRUE))
262 {
263 DPRINT1("RtlCutoverTimeToSystemTime() for DaylightDate failed!\n");
264 return FALSE;
265 }
266
267 /* Determine the time zone id and update the time zone bias */
268 if (DaylightTime.QuadPart < StandardTime.QuadPart)
269 {
270 if ((CurrentBootTime->QuadPart >= DaylightTime.QuadPart) &&
271 (CurrentBootTime->QuadPart < StandardTime.QuadPart))
272 {
273 DPRINT("Daylight time!\n");
276 }
277 else
278 {
279 DPRINT("Standard time!\n");
282 }
283 }
284 else
285 {
286 if ((CurrentBootTime->QuadPart >= StandardTime.QuadPart) &&
287 (CurrentBootTime->QuadPart < DaylightTime.QuadPart))
288 {
289 DPRINT("Standard time!\n");
292 }
293 else
294 {
295 DPRINT("Daylight time!\n");
298 }
299 }
300 }
301 else
302 {
304 }
305
306 /* Change it for user-mode applications */
307 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
308 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
309 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
310 SharedUserData->TimeZoneId = ExpTimeZoneId;
311
312 /* Convert boot time from local time to UTC */
314
315 /* Convert system time from local time to UTC */
316 do
317 {
318 CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
319 CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
320 } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
321
322 /* Change it for user-mode applications */
323 CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
324 SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
325 SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
326 SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
327
328 /* Return success */
329 return TRUE;
330}
331
334{
335 LARGE_INTEGER LocalTime, SystemTime, OldTime;
337 DPRINT("ExpSetTimeZoneInformation() called\n");
338
339 DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
340 DPRINT("Old time zone standard bias: %d minutes\n",
342 DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation->Bias);
343 DPRINT("New time zone standard bias: %d minutes\n",
344 TimeZoneInformation->StandardBias);
345
346 /* Get the local time */
348 RtlTimeFieldsToTime(&TimeFields, &LocalTime);
349
350 /* FIXME: Calculate transition dates */
351
352 /* Calculate the bias and set the ID */
353 ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
354 TimeZoneInformation->StandardBias)) *
357
358 /* Copy the timezone information */
360 TimeZoneInformation,
362
363 /* Set the new time zone information */
364 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
365 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
366 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
367 SharedUserData->TimeZoneId = ExpTimeZoneId;
368
369 DPRINT("New time zone bias: %I64d minutes\n",
371
372 /* Calculate the new system time */
373 ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
374
375 /* Set the new system time */
376 KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL);
377
378 /* Return success */
379 DPRINT("ExpSetTimeZoneInformation() done\n");
380 return STATUS_SUCCESS;
381}
382
383/*
384 * FUNCTION: Sets the system time.
385 * PARAMETERS:
386 * NewTime - Points to a variable that specified the new time
387 * of day in the standard time format.
388 * OldTime - Optionally points to a variable that receives the
389 * old time of day in the standard time format.
390 * RETURNS: Status
391 */
393NTAPI
395 OUT PLARGE_INTEGER PreviousTime OPTIONAL)
396{
397 LARGE_INTEGER OldSystemTime;
398 LARGE_INTEGER NewSystemTime;
399 LARGE_INTEGER LocalTime;
403 PAGED_CODE();
404
405 /* Check if we were called from user-mode */
407 {
409 {
410 /* Verify the time pointers */
411 NewSystemTime = ProbeForReadLargeInteger(SystemTime);
412 if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
413 }
415 {
416 /* Return the exception code */
418 }
419 _SEH2_END;
420 }
421 else
422 {
423 /* Reuse the pointer */
424 NewSystemTime = *SystemTime;
425 }
426
427 /* Make sure we have permission to change the time */
429 {
430 DPRINT1("NtSetSystemTime: Caller requires the "
431 "SeSystemtimePrivilege privilege!\n");
433 }
434
435 /* Convert the time and set it in HAL */
436 ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
437 RtlTimeToTimeFields(&LocalTime, &TimeFields);
439
440 /* Now set system time */
441 KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
442
443 /* Check if caller wanted previous time */
444 if (PreviousTime)
445 {
446 /* Enter SEH Block for return */
448 {
449 /* Return the previous time */
450 *PreviousTime = OldSystemTime;
451 }
453 {
454 /* Get the exception code */
456 }
457 _SEH2_END;
458 }
459
460 /* Return status */
461 return Status;
462}
463
464/*
465 * FUNCTION: Retrieves the system time.
466 * PARAMETERS:
467 * CurrentTime - Points to a variable that receives the current
468 * time of day in the standard time format.
469 */
471NTAPI
473{
475 PAGED_CODE();
476
477 /* Check if we were called from user-mode */
479 {
481 {
482 /* Verify the time pointer */
483 ProbeForWriteLargeInteger(SystemTime);
484
485 /*
486 * It's safe to pass the pointer directly to KeQuerySystemTime
487 * as it's just a basic copy to this pointer. If it raises an
488 * exception nothing dangerous can happen!
489 */
490 KeQuerySystemTime(SystemTime);
491 }
493 {
494 /* Return the exception code */
496 }
497 _SEH2_END;
498 }
499 else
500 {
501 /* Query the time directly */
502 KeQuerySystemTime(SystemTime);
503 }
504
505 /* Return success */
506 return STATUS_SUCCESS;
507}
508
509/*
510 * @implemented
511 */
512VOID
513NTAPI
515 PLARGE_INTEGER SystemTime)
516{
517 SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
518}
519
520/*
521 * @implemented
522 */
523VOID
524NTAPI
526 PLARGE_INTEGER LocalTime)
527{
528 LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
529}
530
531/*
532 * @implemented
533 */
535NTAPI
537 OUT PULONG MaximumResolution,
538 OUT PULONG ActualResolution)
539{
541
542 /* Check if the call came from user-mode */
544 {
546 {
547 /* Probe the parameters */
548 ProbeForWriteUlong(MinimumResolution);
549 ProbeForWriteUlong(MaximumResolution);
550 ProbeForWriteUlong(ActualResolution);
551
552 /*
553 * Set the parameters to the actual values.
554 *
555 * NOTE:
556 * MinimumResolution corresponds to the biggest time increment and
557 * MaximumResolution corresponds to the smallest time increment.
558 */
559 *MinimumResolution = KeMaximumIncrement;
560 *MaximumResolution = KeMinimumIncrement;
561 *ActualResolution = KeTimeIncrement;
562 }
564 {
565 /* Return the exception code */
567 }
568 _SEH2_END;
569 }
570 else
571 {
572 /* Set the parameters to the actual values */
573 *MinimumResolution = KeMaximumIncrement;
574 *MaximumResolution = KeMinimumIncrement;
575 *ActualResolution = KeTimeIncrement;
576 }
577
578 /* Return success */
579 return STATUS_SUCCESS;
580}
581
582/*
583 * @implemented
584 */
586NTAPI
587NtSetTimerResolution(IN ULONG DesiredResolution,
589 OUT PULONG CurrentResolution)
590{
594 ULONG NewResolution;
595
596 /* Check if the call came from user-mode */
598 {
600 {
601 /* Probe the parameter */
602 ProbeForWriteUlong(CurrentResolution);
603 }
605 {
606 /* Return the exception code */
608 }
609 _SEH2_END;
610 }
611
612 /* Set and return the new resolution */
613 NewResolution = ExSetTimerResolution(DesiredResolution, SetResolution);
614
616 {
618 {
619 *CurrentResolution = NewResolution;
620 }
622 {
623 /* Return the exception code */
625 }
626 _SEH2_END;
627 }
628 else
629 {
630 *CurrentResolution = NewResolution;
631 }
632
633 if (SetResolution || Process->SetTimerResolution)
634 {
635 /* The resolution has been changed now or in an earlier call */
637 }
638 else
639 {
640 /* The resolution hasn't been changed */
642 }
643
644 /* Update the flag */
645 Process->SetTimerResolution = SetResolution;
646
647 return Status;
648}
649
650/* EOF */
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
BOOLEAN RtlTimeToTimeFields(IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields)
BOOLEAN RtlTimeFieldsToTime(IN PTIME_FIELDS TimeFields, IN PLARGE_INTEGER Time)
#define ExLocalTimeToSystemTime(LocTime, SysTime)
Definition: env_spec_w32.h:738
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
ULONG ERESOURCE
Definition: env_spec_w32.h:594
#define ExSystemTimeToLocalTime(SysTime, LocTime)
Definition: env_spec_w32.h:729
#define ExGetPreviousMode
Definition: ex.h:139
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
ULONG NTAPI HalSetTimeIncrement(IN ULONG Increment)
Definition: timer.c:102
LONG NTAPI ExSystemExceptionFilter(VOID)
Definition: harderr.c:349
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define KeLeaveCriticalRegion()
Definition: ke_x.h:119
#define KeEnterCriticalRegion()
Definition: ke_x.h:88
if(dx< 0)
Definition: linetemp.h:194
static PTIME_FIELDS TimeFields
Definition: time.c:104
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI RtlQueryTimeZoneInformation(_Out_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
NTSYSAPI BOOLEAN NTAPI RtlCutoverTimeToSystemTime(_In_ PTIME_FIELDS CutoverTimeFields, _Out_ PLARGE_INTEGER SystemTime, _In_ PLARGE_INTEGER CurrentTime, _In_ BOOLEAN ThisYearsCutoverOnly)
#define TIME_ZONE_ID_UNKNOWN
Definition: rtltypes.h:252
#define TIME_ZONE_ID_STANDARD
Definition: rtltypes.h:253
#define TIME_ZONE_ID_DAYLIGHT
Definition: rtltypes.h:254
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1817
LARGE_INTEGER ExpTimeZoneBias
Definition: time.c:23
RTL_TIME_ZONE_INFORMATION ExpTimeZoneInfo
Definition: time.c:21
ULONG NTAPI ExSetTimerResolution(IN ULONG DesiredTime, IN BOOLEAN SetResolution)
Definition: time.c:131
NTSTATUS NTAPI NtQueryTimerResolution(OUT PULONG MinimumResolution, OUT PULONG MaximumResolution, OUT PULONG ActualResolution)
Definition: time.c:536
VOID NTAPI ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime, IN ULONG MaxSepInSeconds)
Definition: time.c:217
ERESOURCE ExpTimeRefreshLock
Definition: time.c:27
NTSTATUS NTAPI NtSetTimerResolution(IN ULONG DesiredResolution, IN BOOLEAN SetResolution, OUT PULONG CurrentResolution)
Definition: time.c:587
ULONG ExpAltTimeZoneBias
Definition: time.c:24
#define TICKSPERMINUTE
Definition: time.c:16
ULONG ExpTickCountMultiplier
Definition: time.c:26
ULONG ExpLastTimeZoneBias
Definition: time.c:22
ULONG ExpTimeZoneId
Definition: time.c:25
ULONG ExpTimerResolutionCount
Definition: time.c:29
VOID NTAPI ExReleaseTimeRefreshLock(VOID)
Definition: time.c:83
ULONG ExpKernelResolutionCount
Definition: time.c:28
NTSTATUS ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
Definition: time.c:333
BOOLEAN NTAPI ExAcquireTimeRefreshLock(IN BOOLEAN Wait)
Definition: time.c:51
NTSTATUS NTAPI NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
Definition: time.c:472
NTSTATUS NTAPI NtSetSystemTime(IN PLARGE_INTEGER SystemTime, OUT PLARGE_INTEGER PreviousTime OPTIONAL)
Definition: time.c:394
BOOLEAN NTAPI ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
Definition: time.c:226
VOID NTAPI KeSetSystemTime(IN PLARGE_INTEGER NewSystemTime, OUT PLARGE_INTEGER OldSystemTime, IN BOOLEAN FixInterruptTime, IN PLARGE_INTEGER HalTime)
Definition: clock.c:28
ULONG KeTimeIncrement
Definition: clock.c:22
LARGE_INTEGER KeBootTime
Definition: clock.c:17
const LUID SeSystemtimePrivilege
Definition: priv.c:31
ULONG KeMinimumIncrement
Definition: clock.c:21
ULONG KeMaximumIncrement
Definition: clock.c:20
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_TIMER_RESOLUTION_NOT_SET
Definition: ntstatus.h:713
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
BOOLEAN NTAPI HalQueryRealTimeClock(IN PTIME_FIELDS Time)
Definition: rtc.c:24
BOOLEAN NTAPI HalSetRealTimeClock(IN PTIME_FIELDS Time)
Definition: rtc.c:45
#define ProbeForWriteLargeInteger(Ptr)
Definition: probe.h:46
#define ProbeForWriteUlong(Ptr)
Definition: probe.h:36
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
#define SharedUserData
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
VOID NTAPI KeSetSystemAffinityThread(IN KAFFINITY Affinity)
Definition: thrdobj.c:1116
VOID NTAPI KeRevertToUserAffinityThread(VOID)
Definition: thrdobj.c:1030
uint32_t * PULONG
Definition: typedefs.h:59
int64_t LONGLONG
Definition: typedefs.h:68
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
LONGLONG QuadPart
Definition: typedefs.h:114
struct _LARGE_INTEGER::@2268 u
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
_In_ BOOLEAN SetResolution
Definition: exfuncs.h:1078
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define PsGetCurrentProcess
Definition: psfuncs.h:17
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103