xref: /reactos/ntoskrnl/mm/ARM3/miarm.h (revision 53221834)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/mm/ARM3/miarm.h
5  * PURPOSE:         ARM Memory Manager Header
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 #pragma once
10 
11 #ifdef __cplusplus
12 extern "C" {
13 #endif
14 
15 #define MI_LOWEST_VAD_ADDRESS                   (PVOID)MM_LOWEST_USER_ADDRESS
16 
17 /* Make the code cleaner with some definitions for size multiples */
18 #define _1KB (1024u)
19 #define _1MB (1024 * _1KB)
20 #define _1GB (1024 * _1MB)
21 
22 /* Everyone loves 64K */
23 #define _64K (64 * _1KB)
24 
25 /* Size of a page table */
26 #define PT_SIZE  (PTE_PER_PAGE * sizeof(MMPTE))
27 
28 /* Size of a page directory */
29 #define PD_SIZE  (PDE_PER_PAGE * sizeof(MMPDE))
30 
31 /* Size of all page directories for a process */
32 #define SYSTEM_PD_SIZE (PPE_PER_PAGE * PD_SIZE)
33 #ifdef _M_IX86
34 C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE);
35 #endif
36 
37 //
38 // Protection Bits part of the internal memory manager Protection Mask, from:
39 // http://reactos.org/wiki/Techwiki:Memory_management_in_the_Windows_XP_kernel
40 // https://www.reactos.org/wiki/Techwiki:Memory_Protection_constants
41 // and public assertions.
42 //
43 #define MM_ZERO_ACCESS         0
44 #define MM_READONLY            1
45 #define MM_EXECUTE             2
46 #define MM_EXECUTE_READ        3
47 #define MM_READWRITE           4
48 #define MM_WRITECOPY           5
49 #define MM_EXECUTE_READWRITE   6
50 #define MM_EXECUTE_WRITECOPY   7
51 #define MM_PROTECT_ACCESS      7
52 
53 //
54 // These are flags on top of the actual protection mask
55 //
56 #define MM_NOCACHE            0x08
57 #define MM_GUARDPAGE          0x10
58 #define MM_WRITECOMBINE       0x18
59 #define MM_PROTECT_SPECIAL    0x18
60 
61 //
62 // These are special cases
63 //
64 #define MM_DECOMMIT           (MM_ZERO_ACCESS | MM_GUARDPAGE)
65 #define MM_NOACCESS           (MM_ZERO_ACCESS | MM_WRITECOMBINE)
66 #define MM_OUTSWAPPED_KSTACK  (MM_EXECUTE_WRITECOPY | MM_WRITECOMBINE)
67 #define MM_INVALID_PROTECTION  0xFFFFFFFF
68 
69 //
70 // Specific PTE Definitions that map to the Memory Manager's Protection Mask Bits
71 // The Memory Manager's definition define the attributes that must be preserved
72 // and these PTE definitions describe the attributes in the hardware sense. This
73 // helps deal with hardware differences between the actual boolean expression of
74 // the argument.
75 //
76 // For example, in the logical attributes, we want to express read-only as a flag
77 // but on x86, it is writability that must be set. On the other hand, on x86, just
78 // like in the kernel, it is disabling the caches that requires a special flag,
79 // while on certain architectures such as ARM, it is enabling the cache which
80 // requires a flag.
81 //
82 #if defined(_M_IX86)
83 //
84 // Access Flags
85 //
86 #define PTE_READONLY            0 // Doesn't exist on x86
87 #define PTE_EXECUTE             0 // Not worrying about NX yet
88 #define PTE_EXECUTE_READ        0 // Not worrying about NX yet
89 #define PTE_READWRITE           0x2
90 #define PTE_WRITECOPY           0x200
91 #define PTE_EXECUTE_READWRITE   0x2 // Not worrying about NX yet
92 #define PTE_EXECUTE_WRITECOPY   0x200
93 #define PTE_PROTOTYPE           0x400
94 
95 //
96 // State Flags
97 //
98 #define PTE_VALID               0x1
99 #define PTE_ACCESSED            0x20
100 #define PTE_DIRTY               0x40
101 
102 //
103 // Cache flags
104 //
105 #define PTE_ENABLE_CACHE        0
106 #define PTE_DISABLE_CACHE       0x10
107 #define PTE_WRITECOMBINED_CACHE 0x10
108 #define PTE_PROTECT_MASK        0x612
109 #elif defined(_M_AMD64)
110 //
111 // Access Flags
112 //
113 #define PTE_READONLY            0x8000000000000000ULL
114 #define PTE_EXECUTE             0x0000000000000000ULL
115 #define PTE_EXECUTE_READ        PTE_EXECUTE /* EXECUTE implies READ on x64 */
116 #define PTE_READWRITE           0x8000000000000002ULL
117 #define PTE_WRITECOPY           0x8000000000000200ULL
118 #define PTE_EXECUTE_READWRITE   0x0000000000000002ULL
119 #define PTE_EXECUTE_WRITECOPY   0x0000000000000200ULL
120 #define PTE_PROTOTYPE           0x0000000000000400ULL
121 
122 //
123 // State Flags
124 //
125 #define PTE_VALID               0x0000000000000001ULL
126 #define PTE_ACCESSED            0x0000000000000020ULL
127 #define PTE_DIRTY               0x0000000000000040ULL
128 
129 //
130 // Cache flags
131 //
132 #define PTE_ENABLE_CACHE        0x0000000000000000ULL
133 #define PTE_DISABLE_CACHE       0x0000000000000010ULL
134 #define PTE_WRITECOMBINED_CACHE 0x0000000000000010ULL
135 #define PTE_PROTECT_MASK        0x8000000000000612ULL
136 #elif defined(_M_ARM)
137 #define PTE_READONLY            0x200
138 #define PTE_EXECUTE             0 // Not worrying about NX yet
139 #define PTE_EXECUTE_READ        0 // Not worrying about NX yet
140 #define PTE_READWRITE           0 // Doesn't exist on ARM
141 #define PTE_WRITECOPY           0 // Doesn't exist on ARM
142 #define PTE_EXECUTE_READWRITE   0 // Not worrying about NX yet
143 #define PTE_EXECUTE_WRITECOPY   0 // Not worrying about NX yet
144 #define PTE_PROTOTYPE           0x400 // Using the Shared bit
145 
146 //
147 // Cache flags
148 //
149 #define PTE_ENABLE_CACHE        0
150 #define PTE_DISABLE_CACHE       0x10
151 #define PTE_WRITECOMBINED_CACHE 0x10
152 #define PTE_PROTECT_MASK        0x610
153 #else
154 #error Define these please!
155 #endif
156 
157 //
158 // Mask for image section page protection
159 //
160 #define IMAGE_SCN_PROTECTION_MASK (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE)
161 
162 extern const ULONG_PTR MmProtectToPteMask[32];
163 extern const ULONG MmProtectToValue[32];
164 
165 //
166 // Assertions for session images, addresses, and PTEs
167 //
168 #define MI_IS_SESSION_IMAGE_ADDRESS(Address) \
169     (((Address) >= MiSessionImageStart) && ((Address) < MiSessionImageEnd))
170 
171 #define MI_IS_SESSION_ADDRESS(Address) \
172     (((Address) >= MmSessionBase) && ((Address) < MiSessionSpaceEnd))
173 
174 #define MI_IS_SESSION_PTE(Pte) \
175     ((((PMMPTE)Pte) >= MiSessionBasePte) && (((PMMPTE)Pte) < MiSessionLastPte))
176 
177 #define MI_IS_PAGE_TABLE_ADDRESS(Address) \
178     (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)PTE_TOP))
179 
180 #define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address) \
181     (((Address) >= (PVOID)MiAddressToPte(MmSystemRangeStart)) && ((Address) <= (PVOID)PTE_TOP))
182 
183 #define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address) \
184     (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)MmHyperSpaceEnd))
185 
186 //
187 // Creates a software PTE with the given protection
188 //
189 #define MI_MAKE_SOFTWARE_PTE(p, x)          ((p)->u.Long = (x << MM_PTE_SOFTWARE_PROTECTION_BITS))
190 
191 //
192 // Marks a PTE as deleted
193 //
194 #define MI_SET_PFN_DELETED(x)               ((x)->PteAddress = (PMMPTE)((ULONG_PTR)(x)->PteAddress | 1))
195 #define MI_IS_PFN_DELETED(x)                ((ULONG_PTR)((x)->PteAddress) & 1)
196 
197 //
198 // Special values for LoadedImports
199 //
200 #ifdef _WIN64
201 #define MM_SYSLDR_NO_IMPORTS   (PVOID)0xFFFFFFFFFFFFFFFEULL
202 #define MM_SYSLDR_BOOT_LOADED  (PVOID)0xFFFFFFFFFFFFFFFFULL
203 #else
204 #define MM_SYSLDR_NO_IMPORTS   (PVOID)0xFFFFFFFE
205 #define MM_SYSLDR_BOOT_LOADED  (PVOID)0xFFFFFFFF
206 #endif
207 #define MM_SYSLDR_SINGLE_ENTRY 0x1
208 
209 //
210 // Number of initial session IDs
211 //
212 #define MI_INITIAL_SESSION_IDS  64
213 
214 #if defined(_M_IX86) || defined(_M_ARM)
215 //
216 // PFN List Sentinel
217 //
218 #define LIST_HEAD 0xFFFFFFFF
219 
220 //
221 // Because GCC cannot automatically downcast 0xFFFFFFFF to lesser-width bits,
222 // we need a manual definition suited to the number of bits in the PteFrame.
223 // This is used as a LIST_HEAD for the colored list
224 //
225 #define COLORED_LIST_HEAD ((1 << 25) - 1) // 0x1FFFFFF
226 #elif defined(_M_AMD64)
227 #define LIST_HEAD 0xFFFFFFFFFFFFFFFFLL
228 #define COLORED_LIST_HEAD ((1ULL << 57) - 1) // 0x1FFFFFFFFFFFFFFLL
229 #else
230 #error Define these please!
231 #endif
232 
233 //
234 // Returns the color of a page
235 //
236 #define MI_GET_PAGE_COLOR(x)                ((x) & MmSecondaryColorMask)
237 #define MI_GET_NEXT_COLOR()                 (MI_GET_PAGE_COLOR(++MmSystemPageColor))
238 #define MI_GET_NEXT_PROCESS_COLOR(x)        (MI_GET_PAGE_COLOR(++(x)->NextPageColor))
239 
240 //
241 // Prototype PTEs that don't yet have a pagefile association
242 //
243 #ifdef _WIN64
244 #define MI_PTE_LOOKUP_NEEDED 0xffffffffULL
245 #else
246 #define MI_PTE_LOOKUP_NEEDED 0xFFFFF
247 #endif
248 
249 //
250 // Number of session data and tag pages
251 //
252 #define MI_SESSION_DATA_PAGES_MAXIMUM (MM_ALLOCATION_GRANULARITY / PAGE_SIZE)
253 #define MI_SESSION_TAG_PAGES_MAXIMUM  (MM_ALLOCATION_GRANULARITY / PAGE_SIZE)
254 
255 //
256 // Used by MiCheckSecuredVad
257 //
258 #define MM_READ_WRITE_ALLOWED   11
259 #define MM_READ_ONLY_ALLOWED    10
260 #define MM_NO_ACCESS_ALLOWED    01
261 #define MM_DELETE_CHECK         85
262 
263 //
264 // System views are binned into 64K chunks
265 //
266 #define MI_SYSTEM_VIEW_BUCKET_SIZE  _64K
267 
268 //
269 // FIXFIX: These should go in ex.h after the pool merge
270 //
271 #ifdef _WIN64
272 #define POOL_BLOCK_SIZE 16
273 #else
274 #define POOL_BLOCK_SIZE  8
275 #endif
276 #define POOL_LISTS_PER_PAGE (PAGE_SIZE / POOL_BLOCK_SIZE)
277 #define BASE_POOL_TYPE_MASK 1
278 #define POOL_MAX_ALLOC (PAGE_SIZE - (sizeof(POOL_HEADER) + POOL_BLOCK_SIZE))
279 
280 //
281 // Pool debugging/analysis/tracing flags
282 //
283 #define POOL_FLAG_CHECK_TIMERS 0x1
284 #define POOL_FLAG_CHECK_WORKERS 0x2
285 #define POOL_FLAG_CHECK_RESOURCES 0x4
286 #define POOL_FLAG_VERIFIER 0x8
287 #define POOL_FLAG_CHECK_DEADLOCK 0x10
288 #define POOL_FLAG_SPECIAL_POOL 0x20
289 #define POOL_FLAG_DBGPRINT_ON_FAILURE 0x40
290 #define POOL_FLAG_CRASH_ON_FAILURE 0x80
291 
292 //
293 // BAD_POOL_HEADER codes during pool bugcheck
294 //
295 #define POOL_CORRUPTED_LIST 3
296 #define POOL_SIZE_OR_INDEX_MISMATCH 5
297 #define POOL_ENTRIES_NOT_ALIGNED_PREVIOUS 6
298 #define POOL_HEADER_NOT_ALIGNED 7
299 #define POOL_HEADER_IS_ZERO 8
300 #define POOL_ENTRIES_NOT_ALIGNED_NEXT 9
301 #define POOL_ENTRY_NOT_FOUND 10
302 
303 //
304 // BAD_POOL_CALLER codes during pool bugcheck
305 //
306 #define POOL_ENTRY_CORRUPTED 1
307 #define POOL_ENTRY_ALREADY_FREE 6
308 #define POOL_ENTRY_NOT_ALLOCATED 7
309 #define POOL_ALLOC_IRQL_INVALID 8
310 #define POOL_FREE_IRQL_INVALID 9
311 #define POOL_BILLED_PROCESS_INVALID 13
312 #define POOL_HEADER_SIZE_INVALID 32
313 
314 typedef struct _POOL_DESCRIPTOR
315 {
316     POOL_TYPE PoolType;
317     ULONG PoolIndex;
318     ULONG RunningAllocs;
319     ULONG RunningDeAllocs;
320     ULONG TotalPages;
321     ULONG TotalBigPages;
322     ULONG Threshold;
323     PVOID LockAddress;
324     PVOID PendingFrees;
325     LONG PendingFreeDepth;
326     SIZE_T TotalBytes;
327     SIZE_T Spare0;
328     LIST_ENTRY ListHeads[POOL_LISTS_PER_PAGE];
329 } POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR;
330 
331 typedef struct _POOL_HEADER
332 {
333     union
334     {
335         struct
336         {
337 #ifdef _WIN64
338             USHORT PreviousSize:8;
339             USHORT PoolIndex:8;
340             USHORT BlockSize:8;
341             USHORT PoolType:8;
342 #else
343             USHORT PreviousSize:9;
344             USHORT PoolIndex:7;
345             USHORT BlockSize:9;
346             USHORT PoolType:7;
347 #endif
348         };
349         ULONG Ulong1;
350     };
351 #ifdef _WIN64
352     ULONG PoolTag;
353 #endif
354     union
355     {
356 #ifdef _WIN64
357         PEPROCESS ProcessBilled;
358 #else
359         ULONG PoolTag;
360 #endif
361         struct
362         {
363             USHORT AllocatorBackTraceIndex;
364             USHORT PoolTagHash;
365         };
366     };
367 } POOL_HEADER, *PPOOL_HEADER;
368 
369 C_ASSERT(sizeof(POOL_HEADER) == POOL_BLOCK_SIZE);
370 C_ASSERT(POOL_BLOCK_SIZE == sizeof(LIST_ENTRY));
371 
372 typedef struct _POOL_TRACKER_TABLE
373 {
374     ULONG Key;
375     LONG NonPagedAllocs;
376     LONG NonPagedFrees;
377     SIZE_T NonPagedBytes;
378     LONG PagedAllocs;
379     LONG PagedFrees;
380     SIZE_T PagedBytes;
381 } POOL_TRACKER_TABLE, *PPOOL_TRACKER_TABLE;
382 
383 typedef struct _POOL_TRACKER_BIG_PAGES
384 {
385     PVOID Va;
386     ULONG Key;
387     ULONG NumberOfPages;
388     PVOID QuotaObject;
389 } POOL_TRACKER_BIG_PAGES, *PPOOL_TRACKER_BIG_PAGES;
390 
391 extern ULONG ExpNumberOfPagedPools;
392 extern POOL_DESCRIPTOR NonPagedPoolDescriptor;
393 extern PPOOL_DESCRIPTOR ExpPagedPoolDescriptor[16 + 1];
394 extern PPOOL_TRACKER_TABLE PoolTrackTable;
395 
396 //
397 // END FIXFIX
398 //
399 
400 typedef struct _MI_LARGE_PAGE_DRIVER_ENTRY
401 {
402     LIST_ENTRY Links;
403     UNICODE_STRING BaseName;
404 } MI_LARGE_PAGE_DRIVER_ENTRY, *PMI_LARGE_PAGE_DRIVER_ENTRY;
405 
406 typedef enum _MMSYSTEM_PTE_POOL_TYPE
407 {
408     SystemPteSpace,
409     NonPagedPoolExpansion,
410     MaximumPtePoolTypes
411 } MMSYSTEM_PTE_POOL_TYPE;
412 
413 typedef enum _MI_PFN_CACHE_ATTRIBUTE
414 {
415     MiNonCached,
416     MiCached,
417     MiWriteCombined,
418     MiNotMapped
419 } MI_PFN_CACHE_ATTRIBUTE, *PMI_PFN_CACHE_ATTRIBUTE;
420 
421 typedef struct _PHYSICAL_MEMORY_RUN
422 {
423     PFN_NUMBER BasePage;
424     PFN_NUMBER PageCount;
425 } PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;
426 
427 typedef struct _PHYSICAL_MEMORY_DESCRIPTOR
428 {
429     ULONG NumberOfRuns;
430     PFN_NUMBER NumberOfPages;
431     PHYSICAL_MEMORY_RUN Run[1];
432 } PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;
433 
434 typedef struct _MMCOLOR_TABLES
435 {
436     PFN_NUMBER Flink;
437     PVOID Blink;
438     PFN_NUMBER Count;
439 } MMCOLOR_TABLES, *PMMCOLOR_TABLES;
440 
441 typedef struct _MI_LARGE_PAGE_RANGES
442 {
443     PFN_NUMBER StartFrame;
444     PFN_NUMBER LastFrame;
445 } MI_LARGE_PAGE_RANGES, *PMI_LARGE_PAGE_RANGES;
446 
447 typedef struct _MMVIEW
448 {
449     ULONG_PTR Entry;
450     PCONTROL_AREA ControlArea;
451 } MMVIEW, *PMMVIEW;
452 
453 typedef struct _MMSESSION
454 {
455     KGUARDED_MUTEX SystemSpaceViewLock;
456     PKGUARDED_MUTEX SystemSpaceViewLockPointer;
457     PCHAR SystemSpaceViewStart;
458     PMMVIEW SystemSpaceViewTable;
459     ULONG SystemSpaceHashSize;
460     ULONG SystemSpaceHashEntries;
461     ULONG SystemSpaceHashKey;
462     ULONG BitmapFailures;
463     PRTL_BITMAP SystemSpaceBitMap;
464 } MMSESSION, *PMMSESSION;
465 
466 typedef struct _MM_SESSION_SPACE_FLAGS
467 {
468     ULONG Initialized:1;
469     ULONG DeletePending:1;
470     ULONG Filler:30;
471 } MM_SESSION_SPACE_FLAGS;
472 
473 typedef struct _MM_SESSION_SPACE
474 {
475     struct _MM_SESSION_SPACE *GlobalVirtualAddress;
476     LONG ReferenceCount;
477     union
478     {
479         ULONG LongFlags;
480         MM_SESSION_SPACE_FLAGS Flags;
481     } u;
482     ULONG SessionId;
483     LIST_ENTRY ProcessList;
484     LARGE_INTEGER LastProcessSwappedOutTime;
485     PFN_NUMBER SessionPageDirectoryIndex;
486     SIZE_T NonPageablePages;
487     SIZE_T CommittedPages;
488     PVOID PagedPoolStart;
489     PVOID PagedPoolEnd;
490     PMMPDE PagedPoolBasePde;
491     ULONG Color;
492     LONG ResidentProcessCount;
493     ULONG SessionPoolAllocationFailures[4];
494     LIST_ENTRY ImageList;
495     LCID LocaleId;
496     ULONG AttachCount;
497     KEVENT AttachEvent;
498     PEPROCESS LastProcess;
499     LONG ProcessReferenceToSession;
500     LIST_ENTRY WsListEntry;
501     GENERAL_LOOKASIDE Lookaside[SESSION_POOL_LOOKASIDES];
502     MMSESSION Session;
503     KGUARDED_MUTEX PagedPoolMutex;
504     MM_PAGED_POOL_INFO PagedPoolInfo;
505     MMSUPPORT Vm;
506     PMMWSLE Wsle;
507     PDRIVER_UNLOAD Win32KDriverUnload;
508     POOL_DESCRIPTOR PagedPool;
509 #if defined (_M_AMD64)
510     MMPDE PageDirectory;
511 #else
512     PMMPDE PageTables;
513 #endif
514 #if defined (_M_AMD64)
515     PMMPTE SpecialPoolFirstPte;
516     PMMPTE SpecialPoolLastPte;
517     PMMPTE NextPdeForSpecialPoolExpansion;
518     PMMPTE LastPdeForSpecialPoolExpansion;
519     PFN_NUMBER SpecialPagesInUse;
520 #endif
521     LONG ImageLoadingCount;
522 } MM_SESSION_SPACE, *PMM_SESSION_SPACE;
523 
524 extern PMM_SESSION_SPACE MmSessionSpace;
525 extern MMPTE HyperTemplatePte;
526 extern MMPDE ValidKernelPde;
527 extern MMPTE ValidKernelPte;
528 extern MMPDE ValidKernelPdeLocal;
529 extern MMPTE ValidKernelPteLocal;
530 extern MMPDE DemandZeroPde;
531 extern MMPTE DemandZeroPte;
532 extern MMPTE PrototypePte;
533 extern MMPTE MmDecommittedPte;
534 extern BOOLEAN MmLargeSystemCache;
535 extern BOOLEAN MmZeroPageFile;
536 extern BOOLEAN MmProtectFreedNonPagedPool;
537 extern BOOLEAN MmTrackLockedPages;
538 extern BOOLEAN MmTrackPtes;
539 extern BOOLEAN MmDynamicPfn;
540 extern BOOLEAN MmMirroring;
541 extern BOOLEAN MmMakeLowMemory;
542 extern BOOLEAN MmEnforceWriteProtection;
543 extern SIZE_T MmAllocationFragment;
544 extern ULONG MmConsumedPoolPercentage;
545 extern ULONG MmVerifyDriverBufferType;
546 extern ULONG MmVerifyDriverLevel;
547 extern WCHAR MmVerifyDriverBuffer[512];
548 extern WCHAR MmLargePageDriverBuffer[512];
549 extern LIST_ENTRY MiLargePageDriverList;
550 extern BOOLEAN MiLargePageAllDrivers;
551 extern ULONG MmVerifyDriverBufferLength;
552 extern ULONG MmLargePageDriverBufferLength;
553 extern SIZE_T MmSizeOfNonPagedPoolInBytes;
554 extern SIZE_T MmMaximumNonPagedPoolInBytes;
555 extern PFN_NUMBER MmMaximumNonPagedPoolInPages;
556 extern PFN_NUMBER MmSizeOfPagedPoolInPages;
557 extern PVOID MmNonPagedSystemStart;
558 extern PVOID MmNonPagedPoolStart;
559 extern PVOID MmNonPagedPoolExpansionStart;
560 extern PVOID MmNonPagedPoolEnd;
561 extern SIZE_T MmSizeOfPagedPoolInBytes;
562 extern PVOID MmPagedPoolStart;
563 extern PVOID MmPagedPoolEnd;
564 extern PVOID MmSessionBase;
565 extern SIZE_T MmSessionSize;
566 extern PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
567 extern PMMPTE MiFirstReservedZeroingPte;
568 extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType];
569 extern PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
570 extern SIZE_T MmBootImageSize;
571 extern PMMPTE MmSystemPtesStart[MaximumPtePoolTypes];
572 extern PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes];
573 extern PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
574 extern MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
575 extern ULONG_PTR MxPfnAllocation;
576 extern MM_PAGED_POOL_INFO MmPagedPoolInfo;
577 extern KGUARDED_MUTEX MmPagedPoolMutex;
578 extern KGUARDED_MUTEX MmSectionCommitMutex;
579 extern PVOID MmPagedPoolStart;
580 extern PVOID MmPagedPoolEnd;
581 extern PVOID MmNonPagedSystemStart;
582 extern PVOID MiSystemViewStart;
583 extern SIZE_T MmSystemViewSize;
584 extern PVOID MmSessionBase;
585 extern PVOID MiSessionSpaceEnd;
586 extern PMMPTE MiSessionImagePteStart;
587 extern PMMPTE MiSessionImagePteEnd;
588 extern PMMPTE MiSessionBasePte;
589 extern PMMPTE MiSessionLastPte;
590 extern SIZE_T MmSizeOfPagedPoolInBytes;
591 extern PMMPDE MmSystemPagePtes;
592 extern PVOID MmSystemCacheStart;
593 extern PVOID MmSystemCacheEnd;
594 extern MMSUPPORT MmSystemCacheWs;
595 extern SIZE_T MmAllocatedNonPagedPool;
596 extern ULONG MmSpecialPoolTag;
597 extern PVOID MmHyperSpaceEnd;
598 extern PMMWSL MmSystemCacheWorkingSetList;
599 extern SIZE_T MmMinimumNonPagedPoolSize;
600 extern ULONG MmMinAdditionNonPagedPoolPerMb;
601 extern SIZE_T MmDefaultMaximumNonPagedPool;
602 extern ULONG MmMaxAdditionNonPagedPoolPerMb;
603 extern ULONG MmSecondaryColors;
604 extern ULONG MmSecondaryColorMask;
605 extern ULONG MmNumberOfSystemPtes;
606 extern ULONG MmMaximumNonPagedPoolPercent;
607 extern ULONG MmLargeStackSize;
608 extern PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1];
609 extern MMPFNLIST MmStandbyPageListByPriority[8];
610 extern ULONG MmProductType;
611 extern MM_SYSTEMSIZE MmSystemSize;
612 extern PKEVENT MiLowMemoryEvent;
613 extern PKEVENT MiHighMemoryEvent;
614 extern PKEVENT MiLowPagedPoolEvent;
615 extern PKEVENT MiHighPagedPoolEvent;
616 extern PKEVENT MiLowNonPagedPoolEvent;
617 extern PKEVENT MiHighNonPagedPoolEvent;
618 extern PFN_NUMBER MmLowMemoryThreshold;
619 extern PFN_NUMBER MmHighMemoryThreshold;
620 extern PFN_NUMBER MiLowPagedPoolThreshold;
621 extern PFN_NUMBER MiHighPagedPoolThreshold;
622 extern PFN_NUMBER MiLowNonPagedPoolThreshold;
623 extern PFN_NUMBER MiHighNonPagedPoolThreshold;
624 extern PFN_NUMBER MmMinimumFreePages;
625 extern PFN_NUMBER MmPlentyFreePages;
626 extern SIZE_T MmMinimumStackCommitInBytes;
627 extern PFN_COUNT MiExpansionPoolPagesInitialCharge;
628 extern PFN_NUMBER MmResidentAvailableAtInit;
629 extern ULONG MmTotalFreeSystemPtes[MaximumPtePoolTypes];
630 extern PFN_NUMBER MmTotalSystemDriverPages;
631 extern ULONG MmCritsectTimeoutSeconds;
632 extern PVOID MiSessionImageStart;
633 extern PVOID MiSessionImageEnd;
634 extern PMMPTE MiHighestUserPte;
635 extern PMMPDE MiHighestUserPde;
636 extern PFN_NUMBER MmSystemPageDirectory[PPE_PER_PAGE];
637 extern PMMPTE MmSharedUserDataPte;
638 extern LIST_ENTRY MmProcessList;
639 extern KEVENT MmZeroingPageEvent;
640 extern ULONG MmSystemPageColor;
641 extern ULONG MmProcessColorSeed;
642 extern PMMWSL MmWorkingSetList;
643 extern PFN_NUMBER MiNumberOfFreePages;
644 extern SIZE_T MmSessionViewSize;
645 extern SIZE_T MmSessionPoolSize;
646 extern SIZE_T MmSessionImageSize;
647 extern PVOID MiSystemViewStart;
648 extern PVOID MiSessionPoolEnd;     // 0xBE000000
649 extern PVOID MiSessionPoolStart;   // 0xBD000000
650 extern PVOID MiSessionViewStart;   // 0xBE000000
651 extern PVOID MiSessionSpaceWs;
652 extern ULONG MmMaximumDeadKernelStacks;
653 extern SLIST_HEADER MmDeadStackSListHead;
654 extern MM_AVL_TABLE MmSectionBasedRoot;
655 extern KGUARDED_MUTEX MmSectionBasedMutex;
656 extern PVOID MmHighSectionBase;
657 extern SIZE_T MmSystemLockPagesCount;
658 extern ULONG_PTR MmSubsectionBase;
659 extern LARGE_INTEGER MmCriticalSectionTimeout;
660 extern LIST_ENTRY MmWorkingSetExpansionHead;
661 extern KSPIN_LOCK MmExpansionLock;
662 extern PETHREAD MiExpansionLockOwner;
663 
664 FORCEINLINE
665 BOOLEAN
666 MI_IS_PROCESS_WORKING_SET(PMMSUPPORT WorkingSet)
667 {
668     return (WorkingSet != &MmSystemCacheWs) && !WorkingSet->Flags.SessionSpace;
669 }
670 
671 FORCEINLINE
672 BOOLEAN
673 MiIsMemoryTypeFree(TYPE_OF_MEMORY MemoryType)
674 {
675     return ((MemoryType == LoaderFree) ||
676             (MemoryType == LoaderLoadedProgram) ||
677             (MemoryType == LoaderFirmwareTemporary) ||
678             (MemoryType == LoaderOsloaderStack));
679 }
680 
681 FORCEINLINE
682 BOOLEAN
683 MiIsMemoryTypeInvisible(TYPE_OF_MEMORY MemoryType)
684 {
685     return ((MemoryType == LoaderFirmwarePermanent) ||
686             (MemoryType == LoaderSpecialMemory) ||
687             (MemoryType == LoaderHALCachedMemory) ||
688             (MemoryType == LoaderBBTMemory));
689 }
690 
691 #ifdef _M_AMD64
692 FORCEINLINE
693 BOOLEAN
694 MiIsUserPxe(PVOID Address)
695 {
696     return ((ULONG_PTR)Address >> 7) == 0x1FFFFEDF6FB7DA0ULL;
697 }
698 
699 FORCEINLINE
700 BOOLEAN
701 MiIsUserPpe(PVOID Address)
702 {
703     return ((ULONG_PTR)Address >> 16) == 0xFFFFF6FB7DA0ULL;
704 }
705 
706 FORCEINLINE
707 BOOLEAN
708 MiIsUserPde(PVOID Address)
709 {
710     return ((ULONG_PTR)Address >> 25) == 0x7FFFFB7DA0ULL;
711 }
712 
713 FORCEINLINE
714 BOOLEAN
715 MiIsUserPte(PVOID Address)
716 {
717     return ((ULONG_PTR)Address >> 34) == 0x3FFFFDA0ULL;
718 }
719 #else
720 FORCEINLINE
721 BOOLEAN
722 MiIsUserPde(PVOID Address)
723 {
724     return ((Address >= (PVOID)MiAddressToPde(NULL)) &&
725             (Address <= (PVOID)MiHighestUserPde));
726 }
727 
728 FORCEINLINE
729 BOOLEAN
730 MiIsUserPte(PVOID Address)
731 {
732     return (Address >= (PVOID)PTE_BASE) && (Address <= (PVOID)MiHighestUserPte);
733 }
734 #endif
735 
736 //
737 // Figures out the hardware bits for a PTE
738 //
739 FORCEINLINE
740 ULONG_PTR
741 MiDetermineUserGlobalPteMask(IN PVOID PointerPte)
742 {
743     MMPTE TempPte;
744 
745     /* Start fresh */
746     TempPte.u.Long = 0;
747 
748     /* Make it valid and accessed */
749     TempPte.u.Hard.Valid = TRUE;
750     MI_MAKE_ACCESSED_PAGE(&TempPte);
751 
752     /* Is this for user-mode? */
753     if (
754 #if (_MI_PAGING_LEVELS == 4)
755         MiIsUserPxe(PointerPte) ||
756 #endif
757 #if (_MI_PAGING_LEVELS >= 3)
758         MiIsUserPpe(PointerPte) ||
759 #endif
760         MiIsUserPde(PointerPte) ||
761         MiIsUserPte(PointerPte))
762     {
763         /* Set the owner bit */
764         MI_MAKE_OWNER_PAGE(&TempPte);
765     }
766 
767     /* FIXME: We should also set the global bit */
768 
769     /* Return the protection */
770     return TempPte.u.Long;
771 }
772 
773 //
774 // Creates a valid kernel PTE with the given protection
775 //
776 FORCEINLINE
777 VOID
778 MI_MAKE_HARDWARE_PTE_KERNEL(IN PMMPTE NewPte,
779                             IN PMMPTE MappingPte,
780                             IN ULONG_PTR ProtectionMask,
781                             IN PFN_NUMBER PageFrameNumber)
782 {
783     /* Only valid for kernel, non-session PTEs */
784     ASSERT(MappingPte > MiHighestUserPte);
785     ASSERT(!MI_IS_SESSION_PTE(MappingPte));
786     ASSERT((MappingPte < (PMMPTE)PDE_BASE) || (MappingPte > (PMMPTE)PDE_TOP));
787 
788     /* Check that we are not setting valid a page that should not be */
789     ASSERT(ProtectionMask & MM_PROTECT_ACCESS);
790     ASSERT((ProtectionMask & MM_GUARDPAGE) == 0);
791 
792     /* Start fresh */
793     NewPte->u.Long = 0;
794 
795     /* Set the protection and page */
796     NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
797     NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
798 
799     /* Make this valid & global */
800 #ifdef _GLOBAL_PAGES_ARE_AWESOME_
801     if (KeFeatureBits & KF_GLOBAL_PAGE)
802         NewPte->u.Hard.Global = 1;
803 #endif
804     NewPte->u.Hard.Valid = 1;
805 }
806 
807 //
808 // Creates a valid PTE with the given protection
809 //
810 FORCEINLINE
811 VOID
812 MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte,
813                      IN PMMPTE MappingPte,
814                      IN ULONG_PTR ProtectionMask,
815                      IN PFN_NUMBER PageFrameNumber)
816 {
817     /* Check that we are not setting valid a page that should not be */
818     ASSERT(ProtectionMask & MM_PROTECT_ACCESS);
819     ASSERT((ProtectionMask & MM_GUARDPAGE) == 0);
820 
821     /* Set the protection and page */
822     NewPte->u.Long = MiDetermineUserGlobalPteMask(MappingPte);
823     NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
824     NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
825 }
826 
827 //
828 // Creates a valid user PTE with the given protection
829 //
830 FORCEINLINE
831 VOID
832 MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte,
833                           IN PMMPTE MappingPte,
834                           IN ULONG_PTR ProtectionMask,
835                           IN PFN_NUMBER PageFrameNumber)
836 {
837     /* Only valid for kernel, non-session PTEs */
838     ASSERT(MappingPte <= MiHighestUserPte);
839 
840     /* Start fresh */
841     NewPte->u.Long = 0;
842 
843     /* Check that we are not setting valid a page that should not be */
844     ASSERT(ProtectionMask & MM_PROTECT_ACCESS);
845     ASSERT((ProtectionMask & MM_GUARDPAGE) == 0);
846 
847     NewPte->u.Hard.Valid = TRUE;
848     NewPte->u.Hard.Owner = TRUE;
849     NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
850     NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
851 }
852 
853 #ifndef _M_AMD64
854 //
855 // Builds a Prototype PTE for the address of the PTE
856 //
857 FORCEINLINE
858 VOID
859 MI_MAKE_PROTOTYPE_PTE(IN PMMPTE NewPte,
860                       IN PMMPTE PointerPte)
861 {
862     ULONG_PTR Offset;
863 
864     /* Mark this as a prototype */
865     NewPte->u.Long = 0;
866     NewPte->u.Proto.Prototype = 1;
867 
868     /*
869      * Prototype PTEs are only valid in paged pool by design, this little trick
870      * lets us only use 30 bits for the adress of the PTE, as long as the area
871      * stays 1024MB At most.
872      */
873     Offset = (ULONG_PTR)PointerPte - (ULONG_PTR)MmPagedPoolStart;
874 
875     /*
876      * 7 bits go in the "low" (but we assume the bottom 2 are zero)
877      * and the other 21 bits go in the "high"
878      */
879     NewPte->u.Proto.ProtoAddressLow = (Offset & 0x1FC) >> 2;
880     NewPte->u.Proto.ProtoAddressHigh = (Offset & 0x3FFFFE00) >> 9;
881 }
882 
883 //
884 // Builds a Subsection PTE for the address of the Segment
885 //
886 FORCEINLINE
887 VOID
888 MI_MAKE_SUBSECTION_PTE(IN PMMPTE NewPte,
889                        IN PVOID Segment)
890 {
891     ULONG_PTR Offset;
892 
893     /* Mark this as a prototype */
894     NewPte->u.Long = 0;
895     NewPte->u.Subsect.Prototype = 1;
896 
897     /*
898      * Segments are only valid either in nonpaged pool. We store the 20 bit
899      * difference either from the top or bottom of nonpaged pool, giving a
900      * maximum of 128MB to each delta, meaning nonpaged pool cannot exceed
901      * 256MB.
902      */
903     if ((ULONG_PTR)Segment < ((ULONG_PTR)MmSubsectionBase + (128 * _1MB)))
904     {
905         Offset = (ULONG_PTR)Segment - (ULONG_PTR)MmSubsectionBase;
906         NewPte->u.Subsect.WhichPool = PagedPool;
907     }
908     else
909     {
910         Offset = (ULONG_PTR)MmNonPagedPoolEnd - (ULONG_PTR)Segment;
911         NewPte->u.Subsect.WhichPool = NonPagedPool;
912     }
913 
914     /*
915      * 4 bits go in the "low" (but we assume the bottom 3 are zero)
916      * and the other 20 bits go in the "high"
917      */
918     NewPte->u.Subsect.SubsectionAddressLow = (Offset & 0x78) >> 3;
919     NewPte->u.Subsect.SubsectionAddressHigh = (Offset & 0xFFFFF80) >> 7;
920 }
921 
922 FORCEINLINE
923 BOOLEAN
924 MI_IS_MAPPED_PTE(PMMPTE PointerPte)
925 {
926     /// \todo Make this reasonable code, this is UGLY!
927     return ((PointerPte->u.Long & 0xFFFFFC01) != 0);
928 }
929 
930 #endif
931 
932 FORCEINLINE
933 VOID
934 MI_MAKE_TRANSITION_PTE(_Out_ PMMPTE NewPte,
935                        _In_ PFN_NUMBER Page,
936                        _In_ ULONG Protection)
937 {
938     NewPte->u.Long = 0;
939     NewPte->u.Trans.Transition = 1;
940     NewPte->u.Trans.Protection = Protection;
941     NewPte->u.Trans.PageFrameNumber = Page;
942 }
943 
944 //
945 // Returns if the page is physically resident (ie: a large page)
946 // FIXFIX: CISC/x86 only?
947 //
948 FORCEINLINE
949 BOOLEAN
950 MI_IS_PHYSICAL_ADDRESS(IN PVOID Address)
951 {
952     PMMPDE PointerPde;
953 
954     /* Large pages are never paged out, always physically resident */
955     PointerPde = MiAddressToPde(Address);
956     return ((PointerPde->u.Hard.LargePage) && (PointerPde->u.Hard.Valid));
957 }
958 
959 //
960 // Writes a valid PTE
961 //
962 FORCEINLINE
963 VOID
964 MI_WRITE_VALID_PTE(IN PMMPTE PointerPte,
965                    IN MMPTE TempPte)
966 {
967     /* Write the valid PTE */
968     ASSERT(PointerPte->u.Hard.Valid == 0);
969     ASSERT(TempPte.u.Hard.Valid == 1);
970 #if _M_AMD64
971     ASSERT(!MI_IS_PAGE_TABLE_ADDRESS(MiPteToAddress(PointerPte)) ||
972            (TempPte.u.Hard.NoExecute == 0));
973 #endif
974     *PointerPte = TempPte;
975 }
976 
977 //
978 // Updates a valid PTE
979 //
980 FORCEINLINE
981 VOID
982 MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte,
983                    IN MMPTE TempPte)
984 {
985     /* Write the valid PTE */
986     ASSERT(PointerPte->u.Hard.Valid == 1);
987     ASSERT(TempPte.u.Hard.Valid == 1);
988     ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
989     *PointerPte = TempPte;
990 }
991 
992 //
993 // Writes an invalid PTE
994 //
995 FORCEINLINE
996 VOID
997 MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte,
998                      IN MMPTE InvalidPte)
999 {
1000     /* Write the invalid PTE */
1001     ASSERT(InvalidPte.u.Hard.Valid == 0);
1002     ASSERT(InvalidPte.u.Long != 0);
1003     *PointerPte = InvalidPte;
1004 }
1005 
1006 //
1007 // Erase the PTE completely
1008 //
1009 FORCEINLINE
1010 VOID
1011 MI_ERASE_PTE(IN PMMPTE PointerPte)
1012 {
1013     /* Zero out the PTE */
1014     ASSERT(PointerPte->u.Long != 0);
1015     PointerPte->u.Long = 0;
1016 }
1017 
1018 //
1019 // Writes a valid PDE
1020 //
1021 FORCEINLINE
1022 VOID
1023 MI_WRITE_VALID_PDE(IN PMMPDE PointerPde,
1024                    IN MMPDE TempPde)
1025 {
1026     /* Write the valid PDE */
1027     ASSERT(PointerPde->u.Hard.Valid == 0);
1028 #ifdef _M_AMD64
1029     ASSERT(PointerPde->u.Hard.NoExecute == 0);
1030 #endif
1031     ASSERT(TempPde.u.Hard.Valid == 1);
1032     *PointerPde = TempPde;
1033 }
1034 
1035 //
1036 // Writes an invalid PDE
1037 //
1038 FORCEINLINE
1039 VOID
1040 MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde,
1041                      IN MMPDE InvalidPde)
1042 {
1043     /* Write the invalid PDE */
1044     ASSERT(InvalidPde.u.Hard.Valid == 0);
1045     ASSERT(InvalidPde.u.Long != 0);
1046 #ifdef _M_AMD64
1047     ASSERT(InvalidPde.u.Soft.Protection == MM_EXECUTE_READWRITE);
1048 #endif
1049     *PointerPde = InvalidPde;
1050 }
1051 
1052 //
1053 // Checks if the thread already owns a working set
1054 //
1055 FORCEINLINE
1056 BOOLEAN
1057 MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
1058 {
1059     /* If any of these are held, return TRUE */
1060     return ((Thread->OwnsProcessWorkingSetExclusive) ||
1061             (Thread->OwnsProcessWorkingSetShared) ||
1062             (Thread->OwnsSystemWorkingSetExclusive) ||
1063             (Thread->OwnsSystemWorkingSetShared) ||
1064             (Thread->OwnsSessionWorkingSetExclusive) ||
1065             (Thread->OwnsSessionWorkingSetShared));
1066 }
1067 
1068 FORCEINLINE
1069 BOOLEAN
1070 MM_ANY_WS_LOCK_HELD_EXCLUSIVE(_In_ PETHREAD Thread)
1071 {
1072     return ((Thread->OwnsProcessWorkingSetExclusive) ||
1073             (Thread->OwnsSystemWorkingSetExclusive) ||
1074             (Thread->OwnsSessionWorkingSetExclusive));
1075 }
1076 
1077 //
1078 // Checks if the process owns the working set lock
1079 //
1080 FORCEINLINE
1081 BOOLEAN
1082 MI_WS_OWNER(IN PEPROCESS Process)
1083 {
1084     /* Check if this process is the owner, and that the thread owns the WS */
1085     if (PsGetCurrentThread()->OwnsProcessWorkingSetExclusive == 0)
1086     {
1087         DPRINT("Thread: %p is not an owner\n", PsGetCurrentThread());
1088     }
1089     if (KeGetCurrentThread()->ApcState.Process != &Process->Pcb)
1090     {
1091         DPRINT("Current thread %p is attached to another process %p\n", PsGetCurrentThread(), Process);
1092     }
1093     return ((KeGetCurrentThread()->ApcState.Process == &Process->Pcb) &&
1094             ((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) ||
1095              (PsGetCurrentThread()->OwnsProcessWorkingSetShared)));
1096 }
1097 
1098 //
1099 // New ARM3<->RosMM PAGE Architecture
1100 //
1101 FORCEINLINE
1102 BOOLEAN
1103 MiIsRosSectionObject(IN PSECTION Section)
1104 {
1105     return Section->u.Flags.filler;
1106 }
1107 
1108 #define MI_IS_ROS_PFN(x)     ((x)->u4.AweAllocation == TRUE)
1109 
1110 VOID
1111 NTAPI
1112 MiDecrementReferenceCount(
1113     IN PMMPFN Pfn1,
1114     IN PFN_NUMBER PageFrameIndex
1115 );
1116 
1117 FORCEINLINE
1118 BOOLEAN
1119 MI_IS_WS_UNSAFE(IN PEPROCESS Process)
1120 {
1121     return (Process->Vm.Flags.AcquiredUnsafe == TRUE);
1122 }
1123 
1124 //
1125 // Locks the working set for the given process
1126 //
1127 FORCEINLINE
1128 VOID
1129 MiLockProcessWorkingSet(IN PEPROCESS Process,
1130                         IN PETHREAD Thread)
1131 {
1132     /* Shouldn't already be owning the process working set */
1133     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1134     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1135 
1136     /* Block APCs, make sure that still nothing is already held */
1137     KeEnterGuardedRegion();
1138     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1139 
1140     /* Lock the working set */
1141     ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
1142 
1143     /* Now claim that we own the lock */
1144     ASSERT(!MI_IS_WS_UNSAFE(Process));
1145     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1146     Thread->OwnsProcessWorkingSetExclusive = TRUE;
1147 }
1148 
1149 FORCEINLINE
1150 VOID
1151 MiLockProcessWorkingSetShared(IN PEPROCESS Process,
1152                               IN PETHREAD Thread)
1153 {
1154     /* Shouldn't already be owning the process working set */
1155     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1156     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1157 
1158     /* Block APCs, make sure that still nothing is already held */
1159     KeEnterGuardedRegion();
1160     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1161 
1162     /* Lock the working set */
1163     ExAcquirePushLockShared(&Process->Vm.WorkingSetMutex);
1164 
1165     /* Now claim that we own the lock */
1166     ASSERT(!MI_IS_WS_UNSAFE(Process));
1167     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1168     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1169     Thread->OwnsProcessWorkingSetShared = TRUE;
1170 }
1171 
1172 FORCEINLINE
1173 VOID
1174 MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process,
1175                               IN PETHREAD Thread)
1176 {
1177     /* Shouldn't already be owning the process working set */
1178     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1179 
1180     /* APCs must be blocked, make sure that still nothing is already held */
1181     ASSERT(KeAreAllApcsDisabled() == TRUE);
1182     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1183 
1184     /* Lock the working set */
1185     ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
1186 
1187     /* Now claim that we own the lock */
1188     ASSERT(!MI_IS_WS_UNSAFE(Process));
1189     Process->Vm.Flags.AcquiredUnsafe = 1;
1190     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1191     Thread->OwnsProcessWorkingSetExclusive = TRUE;
1192 }
1193 
1194 //
1195 // Unlocks the working set for the given process
1196 //
1197 FORCEINLINE
1198 VOID
1199 MiUnlockProcessWorkingSet(IN PEPROCESS Process,
1200                           IN PETHREAD Thread)
1201 {
1202     /* Make sure we are the owner of a safe acquisition */
1203     ASSERT(MI_WS_OWNER(Process));
1204     ASSERT(!MI_IS_WS_UNSAFE(Process));
1205 
1206     /* The thread doesn't own it anymore */
1207     ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
1208     Thread->OwnsProcessWorkingSetExclusive = FALSE;
1209 
1210     /* Release the lock and re-enable APCs */
1211     ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
1212     KeLeaveGuardedRegion();
1213 }
1214 
1215 //
1216 // Unlocks the working set for the given process
1217 //
1218 FORCEINLINE
1219 VOID
1220 MiUnlockProcessWorkingSetShared(IN PEPROCESS Process,
1221                                 IN PETHREAD Thread)
1222 {
1223     /* Make sure we are the owner of a safe acquisition (because shared) */
1224     ASSERT(MI_WS_OWNER(Process));
1225     ASSERT(!MI_IS_WS_UNSAFE(Process));
1226 
1227     /* Ensure we are in a shared acquisition */
1228     ASSERT(Thread->OwnsProcessWorkingSetShared == TRUE);
1229     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1230 
1231     /* Don't claim the lock anylonger */
1232     Thread->OwnsProcessWorkingSetShared = FALSE;
1233 
1234     /* Release the lock and re-enable APCs */
1235     ExReleasePushLockShared(&Process->Vm.WorkingSetMutex);
1236     KeLeaveGuardedRegion();
1237 }
1238 
1239 //
1240 // Unlocks the working set for the given process
1241 //
1242 FORCEINLINE
1243 VOID
1244 MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process,
1245                                 IN PETHREAD Thread)
1246 {
1247     /* Make sure we are the owner of an unsafe acquisition */
1248     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1249     ASSERT(KeAreAllApcsDisabled() == TRUE);
1250     ASSERT(MI_WS_OWNER(Process));
1251     ASSERT(MI_IS_WS_UNSAFE(Process));
1252 
1253     /* No longer unsafe */
1254     Process->Vm.Flags.AcquiredUnsafe = 0;
1255 
1256     /* The thread doesn't own it anymore */
1257     ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
1258     Thread->OwnsProcessWorkingSetExclusive = FALSE;
1259 
1260     /* Release the lock but don't touch APC state */
1261     ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
1262     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1263 }
1264 
1265 //
1266 // Locks the working set
1267 //
1268 FORCEINLINE
1269 VOID
1270 MiLockWorkingSet(IN PETHREAD Thread,
1271                  IN PMMSUPPORT WorkingSet)
1272 {
1273     /* Block APCs */
1274     KeEnterGuardedRegion();
1275 
1276     /* Working set should be in global memory */
1277     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1278 
1279     /* Thread shouldn't already be owning something */
1280     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1281 
1282     /* Lock this working set */
1283     ExAcquirePushLockExclusive(&WorkingSet->WorkingSetMutex);
1284 
1285     /* Which working set is this? */
1286     if (WorkingSet == &MmSystemCacheWs)
1287     {
1288         /* Own the system working set */
1289         ASSERT((Thread->OwnsSystemWorkingSetExclusive == FALSE) &&
1290                (Thread->OwnsSystemWorkingSetShared == FALSE));
1291         Thread->OwnsSystemWorkingSetExclusive = TRUE;
1292     }
1293     else if (WorkingSet->Flags.SessionSpace)
1294     {
1295         /* Own the session working set */
1296         ASSERT((Thread->OwnsSessionWorkingSetExclusive == FALSE) &&
1297                (Thread->OwnsSessionWorkingSetShared == FALSE));
1298         Thread->OwnsSessionWorkingSetExclusive = TRUE;
1299     }
1300     else
1301     {
1302         /* Own the process working set */
1303         ASSERT((Thread->OwnsProcessWorkingSetExclusive == FALSE) &&
1304                (Thread->OwnsProcessWorkingSetShared == FALSE));
1305         Thread->OwnsProcessWorkingSetExclusive = TRUE;
1306     }
1307 }
1308 
1309 FORCEINLINE
1310 VOID
1311 MiLockWorkingSetShared(
1312     _In_ PETHREAD Thread,
1313     _In_ PMMSUPPORT WorkingSet)
1314 {
1315     /* Block APCs */
1316     KeEnterGuardedRegion();
1317 
1318     /* Working set should be in global memory */
1319     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1320 
1321     /* Thread shouldn't already be owning something */
1322     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1323 
1324     /* Lock this working set */
1325     ExAcquirePushLockShared(&WorkingSet->WorkingSetMutex);
1326 
1327     /* Which working set is this? */
1328     if (WorkingSet == &MmSystemCacheWs)
1329     {
1330         /* Own the system working set */
1331         ASSERT((Thread->OwnsSystemWorkingSetExclusive == FALSE) &&
1332                (Thread->OwnsSystemWorkingSetShared == FALSE));
1333         Thread->OwnsSystemWorkingSetShared = TRUE;
1334     }
1335     else if (WorkingSet->Flags.SessionSpace)
1336     {
1337         /* Own the session working set */
1338         ASSERT((Thread->OwnsSessionWorkingSetExclusive == FALSE) &&
1339                (Thread->OwnsSessionWorkingSetShared == FALSE));
1340         Thread->OwnsSessionWorkingSetShared = TRUE;
1341     }
1342     else
1343     {
1344         /* Own the process working set */
1345         ASSERT((Thread->OwnsProcessWorkingSetExclusive == FALSE) &&
1346                (Thread->OwnsProcessWorkingSetShared == FALSE));
1347         Thread->OwnsProcessWorkingSetShared = TRUE;
1348     }
1349 }
1350 
1351 //
1352 // Unlocks the working set
1353 //
1354 FORCEINLINE
1355 VOID
1356 MiUnlockWorkingSet(IN PETHREAD Thread,
1357                    IN PMMSUPPORT WorkingSet)
1358 {
1359     /* Working set should be in global memory */
1360     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1361 
1362     /* Which working set is this? */
1363     if (WorkingSet == &MmSystemCacheWs)
1364     {
1365         /* Release the system working set */
1366         ASSERT((Thread->OwnsSystemWorkingSetExclusive == TRUE) &&
1367                (Thread->OwnsSystemWorkingSetShared == FALSE));
1368         Thread->OwnsSystemWorkingSetExclusive = FALSE;
1369     }
1370     else if (WorkingSet->Flags.SessionSpace)
1371     {
1372         /* Release the session working set */
1373         ASSERT((Thread->OwnsSessionWorkingSetExclusive == TRUE) &&
1374                (Thread->OwnsSessionWorkingSetShared == FALSE));
1375         Thread->OwnsSessionWorkingSetExclusive = FALSE;
1376     }
1377     else
1378     {
1379         /* Release the process working set */
1380         ASSERT((Thread->OwnsProcessWorkingSetExclusive == TRUE) &&
1381                (Thread->OwnsProcessWorkingSetShared == FALSE));
1382         Thread->OwnsProcessWorkingSetExclusive = FALSE;
1383     }
1384 
1385     /* Release the working set lock */
1386     ExReleasePushLockExclusive(&WorkingSet->WorkingSetMutex);
1387 
1388     /* Unblock APCs */
1389     KeLeaveGuardedRegion();
1390 }
1391 
1392 FORCEINLINE
1393 VOID
1394 MiUnlockWorkingSetShared(
1395     _In_ PETHREAD Thread,
1396     _In_ PMMSUPPORT WorkingSet)
1397 {
1398     /* Working set should be in global memory */
1399     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1400 
1401     /* Which working set is this? */
1402     if (WorkingSet == &MmSystemCacheWs)
1403     {
1404         /* Release the system working set */
1405         ASSERT((Thread->OwnsSystemWorkingSetExclusive == FALSE) &&
1406                (Thread->OwnsSystemWorkingSetShared == TRUE));
1407         Thread->OwnsSystemWorkingSetShared = FALSE;
1408     }
1409     else if (WorkingSet->Flags.SessionSpace)
1410     {
1411         /* Release the session working set */
1412         ASSERT((Thread->OwnsSessionWorkingSetExclusive == FALSE) &&
1413                (Thread->OwnsSessionWorkingSetShared == TRUE));
1414         Thread->OwnsSessionWorkingSetShared = FALSE;
1415     }
1416     else
1417     {
1418         /* Release the process working set */
1419         ASSERT((Thread->OwnsProcessWorkingSetExclusive == FALSE) &&
1420                (Thread->OwnsProcessWorkingSetShared == TRUE));
1421         Thread->OwnsProcessWorkingSetShared = FALSE;
1422     }
1423 
1424     /* Release the working set lock */
1425     ExReleasePushLockShared(&WorkingSet->WorkingSetMutex);
1426 
1427     /* Unblock APCs */
1428     KeLeaveGuardedRegion();
1429 }
1430 
1431 FORCEINLINE
1432 BOOLEAN
1433 MiConvertSharedWorkingSetLockToExclusive(
1434     _In_ PETHREAD Thread,
1435     _In_ PMMSUPPORT Vm)
1436 {
1437     /* Sanity check: No exclusive lock. */
1438     ASSERT(!Thread->OwnsProcessWorkingSetExclusive);
1439     ASSERT(!Thread->OwnsSessionWorkingSetExclusive);
1440     ASSERT(!Thread->OwnsSystemWorkingSetExclusive);
1441 
1442     /* And it should have one and only one shared lock */
1443     ASSERT((Thread->OwnsProcessWorkingSetShared + Thread->OwnsSessionWorkingSetShared + Thread->OwnsSystemWorkingSetShared) == 1);
1444 
1445     /* Try. */
1446     if (!ExConvertPushLockSharedToExclusive(&Vm->WorkingSetMutex))
1447         return FALSE;
1448 
1449     if (Vm == &MmSystemCacheWs)
1450     {
1451         ASSERT(Thread->OwnsSystemWorkingSetShared);
1452         Thread->OwnsSystemWorkingSetShared = FALSE;
1453         Thread->OwnsSystemWorkingSetExclusive = TRUE;
1454     }
1455     else if (Vm->Flags.SessionSpace)
1456     {
1457         ASSERT(Thread->OwnsSessionWorkingSetShared);
1458         Thread->OwnsSessionWorkingSetShared = FALSE;
1459         Thread->OwnsSessionWorkingSetExclusive = TRUE;
1460     }
1461     else
1462     {
1463         ASSERT(Thread->OwnsProcessWorkingSetShared);
1464         Thread->OwnsProcessWorkingSetShared = FALSE;
1465         Thread->OwnsProcessWorkingSetExclusive = TRUE;
1466     }
1467 
1468     return TRUE;
1469 }
1470 
1471 FORCEINLINE
1472 VOID
1473 MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process,
1474                                   IN PETHREAD Thread,
1475                                   OUT PBOOLEAN Safe,
1476                                   OUT PBOOLEAN Shared)
1477 {
1478     ASSERT(MI_WS_OWNER(Process));
1479 
1480     /* Check if the current owner is unsafe */
1481     if (MI_IS_WS_UNSAFE(Process))
1482     {
1483         /* Release unsafely */
1484         MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1485         *Safe = FALSE;
1486         *Shared = FALSE;
1487     }
1488     else if (Thread->OwnsProcessWorkingSetExclusive == 1)
1489     {
1490         /* Owner is safe and exclusive, release normally */
1491         MiUnlockProcessWorkingSet(Process, Thread);
1492         *Safe = TRUE;
1493         *Shared = FALSE;
1494     }
1495     else
1496     {
1497         /* Owner is shared (implies safe), release normally */
1498         MiUnlockProcessWorkingSetShared(Process, Thread);
1499         *Safe = TRUE;
1500         *Shared = TRUE;
1501     }
1502 }
1503 
1504 FORCEINLINE
1505 VOID
1506 MiLockProcessWorkingSetForFault(IN PEPROCESS Process,
1507                                 IN PETHREAD Thread,
1508                                 IN BOOLEAN Safe,
1509                                 IN BOOLEAN Shared)
1510 {
1511     /* Check if this was a safe lock or not */
1512     if (Safe)
1513     {
1514         if (Shared)
1515         {
1516             /* Reacquire safely & shared */
1517             MiLockProcessWorkingSetShared(Process, Thread);
1518         }
1519         else
1520         {
1521             /* Reacquire safely */
1522             MiLockProcessWorkingSet(Process, Thread);
1523         }
1524     }
1525     else
1526     {
1527         /* Unsafe lock cannot be shared */
1528         ASSERT(Shared == FALSE);
1529         /* Reacquire unsafely */
1530         MiLockProcessWorkingSetUnsafe(Process, Thread);
1531     }
1532 }
1533 
1534 FORCEINLINE
1535 KIRQL
1536 MiAcquireExpansionLock(VOID)
1537 {
1538     KIRQL OldIrql;
1539 
1540     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1541     KeAcquireSpinLock(&MmExpansionLock, &OldIrql);
1542     ASSERT(MiExpansionLockOwner == NULL);
1543     MiExpansionLockOwner = PsGetCurrentThread();
1544     return OldIrql;
1545 }
1546 
1547 FORCEINLINE
1548 VOID
1549 MiReleaseExpansionLock(KIRQL OldIrql)
1550 {
1551     ASSERT(MiExpansionLockOwner == PsGetCurrentThread());
1552     MiExpansionLockOwner = NULL;
1553     KeReleaseSpinLock(&MmExpansionLock, OldIrql);
1554     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1555 }
1556 
1557 //
1558 // Returns the ProtoPTE inside a VAD for the given VPN
1559 //
1560 FORCEINLINE
1561 PMMPTE
1562 MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad,
1563                              IN ULONG_PTR Vpn)
1564 {
1565     PMMPTE ProtoPte;
1566 
1567     /* Find the offset within the VAD's prototype PTEs */
1568     ProtoPte = Vad->FirstPrototypePte + (Vpn - Vad->StartingVpn);
1569     ASSERT(ProtoPte <= Vad->LastContiguousPte);
1570     return ProtoPte;
1571 }
1572 
1573 //
1574 // Returns the PFN Database entry for the given page number
1575 // Warning: This is not necessarily a valid PFN database entry!
1576 //
1577 FORCEINLINE
1578 PMMPFN
1579 MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
1580 {
1581     /* Get the entry */
1582     return &MmPfnDatabase[Pfn];
1583 };
1584 
1585 //
1586 // Drops a locked page without dereferencing it
1587 //
1588 FORCEINLINE
1589 VOID
1590 MiDropLockCount(IN PMMPFN Pfn1)
1591 {
1592     /* This page shouldn't be locked, but it should be valid */
1593     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1594     ASSERT(Pfn1->u2.ShareCount == 0);
1595 
1596     /* Is this the last reference to the page */
1597     if (Pfn1->u3.e2.ReferenceCount == 1)
1598     {
1599         /* It better not be valid */
1600         ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1601 
1602         /* Is it a prototype PTE? */
1603         if ((Pfn1->u3.e1.PrototypePte == 1) &&
1604             (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1605         {
1606             /* FIXME: We should return commit */
1607             DPRINT1("Not returning commit for prototype PTE\n");
1608         }
1609 
1610         /* Update the counter */
1611         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1612     }
1613 }
1614 
1615 //
1616 // Drops a locked page and dereferences it
1617 //
1618 FORCEINLINE
1619 VOID
1620 MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
1621 {
1622     USHORT RefCount, OldRefCount;
1623     PFN_NUMBER PageFrameIndex;
1624 
1625     /* Loop while we decrement the page successfully */
1626     do
1627     {
1628         /* There should be at least one reference */
1629         OldRefCount = Pfn1->u3.e2.ReferenceCount;
1630         ASSERT(OldRefCount != 0);
1631 
1632         /* Are we the last one */
1633         if (OldRefCount == 1)
1634         {
1635             /* The page shoudln't be shared not active at this point */
1636             ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
1637             ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1638             ASSERT(Pfn1->u2.ShareCount == 0);
1639 
1640             /* Is it a prototype PTE? */
1641             if ((Pfn1->u3.e1.PrototypePte == 1) &&
1642                 (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1643             {
1644                 /* FIXME: We should return commit */
1645                 DPRINT1("Not returning commit for prototype PTE\n");
1646             }
1647 
1648             /* Update the counter, and drop a reference the long way */
1649             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1650             PageFrameIndex = MiGetPfnEntryIndex(Pfn1);
1651             MiDecrementReferenceCount(Pfn1, PageFrameIndex);
1652             return;
1653         }
1654 
1655         /* Drop a reference the short way, and that's it */
1656         RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
1657                                                 OldRefCount - 1,
1658                                                 OldRefCount);
1659         ASSERT(RefCount != 0);
1660     } while (OldRefCount != RefCount);
1661 
1662     /* If we got here, there should be more than one reference */
1663     ASSERT(RefCount > 1);
1664     if (RefCount == 2)
1665     {
1666         /* Is it still being shared? */
1667         if (Pfn1->u2.ShareCount >= 1)
1668         {
1669             /* Then it should be valid */
1670             ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1671 
1672             /* Is it a prototype PTE? */
1673             if ((Pfn1->u3.e1.PrototypePte == 1) &&
1674                 (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1675             {
1676                 /* We don't handle ethis */
1677                 ASSERT(FALSE);
1678             }
1679 
1680             /* Update the counter */
1681             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1682         }
1683     }
1684 }
1685 
1686 //
1687 // References a locked page and updates the counter
1688 // Used in MmProbeAndLockPages to handle different edge cases
1689 //
1690 FORCEINLINE
1691 VOID
1692 MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
1693 {
1694     USHORT RefCount, OldRefCount;
1695 
1696     /* Sanity check */
1697     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1698 
1699     /* Does ARM3 own the page? */
1700     if (MI_IS_ROS_PFN(Pfn1))
1701     {
1702         /* ReactOS Mm doesn't track share count */
1703         ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1704     }
1705     else
1706     {
1707         /* On ARM3 pages, we should see a valid share count */
1708         ASSERT((Pfn1->u2.ShareCount != 0) && (Pfn1->u3.e1.PageLocation == ActiveAndValid));
1709 
1710         /* Is it a prototype PTE? */
1711         if ((Pfn1->u3.e1.PrototypePte == 1) &&
1712             (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1713         {
1714             /* FIXME: We should charge commit */
1715             DPRINT1("Not charging commit for prototype PTE\n");
1716         }
1717     }
1718 
1719     /* More locked pages! */
1720     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1721 
1722     /* Loop trying to update the reference count */
1723     do
1724     {
1725         /* Get the current reference count, make sure it's valid */
1726         OldRefCount = Pfn1->u3.e2.ReferenceCount;
1727         ASSERT(OldRefCount != 0);
1728         ASSERT(OldRefCount < 2500);
1729 
1730         /* Bump it up by one */
1731         RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
1732                                                 OldRefCount + 1,
1733                                                 OldRefCount);
1734         ASSERT(RefCount != 0);
1735     } while (OldRefCount != RefCount);
1736 
1737     /* Was this the first lock attempt? If not, undo our bump */
1738     if (OldRefCount != 1) InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1739 }
1740 
1741 //
1742 // References a locked page and updates the counter
1743 // Used in all other cases except MmProbeAndLockPages
1744 //
1745 FORCEINLINE
1746 VOID
1747 MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1)
1748 {
1749     USHORT NewRefCount;
1750 
1751     /* Is it a prototype PTE? */
1752     if ((Pfn1->u3.e1.PrototypePte == 1) &&
1753         (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1754     {
1755         /* FIXME: We should charge commit */
1756         DPRINT1("Not charging commit for prototype PTE\n");
1757     }
1758 
1759     /* More locked pages! */
1760     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1761 
1762     /* Update the reference count */
1763     NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1764     if (NewRefCount == 2)
1765     {
1766         /* Is it locked or shared? */
1767         if (Pfn1->u2.ShareCount)
1768         {
1769             /* It's shared, so make sure it's active */
1770             ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1771         }
1772         else
1773         {
1774             /* It's locked, so we shouldn't lock again */
1775             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1776         }
1777     }
1778     else
1779     {
1780         /* Someone had already locked the page, so undo our bump */
1781         ASSERT(NewRefCount < 2500);
1782         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1783     }
1784 }
1785 
1786 //
1787 // References a locked page and updates the counter
1788 // Used in all other cases except MmProbeAndLockPages
1789 //
1790 FORCEINLINE
1791 VOID
1792 MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
1793 {
1794     USHORT NewRefCount;
1795 
1796     /* Make sure the page isn't used yet */
1797     ASSERT(Pfn1->u2.ShareCount == 0);
1798     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1799 
1800     /* Is it a prototype PTE? */
1801     if ((Pfn1->u3.e1.PrototypePte == 1) &&
1802         (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1803     {
1804         /* FIXME: We should charge commit */
1805         DPRINT1("Not charging commit for prototype PTE\n");
1806     }
1807 
1808     /* More locked pages! */
1809     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1810 
1811     /* Update the reference count */
1812     NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1813     if (NewRefCount != 1)
1814     {
1815         /* Someone had already locked the page, so undo our bump */
1816         ASSERT(NewRefCount < 2500);
1817         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1818     }
1819 }
1820 
1821 
1822 
1823 CODE_SEG("INIT")
1824 BOOLEAN
1825 NTAPI
1826 MmArmInitSystem(
1827     IN ULONG Phase,
1828     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1829 );
1830 
1831 CODE_SEG("INIT")
1832 VOID
1833 NTAPI
1834 MiInitializeSessionSpaceLayout(VOID);
1835 
1836 CODE_SEG("INIT")
1837 NTSTATUS
1838 NTAPI
1839 MiInitMachineDependent(
1840     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1841 );
1842 
1843 CODE_SEG("INIT")
1844 VOID
1845 NTAPI
1846 MiComputeColorInformation(
1847     VOID
1848 );
1849 
1850 CODE_SEG("INIT")
1851 VOID
1852 NTAPI
1853 MiMapPfnDatabase(
1854     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1855 );
1856 
1857 CODE_SEG("INIT")
1858 VOID
1859 NTAPI
1860 MiInitializeColorTables(
1861     VOID
1862 );
1863 
1864 CODE_SEG("INIT")
1865 VOID
1866 NTAPI
1867 MiInitializePfnDatabase(
1868     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1869 );
1870 
1871 VOID
1872 NTAPI
1873 MiInitializeSessionWsSupport(
1874     VOID
1875 );
1876 
1877 VOID
1878 NTAPI
1879 MiInitializeSessionIds(
1880     VOID
1881 );
1882 
1883 CODE_SEG("INIT")
1884 BOOLEAN
1885 NTAPI
1886 MiInitializeMemoryEvents(
1887     VOID
1888 );
1889 
1890 CODE_SEG("INIT")
1891 PFN_NUMBER
1892 NTAPI
1893 MxGetNextPage(
1894     IN PFN_NUMBER PageCount
1895 );
1896 
1897 CODE_SEG("INIT")
1898 PPHYSICAL_MEMORY_DESCRIPTOR
1899 NTAPI
1900 MmInitializeMemoryLimits(
1901     IN PLOADER_PARAMETER_BLOCK LoaderBlock,
1902     IN PBOOLEAN IncludeType
1903 );
1904 
1905 PFN_NUMBER
1906 NTAPI
1907 MiPagesInLoaderBlock(
1908     IN PLOADER_PARAMETER_BLOCK LoaderBlock,
1909     IN PBOOLEAN IncludeType
1910 );
1911 
1912 VOID
1913 FASTCALL
1914 MiSyncARM3WithROS(
1915     IN PVOID AddressStart,
1916     IN PVOID AddressEnd
1917 );
1918 
1919 NTSTATUS
1920 NTAPI
1921 MiRosProtectVirtualMemory(
1922     IN PEPROCESS Process,
1923     IN OUT PVOID *BaseAddress,
1924     IN OUT PSIZE_T NumberOfBytesToProtect,
1925     IN ULONG NewAccessProtection,
1926     OUT PULONG OldAccessProtection OPTIONAL
1927 );
1928 
1929 NTSTATUS
1930 NTAPI
1931 MmArmAccessFault(
1932     IN ULONG FaultCode,
1933     IN PVOID Address,
1934     IN KPROCESSOR_MODE Mode,
1935     IN PVOID TrapInformation
1936 );
1937 
1938 NTSTATUS
1939 FASTCALL
1940 MiCheckPdeForPagedPool(
1941     IN PVOID Address
1942 );
1943 
1944 CODE_SEG("INIT")
1945 VOID
1946 NTAPI
1947 MiInitializeNonPagedPoolThresholds(
1948     VOID
1949 );
1950 
1951 CODE_SEG("INIT")
1952 VOID
1953 NTAPI
1954 MiInitializePoolEvents(
1955     VOID
1956 );
1957 
1958 CODE_SEG("INIT")
1959 VOID                      //
1960 NTAPI                     //
1961 InitializePool(           //
1962     IN POOL_TYPE PoolType,// FIXFIX: This should go in ex.h after the pool merge
1963     IN ULONG Threshold    //
1964 );                        //
1965 
1966 // FIXFIX: THIS ONE TOO
1967 CODE_SEG("INIT")
1968 VOID
1969 NTAPI
1970 ExInitializePoolDescriptor(
1971     IN PPOOL_DESCRIPTOR PoolDescriptor,
1972     IN POOL_TYPE PoolType,
1973     IN ULONG PoolIndex,
1974     IN ULONG Threshold,
1975     IN PVOID PoolLock
1976 );
1977 
1978 NTSTATUS
1979 NTAPI
1980 MiInitializeSessionPool(
1981     VOID
1982 );
1983 
1984 CODE_SEG("INIT")
1985 VOID
1986 NTAPI
1987 MiInitializeSystemPtes(
1988     IN PMMPTE StartingPte,
1989     IN ULONG NumberOfPtes,
1990     IN MMSYSTEM_PTE_POOL_TYPE PoolType
1991 );
1992 
1993 PMMPTE
1994 NTAPI
1995 MiReserveSystemPtes(
1996     IN ULONG NumberOfPtes,
1997     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
1998 );
1999 
2000 VOID
2001 NTAPI
2002 MiReleaseSystemPtes(
2003     IN PMMPTE StartingPte,
2004     IN ULONG NumberOfPtes,
2005     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
2006 );
2007 
2008 
2009 PFN_NUMBER
2010 NTAPI
2011 MiFindContiguousPages(
2012     IN PFN_NUMBER LowestPfn,
2013     IN PFN_NUMBER HighestPfn,
2014     IN PFN_NUMBER BoundaryPfn,
2015     IN PFN_NUMBER SizeInPages,
2016     IN MEMORY_CACHING_TYPE CacheType
2017 );
2018 
2019 PVOID
2020 NTAPI
2021 MiCheckForContiguousMemory(
2022     IN PVOID BaseAddress,
2023     IN PFN_NUMBER BaseAddressPages,
2024     IN PFN_NUMBER SizeInPages,
2025     IN PFN_NUMBER LowestPfn,
2026     IN PFN_NUMBER HighestPfn,
2027     IN PFN_NUMBER BoundaryPfn,
2028     IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
2029 );
2030 
2031 PMDL
2032 NTAPI
2033 MiAllocatePagesForMdl(
2034     IN PHYSICAL_ADDRESS LowAddress,
2035     IN PHYSICAL_ADDRESS HighAddress,
2036     IN PHYSICAL_ADDRESS SkipBytes,
2037     IN SIZE_T TotalBytes,
2038     IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute,
2039     IN ULONG Flags
2040 );
2041 
2042 VOID
2043 NTAPI
2044 MiInsertPageInList(
2045     IN PMMPFNLIST ListHead,
2046     IN PFN_NUMBER PageFrameIndex
2047 );
2048 
2049 VOID
2050 NTAPI
2051 MiUnlinkFreeOrZeroedPage(
2052     IN PMMPFN Entry
2053 );
2054 
2055 VOID
2056 NTAPI
2057 MiUnlinkPageFromList(
2058     IN PMMPFN Pfn
2059 );
2060 
2061 VOID
2062 NTAPI
2063 MiInitializePfn(
2064     IN PFN_NUMBER PageFrameIndex,
2065     IN PMMPTE PointerPte,
2066     IN BOOLEAN Modified
2067 );
2068 
2069 NTSTATUS
2070 NTAPI
2071 MiInitializeAndChargePfn(
2072     OUT PPFN_NUMBER PageFrameIndex,
2073     IN PMMPDE PointerPde,
2074     IN PFN_NUMBER ContainingPageFrame,
2075     IN BOOLEAN SessionAllocation
2076 );
2077 
2078 VOID
2079 NTAPI
2080 MiInitializePfnAndMakePteValid(
2081     IN PFN_NUMBER PageFrameIndex,
2082     IN PMMPTE PointerPte,
2083     IN MMPTE TempPte
2084 );
2085 
2086 VOID
2087 NTAPI
2088 MiInitializePfnForOtherProcess(
2089     IN PFN_NUMBER PageFrameIndex,
2090     IN PVOID PteAddress,
2091     IN PFN_NUMBER PteFrame
2092 );
2093 
2094 VOID
2095 NTAPI
2096 MiDecrementShareCount(
2097     IN PMMPFN Pfn1,
2098     IN PFN_NUMBER PageFrameIndex
2099 );
2100 
2101 PFN_NUMBER
2102 NTAPI
2103 MiRemoveAnyPage(
2104     IN ULONG Color
2105 );
2106 
2107 PFN_NUMBER
2108 NTAPI
2109 MiRemoveZeroPage(
2110     IN ULONG Color
2111 );
2112 
2113 VOID
2114 NTAPI
2115 MiZeroPhysicalPage(
2116     IN PFN_NUMBER PageFrameIndex
2117 );
2118 
2119 VOID
2120 NTAPI
2121 MiInsertPageInFreeList(
2122     IN PFN_NUMBER PageFrameIndex
2123 );
2124 
2125 PFN_COUNT
2126 NTAPI
2127 MiDeleteSystemPageableVm(
2128     IN PMMPTE PointerPte,
2129     IN PFN_NUMBER PageCount,
2130     IN ULONG Flags,
2131     OUT PPFN_NUMBER ValidPages
2132 );
2133 
2134 ULONG
2135 NTAPI
2136 MiGetPageProtection(
2137     IN PMMPTE PointerPte
2138 );
2139 
2140 PLDR_DATA_TABLE_ENTRY
2141 NTAPI
2142 MiLookupDataTableEntry(
2143     IN PVOID Address
2144 );
2145 
2146 CODE_SEG("INIT")
2147 VOID
2148 NTAPI
2149 MiInitializeDriverLargePageList(
2150     VOID
2151 );
2152 
2153 CODE_SEG("INIT")
2154 VOID
2155 NTAPI
2156 MiInitializeLargePageSupport(
2157     VOID
2158 );
2159 
2160 CODE_SEG("INIT")
2161 VOID
2162 NTAPI
2163 MiSyncCachedRanges(
2164     VOID
2165 );
2166 
2167 BOOLEAN
2168 NTAPI
2169 MiIsPfnInUse(
2170     IN PMMPFN Pfn1
2171 );
2172 
2173 PMMVAD
2174 NTAPI
2175 MiLocateAddress(
2176     IN PVOID VirtualAddress
2177 );
2178 
2179 TABLE_SEARCH_RESULT
2180 NTAPI
2181 MiCheckForConflictingNode(
2182     IN ULONG_PTR StartVpn,
2183     IN ULONG_PTR EndVpn,
2184     IN PMM_AVL_TABLE Table,
2185     OUT PMMADDRESS_NODE *NodeOrParent
2186 );
2187 
2188 TABLE_SEARCH_RESULT
2189 NTAPI
2190 MiFindEmptyAddressRangeDownTree(
2191     IN SIZE_T Length,
2192     IN ULONG_PTR BoundaryAddress,
2193     IN ULONG_PTR Alignment,
2194     IN PMM_AVL_TABLE Table,
2195     OUT PULONG_PTR Base,
2196     OUT PMMADDRESS_NODE *Parent
2197 );
2198 
2199 NTSTATUS
2200 NTAPI
2201 MiFindEmptyAddressRangeDownBasedTree(
2202     IN SIZE_T Length,
2203     IN ULONG_PTR BoundaryAddress,
2204     IN ULONG_PTR Alignment,
2205     IN PMM_AVL_TABLE Table,
2206     OUT PULONG_PTR Base
2207 );
2208 
2209 TABLE_SEARCH_RESULT
2210 NTAPI
2211 MiFindEmptyAddressRangeInTree(
2212     IN SIZE_T Length,
2213     IN ULONG_PTR Alignment,
2214     IN PMM_AVL_TABLE Table,
2215     OUT PMMADDRESS_NODE *PreviousVad,
2216     OUT PULONG_PTR Base
2217 );
2218 
2219 NTSTATUS
2220 NTAPI
2221 MiCheckSecuredVad(
2222     IN PMMVAD Vad,
2223     IN PVOID Base,
2224     IN SIZE_T Size,
2225     IN ULONG ProtectionMask
2226 );
2227 
2228 VOID
2229 NTAPI
2230 MiInsertVad(
2231     _Inout_ PMMVAD Vad,
2232     _Inout_ PMM_AVL_TABLE VadRoot);
2233 
2234 NTSTATUS
2235 NTAPI
2236 MiInsertVadEx(
2237     _Inout_ PMMVAD Vad,
2238     _In_ ULONG_PTR *BaseAddress,
2239     _In_ SIZE_T ViewSize,
2240     _In_ ULONG_PTR HighestAddress,
2241     _In_ ULONG_PTR Alignment,
2242     _In_ ULONG AllocationType);
2243 
2244 VOID
2245 NTAPI
2246 MiInsertBasedSection(
2247     IN PSECTION Section
2248 );
2249 
2250 NTSTATUS
2251 NTAPI
2252 MiUnmapViewOfSection(
2253     IN PEPROCESS Process,
2254     IN PVOID BaseAddress,
2255     IN ULONG Flags
2256 );
2257 
2258 NTSTATUS
2259 NTAPI
2260 MiRosUnmapViewOfSection(
2261     IN PEPROCESS Process,
2262     IN PVOID BaseAddress,
2263     IN BOOLEAN SkipDebuggerNotify
2264 );
2265 
2266 VOID
2267 NTAPI
2268 MiInsertNode(
2269     IN PMM_AVL_TABLE Table,
2270     IN PMMADDRESS_NODE NewNode,
2271     PMMADDRESS_NODE Parent,
2272     TABLE_SEARCH_RESULT Result
2273 );
2274 
2275 VOID
2276 NTAPI
2277 MiRemoveNode(
2278     IN PMMADDRESS_NODE Node,
2279     IN PMM_AVL_TABLE Table
2280 );
2281 
2282 PMMADDRESS_NODE
2283 NTAPI
2284 MiGetPreviousNode(
2285     IN PMMADDRESS_NODE Node
2286 );
2287 
2288 PMMADDRESS_NODE
2289 NTAPI
2290 MiGetNextNode(
2291     IN PMMADDRESS_NODE Node
2292 );
2293 
2294 BOOLEAN
2295 NTAPI
2296 MiInitializeSystemSpaceMap(
2297     IN PMMSESSION InputSession OPTIONAL
2298 );
2299 
2300 VOID
2301 NTAPI
2302 MiSessionRemoveProcess(
2303     VOID
2304 );
2305 
2306 VOID
2307 NTAPI
2308 MiReleaseProcessReferenceToSessionDataPage(
2309     IN PMM_SESSION_SPACE SessionGlobal
2310 );
2311 
2312 VOID
2313 NTAPI
2314 MiSessionAddProcess(
2315     IN PEPROCESS NewProcess
2316 );
2317 
2318 NTSTATUS
2319 NTAPI
2320 MiSessionCommitPageTables(
2321     IN PVOID StartVa,
2322     IN PVOID EndVa
2323 );
2324 
2325 ULONG
2326 NTAPI
2327 MiMakeProtectionMask(
2328     IN ULONG Protect
2329 );
2330 
2331 VOID
2332 NTAPI
2333 MiDeleteVirtualAddresses(
2334     IN ULONG_PTR Va,
2335     IN ULONG_PTR EndingAddress,
2336     IN PMMVAD Vad
2337 );
2338 
2339 VOID
2340 NTAPI
2341 MiDeletePte(
2342     IN PMMPTE PointerPte,
2343     IN PVOID VirtualAddress,
2344     IN PEPROCESS CurrentProcess,
2345     IN PMMPTE PrototypePte
2346 );
2347 
2348 ULONG
2349 NTAPI
2350 MiMakeSystemAddressValid(
2351     IN PVOID PageTableVirtualAddress,
2352     IN PEPROCESS CurrentProcess
2353 );
2354 
2355 ULONG
2356 NTAPI
2357 MiMakeSystemAddressValidPfn(
2358     IN PVOID VirtualAddress,
2359     IN KIRQL OldIrql
2360 );
2361 
2362 VOID
2363 NTAPI
2364 MiRemoveMappedView(
2365     IN PEPROCESS CurrentProcess,
2366     IN PMMVAD Vad
2367 );
2368 
2369 PSUBSECTION
2370 NTAPI
2371 MiLocateSubsection(
2372     IN PMMVAD Vad,
2373     IN ULONG_PTR Vpn
2374 );
2375 
2376 VOID
2377 NTAPI
2378 MiDeleteARM3Section(
2379     PVOID ObjectBody
2380 );
2381 
2382 NTSTATUS
2383 NTAPI
2384 MiQueryMemorySectionName(
2385     IN HANDLE ProcessHandle,
2386     IN PVOID BaseAddress,
2387     OUT PVOID MemoryInformation,
2388     IN SIZE_T MemoryInformationLength,
2389     OUT PSIZE_T ReturnLength
2390 );
2391 
2392 NTSTATUS
2393 NTAPI
2394 MiRosUnmapViewInSystemSpace(
2395     IN PVOID MappedBase
2396 );
2397 
2398 VOID
2399 NTAPI
2400 MiMakePdeExistAndMakeValid(
2401     IN PMMPDE PointerPde,
2402     IN PEPROCESS TargetProcess,
2403     IN KIRQL OldIrql
2404 );
2405 
2406 VOID
2407 NTAPI
2408 MiWriteProtectSystemImage(
2409     _In_ PVOID ImageBase);
2410 
2411 //
2412 // MiRemoveZeroPage will use inline code to zero out the page manually if only
2413 // free pages are available. In some scenarios, we don't/can't run that piece of
2414 // code and would rather only have a real zero page. If we can't have a zero page,
2415 // then we'd like to have our own code to grab a free page and zero it out, by
2416 // using MiRemoveAnyPage. This macro implements this.
2417 //
2418 FORCEINLINE
2419 PFN_NUMBER
2420 MiRemoveZeroPageSafe(IN ULONG Color)
2421 {
2422     if (MmFreePagesByColor[ZeroedPageList][Color].Flink != LIST_HEAD) return MiRemoveZeroPage(Color);
2423     return 0;
2424 }
2425 
2426 #if (_MI_PAGING_LEVELS == 2)
2427 FORCEINLINE
2428 BOOLEAN
2429 MiSynchronizeSystemPde(PMMPDE PointerPde)
2430 {
2431     MMPDE SystemPde;
2432     ULONG Index;
2433 
2434     /* Get the Index from the PDE */
2435     Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE);
2436 
2437     /* Copy the PDE from the double-mapped system page directory */
2438     SystemPde = MmSystemPagePtes[Index];
2439     *PointerPde = SystemPde;
2440 
2441     /* Make sure we re-read the PDE and PTE */
2442     KeMemoryBarrierWithoutFence();
2443 
2444     /* Return, if we had success */
2445     return SystemPde.u.Hard.Valid != 0;
2446 }
2447 #endif
2448 
2449 #if _MI_PAGING_LEVELS == 2
2450 FORCEINLINE
2451 USHORT
2452 MiIncrementPageTableReferences(IN PVOID Address)
2453 {
2454     PUSHORT RefCount;
2455 
2456     RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
2457 
2458     *RefCount += 1;
2459     ASSERT(*RefCount <= PTE_PER_PAGE);
2460     return *RefCount;
2461 }
2462 
2463 FORCEINLINE
2464 USHORT
2465 MiDecrementPageTableReferences(IN PVOID Address)
2466 {
2467     PUSHORT RefCount;
2468 
2469     RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
2470 
2471     *RefCount -= 1;
2472     ASSERT(*RefCount < PTE_PER_PAGE);
2473     return *RefCount;
2474 }
2475 #else
2476 FORCEINLINE
2477 USHORT
2478 MiIncrementPageTableReferences(IN PVOID Address)
2479 {
2480     PMMPDE PointerPde = MiAddressToPde(Address);
2481     PMMPFN Pfn;
2482 
2483     /* We should not tinker with this one. */
2484     ASSERT(PointerPde != (PMMPDE)PXE_SELFMAP);
2485     DPRINT("Incrementing %p from %p\n", Address, _ReturnAddress());
2486 
2487     /* Make sure we're locked */
2488     ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive);
2489 
2490     /* If we're bumping refcount, then it must be valid! */
2491     ASSERT(PointerPde->u.Hard.Valid == 1);
2492 
2493     /* This lies on the PFN */
2494     Pfn = MiGetPfnEntry(PFN_FROM_PDE(PointerPde));
2495     Pfn->OriginalPte.u.Soft.UsedPageTableEntries++;
2496 
2497     ASSERT(Pfn->OriginalPte.u.Soft.UsedPageTableEntries <= PTE_PER_PAGE);
2498 
2499     return Pfn->OriginalPte.u.Soft.UsedPageTableEntries;
2500 }
2501 
2502 FORCEINLINE
2503 USHORT
2504 MiDecrementPageTableReferences(IN PVOID Address)
2505 {
2506     PMMPDE PointerPde = MiAddressToPde(Address);
2507     PMMPFN Pfn;
2508 
2509     /* We should not tinker with this one. */
2510     ASSERT(PointerPde != (PMMPDE)PXE_SELFMAP);
2511 
2512     DPRINT("Decrementing %p from %p\n", PointerPde, _ReturnAddress());
2513 
2514     /* Make sure we're locked */
2515     ASSERT(PsGetCurrentThread()->OwnsProcessWorkingSetExclusive);
2516 
2517     /* If we're decreasing refcount, then it must be valid! */
2518     ASSERT(PointerPde->u.Hard.Valid == 1);
2519 
2520     /* This lies on the PFN */
2521     Pfn = MiGetPfnEntry(PFN_FROM_PDE(PointerPde));
2522 
2523     ASSERT(Pfn->OriginalPte.u.Soft.UsedPageTableEntries != 0);
2524     Pfn->OriginalPte.u.Soft.UsedPageTableEntries--;
2525 
2526     ASSERT(Pfn->OriginalPte.u.Soft.UsedPageTableEntries < PTE_PER_PAGE);
2527 
2528     return Pfn->OriginalPte.u.Soft.UsedPageTableEntries;
2529 }
2530 #endif
2531 
2532 #ifdef __cplusplus
2533 } // extern "C"
2534 #endif
2535 
2536 FORCEINLINE
2537 VOID
2538 MiDeletePde(
2539     _In_ PMMPDE PointerPde,
2540     _In_ PEPROCESS CurrentProcess)
2541 {
2542     /* Only for user-mode ones */
2543     ASSERT(MiIsUserPde(PointerPde));
2544 
2545     /* Kill this one as a PTE */
2546     MiDeletePte((PMMPTE)PointerPde, MiPdeToPte(PointerPde), CurrentProcess, NULL);
2547 #if _MI_PAGING_LEVELS >= 3
2548     /* Cascade down */
2549     if (MiDecrementPageTableReferences(MiPdeToPte(PointerPde)) == 0)
2550     {
2551         MiDeletePte(MiPdeToPpe(PointerPde), PointerPde, CurrentProcess, NULL);
2552 #if _MI_PAGING_LEVELS == 4
2553         if (MiDecrementPageTableReferences(PointerPde) == 0)
2554         {
2555             MiDeletePte(MiPdeToPxe(PointerPde), MiPdeToPpe(PointerPde), CurrentProcess, NULL);
2556         }
2557 #endif
2558     }
2559 #endif
2560 }
2561 
2562 /* EOF */
2563