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