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