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