xref: /reactos/ntoskrnl/mm/ARM3/miarm.h (revision 92dfec21)
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     *PointerPte = TempPte;
949 }
950 
951 //
952 // Updates a valid PTE
953 //
954 FORCEINLINE
955 VOID
956 MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte,
957                    IN MMPTE TempPte)
958 {
959     /* Write the valid PTE */
960     ASSERT(PointerPte->u.Hard.Valid == 1);
961     ASSERT(TempPte.u.Hard.Valid == 1);
962     ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
963     *PointerPte = TempPte;
964 }
965 
966 //
967 // Writes an invalid PTE
968 //
969 FORCEINLINE
970 VOID
971 MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte,
972                      IN MMPTE InvalidPte)
973 {
974     /* Write the invalid PTE */
975     ASSERT(InvalidPte.u.Hard.Valid == 0);
976     ASSERT(InvalidPte.u.Long != 0);
977     *PointerPte = InvalidPte;
978 }
979 
980 //
981 // Erase the PTE completely
982 //
983 FORCEINLINE
984 VOID
985 MI_ERASE_PTE(IN PMMPTE PointerPte)
986 {
987     /* Zero out the PTE */
988     ASSERT(PointerPte->u.Long != 0);
989     PointerPte->u.Long = 0;
990 }
991 
992 //
993 // Writes a valid PDE
994 //
995 FORCEINLINE
996 VOID
997 MI_WRITE_VALID_PDE(IN PMMPDE PointerPde,
998                    IN MMPDE TempPde)
999 {
1000     /* Write the valid PDE */
1001     ASSERT(PointerPde->u.Hard.Valid == 0);
1002     ASSERT(TempPde.u.Hard.Valid == 1);
1003     *PointerPde = TempPde;
1004 }
1005 
1006 //
1007 // Writes an invalid PDE
1008 //
1009 FORCEINLINE
1010 VOID
1011 MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde,
1012                      IN MMPDE InvalidPde)
1013 {
1014     /* Write the invalid PDE */
1015     ASSERT(InvalidPde.u.Hard.Valid == 0);
1016     ASSERT(InvalidPde.u.Long != 0);
1017     *PointerPde = InvalidPde;
1018 }
1019 
1020 //
1021 // Checks if the thread already owns a working set
1022 //
1023 FORCEINLINE
1024 BOOLEAN
1025 MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
1026 {
1027     /* If any of these are held, return TRUE */
1028     return ((Thread->OwnsProcessWorkingSetExclusive) ||
1029             (Thread->OwnsProcessWorkingSetShared) ||
1030             (Thread->OwnsSystemWorkingSetExclusive) ||
1031             (Thread->OwnsSystemWorkingSetShared) ||
1032             (Thread->OwnsSessionWorkingSetExclusive) ||
1033             (Thread->OwnsSessionWorkingSetShared));
1034 }
1035 
1036 //
1037 // Checks if the process owns the working set lock
1038 //
1039 FORCEINLINE
1040 BOOLEAN
1041 MI_WS_OWNER(IN PEPROCESS Process)
1042 {
1043     /* Check if this process is the owner, and that the thread owns the WS */
1044     if (PsGetCurrentThread()->OwnsProcessWorkingSetExclusive == 0)
1045     {
1046         DPRINT("Thread: %p is not an owner\n", PsGetCurrentThread());
1047     }
1048     if (KeGetCurrentThread()->ApcState.Process != &Process->Pcb)
1049     {
1050         DPRINT("Current thread %p is attached to another process %p\n", PsGetCurrentThread(), Process);
1051     }
1052     return ((KeGetCurrentThread()->ApcState.Process == &Process->Pcb) &&
1053             ((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive) ||
1054              (PsGetCurrentThread()->OwnsProcessWorkingSetShared)));
1055 }
1056 
1057 //
1058 // New ARM3<->RosMM PAGE Architecture
1059 //
1060 FORCEINLINE
1061 BOOLEAN
1062 MiIsRosSectionObject(IN PVOID Section)
1063 {
1064     PROS_SECTION_OBJECT RosSection = Section;
1065     if ((RosSection->Type == 'SC') && (RosSection->Size == 'TN')) return TRUE;
1066     return FALSE;
1067 }
1068 
1069 #define MI_IS_ROS_PFN(x)     ((x)->u4.AweAllocation == TRUE)
1070 
1071 VOID
1072 NTAPI
1073 MiDecrementReferenceCount(
1074     IN PMMPFN Pfn1,
1075     IN PFN_NUMBER PageFrameIndex
1076 );
1077 
1078 FORCEINLINE
1079 BOOLEAN
1080 MI_IS_WS_UNSAFE(IN PEPROCESS Process)
1081 {
1082     return (Process->Vm.Flags.AcquiredUnsafe == TRUE);
1083 }
1084 
1085 //
1086 // Locks the working set for the given process
1087 //
1088 FORCEINLINE
1089 VOID
1090 MiLockProcessWorkingSet(IN PEPROCESS Process,
1091                         IN PETHREAD Thread)
1092 {
1093     /* Shouldn't already be owning the process working set */
1094     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1095     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1096 
1097     /* Block APCs, make sure that still nothing is already held */
1098     KeEnterGuardedRegion();
1099     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1100 
1101     /* Lock the working set */
1102     ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
1103 
1104     /* Now claim that we own the lock */
1105     ASSERT(!MI_IS_WS_UNSAFE(Process));
1106     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1107     Thread->OwnsProcessWorkingSetExclusive = TRUE;
1108 }
1109 
1110 FORCEINLINE
1111 VOID
1112 MiLockProcessWorkingSetShared(IN PEPROCESS Process,
1113                               IN PETHREAD Thread)
1114 {
1115     /* Shouldn't already be owning the process working set */
1116     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1117     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1118 
1119     /* Block APCs, make sure that still nothing is already held */
1120     KeEnterGuardedRegion();
1121     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1122 
1123     /* Lock the working set */
1124     ExAcquirePushLockShared(&Process->Vm.WorkingSetMutex);
1125 
1126     /* Now claim that we own the lock */
1127     ASSERT(!MI_IS_WS_UNSAFE(Process));
1128     ASSERT(Thread->OwnsProcessWorkingSetShared == FALSE);
1129     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1130     Thread->OwnsProcessWorkingSetShared = TRUE;
1131 }
1132 
1133 FORCEINLINE
1134 VOID
1135 MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process,
1136                               IN PETHREAD Thread)
1137 {
1138     /* Shouldn't already be owning the process working set */
1139     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1140 
1141     /* APCs must be blocked, make sure that still nothing is already held */
1142     ASSERT(KeAreAllApcsDisabled() == TRUE);
1143     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1144 
1145     /* Lock the working set */
1146     ExAcquirePushLockExclusive(&Process->Vm.WorkingSetMutex);
1147 
1148     /* Now claim that we own the lock */
1149     ASSERT(!MI_IS_WS_UNSAFE(Process));
1150     Process->Vm.Flags.AcquiredUnsafe = 1;
1151     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1152     Thread->OwnsProcessWorkingSetExclusive = TRUE;
1153 }
1154 
1155 //
1156 // Unlocks the working set for the given process
1157 //
1158 FORCEINLINE
1159 VOID
1160 MiUnlockProcessWorkingSet(IN PEPROCESS Process,
1161                           IN PETHREAD Thread)
1162 {
1163     /* Make sure we are the owner of a safe acquisition */
1164     ASSERT(MI_WS_OWNER(Process));
1165     ASSERT(!MI_IS_WS_UNSAFE(Process));
1166 
1167     /* The thread doesn't own it anymore */
1168     ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
1169     Thread->OwnsProcessWorkingSetExclusive = FALSE;
1170 
1171     /* Release the lock and re-enable APCs */
1172     ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
1173     KeLeaveGuardedRegion();
1174 }
1175 
1176 //
1177 // Unlocks the working set for the given process
1178 //
1179 FORCEINLINE
1180 VOID
1181 MiUnlockProcessWorkingSetShared(IN PEPROCESS Process,
1182                                 IN PETHREAD Thread)
1183 {
1184     /* Make sure we are the owner of a safe acquisition (because shared) */
1185     ASSERT(MI_WS_OWNER(Process));
1186     ASSERT(!MI_IS_WS_UNSAFE(Process));
1187 
1188     /* Ensure we are in a shared acquisition */
1189     ASSERT(Thread->OwnsProcessWorkingSetShared == TRUE);
1190     ASSERT(Thread->OwnsProcessWorkingSetExclusive == FALSE);
1191 
1192     /* Don't claim the lock anylonger */
1193     Thread->OwnsProcessWorkingSetShared = FALSE;
1194 
1195     /* Release the lock and re-enable APCs */
1196     ExReleasePushLockShared(&Process->Vm.WorkingSetMutex);
1197     KeLeaveGuardedRegion();
1198 }
1199 
1200 //
1201 // Unlocks the working set for the given process
1202 //
1203 FORCEINLINE
1204 VOID
1205 MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process,
1206                                 IN PETHREAD Thread)
1207 {
1208     /* Make sure we are the owner of an unsafe acquisition */
1209     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1210     ASSERT(KeAreAllApcsDisabled() == TRUE);
1211     ASSERT(MI_WS_OWNER(Process));
1212     ASSERT(MI_IS_WS_UNSAFE(Process));
1213 
1214     /* No longer unsafe */
1215     Process->Vm.Flags.AcquiredUnsafe = 0;
1216 
1217     /* The thread doesn't own it anymore */
1218     ASSERT(Thread->OwnsProcessWorkingSetExclusive == TRUE);
1219     Thread->OwnsProcessWorkingSetExclusive = FALSE;
1220 
1221     /* Release the lock but don't touch APC state */
1222     ExReleasePushLockExclusive(&Process->Vm.WorkingSetMutex);
1223     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1224 }
1225 
1226 //
1227 // Locks the working set
1228 //
1229 FORCEINLINE
1230 VOID
1231 MiLockWorkingSet(IN PETHREAD Thread,
1232                  IN PMMSUPPORT WorkingSet)
1233 {
1234     /* Block APCs */
1235     KeEnterGuardedRegion();
1236 
1237     /* Working set should be in global memory */
1238     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1239 
1240     /* Thread shouldn't already be owning something */
1241     ASSERT(!MM_ANY_WS_LOCK_HELD(Thread));
1242 
1243     /* Lock this working set */
1244     ExAcquirePushLockExclusive(&WorkingSet->WorkingSetMutex);
1245 
1246     /* Which working set is this? */
1247     if (WorkingSet == &MmSystemCacheWs)
1248     {
1249         /* Own the system working set */
1250         ASSERT((Thread->OwnsSystemWorkingSetExclusive == FALSE) &&
1251                (Thread->OwnsSystemWorkingSetShared == FALSE));
1252         Thread->OwnsSystemWorkingSetExclusive = TRUE;
1253     }
1254     else if (WorkingSet->Flags.SessionSpace)
1255     {
1256         /* Own the session working set */
1257         ASSERT((Thread->OwnsSessionWorkingSetExclusive == FALSE) &&
1258                (Thread->OwnsSessionWorkingSetShared == FALSE));
1259         Thread->OwnsSessionWorkingSetExclusive = TRUE;
1260     }
1261     else
1262     {
1263         /* Own the process working set */
1264         ASSERT((Thread->OwnsProcessWorkingSetExclusive == FALSE) &&
1265                (Thread->OwnsProcessWorkingSetShared == FALSE));
1266         Thread->OwnsProcessWorkingSetExclusive = TRUE;
1267     }
1268 }
1269 
1270 //
1271 // Unlocks the working set
1272 //
1273 FORCEINLINE
1274 VOID
1275 MiUnlockWorkingSet(IN PETHREAD Thread,
1276                    IN PMMSUPPORT WorkingSet)
1277 {
1278     /* Working set should be in global memory */
1279     ASSERT(MI_IS_SESSION_ADDRESS((PVOID)WorkingSet) == FALSE);
1280 
1281     /* Which working set is this? */
1282     if (WorkingSet == &MmSystemCacheWs)
1283     {
1284         /* Release the system working set */
1285         ASSERT((Thread->OwnsSystemWorkingSetExclusive == TRUE) ||
1286                (Thread->OwnsSystemWorkingSetShared == TRUE));
1287         Thread->OwnsSystemWorkingSetExclusive = FALSE;
1288     }
1289     else if (WorkingSet->Flags.SessionSpace)
1290     {
1291         /* Release the session working set */
1292         ASSERT((Thread->OwnsSessionWorkingSetExclusive == TRUE) ||
1293                (Thread->OwnsSessionWorkingSetShared == TRUE));
1294         Thread->OwnsSessionWorkingSetExclusive = 0;
1295     }
1296     else
1297     {
1298         /* Release the process working set */
1299         ASSERT((Thread->OwnsProcessWorkingSetExclusive) ||
1300                (Thread->OwnsProcessWorkingSetShared));
1301         Thread->OwnsProcessWorkingSetExclusive = FALSE;
1302     }
1303 
1304     /* Release the working set lock */
1305     ExReleasePushLockExclusive(&WorkingSet->WorkingSetMutex);
1306 
1307     /* Unblock APCs */
1308     KeLeaveGuardedRegion();
1309 }
1310 
1311 FORCEINLINE
1312 VOID
1313 MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process,
1314                                   IN PETHREAD Thread,
1315                                   OUT PBOOLEAN Safe,
1316                                   OUT PBOOLEAN Shared)
1317 {
1318     ASSERT(MI_WS_OWNER(Process));
1319 
1320     /* Check if the current owner is unsafe */
1321     if (MI_IS_WS_UNSAFE(Process))
1322     {
1323         /* Release unsafely */
1324         MiUnlockProcessWorkingSetUnsafe(Process, Thread);
1325         *Safe = FALSE;
1326         *Shared = FALSE;
1327     }
1328     else if (Thread->OwnsProcessWorkingSetExclusive == 1)
1329     {
1330         /* Owner is safe and exclusive, release normally */
1331         MiUnlockProcessWorkingSet(Process, Thread);
1332         *Safe = TRUE;
1333         *Shared = FALSE;
1334     }
1335     else
1336     {
1337         /* Owner is shared (implies safe), release normally */
1338         MiUnlockProcessWorkingSetShared(Process, Thread);
1339         *Safe = TRUE;
1340         *Shared = TRUE;
1341     }
1342 }
1343 
1344 FORCEINLINE
1345 VOID
1346 MiLockProcessWorkingSetForFault(IN PEPROCESS Process,
1347                                 IN PETHREAD Thread,
1348                                 IN BOOLEAN Safe,
1349                                 IN BOOLEAN Shared)
1350 {
1351     /* Check if this was a safe lock or not */
1352     if (Safe)
1353     {
1354         if (Shared)
1355         {
1356             /* Reacquire safely & shared */
1357             MiLockProcessWorkingSetShared(Process, Thread);
1358         }
1359         else
1360         {
1361             /* Reacquire safely */
1362             MiLockProcessWorkingSet(Process, Thread);
1363         }
1364     }
1365     else
1366     {
1367         /* Unsafe lock cannot be shared */
1368         ASSERT(Shared == FALSE);
1369         /* Reacquire unsafely */
1370         MiLockProcessWorkingSetUnsafe(Process, Thread);
1371     }
1372 }
1373 
1374 FORCEINLINE
1375 KIRQL
1376 MiAcquireExpansionLock(VOID)
1377 {
1378     KIRQL OldIrql;
1379 
1380     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1381     KeAcquireSpinLock(&MmExpansionLock, &OldIrql);
1382     ASSERT(MiExpansionLockOwner == NULL);
1383     MiExpansionLockOwner = PsGetCurrentThread();
1384     return OldIrql;
1385 }
1386 
1387 FORCEINLINE
1388 VOID
1389 MiReleaseExpansionLock(KIRQL OldIrql)
1390 {
1391     ASSERT(MiExpansionLockOwner == PsGetCurrentThread());
1392     MiExpansionLockOwner = NULL;
1393     KeReleaseSpinLock(&MmExpansionLock, OldIrql);
1394     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1395 }
1396 
1397 //
1398 // Returns the ProtoPTE inside a VAD for the given VPN
1399 //
1400 FORCEINLINE
1401 PMMPTE
1402 MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad,
1403                              IN ULONG_PTR Vpn)
1404 {
1405     PMMPTE ProtoPte;
1406 
1407     /* Find the offset within the VAD's prototype PTEs */
1408     ProtoPte = Vad->FirstPrototypePte + (Vpn - Vad->StartingVpn);
1409     ASSERT(ProtoPte <= Vad->LastContiguousPte);
1410     return ProtoPte;
1411 }
1412 
1413 //
1414 // Returns the PFN Database entry for the given page number
1415 // Warning: This is not necessarily a valid PFN database entry!
1416 //
1417 FORCEINLINE
1418 PMMPFN
1419 MI_PFN_ELEMENT(IN PFN_NUMBER Pfn)
1420 {
1421     /* Get the entry */
1422     return &MmPfnDatabase[Pfn];
1423 };
1424 
1425 //
1426 // Drops a locked page without dereferencing it
1427 //
1428 FORCEINLINE
1429 VOID
1430 MiDropLockCount(IN PMMPFN Pfn1)
1431 {
1432     /* This page shouldn't be locked, but it should be valid */
1433     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1434     ASSERT(Pfn1->u2.ShareCount == 0);
1435 
1436     /* Is this the last reference to the page */
1437     if (Pfn1->u3.e2.ReferenceCount == 1)
1438     {
1439         /* It better not be valid */
1440         ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1441 
1442         /* Is it a prototype PTE? */
1443         if ((Pfn1->u3.e1.PrototypePte == 1) &&
1444             (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1445         {
1446             /* FIXME: We should return commit */
1447             DPRINT1("Not returning commit for prototype PTE\n");
1448         }
1449 
1450         /* Update the counter */
1451         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1452     }
1453 }
1454 
1455 //
1456 // Drops a locked page and dereferences it
1457 //
1458 FORCEINLINE
1459 VOID
1460 MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1)
1461 {
1462     USHORT RefCount, OldRefCount;
1463     PFN_NUMBER PageFrameIndex;
1464 
1465     /* Loop while we decrement the page successfully */
1466     do
1467     {
1468         /* There should be at least one reference */
1469         OldRefCount = Pfn1->u3.e2.ReferenceCount;
1470         ASSERT(OldRefCount != 0);
1471 
1472         /* Are we the last one */
1473         if (OldRefCount == 1)
1474         {
1475             /* The page shoudln't be shared not active at this point */
1476             ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
1477             ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1478             ASSERT(Pfn1->u2.ShareCount == 0);
1479 
1480             /* Is it a prototype PTE? */
1481             if ((Pfn1->u3.e1.PrototypePte == 1) &&
1482                 (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1483             {
1484                 /* FIXME: We should return commit */
1485                 DPRINT1("Not returning commit for prototype PTE\n");
1486             }
1487 
1488             /* Update the counter, and drop a reference the long way */
1489             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1490             PageFrameIndex = MiGetPfnEntryIndex(Pfn1);
1491             MiDecrementReferenceCount(Pfn1, PageFrameIndex);
1492             return;
1493         }
1494 
1495         /* Drop a reference the short way, and that's it */
1496         RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
1497                                                 OldRefCount - 1,
1498                                                 OldRefCount);
1499         ASSERT(RefCount != 0);
1500     } while (OldRefCount != RefCount);
1501 
1502     /* If we got here, there should be more than one reference */
1503     ASSERT(RefCount > 1);
1504     if (RefCount == 2)
1505     {
1506         /* Is it still being shared? */
1507         if (Pfn1->u2.ShareCount >= 1)
1508         {
1509             /* Then it should be valid */
1510             ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1511 
1512             /* Is it a prototype PTE? */
1513             if ((Pfn1->u3.e1.PrototypePte == 1) &&
1514                 (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1515             {
1516                 /* We don't handle ethis */
1517                 ASSERT(FALSE);
1518             }
1519 
1520             /* Update the counter */
1521             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1522         }
1523     }
1524 }
1525 
1526 //
1527 // References a locked page and updates the counter
1528 // Used in MmProbeAndLockPages to handle different edge cases
1529 //
1530 FORCEINLINE
1531 VOID
1532 MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1)
1533 {
1534     USHORT RefCount, OldRefCount;
1535 
1536     /* Sanity check */
1537     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1538 
1539     /* Does ARM3 own the page? */
1540     if (MI_IS_ROS_PFN(Pfn1))
1541     {
1542         /* ReactOS Mm doesn't track share count */
1543         ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1544     }
1545     else
1546     {
1547         /* On ARM3 pages, we should see a valid share count */
1548         ASSERT((Pfn1->u2.ShareCount != 0) && (Pfn1->u3.e1.PageLocation == ActiveAndValid));
1549 
1550         /* Is it a prototype PTE? */
1551         if ((Pfn1->u3.e1.PrototypePte == 1) &&
1552             (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1553         {
1554             /* FIXME: We should charge commit */
1555             DPRINT1("Not charging commit for prototype PTE\n");
1556         }
1557     }
1558 
1559     /* More locked pages! */
1560     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1561 
1562     /* Loop trying to update the reference count */
1563     do
1564     {
1565         /* Get the current reference count, make sure it's valid */
1566         OldRefCount = Pfn1->u3.e2.ReferenceCount;
1567         ASSERT(OldRefCount != 0);
1568         ASSERT(OldRefCount < 2500);
1569 
1570         /* Bump it up by one */
1571         RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
1572                                                 OldRefCount + 1,
1573                                                 OldRefCount);
1574         ASSERT(RefCount != 0);
1575     } while (OldRefCount != RefCount);
1576 
1577     /* Was this the first lock attempt? If not, undo our bump */
1578     if (OldRefCount != 1) InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1579 }
1580 
1581 //
1582 // References a locked page and updates the counter
1583 // Used in all other cases except MmProbeAndLockPages
1584 //
1585 FORCEINLINE
1586 VOID
1587 MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1)
1588 {
1589     USHORT NewRefCount;
1590 
1591     /* Is it a prototype PTE? */
1592     if ((Pfn1->u3.e1.PrototypePte == 1) &&
1593         (Pfn1->OriginalPte.u.Soft.Prototype == 1))
1594     {
1595         /* FIXME: We should charge commit */
1596         DPRINT1("Not charging commit for prototype PTE\n");
1597     }
1598 
1599     /* More locked pages! */
1600     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1601 
1602     /* Update the reference count */
1603     NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1604     if (NewRefCount == 2)
1605     {
1606         /* Is it locked or shared? */
1607         if (Pfn1->u2.ShareCount)
1608         {
1609             /* It's shared, so make sure it's active */
1610             ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
1611         }
1612         else
1613         {
1614             /* It's locked, so we shouldn't lock again */
1615             InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1616         }
1617     }
1618     else
1619     {
1620         /* Someone had already locked the page, so undo our bump */
1621         ASSERT(NewRefCount < 2500);
1622         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1623     }
1624 }
1625 
1626 //
1627 // References a locked page and updates the counter
1628 // Used in all other cases except MmProbeAndLockPages
1629 //
1630 FORCEINLINE
1631 VOID
1632 MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
1633 {
1634     USHORT NewRefCount;
1635 
1636     /* Make sure the page isn't used yet */
1637     ASSERT(Pfn1->u2.ShareCount == 0);
1638     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
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 charge commit */
1645         DPRINT1("Not charging commit for prototype PTE\n");
1646     }
1647 
1648     /* More locked pages! */
1649     InterlockedIncrementSizeT(&MmSystemLockPagesCount);
1650 
1651     /* Update the reference count */
1652     NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1653     if (NewRefCount != 1)
1654     {
1655         /* Someone had already locked the page, so undo our bump */
1656         ASSERT(NewRefCount < 2500);
1657         InterlockedDecrementSizeT(&MmSystemLockPagesCount);
1658     }
1659 }
1660 
1661 FORCEINLINE
1662 VOID
1663 MiIncrementPageTableReferences(IN PVOID Address)
1664 {
1665     PUSHORT RefCount;
1666 
1667     RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
1668 
1669     *RefCount += 1;
1670     ASSERT(*RefCount <= PTE_PER_PAGE);
1671 }
1672 
1673 FORCEINLINE
1674 VOID
1675 MiDecrementPageTableReferences(IN PVOID Address)
1676 {
1677     PUSHORT RefCount;
1678 
1679     RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
1680 
1681     *RefCount -= 1;
1682     ASSERT(*RefCount < PTE_PER_PAGE);
1683 }
1684 
1685 FORCEINLINE
1686 USHORT
1687 MiQueryPageTableReferences(IN PVOID Address)
1688 {
1689     PUSHORT RefCount;
1690 
1691     RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
1692 
1693     return *RefCount;
1694 }
1695 
1696 INIT_FUNCTION
1697 BOOLEAN
1698 NTAPI
1699 MmArmInitSystem(
1700     IN ULONG Phase,
1701     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1702 );
1703 
1704 INIT_FUNCTION
1705 VOID
1706 NTAPI
1707 MiInitializeSessionSpaceLayout(VOID);
1708 
1709 INIT_FUNCTION
1710 NTSTATUS
1711 NTAPI
1712 MiInitMachineDependent(
1713     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1714 );
1715 
1716 INIT_FUNCTION
1717 VOID
1718 NTAPI
1719 MiComputeColorInformation(
1720     VOID
1721 );
1722 
1723 INIT_FUNCTION
1724 VOID
1725 NTAPI
1726 MiMapPfnDatabase(
1727     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1728 );
1729 
1730 INIT_FUNCTION
1731 VOID
1732 NTAPI
1733 MiInitializeColorTables(
1734     VOID
1735 );
1736 
1737 INIT_FUNCTION
1738 VOID
1739 NTAPI
1740 MiInitializePfnDatabase(
1741     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1742 );
1743 
1744 VOID
1745 NTAPI
1746 MiInitializeSessionWsSupport(
1747     VOID
1748 );
1749 
1750 VOID
1751 NTAPI
1752 MiInitializeSessionIds(
1753     VOID
1754 );
1755 
1756 INIT_FUNCTION
1757 BOOLEAN
1758 NTAPI
1759 MiInitializeMemoryEvents(
1760     VOID
1761 );
1762 
1763 INIT_FUNCTION
1764 PFN_NUMBER
1765 NTAPI
1766 MxGetNextPage(
1767     IN PFN_NUMBER PageCount
1768 );
1769 
1770 INIT_FUNCTION
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 INIT_FUNCTION
1818 VOID
1819 NTAPI
1820 MiInitializeNonPagedPool(
1821     VOID
1822 );
1823 
1824 INIT_FUNCTION
1825 VOID
1826 NTAPI
1827 MiInitializeNonPagedPoolThresholds(
1828     VOID
1829 );
1830 
1831 INIT_FUNCTION
1832 VOID
1833 NTAPI
1834 MiInitializePoolEvents(
1835     VOID
1836 );
1837 
1838 INIT_FUNCTION
1839 VOID                      //
1840 NTAPI                     //
1841 InitializePool(           //
1842     IN POOL_TYPE PoolType,// FIXFIX: This should go in ex.h after the pool merge
1843     IN ULONG Threshold    //
1844 );                        //
1845 
1846 // FIXFIX: THIS ONE TOO
1847 INIT_FUNCTION
1848 VOID
1849 NTAPI
1850 ExInitializePoolDescriptor(
1851     IN PPOOL_DESCRIPTOR PoolDescriptor,
1852     IN POOL_TYPE PoolType,
1853     IN ULONG PoolIndex,
1854     IN ULONG Threshold,
1855     IN PVOID PoolLock
1856 );
1857 
1858 NTSTATUS
1859 NTAPI
1860 MiInitializeSessionPool(
1861     VOID
1862 );
1863 
1864 INIT_FUNCTION
1865 VOID
1866 NTAPI
1867 MiInitializeSystemPtes(
1868     IN PMMPTE StartingPte,
1869     IN ULONG NumberOfPtes,
1870     IN MMSYSTEM_PTE_POOL_TYPE PoolType
1871 );
1872 
1873 PMMPTE
1874 NTAPI
1875 MiReserveSystemPtes(
1876     IN ULONG NumberOfPtes,
1877     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
1878 );
1879 
1880 VOID
1881 NTAPI
1882 MiReleaseSystemPtes(
1883     IN PMMPTE StartingPte,
1884     IN ULONG NumberOfPtes,
1885     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
1886 );
1887 
1888 
1889 PFN_NUMBER
1890 NTAPI
1891 MiFindContiguousPages(
1892     IN PFN_NUMBER LowestPfn,
1893     IN PFN_NUMBER HighestPfn,
1894     IN PFN_NUMBER BoundaryPfn,
1895     IN PFN_NUMBER SizeInPages,
1896     IN MEMORY_CACHING_TYPE CacheType
1897 );
1898 
1899 PVOID
1900 NTAPI
1901 MiCheckForContiguousMemory(
1902     IN PVOID BaseAddress,
1903     IN PFN_NUMBER BaseAddressPages,
1904     IN PFN_NUMBER SizeInPages,
1905     IN PFN_NUMBER LowestPfn,
1906     IN PFN_NUMBER HighestPfn,
1907     IN PFN_NUMBER BoundaryPfn,
1908     IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
1909 );
1910 
1911 PMDL
1912 NTAPI
1913 MiAllocatePagesForMdl(
1914     IN PHYSICAL_ADDRESS LowAddress,
1915     IN PHYSICAL_ADDRESS HighAddress,
1916     IN PHYSICAL_ADDRESS SkipBytes,
1917     IN SIZE_T TotalBytes,
1918     IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute,
1919     IN ULONG Flags
1920 );
1921 
1922 VOID
1923 NTAPI
1924 MiInsertPageInList(
1925     IN PMMPFNLIST ListHead,
1926     IN PFN_NUMBER PageFrameIndex
1927 );
1928 
1929 VOID
1930 NTAPI
1931 MiUnlinkFreeOrZeroedPage(
1932     IN PMMPFN Entry
1933 );
1934 
1935 VOID
1936 NTAPI
1937 MiUnlinkPageFromList(
1938     IN PMMPFN Pfn
1939 );
1940 
1941 VOID
1942 NTAPI
1943 MiInitializePfn(
1944     IN PFN_NUMBER PageFrameIndex,
1945     IN PMMPTE PointerPte,
1946     IN BOOLEAN Modified
1947 );
1948 
1949 NTSTATUS
1950 NTAPI
1951 MiInitializeAndChargePfn(
1952     OUT PPFN_NUMBER PageFrameIndex,
1953     IN PMMPDE PointerPde,
1954     IN PFN_NUMBER ContainingPageFrame,
1955     IN BOOLEAN SessionAllocation
1956 );
1957 
1958 VOID
1959 NTAPI
1960 MiInitializePfnAndMakePteValid(
1961     IN PFN_NUMBER PageFrameIndex,
1962     IN PMMPTE PointerPte,
1963     IN MMPTE TempPte
1964 );
1965 
1966 VOID
1967 NTAPI
1968 MiInitializePfnForOtherProcess(
1969     IN PFN_NUMBER PageFrameIndex,
1970     IN PVOID PteAddress,
1971     IN PFN_NUMBER PteFrame
1972 );
1973 
1974 VOID
1975 NTAPI
1976 MiDecrementShareCount(
1977     IN PMMPFN Pfn1,
1978     IN PFN_NUMBER PageFrameIndex
1979 );
1980 
1981 PFN_NUMBER
1982 NTAPI
1983 MiRemoveAnyPage(
1984     IN ULONG Color
1985 );
1986 
1987 PFN_NUMBER
1988 NTAPI
1989 MiRemoveZeroPage(
1990     IN ULONG Color
1991 );
1992 
1993 VOID
1994 NTAPI
1995 MiZeroPhysicalPage(
1996     IN PFN_NUMBER PageFrameIndex
1997 );
1998 
1999 VOID
2000 NTAPI
2001 MiInsertPageInFreeList(
2002     IN PFN_NUMBER PageFrameIndex
2003 );
2004 
2005 PFN_COUNT
2006 NTAPI
2007 MiDeleteSystemPageableVm(
2008     IN PMMPTE PointerPte,
2009     IN PFN_NUMBER PageCount,
2010     IN ULONG Flags,
2011     OUT PPFN_NUMBER ValidPages
2012 );
2013 
2014 ULONG
2015 NTAPI
2016 MiGetPageProtection(
2017     IN PMMPTE PointerPte
2018 );
2019 
2020 PLDR_DATA_TABLE_ENTRY
2021 NTAPI
2022 MiLookupDataTableEntry(
2023     IN PVOID Address
2024 );
2025 
2026 INIT_FUNCTION
2027 VOID
2028 NTAPI
2029 MiInitializeDriverLargePageList(
2030     VOID
2031 );
2032 
2033 INIT_FUNCTION
2034 VOID
2035 NTAPI
2036 MiInitializeLargePageSupport(
2037     VOID
2038 );
2039 
2040 INIT_FUNCTION
2041 VOID
2042 NTAPI
2043 MiSyncCachedRanges(
2044     VOID
2045 );
2046 
2047 BOOLEAN
2048 NTAPI
2049 MiIsPfnInUse(
2050     IN PMMPFN Pfn1
2051 );
2052 
2053 PMMVAD
2054 NTAPI
2055 MiLocateAddress(
2056     IN PVOID VirtualAddress
2057 );
2058 
2059 TABLE_SEARCH_RESULT
2060 NTAPI
2061 MiCheckForConflictingNode(
2062     IN ULONG_PTR StartVpn,
2063     IN ULONG_PTR EndVpn,
2064     IN PMM_AVL_TABLE Table,
2065     OUT PMMADDRESS_NODE *NodeOrParent
2066 );
2067 
2068 TABLE_SEARCH_RESULT
2069 NTAPI
2070 MiFindEmptyAddressRangeDownTree(
2071     IN SIZE_T Length,
2072     IN ULONG_PTR BoundaryAddress,
2073     IN ULONG_PTR Alignment,
2074     IN PMM_AVL_TABLE Table,
2075     OUT PULONG_PTR Base,
2076     OUT PMMADDRESS_NODE *Parent
2077 );
2078 
2079 NTSTATUS
2080 NTAPI
2081 MiFindEmptyAddressRangeDownBasedTree(
2082     IN SIZE_T Length,
2083     IN ULONG_PTR BoundaryAddress,
2084     IN ULONG_PTR Alignment,
2085     IN PMM_AVL_TABLE Table,
2086     OUT PULONG_PTR Base
2087 );
2088 
2089 TABLE_SEARCH_RESULT
2090 NTAPI
2091 MiFindEmptyAddressRangeInTree(
2092     IN SIZE_T Length,
2093     IN ULONG_PTR Alignment,
2094     IN PMM_AVL_TABLE Table,
2095     OUT PMMADDRESS_NODE *PreviousVad,
2096     OUT PULONG_PTR Base
2097 );
2098 
2099 NTSTATUS
2100 NTAPI
2101 MiCheckSecuredVad(
2102     IN PMMVAD Vad,
2103     IN PVOID Base,
2104     IN SIZE_T Size,
2105     IN ULONG ProtectionMask
2106 );
2107 
2108 VOID
2109 NTAPI
2110 MiInsertVad(
2111     _Inout_ PMMVAD Vad,
2112     _Inout_ PMM_AVL_TABLE VadRoot);
2113 
2114 NTSTATUS
2115 NTAPI
2116 MiInsertVadEx(
2117     _Inout_ PMMVAD Vad,
2118     _In_ ULONG_PTR *BaseAddress,
2119     _In_ SIZE_T ViewSize,
2120     _In_ ULONG_PTR HighestAddress,
2121     _In_ ULONG_PTR Alignment,
2122     _In_ ULONG AllocationType);
2123 
2124 VOID
2125 NTAPI
2126 MiInsertBasedSection(
2127     IN PSECTION Section
2128 );
2129 
2130 NTSTATUS
2131 NTAPI
2132 MiUnmapViewOfSection(
2133     IN PEPROCESS Process,
2134     IN PVOID BaseAddress,
2135     IN ULONG Flags
2136 );
2137 
2138 NTSTATUS
2139 NTAPI
2140 MiRosUnmapViewOfSection(
2141     IN PEPROCESS Process,
2142     IN PVOID BaseAddress,
2143     IN BOOLEAN SkipDebuggerNotify
2144 );
2145 
2146 VOID
2147 NTAPI
2148 MiInsertNode(
2149     IN PMM_AVL_TABLE Table,
2150     IN PMMADDRESS_NODE NewNode,
2151     PMMADDRESS_NODE Parent,
2152     TABLE_SEARCH_RESULT Result
2153 );
2154 
2155 VOID
2156 NTAPI
2157 MiRemoveNode(
2158     IN PMMADDRESS_NODE Node,
2159     IN PMM_AVL_TABLE Table
2160 );
2161 
2162 PMMADDRESS_NODE
2163 NTAPI
2164 MiGetPreviousNode(
2165     IN PMMADDRESS_NODE Node
2166 );
2167 
2168 PMMADDRESS_NODE
2169 NTAPI
2170 MiGetNextNode(
2171     IN PMMADDRESS_NODE Node
2172 );
2173 
2174 BOOLEAN
2175 NTAPI
2176 MiInitializeSystemSpaceMap(
2177     IN PMMSESSION InputSession OPTIONAL
2178 );
2179 
2180 VOID
2181 NTAPI
2182 MiSessionRemoveProcess(
2183     VOID
2184 );
2185 
2186 VOID
2187 NTAPI
2188 MiReleaseProcessReferenceToSessionDataPage(
2189     IN PMM_SESSION_SPACE SessionGlobal
2190 );
2191 
2192 VOID
2193 NTAPI
2194 MiSessionAddProcess(
2195     IN PEPROCESS NewProcess
2196 );
2197 
2198 NTSTATUS
2199 NTAPI
2200 MiSessionCommitPageTables(
2201     IN PVOID StartVa,
2202     IN PVOID EndVa
2203 );
2204 
2205 ULONG
2206 NTAPI
2207 MiMakeProtectionMask(
2208     IN ULONG Protect
2209 );
2210 
2211 VOID
2212 NTAPI
2213 MiDeleteVirtualAddresses(
2214     IN ULONG_PTR Va,
2215     IN ULONG_PTR EndingAddress,
2216     IN PMMVAD Vad
2217 );
2218 
2219 VOID
2220 NTAPI
2221 MiDeletePte(
2222     IN PMMPTE PointerPte,
2223     IN PVOID VirtualAddress,
2224     IN PEPROCESS CurrentProcess,
2225     IN PMMPTE PrototypePte
2226 );
2227 
2228 ULONG
2229 NTAPI
2230 MiMakeSystemAddressValid(
2231     IN PVOID PageTableVirtualAddress,
2232     IN PEPROCESS CurrentProcess
2233 );
2234 
2235 ULONG
2236 NTAPI
2237 MiMakeSystemAddressValidPfn(
2238     IN PVOID VirtualAddress,
2239     IN KIRQL OldIrql
2240 );
2241 
2242 VOID
2243 NTAPI
2244 MiRemoveMappedView(
2245     IN PEPROCESS CurrentProcess,
2246     IN PMMVAD Vad
2247 );
2248 
2249 PSUBSECTION
2250 NTAPI
2251 MiLocateSubsection(
2252     IN PMMVAD Vad,
2253     IN ULONG_PTR Vpn
2254 );
2255 
2256 VOID
2257 NTAPI
2258 MiDeleteARM3Section(
2259     PVOID ObjectBody
2260 );
2261 
2262 NTSTATUS
2263 NTAPI
2264 MiQueryMemorySectionName(
2265     IN HANDLE ProcessHandle,
2266     IN PVOID BaseAddress,
2267     OUT PVOID MemoryInformation,
2268     IN SIZE_T MemoryInformationLength,
2269     OUT PSIZE_T ReturnLength
2270 );
2271 
2272 NTSTATUS
2273 NTAPI
2274 MiRosUnmapViewInSystemSpace(
2275     IN PVOID MappedBase
2276 );
2277 
2278 POOL_TYPE
2279 NTAPI
2280 MmDeterminePoolType(
2281     IN PVOID PoolAddress
2282 );
2283 
2284 VOID
2285 NTAPI
2286 MiMakePdeExistAndMakeValid(
2287     IN PMMPDE PointerPde,
2288     IN PEPROCESS TargetProcess,
2289     IN KIRQL OldIrql
2290 );
2291 
2292 VOID
2293 NTAPI
2294 MiWriteProtectSystemImage(
2295     _In_ PVOID ImageBase);
2296 
2297 //
2298 // MiRemoveZeroPage will use inline code to zero out the page manually if only
2299 // free pages are available. In some scenarios, we don't/can't run that piece of
2300 // code and would rather only have a real zero page. If we can't have a zero page,
2301 // then we'd like to have our own code to grab a free page and zero it out, by
2302 // using MiRemoveAnyPage. This macro implements this.
2303 //
2304 FORCEINLINE
2305 PFN_NUMBER
2306 MiRemoveZeroPageSafe(IN ULONG Color)
2307 {
2308     if (MmFreePagesByColor[ZeroedPageList][Color].Flink != LIST_HEAD) return MiRemoveZeroPage(Color);
2309     return 0;
2310 }
2311 
2312 #if (_MI_PAGING_LEVELS == 2)
2313 FORCEINLINE
2314 BOOLEAN
2315 MiSynchronizeSystemPde(PMMPDE PointerPde)
2316 {
2317     MMPDE SystemPde;
2318     ULONG Index;
2319 
2320     /* Get the Index from the PDE */
2321     Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE);
2322 
2323     /* Copy the PDE from the double-mapped system page directory */
2324     SystemPde = MmSystemPagePtes[Index];
2325     *PointerPde = SystemPde;
2326 
2327     /* Make sure we re-read the PDE and PTE */
2328     KeMemoryBarrierWithoutFence();
2329 
2330     /* Return, if we had success */
2331     return SystemPde.u.Hard.Valid != 0;
2332 }
2333 #endif
2334 
2335 /* EOF */
2336