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