ReactOS 0.4.15-dev-7958-gcd0bb1a
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 and notify the system */
376 KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL);
378
379 /* Return success */
380 DPRINT("ExpSetTimeZoneInformation() done\n");
381 return STATUS_SUCCESS;
382}
383
384/*
385 * FUNCTION: Sets the system time.
386 * PARAMETERS:
387 * NewTime - Points to a variable that specified the new time
388 * of day in the standard time format.
389 * OldTime - Optionally points to a variable that receives the
390 * old time of day in the standard time format.
391 * RETURNS: Status
392 */
394NTAPI
396 OUT PLARGE_INTEGER PreviousTime OPTIONAL)
397{
398 LARGE_INTEGER OldSystemTime;
399 LARGE_INTEGER NewSystemTime;
400 LARGE_INTEGER LocalTime;
404
405 PAGED_CODE();
406
407 // TODO: Handle the case when SystemTime == NULL, which means:
408 // "update system time using the current time-zone information".
409 if (!SystemTime)
410 {
413 }
414
415 /* Check if we were called from user-mode */
417 {
419 {
420 /* Verify the time pointers */
421 NewSystemTime = ProbeForReadLargeInteger(SystemTime);
422 if (PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
423 }
425 {
426 /* Return the exception code */
428 }
429 _SEH2_END;
430 }
431 else
432 {
433 /* Reuse the pointer */
434 NewSystemTime = *SystemTime;
435 }
436
437 /* Make sure we have permission to change the time */
439 {
440 DPRINT1("NtSetSystemTime: Caller requires the "
441 "SeSystemtimePrivilege privilege!\n");
443 }
444
445 /* Convert the time and set it in HAL */
446 ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
447 RtlTimeToTimeFields(&LocalTime, &TimeFields);
449
450 /* Now set the system time and notify the system */
451 KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
453
454 /* Check if caller wanted previous time */
455 if (PreviousTime)
456 {
457 /* Enter SEH Block for return */
459 {
460 /* Return the previous time */
461 *PreviousTime = OldSystemTime;
462 }
464 {
465 /* Get the exception code */
467 }
468 _SEH2_END;
469 }
470
471 /* Return status */
472 return Status;
473}
474
475/*
476 * FUNCTION: Retrieves the system time.
477 * PARAMETERS:
478 * CurrentTime - Points to a variable that receives the current
479 * time of day in the standard time format.
480 */
482NTAPI
484{
486 PAGED_CODE();
487
488 /* Check if we were called from user-mode */
490 {
492 {
493 /* Verify the time pointer */
494 ProbeForWriteLargeInteger(SystemTime);
495
496 /*
497 * It's safe to pass the pointer directly to KeQuerySystemTime
498 * as it's just a basic copy to this pointer. If it raises an
499 * exception nothing dangerous can happen!
500 */
501 KeQuerySystemTime(SystemTime);
502 }
504 {
505 /* Return the exception code */
507 }
508 _SEH2_END;
509 }
510 else
511 {
512 /* Query the time directly */
513 KeQuerySystemTime(SystemTime);
514 }
515
516 /* Return success */
517 return STATUS_SUCCESS;
518}
519
520/*
521 * @implemented
522 */
523VOID
524NTAPI
526 PLARGE_INTEGER SystemTime)
527{
528 SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
529}
530
531/*
532 * @implemented
533 */
534VOID
535NTAPI
537 PLARGE_INTEGER LocalTime)
538{
539 LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
540}
541
542/*
543 * @implemented
544 */
546NTAPI
548 OUT PULONG MaximumResolution,
549 OUT PULONG ActualResolution)
550{
552
553 /* Check if the call came from user-mode */
555 {
557 {
558 /* Probe the parameters */
559 ProbeForWriteUlong(MinimumResolution);
560 ProbeForWriteUlong(MaximumResolution);
561 ProbeForWriteUlong(ActualResolution);
562
563 /*
564 * Set the parameters to the actual values.
565 *
566 * NOTE:
567 * MinimumResolution corresponds to the biggest time increment and
568 * MaximumResolution corresponds to the smallest time increment.
569 */
570 *MinimumResolution = KeMaximumIncrement;
571 *MaximumResolution = KeMinimumIncrement;
572 *ActualResolution = KeTimeIncrement;
573 }
575 {
576 /* Return the exception code */
578 }
579 _SEH2_END;
580 }
581 else
582 {
583 /* Set the parameters to the actual values */
584 *MinimumResolution = KeMaximumIncrement;
585 *MaximumResolution = KeMinimumIncrement;
586 *ActualResolution = KeTimeIncrement;
587 }
588
589 /* Return success */
590 return STATUS_SUCCESS;
591}
592
593/*
594 * @implemented
595 */
597NTAPI
598NtSetTimerResolution(IN ULONG DesiredResolution,
600 OUT PULONG CurrentResolution)
601{
605 ULONG NewResolution;
606
607 /* Check if the call came from user-mode */
609 {
611 {
612 /* Probe the parameter */
613 ProbeForWriteUlong(CurrentResolution);
614 }
616 {
617 /* Return the exception code */
619 }
620 _SEH2_END;
621 }
622
623 /* Set and return the new resolution */
624 NewResolution = ExSetTimerResolution(DesiredResolution, SetResolution);
625
627 {
629 {
630 *CurrentResolution = NewResolution;
631 }
633 {
634 /* Return the exception code */
636 }
637 _SEH2_END;
638 }
639 else
640 {
641 *CurrentResolution = NewResolution;
642 }
643
644 if (SetResolution || Process->SetTimerResolution)
645 {
646 /* The resolution has been changed now or in an earlier call */
648 }
649 else
650 {
651 /* The resolution hasn't been changed */
653 }
654
655 /* Update the flag */
656 Process->SetTimerResolution = SetResolution;
657
658 return Status;
659}
660
661/* 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 UNIMPLEMENTED
Definition: debug.h:115
#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:140
#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:1822
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:547
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:598
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:483
NTSTATUS NTAPI NtSetSystemTime(IN PLARGE_INTEGER SystemTime, OUT PLARGE_INTEGER PreviousTime OPTIONAL)
Definition: time.c:395
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 STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
VOID NTAPI PoNotifySystemTimeSet(VOID)
Definition: events.c:39
#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:1107
VOID NTAPI KeRevertToUserAffinityThread(VOID)
Definition: thrdobj.c:1021
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::@2295 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