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