xref: /reactos/ntoskrnl/include/internal/ex.h (revision d5399189)
1 #pragma once
2 
3 /* GLOBAL VARIABLES *********************************************************/
4 
5 extern RTL_TIME_ZONE_INFORMATION ExpTimeZoneInfo;
6 extern LARGE_INTEGER ExpTimeZoneBias;
7 extern ULONG ExpTimeZoneId;
8 extern ULONG ExpTickCountMultiplier;
9 extern ULONG ExpLastTimeZoneBias;
10 extern POBJECT_TYPE ExEventPairObjectType;
11 extern POBJECT_TYPE _ExEventObjectType, _ExSemaphoreObjectType;
12 extern FAST_MUTEX ExpEnvironmentLock;
13 extern ERESOURCE ExpFirmwareTableResource;
14 extern LIST_ENTRY ExpFirmwareTableProviderListHead;
15 extern BOOLEAN ExpIsWinPEMode;
16 extern LIST_ENTRY ExpSystemResourcesList;
17 extern ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
18 extern ULONG ExpUnicodeCaseTableDataOffset;
19 extern PVOID ExpNlsSectionPointer;
20 extern ULONG NtGlobalFlag;
21 extern UNICODE_STRING NtSystemRoot;
22 extern ULONG ExpInitializationPhase;
23 extern ULONG ExpAltTimeZoneBias;
24 extern LIST_ENTRY ExSystemLookasideListHead;
25 extern PCALLBACK_OBJECT PowerStateCallback;
26 extern LIST_ENTRY ExPoolLookasideListHead;
27 extern LIST_ENTRY ExpNonPagedLookasideListHead;
28 extern LIST_ENTRY ExpPagedLookasideListHead;
29 extern KSPIN_LOCK ExpNonPagedLookasideListLock;
30 extern KSPIN_LOCK ExpPagedLookasideListLock;
31 extern ULONG ExCriticalWorkerThreads;
32 extern ULONG ExDelayedWorkerThreads;
33 
34 extern PVOID ExpDefaultErrorPort;
35 extern PEPROCESS ExpDefaultErrorPortProcess;
36 
37 /*
38  * NT/Cm Version Info variables
39  */
40 extern ULONG NtMajorVersion;
41 extern ULONG NtMinorVersion;
42 extern ULONG NtBuildNumber;
43 extern ULONG CmNtSpBuildNumber;
44 extern ULONG CmNtCSDVersion;
45 extern ULONG CmNtCSDReleaseType;
46 extern UNICODE_STRING CmVersionString;
47 extern UNICODE_STRING CmCSDVersionString;
48 extern CHAR NtBuildLab[];
49 
50 // #ifdef _WINKD_
51 /*
52  * WinDBG Debugger Worker State Machine data (see dbgctrl.c)
53  */
54 typedef enum _WINKD_WORKER_STATE
55 {
56     WinKdWorkerReady = 0,
57     WinKdWorkerStart,
58     WinKdWorkerInitialized
59 } WINKD_WORKER_STATE;
60 
61 extern WORK_QUEUE_ITEM ExpDebuggerWorkItem;
62 extern WINKD_WORKER_STATE ExpDebuggerWork;
63 extern PEPROCESS ExpDebuggerProcessAttach;
64 extern PEPROCESS ExpDebuggerProcessKill;
65 extern ULONG_PTR ExpDebuggerPageIn;
66 
67 VOID NTAPI ExpDebuggerWorker(IN PVOID Context);
68 // #endif /* _WINKD_ */
69 
70 #ifdef _WIN64
71 #define HANDLE_LOW_BITS (PAGE_SHIFT - 4)
72 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 3)
73 #else
74 #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
75 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
76 #endif
77 #define HANDLE_TAG_BITS (2)
78 #define HANDLE_INDEX_BITS (HANDLE_LOW_BITS + 2*HANDLE_HIGH_BITS)
79 #define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - HANDLE_INDEX_BITS - HANDLE_TAG_BITS)
80 
81 typedef union _EXHANDLE
82 {
83      struct
84      {
85          ULONG_PTR TagBits:     HANDLE_TAG_BITS;
86          ULONG_PTR Index:       HANDLE_INDEX_BITS;
87          ULONG_PTR KernelFlag : KERNEL_FLAG_BITS;
88      };
89      struct
90      {
91          ULONG_PTR TagBits2:    HANDLE_TAG_BITS;
92          ULONG_PTR LowIndex:    HANDLE_LOW_BITS;
93          ULONG_PTR MidIndex:    HANDLE_HIGH_BITS;
94          ULONG_PTR HighIndex:   HANDLE_HIGH_BITS;
95          ULONG_PTR KernelFlag2: KERNEL_FLAG_BITS;
96      };
97      HANDLE GenericHandleOverlay;
98      ULONG_PTR Value;
99      ULONG AsULONG;
100 } EXHANDLE, *PEXHANDLE;
101 
102 typedef struct _ETIMER
103 {
104     KTIMER KeTimer;
105     KAPC TimerApc;
106     KDPC TimerDpc;
107     LIST_ENTRY ActiveTimerListEntry;
108     KSPIN_LOCK Lock;
109     LONG Period;
110     BOOLEAN ApcAssociated;
111     BOOLEAN WakeTimer;
112     LIST_ENTRY WakeTimerListEntry;
113 } ETIMER, *PETIMER;
114 
115 typedef struct
116 {
117     PCALLBACK_OBJECT *CallbackObject;
118     PWSTR Name;
119 } SYSTEM_CALLBACKS;
120 
121 typedef struct _HARDERROR_USER_PARAMETERS
122 {
123     ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS];
124     UNICODE_STRING Strings[MAXIMUM_HARDERROR_PARAMETERS];
125     WCHAR Buffer[ANYSIZE_ARRAY];
126 } HARDERROR_USER_PARAMETERS, *PHARDERROR_USER_PARAMETERS;
127 
128 #define MAX_FAST_REFS           7
129 
130 #define ExAcquireRundownProtection                      _ExAcquireRundownProtection
131 #define ExReleaseRundownProtection                      _ExReleaseRundownProtection
132 #define ExInitializeRundownProtection                   _ExInitializeRundownProtection
133 #define ExWaitForRundownProtectionRelease               _ExWaitForRundownProtectionRelease
134 #define ExRundownCompleted                              _ExRundownCompleted
135 #define ExGetPreviousMode                               KeGetPreviousMode
136 
137 
138 //
139 // Various bits tagged on the handle or handle table
140 //
141 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT    1
142 #define FREE_HANDLE_MASK                -1
143 
144 //
145 // Number of entries in each table level
146 //
147 #define LOW_LEVEL_ENTRIES   (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
148 #define MID_LEVEL_ENTRIES   (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
149 #define HIGH_LEVEL_ENTRIES  (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
150 
151 //
152 // Maximum index in each table level before we need another table
153 //
154 #define MAX_LOW_INDEX       LOW_LEVEL_ENTRIES
155 #define MAX_MID_INDEX       (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
156 #define MAX_HIGH_INDEX      (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
157 
158 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
159 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
160 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
161 
162 NTSTATUS
163 NTAPI
164 ExGetPoolTagInfo(
165     IN PSYSTEM_POOLTAG_INFORMATION SystemInformation,
166     IN ULONG SystemInformationLength,
167     IN OUT PULONG ReturnLength OPTIONAL
168 );
169 
170 /* INITIALIZATION FUNCTIONS *************************************************/
171 
172 BOOLEAN
173 NTAPI
174 ExpWin32kInit(VOID);
175 
176 VOID
177 NTAPI
178 ExInit2(VOID);
179 
180 VOID
181 NTAPI
182 Phase1Initialization(
183     IN PVOID Context
184 );
185 
186 VOID
187 NTAPI
188 ExpInitializePushLocks(VOID);
189 
190 BOOLEAN
191 NTAPI
192 ExRefreshTimeZoneInformation(
193     IN PLARGE_INTEGER SystemBootTime
194 );
195 
196 VOID
197 NTAPI
198 ExpInitializeWorkerThreads(VOID);
199 
200 VOID
201 NTAPI
202 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap);
203 
204 VOID
205 NTAPI
206 ExpInitLookasideLists(VOID);
207 
208 VOID
209 NTAPI
210 ExInitializeSystemLookasideList(
211     IN PGENERAL_LOOKASIDE List,
212     IN POOL_TYPE Type,
213     IN ULONG Size,
214     IN ULONG Tag,
215     IN USHORT MaximumDepth,
216     IN PLIST_ENTRY ListHead
217 );
218 
219 BOOLEAN
220 NTAPI
221 ExpInitializeCallbacks(VOID);
222 
223 VOID
224 NTAPI
225 ExpInitUuids(VOID);
226 
227 VOID
228 NTAPI
229 ExpInitializeExecutive(
230     IN ULONG Cpu,
231     IN PLOADER_PARAMETER_BLOCK LoaderBlock
232 );
233 
234 VOID
235 NTAPI
236 ExShutdownSystem(VOID);
237 
238 BOOLEAN
239 NTAPI
240 ExpInitializeEventImplementation(VOID);
241 
242 BOOLEAN
243 NTAPI
244 ExpInitializeKeyedEventImplementation(VOID);
245 
246 BOOLEAN
247 NTAPI
248 ExpInitializeEventPairImplementation(VOID);
249 
250 BOOLEAN
251 NTAPI
252 ExpInitializeSemaphoreImplementation(VOID);
253 
254 BOOLEAN
255 NTAPI
256 ExpInitializeMutantImplementation(VOID);
257 
258 BOOLEAN
259 NTAPI
260 ExpInitializeTimerImplementation(VOID);
261 
262 BOOLEAN
263 NTAPI
264 ExpInitializeProfileImplementation(VOID);
265 
266 VOID
267 NTAPI
268 ExpResourceInitialization(VOID);
269 
270 VOID
271 NTAPI
272 ExInitPoolLookasidePointers(VOID);
273 
274 /* Callback Functions ********************************************************/
275 
276 VOID
277 NTAPI
278 ExInitializeCallBack(
279     IN OUT PEX_CALLBACK Callback
280 );
281 
282 PEX_CALLBACK_ROUTINE_BLOCK
283 NTAPI
284 ExAllocateCallBack(
285     IN PEX_CALLBACK_FUNCTION Function,
286     IN PVOID Context
287 );
288 
289 VOID
290 NTAPI
291 ExFreeCallBack(
292     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
293 );
294 
295 BOOLEAN
296 NTAPI
297 ExCompareExchangeCallBack (
298     IN OUT PEX_CALLBACK CallBack,
299     IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
300     IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
301 );
302 
303 PEX_CALLBACK_ROUTINE_BLOCK
304 NTAPI
305 ExReferenceCallBackBlock(
306     IN OUT PEX_CALLBACK CallBack
307 );
308 
309 VOID
310 NTAPI
311 ExDereferenceCallBackBlock(
312     IN OUT PEX_CALLBACK CallBack,
313     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
314 );
315 
316 PEX_CALLBACK_FUNCTION
317 NTAPI
318 ExGetCallBackBlockRoutine(
319     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
320 );
321 
322 PVOID
323 NTAPI
324 ExGetCallBackBlockContext(
325     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
326 );
327 
328 VOID
329 NTAPI
330 ExWaitForCallBacks(
331     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
332 );
333 
334 /* Rundown Functions ********************************************************/
335 
336 VOID
337 FASTCALL
338 ExfInitializeRundownProtection(
339      OUT PEX_RUNDOWN_REF RunRef
340 );
341 
342 VOID
343 FASTCALL
344 ExfReInitializeRundownProtection(
345      OUT PEX_RUNDOWN_REF RunRef
346 );
347 
348 BOOLEAN
349 FASTCALL
350 ExfAcquireRundownProtection(
351      IN OUT PEX_RUNDOWN_REF RunRef
352 );
353 
354 BOOLEAN
355 FASTCALL
356 ExfAcquireRundownProtectionEx(
357      IN OUT PEX_RUNDOWN_REF RunRef,
358      IN ULONG Count
359 );
360 
361 VOID
362 FASTCALL
363 ExfReleaseRundownProtection(
364      IN OUT PEX_RUNDOWN_REF RunRef
365 );
366 
367 VOID
368 FASTCALL
369 ExfReleaseRundownProtectionEx(
370      IN OUT PEX_RUNDOWN_REF RunRef,
371      IN ULONG Count
372 );
373 
374 VOID
375 FASTCALL
376 ExfRundownCompleted(
377      OUT PEX_RUNDOWN_REF RunRef
378 );
379 
380 VOID
381 FASTCALL
382 ExfWaitForRundownProtectionRelease(
383      IN OUT PEX_RUNDOWN_REF RunRef
384 );
385 
386 /* HANDLE TABLE FUNCTIONS ***************************************************/
387 
388 typedef BOOLEAN
389 (NTAPI *PEX_SWEEP_HANDLE_CALLBACK)(
390     PHANDLE_TABLE_ENTRY HandleTableEntry,
391     HANDLE Handle,
392     PVOID Context
393 );
394 
395 typedef BOOLEAN
396 (NTAPI *PEX_DUPLICATE_HANDLE_CALLBACK)(
397     IN PEPROCESS Process,
398     IN PHANDLE_TABLE HandleTable,
399     IN PHANDLE_TABLE_ENTRY HandleTableEntry,
400     IN PHANDLE_TABLE_ENTRY NewEntry
401 );
402 
403 typedef BOOLEAN
404 (NTAPI *PEX_CHANGE_HANDLE_CALLBACK)(
405     PHANDLE_TABLE_ENTRY HandleTableEntry,
406     ULONG_PTR Context
407 );
408 
409 VOID
410 NTAPI
411 ExpInitializeHandleTables(
412     VOID
413 );
414 
415 PHANDLE_TABLE
416 NTAPI
417 ExCreateHandleTable(
418     IN PEPROCESS Process OPTIONAL
419 );
420 
421 VOID
422 NTAPI
423 ExUnlockHandleTableEntry(
424     IN PHANDLE_TABLE HandleTable,
425     IN PHANDLE_TABLE_ENTRY HandleTableEntry
426 );
427 
428 HANDLE
429 NTAPI
430 ExCreateHandle(
431     IN PHANDLE_TABLE HandleTable,
432     IN PHANDLE_TABLE_ENTRY HandleTableEntry
433 );
434 
435 VOID
436 NTAPI
437 ExDestroyHandleTable(
438     IN PHANDLE_TABLE HandleTable,
439     IN PVOID DestroyHandleProcedure OPTIONAL
440 );
441 
442 BOOLEAN
443 NTAPI
444 ExDestroyHandle(
445     IN PHANDLE_TABLE HandleTable,
446     IN HANDLE Handle,
447     IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
448 );
449 
450 PHANDLE_TABLE_ENTRY
451 NTAPI
452 ExMapHandleToPointer(
453     IN PHANDLE_TABLE HandleTable,
454     IN HANDLE Handle
455 );
456 
457 PHANDLE_TABLE
458 NTAPI
459 ExDupHandleTable(
460     IN PEPROCESS Process,
461     IN PHANDLE_TABLE HandleTable,
462     IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
463     IN ULONG_PTR Mask
464 );
465 
466 BOOLEAN
467 NTAPI
468 ExChangeHandle(
469     IN PHANDLE_TABLE HandleTable,
470     IN HANDLE Handle,
471     IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
472     IN ULONG_PTR Context
473 );
474 
475 VOID
476 NTAPI
477 ExSweepHandleTable(
478     IN PHANDLE_TABLE HandleTable,
479     IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
480     IN PVOID Context
481 );
482 
483 PHANDLE_TABLE_ENTRY
484 NTAPI
485 ExpLookupHandleTableEntry(
486     IN PHANDLE_TABLE HandleTable,
487     IN EXHANDLE Handle
488 );
489 
490 BOOLEAN
491 NTAPI
492 ExpLockHandleTableEntry(
493     IN PHANDLE_TABLE HandleTable,
494     IN PHANDLE_TABLE_ENTRY HandleTableEntry
495 );
496 
497 /* PSEH EXCEPTION HANDLING **************************************************/
498 
499 LONG
500 NTAPI
501 ExSystemExceptionFilter(VOID);
502 
503 /* CALLBACKS *****************************************************************/
504 
505 FORCEINLINE
506 VOID
507 ExDoCallBack(IN OUT PEX_CALLBACK Callback,
508              IN PVOID Context,
509              IN PVOID Argument1,
510              IN PVOID Argument2)
511 {
512     PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock;
513     PEX_CALLBACK_FUNCTION Function;
514 
515     /* Reference the block */
516     CallbackBlock = ExReferenceCallBackBlock(Callback);
517     if (CallbackBlock)
518     {
519         /* Get the function */
520         Function = ExGetCallBackBlockRoutine(CallbackBlock);
521 
522         /* Do the callback */
523         Function(Context, Argument1, Argument2);
524 
525         /* Now dereference it */
526         ExDereferenceCallBackBlock(Callback, CallbackBlock);
527     }
528 }
529 
530 /* FAST REFS ******************************************************************/
531 
532 FORCEINLINE
533 PVOID
534 ExGetObjectFastReference(IN EX_FAST_REF FastRef)
535 {
536     /* Return the unbiased pointer */
537     return (PVOID)(FastRef.Value & ~MAX_FAST_REFS);
538 }
539 
540 FORCEINLINE
541 ULONG
542 ExGetCountFastReference(IN EX_FAST_REF FastRef)
543 {
544     /* Return the reference count */
545     return (ULONG)FastRef.RefCnt;
546 }
547 
548 FORCEINLINE
549 VOID
550 ExInitializeFastReference(OUT PEX_FAST_REF FastRef,
551                           IN OPTIONAL PVOID Object)
552 {
553     /* Sanity check */
554     ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
555 
556     /* Check if an object is being set */
557     if (!Object)
558     {
559         /* Clear the field */
560         FastRef->Object = NULL;
561     }
562     else
563     {
564         /* Otherwise, we assume the object was referenced and is ready */
565         FastRef->Value = (ULONG_PTR)Object | MAX_FAST_REFS;
566     }
567 }
568 
569 FORCEINLINE
570 EX_FAST_REF
571 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef)
572 {
573     EX_FAST_REF OldValue, NewValue;
574 
575     /* Start reference loop */
576     for (;;)
577     {
578         /* Get the current reference count */
579         OldValue = *FastRef;
580         if (OldValue.RefCnt)
581         {
582             /* Increase the reference count */
583             NewValue.Value = OldValue.Value - 1;
584             NewValue.Object = ExpChangePushlock(&FastRef->Object,
585                                                 NewValue.Object,
586                                                 OldValue.Object);
587             if (NewValue.Object != OldValue.Object) continue;
588         }
589 
590         /* We are done */
591         break;
592     }
593 
594     /* Return the old value */
595     return OldValue;
596 }
597 
598 FORCEINLINE
599 BOOLEAN
600 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef,
601                       IN PVOID Object)
602 {
603     EX_FAST_REF OldValue, NewValue;
604 
605     /* Sanity checks */
606     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
607 
608     /* Start update loop */
609     for (;;)
610     {
611         /* Get the current reference count */
612         OldValue = *FastRef;
613 
614         /* Check if the current count is too high or if the pointer changed */
615         if (((OldValue.RefCnt + MAX_FAST_REFS) > MAX_FAST_REFS) ||
616             ((OldValue.Value &~ MAX_FAST_REFS) != (ULONG_PTR)Object))
617         {
618             /* Fail */
619             return FALSE;
620         }
621 
622         /* Update the reference count */
623         NewValue.Value = OldValue.Value + MAX_FAST_REFS;
624         NewValue.Object = ExpChangePushlock(&FastRef->Object,
625                                             NewValue.Object,
626                                             OldValue.Object);
627         if (NewValue.Object != OldValue.Object) continue;
628 
629         /* We are done */
630         break;
631     }
632 
633     /* Return success */
634     return TRUE;
635 }
636 
637 FORCEINLINE
638 BOOLEAN
639 ExReleaseFastReference(IN PEX_FAST_REF FastRef,
640                        IN PVOID Object)
641 {
642     EX_FAST_REF OldValue, NewValue;
643 
644     /* Sanity checks */
645     ASSERT(Object != NULL);
646     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
647 
648     /* Start reference loop */
649     for (;;)
650     {
651         /* Get the current reference count */
652         OldValue = *FastRef;
653 
654         /* Check if we're full if if the pointer changed */
655         if ((OldValue.Value ^ (ULONG_PTR)Object) >= MAX_FAST_REFS) return FALSE;
656 
657         /* Decrease the reference count */
658         NewValue.Value = OldValue.Value + 1;
659         NewValue.Object = ExpChangePushlock(&FastRef->Object,
660                                             NewValue.Object,
661                                             OldValue.Object);
662         if (NewValue.Object != OldValue.Object) continue;
663 
664         /* We are done */
665         break;
666     }
667 
668     /* Return success */
669     return TRUE;
670 }
671 
672 FORCEINLINE
673 EX_FAST_REF
674 ExSwapFastReference(IN PEX_FAST_REF FastRef,
675                     IN PVOID Object)
676 {
677     EX_FAST_REF NewValue, OldValue;
678 
679     /* Sanity check */
680     ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
681 
682     /* Check if an object is being set */
683     if (!Object)
684     {
685         /* Clear the field */
686         NewValue.Object = NULL;
687     }
688     else
689     {
690         /* Otherwise, we assume the object was referenced and is ready */
691         NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
692     }
693 
694     /* Update the object */
695     OldValue.Object = InterlockedExchangePointer(&FastRef->Object, NewValue.Object);
696     return OldValue;
697 }
698 
699 FORCEINLINE
700 EX_FAST_REF
701 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef,
702                            IN PVOID Object,
703                            IN PVOID OldObject)
704 {
705     EX_FAST_REF OldValue, NewValue;
706 
707     /* Sanity check and start swap loop */
708     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
709     for (;;)
710     {
711         /* Get the current value */
712         OldValue = *FastRef;
713 
714         /* Make sure there's enough references to swap */
715         if (!((OldValue.Value ^ (ULONG_PTR)OldObject) <= MAX_FAST_REFS)) break;
716 
717         /* Check if we have an object to swap */
718         if (Object)
719         {
720             /* Set up the value with maximum fast references */
721             NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
722         }
723         else
724         {
725             /* Write the object address itself (which is empty) */
726             NewValue.Value = (ULONG_PTR)Object;
727         }
728 
729         /* Do the actual compare exchange */
730         NewValue.Object = ExpChangePushlock(&FastRef->Object,
731                                             NewValue.Object,
732                                             OldValue.Object);
733         if (NewValue.Object != OldValue.Object) continue;
734 
735         /* All done */
736         break;
737     }
738 
739     /* Return the old value */
740     return OldValue;
741 }
742 
743 /* RUNDOWN *******************************************************************/
744 
745 /*++
746  * @name ExfAcquireRundownProtection
747  * INTERNAL MACRO
748  *
749  *     The ExfAcquireRundownProtection routine acquires rundown protection for
750  *     the specified descriptor.
751  *
752  * @param RunRef
753  *        Pointer to a rundown reference descriptor.
754  *
755  * @return TRUE if access to the protected structure was granted, FALSE otherwise.
756  *
757  * @remarks This is the internal macro for system use only.In case the rundown
758  *          was active, then the slow-path will be called through the exported
759  *          function.
760  *
761  *--*/
762 FORCEINLINE
763 BOOLEAN
764 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
765 {
766     ULONG_PTR Value, NewValue;
767 
768     /* Get the current value and mask the active bit */
769     Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
770 
771     /* Add a reference */
772     NewValue = Value + EX_RUNDOWN_COUNT_INC;
773 
774     /* Change the value */
775     NewValue = ExpChangeRundown(RunRef, NewValue, Value);
776     if (NewValue != Value)
777     {
778         /* Rundown was active, use long path */
779         return ExfAcquireRundownProtection(RunRef);
780     }
781 
782     /* Success */
783     return TRUE;
784 }
785 
786 /*++
787  * @name ExReleaseRundownProtection
788  * INTERNAL MACRO
789  *
790  *     The ExReleaseRundownProtection routine releases rundown protection for
791  *     the specified descriptor.
792  *
793  * @param RunRef
794  *        Pointer to a rundown reference descriptor.
795  *
796  * @return TRUE if access to the protected structure was granted, FALSE otherwise.
797  *
798  * @remarks This is the internal macro for system use only.In case the rundown
799  *          was active, then the slow-path will be called through the exported
800  *          function.
801  *
802  *--*/
803 FORCEINLINE
804 VOID
805 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
806 {
807     ULONG_PTR Value, NewValue;
808 
809     /* Get the current value and mask the active bit */
810     Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
811 
812     /* Remove a reference */
813     NewValue = Value - EX_RUNDOWN_COUNT_INC;
814 
815     /* Change the value */
816     NewValue = ExpChangeRundown(RunRef, NewValue, Value);
817 
818     /* Check if the rundown was active */
819     if (NewValue != Value)
820     {
821         /* Rundown was active, use long path */
822         ExfReleaseRundownProtection(RunRef);
823     }
824     else
825     {
826         /* Sanity check */
827         ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
828     }
829 }
830 
831 /*++
832  * @name ExInitializeRundownProtection
833  * INTERNAL MACRO
834  *
835  *     The ExInitializeRundownProtection routine initializes a rundown
836  *     protection descriptor.
837  *
838  * @param RunRef
839  *        Pointer to a rundown reference descriptor.
840  *
841  * @return None.
842  *
843  * @remarks This is the internal macro for system use only.
844  *
845  *--*/
846 FORCEINLINE
847 VOID
848 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
849 {
850     /* Set the count to zero */
851     RunRef->Count = 0;
852 }
853 
854 /*++
855  * @name ExWaitForRundownProtectionRelease
856  * INTERNAL MACRO
857  *
858  *     The ExWaitForRundownProtectionRelease routine waits until the specified
859  *     rundown descriptor has been released.
860  *
861  * @param RunRef
862  *        Pointer to a rundown reference descriptor.
863  *
864  * @return None.
865  *
866  * @remarks This is the internal macro for system use only. If a wait is actually
867  *          necessary, then the slow path is taken through the exported function.
868  *
869  *--*/
870 FORCEINLINE
871 VOID
872 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
873 {
874     ULONG_PTR Value;
875 
876     /* Set the active bit */
877     Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
878     if ((Value) && (Value != EX_RUNDOWN_ACTIVE))
879     {
880         /* If the the rundown wasn't already active, then take the long path */
881         ExfWaitForRundownProtectionRelease(RunRef);
882     }
883 }
884 
885 /*++
886  * @name ExRundownCompleted
887  * INTERNAL MACRO
888  *
889  *     The ExRundownCompleted routine completes the rundown of the specified
890  *     descriptor by setting the active bit.
891  *
892  * @param RunRef
893  *        Pointer to a rundown reference descriptor.
894  *
895  * @return None.
896  *
897  * @remarks This is the internal macro for system use only.
898  *
899  *--*/
900 FORCEINLINE
901 VOID
902 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
903 {
904     /* Sanity check */
905     ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
906 
907     /* Mark the counter as active */
908     ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE);
909 }
910 
911 /* PUSHLOCKS *****************************************************************/
912 
913 /* FIXME: VERIFY THESE! */
914 
915 VOID
916 FASTCALL
917 ExBlockPushLock(
918     IN PEX_PUSH_LOCK PushLock,
919     IN PVOID WaitBlock
920 );
921 
922 VOID
923 FASTCALL
924 ExfUnblockPushLock(
925     IN PEX_PUSH_LOCK PushLock,
926     IN PVOID CurrentWaitBlock
927 );
928 
929 VOID
930 FASTCALL
931 ExWaitForUnblockPushLock(
932     IN PEX_PUSH_LOCK PushLock,
933     IN PVOID WaitBlock
934 );
935 
936 /*++
937  * @name _ExInitializePushLock
938  * INTERNAL MACRO
939  *
940  *     The _ExInitializePushLock macro initializes a PushLock.
941  *
942  * @params PushLock
943  *         Pointer to the pushlock which is to be initialized.
944  *
945  * @return None.
946  *
947  * @remarks None.
948  *
949  *--*/
950 FORCEINLINE
951 VOID
952 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock)
953 {
954     /* Set the value to 0 */
955     PushLock->Ptr = 0;
956 }
957 #define ExInitializePushLock _ExInitializePushLock
958 
959 /*++
960  * @name ExAcquirePushLockExclusive
961  * INTERNAL MACRO
962  *
963  *     The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
964  *
965  * @params PushLock
966  *         Pointer to the pushlock which is to be acquired.
967  *
968  * @return None.
969  *
970  * @remarks The function attempts the quickest route to acquire the lock, which is
971  *          to simply set the lock bit.
972  *          However, if the pushlock is already shared, the slower path is taken.
973  *
974  *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
975  *          This macro should usually be paired up with KeAcquireCriticalRegion.
976  *
977  *--*/
978 FORCEINLINE
979 VOID
980 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
981 {
982     /* Try acquiring the lock */
983     if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
984     {
985         /* Someone changed it, use the slow path */
986         ExfAcquirePushLockExclusive(PushLock);
987     }
988 
989     /* Sanity check */
990     ASSERT(PushLock->Locked);
991 }
992 
993 /*++
994 * @name ExTryToAcquirePushLockExclusive
995 * INTERNAL MACRO
996 *
997 *     The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
998 *
999 * @params PushLock
1000 *         Pointer to the pushlock which is to be acquired.
1001 *
1002 * @return None.
1003 *
1004 * @remarks The function attempts the quickest route to acquire the lock, which is
1005 *          to simply set the lock bit.
1006 *          However, if the pushlock is already shared, the slower path is taken.
1007 *
1008 *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1009 *          This macro should usually be paired up with KeAcquireCriticalRegion.
1010 *
1011 *--*/
1012 FORCEINLINE
1013 BOOLEAN
1014 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
1015 {
1016     /* Try acquiring the lock */
1017     if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
1018     {
1019         /* Can't acquire */
1020         return FALSE;
1021     }
1022 
1023     /* Got acquired */
1024     ASSERT (PushLock->Locked);
1025     return TRUE;
1026 }
1027 
1028 /*++
1029  * @name ExAcquirePushLockShared
1030  * INTERNAL MACRO
1031  *
1032  *     The ExAcquirePushLockShared macro acquires a shared PushLock.
1033  *
1034  * @params PushLock
1035  *         Pointer to the pushlock which is to be acquired.
1036  *
1037  * @return None.
1038  *
1039  * @remarks The function attempts the quickest route to acquire the lock, which is
1040  *          to simply set the lock bit and set the share count to one.
1041  *          However, if the pushlock is already shared, the slower path is taken.
1042  *
1043  *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1044  *          This macro should usually be paired up with KeAcquireCriticalRegion.
1045  *
1046  *--*/
1047 FORCEINLINE
1048 VOID
1049 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
1050 {
1051     EX_PUSH_LOCK NewValue;
1052 
1053     /* Try acquiring the lock */
1054     NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1055     if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
1056     {
1057         /* Someone changed it, use the slow path */
1058         ExfAcquirePushLockShared(PushLock);
1059     }
1060 
1061     /* Sanity checks */
1062     ASSERT(PushLock->Locked);
1063 }
1064 
1065 /*++
1066  * @name ExConvertPushLockSharedToExclusive
1067  * INTERNAL MACRO
1068  *
1069  *     The ExConvertPushLockSharedToExclusive macro converts an exclusive
1070  *     pushlock to a shared pushlock.
1071  *
1072  * @params PushLock
1073  *         Pointer to the pushlock which is to be converted.
1074  *
1075  * @return FALSE if conversion failed, TRUE otherwise.
1076  *
1077  * @remarks The function attempts the quickest route to convert the lock, which is
1078  *          to simply set the lock bit and remove any other bits.
1079  *
1080  *--*/
1081 FORCEINLINE
1082 BOOLEAN
1083 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
1084 {
1085     EX_PUSH_LOCK OldValue;
1086 
1087     /* Set the expected old value */
1088     OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1089 
1090     /* Try converting the lock */
1091     if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
1092         OldValue.Ptr)
1093     {
1094         /* Conversion failed */
1095         return FALSE;
1096     }
1097 
1098     /* Sanity check */
1099     ASSERT(PushLock->Locked);
1100     return TRUE;
1101 }
1102 
1103 /*++
1104  * @name ExWaitOnPushLock
1105  * INTERNAL MACRO
1106  *
1107  *     The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1108  *
1109  * @params PushLock
1110  *         Pointer to a pushlock.
1111  *
1112  * @return None.
1113  *
1114  * @remarks The function attempts to get any exclusive waiters out of their slow
1115  *          path by forcing an instant acquire/release operation.
1116  *
1117  *          Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1118  *
1119  *--*/
1120 FORCEINLINE
1121 VOID
1122 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
1123 {
1124     /* Check if we're locked */
1125     if (PushLock->Locked)
1126     {
1127         /* Acquire the lock */
1128         ExfAcquirePushLockExclusive(PushLock);
1129         ASSERT(PushLock->Locked);
1130 
1131         /* Release it */
1132         ExfReleasePushLockExclusive(PushLock);
1133     }
1134 }
1135 
1136 /*++
1137  * @name ExReleasePushLockShared
1138  * INTERNAL MACRO
1139  *
1140  *     The ExReleasePushLockShared macro releases a previously acquired PushLock.
1141  *
1142  * @params PushLock
1143  *         Pointer to a previously acquired pushlock.
1144  *
1145  * @return None.
1146  *
1147  * @remarks The function attempts the quickest route to release the lock, which is
1148  *          to simply decrease the share count and remove the lock bit.
1149  *          However, if the pushlock is being waited on then the long path is taken.
1150  *
1151  *          Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1152  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1153  *
1154  *--*/
1155 FORCEINLINE
1156 VOID
1157 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
1158 {
1159     EX_PUSH_LOCK OldValue;
1160 
1161     /* Sanity checks */
1162     ASSERT(PushLock->Locked);
1163 
1164     /* Try to clear the pushlock */
1165     OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1166     if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
1167     {
1168         /* There are still other people waiting on it */
1169         ExfReleasePushLockShared(PushLock);
1170     }
1171 }
1172 
1173 /*++
1174  * @name ExReleasePushLockExclusive
1175  * INTERNAL MACRO
1176  *
1177  *     The ExReleasePushLockExclusive macro releases a previously
1178  *     exclusively acquired PushLock.
1179  *
1180  * @params PushLock
1181  *         Pointer to a previously acquired pushlock.
1182  *
1183  * @return None.
1184  *
1185  * @remarks The function attempts the quickest route to release the lock, which is
1186  *          to simply clear the locked bit.
1187  *          However, if the pushlock is being waited on, the slow path is taken
1188  *          in an attempt to wake up the lock.
1189  *
1190  *          Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1191  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1192  *
1193  *--*/
1194 FORCEINLINE
1195 VOID
1196 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
1197 {
1198     EX_PUSH_LOCK OldValue;
1199 
1200     /* Sanity checks */
1201     ASSERT(PushLock->Locked);
1202 
1203     /* Unlock the pushlock */
1204     OldValue.Value = InterlockedExchangeAddSizeT((PSIZE_T)PushLock,
1205                                                  -(SSIZE_T)EX_PUSH_LOCK_LOCK);
1206 
1207     /* Sanity checks */
1208     ASSERT(OldValue.Locked);
1209     ASSERT(OldValue.Waiting || OldValue.Shared == 0);
1210 
1211     /* Check if anyone is waiting on it and it's not already waking*/
1212     if ((OldValue.Waiting) && !(OldValue.Waking))
1213     {
1214         /* Wake it up */
1215         ExfTryToWakePushLock(PushLock);
1216     }
1217 }
1218 
1219 /*++
1220  * @name ExReleasePushLock
1221  * INTERNAL MACRO
1222  *
1223  *     The ExReleasePushLock macro releases a previously acquired PushLock.
1224  *
1225  * @params PushLock
1226  *         Pointer to a previously acquired pushlock.
1227  *
1228  * @return None.
1229  *
1230  * @remarks The function attempts the quickest route to release the lock, which is
1231  *          to simply clear all the fields and decrease the share count if required.
1232  *          However, if the pushlock is being waited on then the long path is taken.
1233  *
1234  *          Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1235  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1236  *
1237  *--*/
1238 FORCEINLINE
1239 VOID
1240 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
1241 {
1242     EX_PUSH_LOCK OldValue = *PushLock;
1243     EX_PUSH_LOCK NewValue;
1244 
1245     /* Sanity checks */
1246     ASSERT(OldValue.Locked);
1247 
1248     /* Check if the pushlock is shared */
1249     if (OldValue.Shared > 1)
1250     {
1251         /* Decrease the share count */
1252         NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
1253     }
1254     else
1255     {
1256         /* Clear the pushlock entirely */
1257         NewValue.Value = 0;
1258     }
1259 
1260     /* Check if nobody is waiting on us and try clearing the lock here */
1261     if ((OldValue.Waiting) ||
1262         (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
1263          OldValue.Ptr))
1264     {
1265         /* We have waiters, use the long path */
1266         ExfReleasePushLock(PushLock);
1267     }
1268 }
1269 
1270 /* FAST MUTEX INLINES *********************************************************/
1271 
1272 FORCEINLINE
1273 VOID
1274 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex)
1275 {
1276     PKTHREAD Thread = KeGetCurrentThread();
1277 
1278     /* Sanity check */
1279     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1280            (Thread->CombinedApcDisable != 0) ||
1281            (Thread->Teb == NULL) ||
1282            (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1283     ASSERT(FastMutex->Owner != Thread);
1284 
1285     /* Decrease the count */
1286     if (InterlockedDecrement(&FastMutex->Count))
1287     {
1288         /* Someone is still holding it, use slow path */
1289         KiAcquireFastMutex(FastMutex);
1290     }
1291 
1292     /* Set the owner */
1293     FastMutex->Owner = Thread;
1294 }
1295 
1296 FORCEINLINE
1297 VOID
1298 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1299 {
1300     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1301            (KeGetCurrentThread()->CombinedApcDisable != 0) ||
1302            (KeGetCurrentThread()->Teb == NULL) ||
1303            (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1304     ASSERT(FastMutex->Owner == KeGetCurrentThread());
1305 
1306     /* Erase the owner */
1307     FastMutex->Owner = NULL;
1308 
1309     /* Increase the count */
1310     if (InterlockedIncrement(&FastMutex->Count) <= 0)
1311     {
1312         /* Someone was waiting for it, signal the waiter */
1313         KeSetEventBoostPriority(&FastMutex->Event, NULL);
1314     }
1315 }
1316 
1317 FORCEINLINE
1318 VOID
1319 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
1320 {
1321     KIRQL OldIrql;
1322     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1323 
1324     /* Raise IRQL to APC */
1325     KeRaiseIrql(APC_LEVEL, &OldIrql);
1326 
1327     /* Decrease the count */
1328     if (InterlockedDecrement(&FastMutex->Count))
1329     {
1330         /* Someone is still holding it, use slow path */
1331         KiAcquireFastMutex(FastMutex);
1332     }
1333 
1334     /* Set the owner and IRQL */
1335     FastMutex->Owner = KeGetCurrentThread();
1336     FastMutex->OldIrql = OldIrql;
1337 }
1338 
1339 FORCEINLINE
1340 VOID
1341 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex)
1342 {
1343     KIRQL OldIrql;
1344     ASSERT(KeGetCurrentIrql() == APC_LEVEL);
1345 
1346     /* Erase the owner */
1347     FastMutex->Owner = NULL;
1348     OldIrql = (KIRQL)FastMutex->OldIrql;
1349 
1350     /* Increase the count */
1351     if (InterlockedIncrement(&FastMutex->Count) <= 0)
1352     {
1353         /* Someone was waiting for it, signal the waiter */
1354         KeSetEventBoostPriority(&FastMutex->Event, NULL);
1355     }
1356 
1357     /* Lower IRQL back */
1358     KeLowerIrql(OldIrql);
1359 }
1360 
1361 FORCEINLINE
1362 BOOLEAN
1363 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex)
1364 {
1365     KIRQL OldIrql;
1366     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1367 
1368     /* Raise to APC_LEVEL */
1369     KeRaiseIrql(APC_LEVEL, &OldIrql);
1370 
1371     /* Check if we can quickly acquire it */
1372     if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
1373     {
1374         /* We have, set us as owners */
1375         FastMutex->Owner = KeGetCurrentThread();
1376         FastMutex->OldIrql = OldIrql;
1377         return TRUE;
1378     }
1379     else
1380     {
1381         /* Acquire attempt failed */
1382         KeLowerIrql(OldIrql);
1383         YieldProcessor();
1384         return FALSE;
1385     }
1386 }
1387 
1388 FORCEINLINE
1389 VOID
1390 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1391 {
1392     /* Enter the Critical Region */
1393     KeEnterCriticalRegion();
1394 
1395     /* Acquire the mutex unsafely */
1396     _ExAcquireFastMutexUnsafe(FastMutex);
1397 }
1398 
1399 FORCEINLINE
1400 VOID
1401 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex)
1402 {
1403     /* Release the mutex unsafely */
1404     _ExReleaseFastMutexUnsafe(FastMutex);
1405 
1406     /* Leave the critical region */
1407     KeLeaveCriticalRegion();
1408 }
1409 
1410 /* OTHER FUNCTIONS **********************************************************/
1411 
1412 BOOLEAN
1413 NTAPI
1414 ExTryToAcquireResourceExclusiveLite(
1415     IN PERESOURCE Resource
1416 );
1417 
1418 NTSTATUS
1419 ExpSetTimeZoneInformation(
1420     IN PRTL_TIME_ZONE_INFORMATION TimeZoneInformation
1421 );
1422 
1423 BOOLEAN
1424 NTAPI
1425 ExAcquireTimeRefreshLock(
1426     IN BOOLEAN Wait
1427 );
1428 
1429 VOID
1430 NTAPI
1431 ExReleaseTimeRefreshLock(
1432     VOID
1433 );
1434 
1435 VOID
1436 NTAPI
1437 ExUpdateSystemTimeFromCmos(
1438     IN BOOLEAN UpdateInterruptTime,
1439     IN ULONG MaxSepInSeconds
1440 );
1441 
1442 VOID
1443 NTAPI
1444 ExAllocateLocallyUniqueId(
1445     OUT LUID *LocallyUniqueId
1446 );
1447 
1448 VOID
1449 NTAPI
1450 ExTimerRundown(
1451     VOID
1452 );
1453 
1454 VOID
1455 NTAPI
1456 HeadlessInit(
1457     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1458 );
1459 
1460 VOID
1461 NTAPI
1462 XIPInit(
1463     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1464 );
1465 
1466 #define InterlockedDecrementUL(Addend) \
1467    (ULONG)InterlockedDecrement((PLONG)(Addend))
1468 
1469 #define InterlockedIncrementUL(Addend) \
1470    (ULONG)InterlockedIncrement((PLONG)(Addend))
1471 
1472 #define InterlockedExchangeUL(Target, Value) \
1473    (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1474 
1475 #define InterlockedExchangeAddUL(Addend, Value) \
1476    (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1477 
1478 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1479    (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1480 
1481 #define InterlockedCompareExchangeSizeT(Destination, Exchange, Comperand) \
1482    (SIZE_T)InterlockedCompareExchangePointer((PVOID*)(Destination), (PVOID)(SIZE_T)(Exchange), (PVOID)(SIZE_T)(Comperand))
1483 
1484 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1485    (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
1486