- Stub out ExpSystemErrorHandler more properly.
[reactos.git] / reactos / ntoskrnl / ex / time.c
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 */
21 TIME_ZONE_INFORMATION ExpTimeZoneInfo;
22 ULONG ExpLastTimeZoneBias = -1;
23 LARGE_INTEGER ExpTimeZoneBias;
24 ULONG ExpAltTimeZoneBias;
25 ULONG ExpTimeZoneId;
26 ULONG ExpTickCountMultiplier;
27 ERESOURCE ExpTimeRefreshLock;
28
29 /* FUNCTIONS ****************************************************************/
30
31 BOOLEAN
32 NTAPI
33 ExAcquireTimeRefreshLock(BOOLEAN Wait)
34 {
35 /* Simply acquire the Resource */
36 KeEnterCriticalRegion();
37 if (!(ExAcquireResourceExclusiveLite(&ExpTimeRefreshLock, Wait)))
38 {
39 /* We failed! */
40 KeLeaveCriticalRegion();
41 return FALSE;
42 }
43
44 /* Success */
45 return TRUE;
46 }
47
48 VOID
49 NTAPI
50 ExReleaseTimeRefreshLock(VOID)
51 {
52 /* Simply release the Resource */
53 ExReleaseResourceLite(&ExpTimeRefreshLock);
54 KeLeaveCriticalRegion();
55 }
56
57 VOID
58 NTAPI
59 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
60 IN ULONG MaxSepInSeconds)
61 {
62 /* FIXME: TODO */
63 return;
64 }
65
66 BOOLEAN
67 NTAPI
68 ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
69 {
70 LARGE_INTEGER CurrentTime;
71 NTSTATUS Status;
72
73 /* Read time zone information from the registry */
74 Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
75 if (!NT_SUCCESS(Status))
76 {
77 /* Failed, clear all data */
78 RtlZeroMemory(&ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION));
79 ExpTimeZoneBias.QuadPart = (LONGLONG)0;
80 ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN;
81 }
82 else
83 {
84 /* FIXME: Calculate transition dates */
85
86 /* Set bias and ID */
87 ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias +
88 ExpTimeZoneInfo.StandardBias)) *
89 TICKSPERMINUTE;
90 ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
91 }
92
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;
98
99 /* Convert boot time from local time to UTC */
100 KeBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
101
102 /* Convert system time from local time to UTC */
103 do
104 {
105 CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
106 CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
107 } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
108
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;
114
115 /* Return success */
116 return TRUE;
117 }
118
119 NTSTATUS
120 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
121 {
122 LARGE_INTEGER LocalTime, SystemTime, OldTime;
123 TIME_FIELDS TimeFields;
124 DPRINT("ExpSetTimeZoneInformation() called\n");
125
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);
132
133 /* Get the local time */
134 HalQueryRealTimeClock(&TimeFields);
135 RtlTimeFieldsToTime(&TimeFields, &LocalTime);
136
137 /* FIXME: Calculate transition dates */
138
139 /* Calculate the bias and set the ID */
140 ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
141 TimeZoneInformation->StandardBias)) *
142 TICKSPERMINUTE;
143 ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
144
145 /* Copy the timezone information */
146 RtlCopyMemory(&ExpTimeZoneInfo,
147 TimeZoneInformation,
148 sizeof(TIME_ZONE_INFORMATION));
149
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;
155
156 DPRINT("New time zone bias: %I64d minutes\n",
157 ExpTimeZoneBias.QuadPart / TICKSPERMINUTE);
158
159 /* Calculate the new system time */
160 ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
161
162 /* Set the new system time */
163 KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL);
164
165 /* Return success */
166 DPRINT("ExpSetTimeZoneInformation() done\n");
167 return STATUS_SUCCESS;
168 }
169
170 /*
171 * FUNCTION: Sets the system time.
172 * PARAMETERS:
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.
177 * RETURNS: Status
178 */
179 NTSTATUS
180 NTAPI
181 NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
182 OUT PLARGE_INTEGER PreviousTime OPTIONAL)
183 {
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;
190 PAGED_CODE();
191
192 /* Check if we were called from user-mode */
193 if (PreviousMode != KernelMode)
194 {
195 _SEH2_TRY
196 {
197 /* Verify the time pointers */
198 NewSystemTime = ProbeForReadLargeInteger(SystemTime);
199 if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
200 }
201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
202 {
203 /* Return the exception code */
204 _SEH2_YIELD(return _SEH2_GetExceptionCode());
205 }
206 _SEH2_END;
207 }
208 else
209 {
210 /* Reuse the pointer */
211 NewSystemTime = *SystemTime;
212 }
213
214 /* Make sure we have permission to change the time */
215 if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
216 {
217 DPRINT1("NtSetSystemTime: Caller requires the "
218 "SeSystemtimePrivilege privilege!\n");
219 return STATUS_PRIVILEGE_NOT_HELD;
220 }
221
222 /* Convert the time and set it in HAL */
223 ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
224 RtlTimeToTimeFields(&LocalTime, &TimeFields);
225 HalSetRealTimeClock(&TimeFields);
226
227 /* Now set system time */
228 KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
229
230 /* Check if caller wanted previous time */
231 if (PreviousTime)
232 {
233 /* Enter SEH Block for return */
234 _SEH2_TRY
235 {
236 /* Return the previous time */
237 *PreviousTime = OldSystemTime;
238 }
239 _SEH2_EXCEPT(ExSystemExceptionFilter())
240 {
241 /* Get the exception code */
242 Status = _SEH2_GetExceptionCode();
243 }
244 _SEH2_END;
245 }
246
247 /* Return status */
248 return Status;
249 }
250
251 /*
252 * FUNCTION: Retrieves the system time.
253 * PARAMETERS:
254 * CurrentTime - Points to a variable that receives the current
255 * time of day in the standard time format.
256 */
257 NTSTATUS
258 NTAPI
259 NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
260 {
261 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
262 NTSTATUS Status = STATUS_SUCCESS;
263 PAGED_CODE();
264
265 /* Check if we were called from user-mode */
266 if (PreviousMode != KernelMode)
267 {
268 _SEH2_TRY
269 {
270 /* Verify the time pointer */
271 ProbeForWriteLargeInteger(SystemTime);
272
273 /*
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!
277 */
278 KeQuerySystemTime(SystemTime);
279 }
280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
281 {
282 /* Get the exception code */
283 Status = _SEH2_GetExceptionCode();
284 }
285 _SEH2_END;
286 }
287 else
288 {
289 /* Query the time directly */
290 KeQuerySystemTime(SystemTime);
291 }
292
293 /* Return status to caller */
294 return Status;
295 }
296
297 /*
298 * @implemented
299 */
300 VOID
301 NTAPI
302 ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
303 PLARGE_INTEGER SystemTime)
304 {
305 SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
306 }
307
308 /*
309 * @unimplemented
310 */
311 ULONG
312 NTAPI
313 ExSetTimerResolution(IN ULONG DesiredTime,
314 IN BOOLEAN SetResolution)
315 {
316 UNIMPLEMENTED;
317 return 0;
318 }
319
320 /*
321 * @implemented
322 */
323 VOID
324 NTAPI
325 ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
326 PLARGE_INTEGER LocalTime)
327 {
328 LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
329 }
330
331 /* EOF */