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
10 /* INCLUDES *****************************************************************/
16 #define TICKSPERMINUTE 600000000
18 /* GLOBALS ******************************************************************/
20 /* Note: Bias[minutes] = UTC - local time */
21 TIME_ZONE_INFORMATION ExpTimeZoneInfo
;
22 ULONG ExpLastTimeZoneBias
= -1;
23 LARGE_INTEGER ExpTimeZoneBias
;
24 ULONG ExpAltTimeZoneBias
;
26 ULONG ExpTickCountMultiplier
;
27 ERESOURCE ExpTimeRefreshLock
;
29 /* FUNCTIONS ****************************************************************/
33 ExAcquireTimeRefreshLock(BOOLEAN Wait
)
35 /* Simply acquire the Resource */
36 KeEnterCriticalRegion();
37 if (!(ExAcquireResourceExclusiveLite(&ExpTimeRefreshLock
, Wait
)))
40 KeLeaveCriticalRegion();
50 ExReleaseTimeRefreshLock(VOID
)
52 /* Simply release the Resource */
53 ExReleaseResourceLite(&ExpTimeRefreshLock
);
54 KeLeaveCriticalRegion();
59 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime
,
60 IN ULONG MaxSepInSeconds
)
68 ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime
)
70 LARGE_INTEGER CurrentTime
;
73 /* Read time zone information from the registry */
74 Status
= RtlQueryTimeZoneInformation(&ExpTimeZoneInfo
);
75 if (!NT_SUCCESS(Status
))
77 /* Failed, clear all data */
78 RtlZeroMemory(&ExpTimeZoneInfo
, sizeof(TIME_ZONE_INFORMATION
));
79 ExpTimeZoneBias
.QuadPart
= (LONGLONG
)0;
80 ExpTimeZoneId
= TIME_ZONE_ID_UNKNOWN
;
84 /* FIXME: Calculate transition dates */
87 ExpTimeZoneBias
.QuadPart
= ((LONGLONG
)(ExpTimeZoneInfo
.Bias
+
88 ExpTimeZoneInfo
.StandardBias
)) *
90 ExpTimeZoneId
= TIME_ZONE_ID_STANDARD
;
93 /* Change it for user-mode applications */
94 SharedUserData
->TimeZoneBias
.High1Time
= ExpTimeZoneBias
.u
.HighPart
;
95 SharedUserData
->TimeZoneBias
.High2Time
= ExpTimeZoneBias
.u
.HighPart
;
96 SharedUserData
->TimeZoneBias
.LowPart
= ExpTimeZoneBias
.u
.LowPart
;
97 SharedUserData
->TimeZoneId
= ExpTimeZoneId
;
99 /* Convert boot time from local time to UTC */
100 KeBootTime
.QuadPart
+= ExpTimeZoneBias
.QuadPart
;
102 /* Convert system time from local time to UTC */
105 CurrentTime
.u
.HighPart
= SharedUserData
->SystemTime
.High1Time
;
106 CurrentTime
.u
.LowPart
= SharedUserData
->SystemTime
.LowPart
;
107 } while (CurrentTime
.u
.HighPart
!= SharedUserData
->SystemTime
.High2Time
);
109 /* Change it for user-mode applications */
110 CurrentTime
.QuadPart
+= ExpTimeZoneBias
.QuadPart
;
111 SharedUserData
->SystemTime
.LowPart
= CurrentTime
.u
.LowPart
;
112 SharedUserData
->SystemTime
.High1Time
= CurrentTime
.u
.HighPart
;
113 SharedUserData
->SystemTime
.High2Time
= CurrentTime
.u
.HighPart
;
120 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
)
122 LARGE_INTEGER LocalTime
, SystemTime
, OldTime
;
123 TIME_FIELDS TimeFields
;
124 DPRINT("ExpSetTimeZoneInformation() called\n");
126 DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo
.Bias
);
127 DPRINT("Old time zone standard bias: %d minutes\n",
128 ExpTimeZoneInfo
.StandardBias
);
129 DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation
->Bias
);
130 DPRINT("New time zone standard bias: %d minutes\n",
131 TimeZoneInformation
->StandardBias
);
133 /* Get the local time */
134 HalQueryRealTimeClock(&TimeFields
);
135 RtlTimeFieldsToTime(&TimeFields
, &LocalTime
);
137 /* FIXME: Calculate transition dates */
139 /* Calculate the bias and set the ID */
140 ExpTimeZoneBias
.QuadPart
= ((LONGLONG
)(TimeZoneInformation
->Bias
+
141 TimeZoneInformation
->StandardBias
)) *
143 ExpTimeZoneId
= TIME_ZONE_ID_STANDARD
;
145 /* Copy the timezone information */
146 RtlCopyMemory(&ExpTimeZoneInfo
,
148 sizeof(TIME_ZONE_INFORMATION
));
150 /* Set the new time zone information */
151 SharedUserData
->TimeZoneBias
.High1Time
= ExpTimeZoneBias
.u
.HighPart
;
152 SharedUserData
->TimeZoneBias
.High2Time
= ExpTimeZoneBias
.u
.HighPart
;
153 SharedUserData
->TimeZoneBias
.LowPart
= ExpTimeZoneBias
.u
.LowPart
;
154 SharedUserData
->TimeZoneId
= ExpTimeZoneId
;
156 DPRINT("New time zone bias: %I64d minutes\n",
157 ExpTimeZoneBias
.QuadPart
/ TICKSPERMINUTE
);
159 /* Calculate the new system time */
160 ExLocalTimeToSystemTime(&LocalTime
, &SystemTime
);
162 /* Set the new system time */
163 KeSetSystemTime(&SystemTime
, &OldTime
, FALSE
, NULL
);
166 DPRINT("ExpSetTimeZoneInformation() done\n");
167 return STATUS_SUCCESS
;
171 * FUNCTION: Sets the system time.
173 * NewTime - Points to a variable that specified the new time
174 * of day in the standard time format.
175 * OldTime - Optionally points to a variable that receives the
176 * old time of day in the standard time format.
181 NtSetSystemTime(IN PLARGE_INTEGER SystemTime
,
182 OUT PLARGE_INTEGER PreviousTime OPTIONAL
)
184 LARGE_INTEGER OldSystemTime
;
185 LARGE_INTEGER NewSystemTime
;
186 LARGE_INTEGER LocalTime
;
187 TIME_FIELDS TimeFields
;
188 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
189 NTSTATUS Status
= STATUS_SUCCESS
;
192 /* Check if we were called from user-mode */
193 if (PreviousMode
!= KernelMode
)
197 /* Verify the time pointers */
198 NewSystemTime
= ProbeForReadLargeInteger(SystemTime
);
199 if(PreviousTime
) ProbeForWriteLargeInteger(PreviousTime
);
201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
203 /* Return the exception code */
204 _SEH2_YIELD(return _SEH2_GetExceptionCode());
210 /* Reuse the pointer */
211 NewSystemTime
= *SystemTime
;
214 /* Make sure we have permission to change the time */
215 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege
, PreviousMode
))
217 DPRINT1("NtSetSystemTime: Caller requires the "
218 "SeSystemtimePrivilege privilege!\n");
219 return STATUS_PRIVILEGE_NOT_HELD
;
222 /* Convert the time and set it in HAL */
223 ExSystemTimeToLocalTime(&NewSystemTime
, &LocalTime
);
224 RtlTimeToTimeFields(&LocalTime
, &TimeFields
);
225 HalSetRealTimeClock(&TimeFields
);
227 /* Now set system time */
228 KeSetSystemTime(&NewSystemTime
, &OldSystemTime
, FALSE
, NULL
);
230 /* Check if caller wanted previous time */
233 /* Enter SEH Block for return */
236 /* Return the previous time */
237 *PreviousTime
= OldSystemTime
;
239 _SEH2_EXCEPT(ExSystemExceptionFilter())
241 /* Get the exception code */
242 Status
= _SEH2_GetExceptionCode();
252 * FUNCTION: Retrieves the system time.
254 * CurrentTime - Points to a variable that receives the current
255 * time of day in the standard time format.
259 NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime
)
261 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
262 NTSTATUS Status
= STATUS_SUCCESS
;
265 /* Check if we were called from user-mode */
266 if (PreviousMode
!= KernelMode
)
270 /* Verify the time pointer */
271 ProbeForWriteLargeInteger(SystemTime
);
274 * It's safe to pass the pointer directly to KeQuerySystemTime as
275 * it's just a basic copy to this pointer. If it raises an
276 * exception nothing dangerous can happen!
278 KeQuerySystemTime(SystemTime
);
280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
282 /* Get the exception code */
283 Status
= _SEH2_GetExceptionCode();
289 /* Query the time directly */
290 KeQuerySystemTime(SystemTime
);
293 /* Return status to caller */
302 ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime
,
303 PLARGE_INTEGER SystemTime
)
305 SystemTime
->QuadPart
= LocalTime
->QuadPart
+ ExpTimeZoneBias
.QuadPart
;
313 ExSetTimerResolution(IN ULONG DesiredTime
,
314 IN BOOLEAN SetResolution
)
325 ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime
,
326 PLARGE_INTEGER LocalTime
)
328 LocalTime
->QuadPart
= SystemTime
->QuadPart
- ExpTimeZoneBias
.QuadPart
;