5671b7e755e885acef8e7133c9cf5967bf8dbdc2
[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 <internal/debug.h>
15
16 #define TICKSPERMINUTE 600000000
17
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, ExpInitTimeZoneInfo)
20 #endif
21
22 /* GLOBALS ******************************************************************/
23
24 /* Note: Bias[minutes] = UTC - local time */
25 TIME_ZONE_INFORMATION ExpTimeZoneInfo;
26 LARGE_INTEGER ExpTimeZoneBias;
27 ULONG ExpTimeZoneId;
28
29 /* FUNCTIONS ****************************************************************/
30
31 VOID
32 INIT_FUNCTION
33 NTAPI
34 ExpInitTimeZoneInfo(VOID)
35 {
36 LARGE_INTEGER CurrentTime;
37 NTSTATUS Status;
38
39 /* Read time zone information from the registry */
40 Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
41 if (!NT_SUCCESS(Status))
42 {
43 /* Failed, clear all data */
44 RtlZeroMemory(&ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION));
45 ExpTimeZoneBias.QuadPart = (LONGLONG)0;
46 ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN;
47 }
48 else
49 {
50 /* FIXME: Calculate transition dates */
51
52 /* Set bias and ID */
53 ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias +
54 ExpTimeZoneInfo.StandardBias)) *
55 TICKSPERMINUTE;
56 ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
57 }
58
59 /* Change it for user-mode applications */
60 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
61 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
62 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
63 SharedUserData->TimeZoneId = ExpTimeZoneId;
64
65 /* Convert boot time from local time to UTC */
66 SystemBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
67
68 /* Convert system time from local time to UTC */
69 do
70 {
71 CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
72 CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
73 } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
74
75 /* Change it for user-mode applications */
76 CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
77 SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
78 SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
79 SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
80 }
81
82 NTSTATUS
83 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
84 {
85 LARGE_INTEGER LocalTime, SystemTime;
86 TIME_FIELDS TimeFields;
87 DPRINT("ExpSetTimeZoneInformation() called\n");
88
89 DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
90 DPRINT("Old time zone standard bias: %d minutes\n",
91 ExpTimeZoneInfo.StandardBias);
92 DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation->Bias);
93 DPRINT("New time zone standard bias: %d minutes\n",
94 TimeZoneInformation->StandardBias);
95
96 /* Get the local time */
97 HalQueryRealTimeClock(&TimeFields);
98 RtlTimeFieldsToTime(&TimeFields, &LocalTime);
99
100 /* FIXME: Calculate transition dates */
101
102 /* Calculate the bias and set the ID */
103 ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
104 TimeZoneInformation->StandardBias)) *
105 TICKSPERMINUTE;
106 ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
107
108 /* Copy the timezone information */
109 RtlMoveMemory(&ExpTimeZoneInfo,
110 TimeZoneInformation,
111 sizeof(TIME_ZONE_INFORMATION));
112
113 /* Set the new time zone information */
114 SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
115 SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
116 SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
117 SharedUserData->TimeZoneId = ExpTimeZoneId;
118
119 DPRINT("New time zone bias: %I64d minutes\n",
120 ExpTimeZoneBias.QuadPart / TICKSPERMINUTE);
121
122 /* Calculate the new system time */
123 ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
124
125 /* Set the new system time */
126 KiSetSystemTime(&SystemTime);
127
128 /* Return success */
129 DPRINT("ExpSetTimeZoneInformation() done\n");
130 return STATUS_SUCCESS;
131 }
132
133 /*
134 * FUNCTION: Sets the system time.
135 * PARAMETERS:
136 * NewTime - Points to a variable that specified the new time
137 * of day in the standard time format.
138 * OldTime - Optionally points to a variable that receives the
139 * old time of day in the standard time format.
140 * RETURNS: Status
141 */
142 NTSTATUS
143 NTAPI
144 NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
145 OUT PLARGE_INTEGER PreviousTime OPTIONAL)
146 {
147 LARGE_INTEGER OldSystemTime;
148 LARGE_INTEGER NewSystemTime;
149 LARGE_INTEGER LocalTime;
150 TIME_FIELDS TimeFields;
151 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
152 NTSTATUS Status = STATUS_SUCCESS;
153 PAGED_CODE();
154
155 /* Check if we were called from user-mode */
156 if(PreviousMode != KernelMode)
157 {
158 _SEH_TRY
159 {
160 /* Verify the time pointers */
161 NewSystemTime = ProbeForReadLargeInteger(SystemTime);
162 if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
163 }
164 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
165 {
166 Status = _SEH_GetExceptionCode();
167 }
168 _SEH_END;
169
170 /* If the pointers were invalid, bail out */
171 if(!NT_SUCCESS(Status)) return Status;
172 }
173 else
174 {
175 /* Reuse the pointer */
176 NewSystemTime = *SystemTime;
177 }
178
179 /* Make sure we have permission to change the time */
180 if(!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
181 {
182 DPRINT1("NtSetSystemTime: Caller requires the "
183 "SeSystemtimePrivilege privilege!\n");
184 return STATUS_PRIVILEGE_NOT_HELD;
185 }
186
187 /* Check if caller wants the old time */
188 if(PreviousTime) KeQuerySystemTime(&OldSystemTime);
189
190 /* Convert the time and set it in HAL */
191 ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
192 RtlTimeToTimeFields(&LocalTime, &TimeFields);
193 HalSetRealTimeClock(&TimeFields);
194
195 /* Now set system time */
196 KiSetSystemTime(&NewSystemTime);
197
198 /* Check if caller wanted previous time */
199 if(PreviousTime)
200 {
201 /* Enter SEH Block for return */
202 _SEH_TRY
203 {
204 /* Return the previous time */
205 *PreviousTime = OldSystemTime;
206 }
207 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
208 {
209 Status = _SEH_GetExceptionCode();
210 }
211 _SEH_END;
212 }
213
214 /* Return status */
215 return Status;
216 }
217
218 /*
219 * FUNCTION: Retrieves the system time.
220 * PARAMETERS:
221 * CurrentTime - Points to a variable that receives the current
222 * time of day in the standard time format.
223 */
224 NTSTATUS
225 NTAPI
226 NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
227 {
228 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
229 NTSTATUS Status = STATUS_SUCCESS;
230 PAGED_CODE();
231
232 /* Check if we were called from user-mode */
233 if(PreviousMode != KernelMode)
234 {
235 _SEH_TRY
236 {
237 /* Verify the time pointer */
238 ProbeForWriteLargeInteger(SystemTime);
239
240 /*
241 * It's safe to pass the pointer directly to KeQuerySystemTime as
242 * it's just a basic copy to this pointer. If it raises an
243 * exception nothing dangerous can happen!
244 */
245 KeQuerySystemTime(SystemTime);
246 }
247 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
248 {
249 Status = _SEH_GetExceptionCode();
250 }
251 _SEH_END;
252 }
253 else
254 {
255 /* Query the time directly */
256 KeQuerySystemTime(SystemTime);
257 }
258
259 /* Return status to caller */
260 return Status;
261 }
262
263 /*
264 * @implemented
265 */
266 VOID
267 NTAPI
268 ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
269 PLARGE_INTEGER SystemTime)
270 {
271 SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
272 }
273
274 /*
275 * @unimplemented
276 */
277 ULONG
278 NTAPI
279 ExSetTimerResolution(IN ULONG DesiredTime,
280 IN BOOLEAN SetResolution)
281 {
282 UNIMPLEMENTED;
283 return 0;
284 }
285
286 /*
287 * @implemented
288 */
289 VOID
290 NTAPI
291 ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
292 PLARGE_INTEGER LocalTime)
293 {
294 LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
295 }
296
297 /* EOF */