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
11 #define MI_LOWEST_VAD_ADDRESS (PVOID)MM_LOWEST_USER_ADDRESS
13 /* Make the code cleaner with some definitions for size multiples */
15 #define _1MB (1024 * _1KB)
16 #define _1GB (1024 * _1MB)
18 /* Everyone loves 64K */
19 #define _64K (64 * _1KB)
21 /* Area mapped by a PDE */
22 #define PDE_MAPPED_VA (PTE_COUNT * PAGE_SIZE)
24 /* Size of a page table */
25 #define PT_SIZE (PTE_COUNT * sizeof(MMPTE))
27 /* Size of a page directory */
28 #define PD_SIZE (PDE_COUNT * sizeof(MMPDE))
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
35 /* Size of all page directories for a process */
36 #define SYSTEM_PD_SIZE (PD_COUNT * PD_SIZE)
38 C_ASSERT(SYSTEM_PD_SIZE
== PAGE_SIZE
);
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.
47 #define MM_ZERO_ACCESS 0
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
58 // These are flags on top of the actual protection mask
60 #define MM_NOCACHE 0x08
61 #define MM_GUARDPAGE 0x10
62 #define MM_WRITECOMBINE 0x18
63 #define MM_PROTECT_SPECIAL 0x18
66 // These are special cases
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
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
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
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
102 #define PTE_VALID 0x1
103 #define PTE_ACCESSED 0x20
104 #define PTE_DIRTY 0x40
109 #define PTE_ENABLE_CACHE 0
110 #define PTE_DISABLE_CACHE 0x10
111 #define PTE_WRITECOMBINED_CACHE 0x10
112 #define PTE_PROTECT_MASK 0x612
113 #elif defined(_M_AMD64)
117 #define PTE_READONLY 0x8000000000000000ULL
118 #define PTE_EXECUTE 0x0000000000000000ULL
119 #define PTE_EXECUTE_READ PTE_EXECUTE /* EXECUTE implies READ on x64 */
120 #define PTE_READWRITE 0x8000000000000002ULL
121 #define PTE_WRITECOPY 0x8000000000000200ULL
122 #define PTE_EXECUTE_READWRITE 0x0000000000000002ULL
123 #define PTE_EXECUTE_WRITECOPY 0x0000000000000200ULL
124 #define PTE_PROTOTYPE 0x0000000000000400ULL
129 #define PTE_VALID 0x0000000000000001ULL
130 #define PTE_ACCESSED 0x0000000000000020ULL
131 #define PTE_DIRTY 0x0000000000000040ULL
136 #define PTE_ENABLE_CACHE 0x0000000000000000ULL
137 #define PTE_DISABLE_CACHE 0x0000000000000010ULL
138 #define PTE_WRITECOMBINED_CACHE 0x0000000000000010ULL
139 #define PTE_PROTECT_MASK 0x8000000000000612ULL
140 #elif defined(_M_ARM)
141 #define PTE_READONLY 0x200
142 #define PTE_EXECUTE 0 // Not worrying about NX yet
143 #define PTE_EXECUTE_READ 0 // Not worrying about NX yet
144 #define PTE_READWRITE 0 // Doesn't exist on ARM
145 #define PTE_WRITECOPY 0 // Doesn't exist on ARM
146 #define PTE_EXECUTE_READWRITE 0 // Not worrying about NX yet
147 #define PTE_EXECUTE_WRITECOPY 0 // Not worrying about NX yet
148 #define PTE_PROTOTYPE 0x400 // Using the Shared bit
153 #define PTE_ENABLE_CACHE 0
154 #define PTE_DISABLE_CACHE 0x10
155 #define PTE_WRITECOMBINED_CACHE 0x10
156 #define PTE_PROTECT_MASK 0x610
158 #error Define these please!
162 // Mask for image section page protection
164 #define IMAGE_SCN_PROTECTION_MASK (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE)
166 extern const ULONG_PTR MmProtectToPteMask
[32];
167 extern const ULONG MmProtectToValue
[32];
170 // Assertions for session images, addresses, and PTEs
172 #define MI_IS_SESSION_IMAGE_ADDRESS(Address) \
173 (((Address) >= MiSessionImageStart) && ((Address) < MiSessionImageEnd))
175 #define MI_IS_SESSION_ADDRESS(Address) \
176 (((Address) >= MmSessionBase) && ((Address) < MiSessionSpaceEnd))
178 #define MI_IS_SESSION_PTE(Pte) \
179 ((((PMMPTE)Pte) >= MiSessionBasePte) && (((PMMPTE)Pte) < MiSessionLastPte))
181 #define MI_IS_PAGE_TABLE_ADDRESS(Address) \
182 (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)PTE_TOP))
184 #define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address) \
185 (((Address) >= (PVOID)MiAddressToPte(MmSystemRangeStart)) && ((Address) <= (PVOID)PTE_TOP))
187 #define MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address) \
188 (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)MmHyperSpaceEnd))
191 // Creates a software PTE with the given protection
193 #define MI_MAKE_SOFTWARE_PTE(p, x) ((p)->u.Long = (x << MM_PTE_SOFTWARE_PROTECTION_BITS))
196 // Marks a PTE as deleted
198 #define MI_SET_PFN_DELETED(x) ((x)->PteAddress = (PMMPTE)((ULONG_PTR)(x)->PteAddress | 1))
199 #define MI_IS_PFN_DELETED(x) ((ULONG_PTR)((x)->PteAddress) & 1)
202 // Special values for LoadedImports
205 #define MM_SYSLDR_NO_IMPORTS (PVOID)0xFFFFFFFFFFFFFFFEULL
206 #define MM_SYSLDR_BOOT_LOADED (PVOID)0xFFFFFFFFFFFFFFFFULL
208 #define MM_SYSLDR_NO_IMPORTS (PVOID)0xFFFFFFFE
209 #define MM_SYSLDR_BOOT_LOADED (PVOID)0xFFFFFFFF
211 #define MM_SYSLDR_SINGLE_ENTRY 0x1
214 // Number of initial session IDs
216 #define MI_INITIAL_SESSION_IDS 64
218 #if defined(_M_IX86) || defined(_M_ARM)
222 #define LIST_HEAD 0xFFFFFFFF
225 // Because GCC cannot automatically downcast 0xFFFFFFFF to lesser-width bits,
226 // we need a manual definition suited to the number of bits in the PteFrame.
227 // This is used as a LIST_HEAD for the colored list
229 #define COLORED_LIST_HEAD ((1 << 25) - 1) // 0x1FFFFFF
230 #elif defined(_M_AMD64)
231 #define LIST_HEAD 0xFFFFFFFFFFFFFFFFLL
232 #define COLORED_LIST_HEAD ((1ULL << 57) - 1) // 0x1FFFFFFFFFFFFFFLL
234 #error Define these please!
238 // Special IRQL value (found in assertions)
240 #define MM_NOIRQL (KIRQL)0xFFFFFFFF
243 // Returns the color of a page
245 #define MI_GET_PAGE_COLOR(x) ((x) & MmSecondaryColorMask)
246 #define MI_GET_NEXT_COLOR() (MI_GET_PAGE_COLOR(++MmSystemPageColor))
247 #define MI_GET_NEXT_PROCESS_COLOR(x) (MI_GET_PAGE_COLOR(++(x)->NextPageColor))
250 // Prototype PTEs that don't yet have a pagefile association
253 #define MI_PTE_LOOKUP_NEEDED 0xffffffffULL
255 #define MI_PTE_LOOKUP_NEEDED 0xFFFFF
259 // Number of session data and tag pages
261 #define MI_SESSION_DATA_PAGES_MAXIMUM (MM_ALLOCATION_GRANULARITY / PAGE_SIZE)
262 #define MI_SESSION_TAG_PAGES_MAXIMUM (MM_ALLOCATION_GRANULARITY / PAGE_SIZE)
265 // Used by MiCheckSecuredVad
267 #define MM_READ_WRITE_ALLOWED 11
268 #define MM_READ_ONLY_ALLOWED 10
269 #define MM_NO_ACCESS_ALLOWED 01
270 #define MM_DELETE_CHECK 85
273 // System views are binned into 64K chunks
275 #define MI_SYSTEM_VIEW_BUCKET_SIZE _64K
278 // FIXFIX: These should go in ex.h after the pool merge
281 #define POOL_BLOCK_SIZE 16
283 #define POOL_BLOCK_SIZE 8
285 #define POOL_LISTS_PER_PAGE (PAGE_SIZE / POOL_BLOCK_SIZE)
286 #define BASE_POOL_TYPE_MASK 1
287 #define POOL_MAX_ALLOC (PAGE_SIZE - (sizeof(POOL_HEADER) + POOL_BLOCK_SIZE))
290 // Pool debugging/analysis/tracing flags
292 #define POOL_FLAG_CHECK_TIMERS 0x1
293 #define POOL_FLAG_CHECK_WORKERS 0x2
294 #define POOL_FLAG_CHECK_RESOURCES 0x4
295 #define POOL_FLAG_VERIFIER 0x8
296 #define POOL_FLAG_CHECK_DEADLOCK 0x10
297 #define POOL_FLAG_SPECIAL_POOL 0x20
298 #define POOL_FLAG_DBGPRINT_ON_FAILURE 0x40
299 #define POOL_FLAG_CRASH_ON_FAILURE 0x80
302 // BAD_POOL_HEADER codes during pool bugcheck
304 #define POOL_CORRUPTED_LIST 3
305 #define POOL_SIZE_OR_INDEX_MISMATCH 5
306 #define POOL_ENTRIES_NOT_ALIGNED_PREVIOUS 6
307 #define POOL_HEADER_NOT_ALIGNED 7
308 #define POOL_HEADER_IS_ZERO 8
309 #define POOL_ENTRIES_NOT_ALIGNED_NEXT 9
310 #define POOL_ENTRY_NOT_FOUND 10
313 // BAD_POOL_CALLER codes during pool bugcheck
315 #define POOL_ENTRY_CORRUPTED 1
316 #define POOL_ENTRY_ALREADY_FREE 6
317 #define POOL_ENTRY_NOT_ALLOCATED 7
318 #define POOL_ALLOC_IRQL_INVALID 8
319 #define POOL_FREE_IRQL_INVALID 9
320 #define POOL_BILLED_PROCESS_INVALID 13
321 #define POOL_HEADER_SIZE_INVALID 32
323 typedef struct _POOL_DESCRIPTOR
328 ULONG RunningDeAllocs
;
334 LONG PendingFreeDepth
;
337 LIST_ENTRY ListHeads
[POOL_LISTS_PER_PAGE
];
338 } POOL_DESCRIPTOR
, *PPOOL_DESCRIPTOR
;
340 typedef struct _POOL_HEADER
347 USHORT PreviousSize
:8;
352 USHORT PreviousSize
:9;
366 PEPROCESS ProcessBilled
;
372 USHORT AllocatorBackTraceIndex
;
376 } POOL_HEADER
, *PPOOL_HEADER
;
378 C_ASSERT(sizeof(POOL_HEADER
) == POOL_BLOCK_SIZE
);
379 C_ASSERT(POOL_BLOCK_SIZE
== sizeof(LIST_ENTRY
));
381 typedef struct _POOL_TRACKER_TABLE
386 SIZE_T NonPagedBytes
;
390 } POOL_TRACKER_TABLE
, *PPOOL_TRACKER_TABLE
;
392 typedef struct _POOL_TRACKER_BIG_PAGES
398 } POOL_TRACKER_BIG_PAGES
, *PPOOL_TRACKER_BIG_PAGES
;
400 extern ULONG ExpNumberOfPagedPools
;
401 extern POOL_DESCRIPTOR NonPagedPoolDescriptor
;
402 extern PPOOL_DESCRIPTOR ExpPagedPoolDescriptor
[16 + 1];
403 extern PPOOL_TRACKER_TABLE PoolTrackTable
;
409 typedef struct _MI_LARGE_PAGE_DRIVER_ENTRY
412 UNICODE_STRING BaseName
;
413 } MI_LARGE_PAGE_DRIVER_ENTRY
, *PMI_LARGE_PAGE_DRIVER_ENTRY
;
415 typedef enum _MMSYSTEM_PTE_POOL_TYPE
418 NonPagedPoolExpansion
,
420 } MMSYSTEM_PTE_POOL_TYPE
;
422 typedef enum _MI_PFN_CACHE_ATTRIBUTE
428 } MI_PFN_CACHE_ATTRIBUTE
, *PMI_PFN_CACHE_ATTRIBUTE
;
430 typedef struct _PHYSICAL_MEMORY_RUN
433 PFN_NUMBER PageCount
;
434 } PHYSICAL_MEMORY_RUN
, *PPHYSICAL_MEMORY_RUN
;
436 typedef struct _PHYSICAL_MEMORY_DESCRIPTOR
439 PFN_NUMBER NumberOfPages
;
440 PHYSICAL_MEMORY_RUN Run
[1];
441 } PHYSICAL_MEMORY_DESCRIPTOR
, *PPHYSICAL_MEMORY_DESCRIPTOR
;
443 typedef struct _MMCOLOR_TABLES
448 } MMCOLOR_TABLES
, *PMMCOLOR_TABLES
;
450 typedef struct _MI_LARGE_PAGE_RANGES
452 PFN_NUMBER StartFrame
;
453 PFN_NUMBER LastFrame
;
454 } MI_LARGE_PAGE_RANGES
, *PMI_LARGE_PAGE_RANGES
;
456 typedef struct _MMVIEW
459 PCONTROL_AREA ControlArea
;
462 typedef struct _MMSESSION
464 KGUARDED_MUTEX SystemSpaceViewLock
;
465 PKGUARDED_MUTEX SystemSpaceViewLockPointer
;
466 PCHAR SystemSpaceViewStart
;
467 PMMVIEW SystemSpaceViewTable
;
468 ULONG SystemSpaceHashSize
;
469 ULONG SystemSpaceHashEntries
;
470 ULONG SystemSpaceHashKey
;
471 ULONG BitmapFailures
;
472 PRTL_BITMAP SystemSpaceBitMap
;
473 } MMSESSION
, *PMMSESSION
;
475 typedef struct _MM_SESSION_SPACE_FLAGS
478 ULONG DeletePending
:1;
480 } MM_SESSION_SPACE_FLAGS
;
482 typedef struct _MM_SESSION_SPACE
484 struct _MM_SESSION_SPACE
*GlobalVirtualAddress
;
489 MM_SESSION_SPACE_FLAGS Flags
;
492 LIST_ENTRY ProcessList
;
493 LARGE_INTEGER LastProcessSwappedOutTime
;
494 PFN_NUMBER SessionPageDirectoryIndex
;
495 SIZE_T NonPageablePages
;
496 SIZE_T CommittedPages
;
497 PVOID PagedPoolStart
;
499 PMMPDE PagedPoolBasePde
;
501 LONG ResidentProcessCount
;
502 ULONG SessionPoolAllocationFailures
[4];
503 LIST_ENTRY ImageList
;
507 PEPROCESS LastProcess
;
508 LONG ProcessReferenceToSession
;
509 LIST_ENTRY WsListEntry
;
510 GENERAL_LOOKASIDE Lookaside
[SESSION_POOL_LOOKASIDES
];
512 KGUARDED_MUTEX PagedPoolMutex
;
513 MM_PAGED_POOL_INFO PagedPoolInfo
;
516 PDRIVER_UNLOAD Win32KDriverUnload
;
517 POOL_DESCRIPTOR PagedPool
;
518 #if defined (_M_AMD64)
523 #if defined (_M_AMD64)
524 PMMPTE SpecialPoolFirstPte
;
525 PMMPTE SpecialPoolLastPte
;
526 PMMPTE NextPdeForSpecialPoolExpansion
;
527 PMMPTE LastPdeForSpecialPoolExpansion
;
528 PFN_NUMBER SpecialPagesInUse
;
530 LONG ImageLoadingCount
;
531 } MM_SESSION_SPACE
, *PMM_SESSION_SPACE
;
533 extern PMM_SESSION_SPACE MmSessionSpace
;
534 extern MMPTE HyperTemplatePte
;
535 extern MMPDE ValidKernelPde
;
536 extern MMPTE ValidKernelPte
;
537 extern MMPDE ValidKernelPdeLocal
;
538 extern MMPTE ValidKernelPteLocal
;
539 extern MMPDE DemandZeroPde
;
540 extern MMPTE DemandZeroPte
;
541 extern MMPTE PrototypePte
;
542 extern MMPTE MmDecommittedPte
;
543 extern BOOLEAN MmLargeSystemCache
;
544 extern BOOLEAN MmZeroPageFile
;
545 extern BOOLEAN MmProtectFreedNonPagedPool
;
546 extern BOOLEAN MmTrackLockedPages
;
547 extern BOOLEAN MmTrackPtes
;
548 extern BOOLEAN MmDynamicPfn
;
549 extern BOOLEAN MmMirroring
;
550 extern BOOLEAN MmMakeLowMemory
;
551 extern BOOLEAN MmEnforceWriteProtection
;
552 extern SIZE_T MmAllocationFragment
;
553 extern ULONG MmConsumedPoolPercentage
;
554 extern ULONG MmVerifyDriverBufferType
;
555 extern ULONG MmVerifyDriverLevel
;
556 extern WCHAR MmVerifyDriverBuffer
[512];
557 extern WCHAR MmLargePageDriverBuffer
[512];
558 extern LIST_ENTRY MiLargePageDriverList
;
559 extern BOOLEAN MiLargePageAllDrivers
;
560 extern ULONG MmVerifyDriverBufferLength
;
561 extern ULONG MmLargePageDriverBufferLength
;
562 extern SIZE_T MmSizeOfNonPagedPoolInBytes
;
563 extern SIZE_T MmMaximumNonPagedPoolInBytes
;
564 extern PFN_NUMBER MmMaximumNonPagedPoolInPages
;
565 extern PFN_NUMBER MmSizeOfPagedPoolInPages
;
566 extern PVOID MmNonPagedSystemStart
;
567 extern PVOID MmNonPagedPoolStart
;
568 extern PVOID MmNonPagedPoolExpansionStart
;
569 extern PVOID MmNonPagedPoolEnd
;
570 extern SIZE_T MmSizeOfPagedPoolInBytes
;
571 extern PVOID MmPagedPoolStart
;
572 extern PVOID MmPagedPoolEnd
;
573 extern PVOID MmSessionBase
;
574 extern SIZE_T MmSessionSize
;
575 extern PMMPTE MmFirstReservedMappingPte
, MmLastReservedMappingPte
;
576 extern PMMPTE MiFirstReservedZeroingPte
;
577 extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes
[2][MmMaximumCacheType
];
578 extern PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
;
579 extern SIZE_T MmBootImageSize
;
580 extern PMMPTE MmSystemPtesStart
[MaximumPtePoolTypes
];
581 extern PMMPTE MmSystemPtesEnd
[MaximumPtePoolTypes
];
582 extern PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor
;
583 extern MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor
;
584 extern ULONG_PTR MxPfnAllocation
;
585 extern MM_PAGED_POOL_INFO MmPagedPoolInfo
;
586 extern RTL_BITMAP MiPfnBitMap
;
587 extern KGUARDED_MUTEX MmPagedPoolMutex
;
588 extern KGUARDED_MUTEX MmSectionCommitMutex
;
589 extern PVOID MmPagedPoolStart
;
590 extern PVOID MmPagedPoolEnd
;
591 extern PVOID MmNonPagedSystemStart
;
592 extern PVOID MiSystemViewStart
;
593 extern SIZE_T MmSystemViewSize
;
594 extern PVOID MmSessionBase
;
595 extern PVOID MiSessionSpaceEnd
;
596 extern PMMPTE MiSessionImagePteStart
;
597 extern PMMPTE MiSessionImagePteEnd
;
598 extern PMMPTE MiSessionBasePte
;
599 extern PMMPTE MiSessionLastPte
;
600 extern SIZE_T MmSizeOfPagedPoolInBytes
;
601 extern PMMPDE MmSystemPagePtes
;
602 extern PVOID MmSystemCacheStart
;
603 extern PVOID MmSystemCacheEnd
;
604 extern MMSUPPORT MmSystemCacheWs
;
605 extern SIZE_T MmAllocatedNonPagedPool
;
606 extern ULONG MmSpecialPoolTag
;
607 extern PVOID MmHyperSpaceEnd
;
608 extern PMMWSL MmSystemCacheWorkingSetList
;
609 extern SIZE_T MmMinimumNonPagedPoolSize
;
610 extern ULONG MmMinAdditionNonPagedPoolPerMb
;
611 extern SIZE_T MmDefaultMaximumNonPagedPool
;
612 extern ULONG MmMaxAdditionNonPagedPoolPerMb
;
613 extern ULONG MmSecondaryColors
;
614 extern ULONG MmSecondaryColorMask
;
615 extern ULONG MmNumberOfSystemPtes
;
616 extern ULONG MmMaximumNonPagedPoolPercent
;
617 extern ULONG MmLargeStackSize
;
618 extern PMMCOLOR_TABLES MmFreePagesByColor
[FreePageList
+ 1];
619 extern MMPFNLIST MmStandbyPageListByPriority
[8];
620 extern ULONG MmProductType
;
621 extern MM_SYSTEMSIZE MmSystemSize
;
622 extern PKEVENT MiLowMemoryEvent
;
623 extern PKEVENT MiHighMemoryEvent
;
624 extern PKEVENT MiLowPagedPoolEvent
;
625 extern PKEVENT MiHighPagedPoolEvent
;
626 extern PKEVENT MiLowNonPagedPoolEvent
;
627 extern PKEVENT MiHighNonPagedPoolEvent
;
628 extern PFN_NUMBER MmLowMemoryThreshold
;
629 extern PFN_NUMBER MmHighMemoryThreshold
;
630 extern PFN_NUMBER MiLowPagedPoolThreshold
;
631 extern PFN_NUMBER MiHighPagedPoolThreshold
;
632 extern PFN_NUMBER MiLowNonPagedPoolThreshold
;
633 extern PFN_NUMBER MiHighNonPagedPoolThreshold
;
634 extern PFN_NUMBER MmMinimumFreePages
;
635 extern PFN_NUMBER MmPlentyFreePages
;
636 extern SIZE_T MmMinimumStackCommitInBytes
;
637 extern PFN_COUNT MiExpansionPoolPagesInitialCharge
;
638 extern PFN_NUMBER MmResidentAvailablePages
;
639 extern PFN_NUMBER MmResidentAvailableAtInit
;
640 extern ULONG MmTotalFreeSystemPtes
[MaximumPtePoolTypes
];
641 extern PFN_NUMBER MmTotalSystemDriverPages
;
642 extern ULONG MmCritsectTimeoutSeconds
;
643 extern PVOID MiSessionImageStart
;
644 extern PVOID MiSessionImageEnd
;
645 extern PMMPTE MiHighestUserPte
;
646 extern PMMPDE MiHighestUserPde
;
647 extern PFN_NUMBER MmSystemPageDirectory
[PD_COUNT
];
648 extern PMMPTE MmSharedUserDataPte
;
649 extern LIST_ENTRY MmProcessList
;
650 extern BOOLEAN MmZeroingPageThreadActive
;
651 extern KEVENT MmZeroingPageEvent
;
652 extern ULONG MmSystemPageColor
;
653 extern ULONG MmProcessColorSeed
;
654 extern PMMWSL MmWorkingSetList
;
655 extern PFN_NUMBER MiNumberOfFreePages
;
656 extern SIZE_T MmSessionViewSize
;
657 extern SIZE_T MmSessionPoolSize
;
658 extern SIZE_T MmSessionImageSize
;
659 extern PVOID MiSystemViewStart
;
660 extern PVOID MiSessionPoolEnd
; // 0xBE000000
661 extern PVOID MiSessionPoolStart
; // 0xBD000000
662 extern PVOID MiSessionViewStart
; // 0xBE000000
663 extern PVOID MiSessionSpaceWs
;
664 extern ULONG MmMaximumDeadKernelStacks
;
665 extern SLIST_HEADER MmDeadStackSListHead
;
666 extern MM_AVL_TABLE MmSectionBasedRoot
;
667 extern KGUARDED_MUTEX MmSectionBasedMutex
;
668 extern PVOID MmHighSectionBase
;
669 extern SIZE_T MmSystemLockPagesCount
;
670 extern ULONG_PTR MmSubsectionBase
;
671 extern LARGE_INTEGER MmCriticalSectionTimeout
;
672 extern LIST_ENTRY MmWorkingSetExpansionHead
;
673 extern KSPIN_LOCK MmExpansionLock
;
674 extern PETHREAD MiExpansionLockOwner
;
678 MiIsMemoryTypeFree(TYPE_OF_MEMORY MemoryType
)
680 return ((MemoryType
== LoaderFree
) ||
681 (MemoryType
== LoaderLoadedProgram
) ||
682 (MemoryType
== LoaderFirmwareTemporary
) ||
683 (MemoryType
== LoaderOsloaderStack
));
688 MiIsMemoryTypeInvisible(TYPE_OF_MEMORY MemoryType
)
690 return ((MemoryType
== LoaderFirmwarePermanent
) ||
691 (MemoryType
== LoaderSpecialMemory
) ||
692 (MemoryType
== LoaderHALCachedMemory
) ||
693 (MemoryType
== LoaderBBTMemory
));
699 MiIsUserPxe(PVOID Address
)
701 return ((ULONG_PTR
)Address
>> 7) == 0x1FFFFEDF6FB7DA0ULL
;
706 MiIsUserPpe(PVOID Address
)
708 return ((ULONG_PTR
)Address
>> 16) == 0xFFFFF6FB7DA0ULL
;
713 MiIsUserPde(PVOID Address
)
715 return ((ULONG_PTR
)Address
>> 25) == 0x7FFFFB7DA0ULL
;
720 MiIsUserPte(PVOID Address
)
722 return ((ULONG_PTR
)Address
>> 34) == 0x3FFFFDA0ULL
;
727 MiIsUserPde(PVOID Address
)
729 return ((Address
>= (PVOID
)MiAddressToPde(NULL
)) &&
730 (Address
<= (PVOID
)MiHighestUserPde
));
735 MiIsUserPte(PVOID Address
)
737 return (Address
<= (PVOID
)MiHighestUserPte
);
742 // Figures out the hardware bits for a PTE
746 MiDetermineUserGlobalPteMask(IN PVOID PointerPte
)
753 /* Make it valid and accessed */
754 TempPte
.u
.Hard
.Valid
= TRUE
;
755 MI_MAKE_ACCESSED_PAGE(&TempPte
);
757 /* Is this for user-mode? */
759 #if (_MI_PAGING_LEVELS == 4)
760 MiIsUserPxe(PointerPte
) ||
762 #if (_MI_PAGING_LEVELS >= 3)
763 MiIsUserPpe(PointerPte
) ||
765 MiIsUserPde(PointerPte
) ||
766 MiIsUserPte(PointerPte
))
768 /* Set the owner bit */
769 MI_MAKE_OWNER_PAGE(&TempPte
);
772 /* FIXME: We should also set the global bit */
774 /* Return the protection */
775 return TempPte
.u
.Long
;
779 // Creates a valid kernel PTE with the given protection
783 MI_MAKE_HARDWARE_PTE_KERNEL(IN PMMPTE NewPte
,
784 IN PMMPTE MappingPte
,
785 IN ULONG_PTR ProtectionMask
,
786 IN PFN_NUMBER PageFrameNumber
)
788 /* Only valid for kernel, non-session PTEs */
789 ASSERT(MappingPte
> MiHighestUserPte
);
790 ASSERT(!MI_IS_SESSION_PTE(MappingPte
));
791 ASSERT((MappingPte
< (PMMPTE
)PDE_BASE
) || (MappingPte
> (PMMPTE
)PDE_TOP
));
794 *NewPte
= ValidKernelPte
;
796 /* Set the protection and page */
797 NewPte
->u
.Hard
.PageFrameNumber
= PageFrameNumber
;
798 NewPte
->u
.Long
|= MmProtectToPteMask
[ProtectionMask
];
802 // Creates a valid PTE with the given protection
806 MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte
,
807 IN PMMPTE MappingPte
,
808 IN ULONG_PTR ProtectionMask
,
809 IN PFN_NUMBER PageFrameNumber
)
811 /* Set the protection and page */
812 NewPte
->u
.Long
= MiDetermineUserGlobalPteMask(MappingPte
);
813 NewPte
->u
.Long
|= MmProtectToPteMask
[ProtectionMask
];
814 NewPte
->u
.Hard
.PageFrameNumber
= PageFrameNumber
;
818 // Creates a valid user PTE with the given protection
822 MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte
,
823 IN PMMPTE MappingPte
,
824 IN ULONG_PTR ProtectionMask
,
825 IN PFN_NUMBER PageFrameNumber
)
827 /* Only valid for kernel, non-session PTEs */
828 ASSERT(MappingPte
<= MiHighestUserPte
);
833 /* Set the protection and page */
834 NewPte
->u
.Hard
.Valid
= TRUE
;
835 NewPte
->u
.Hard
.Owner
= TRUE
;
836 NewPte
->u
.Hard
.PageFrameNumber
= PageFrameNumber
;
837 NewPte
->u
.Long
|= MmProtectToPteMask
[ProtectionMask
];
842 // Builds a Prototype PTE for the address of the PTE
846 MI_MAKE_PROTOTYPE_PTE(IN PMMPTE NewPte
,
847 IN PMMPTE PointerPte
)
851 /* Mark this as a prototype */
853 NewPte
->u
.Proto
.Prototype
= 1;
856 * Prototype PTEs are only valid in paged pool by design, this little trick
857 * lets us only use 30 bits for the adress of the PTE, as long as the area
858 * stays 1024MB At most.
860 Offset
= (ULONG_PTR
)PointerPte
- (ULONG_PTR
)MmPagedPoolStart
;
863 * 7 bits go in the "low" (but we assume the bottom 2 are zero)
864 * and the other 21 bits go in the "high"
866 NewPte
->u
.Proto
.ProtoAddressLow
= (Offset
& 0x1FC) >> 2;
867 NewPte
->u
.Proto
.ProtoAddressHigh
= (Offset
& 0x3FFFFE00) >> 9;
871 // Builds a Subsection PTE for the address of the Segment
875 MI_MAKE_SUBSECTION_PTE(IN PMMPTE NewPte
,
880 /* Mark this as a prototype */
882 NewPte
->u
.Subsect
.Prototype
= 1;
885 * Segments are only valid either in nonpaged pool. We store the 20 bit
886 * difference either from the top or bottom of nonpaged pool, giving a
887 * maximum of 128MB to each delta, meaning nonpaged pool cannot exceed
890 if ((ULONG_PTR
)Segment
< ((ULONG_PTR
)MmSubsectionBase
+ (128 * _1MB
)))
892 Offset
= (ULONG_PTR
)Segment
- (ULONG_PTR
)MmSubsectionBase
;
893 NewPte
->u
.Subsect
.WhichPool
= PagedPool
;
897 Offset
= (ULONG_PTR
)MmNonPagedPoolEnd
- (ULONG_PTR
)Segment
;
898 NewPte
->u
.Subsect
.WhichPool
= NonPagedPool
;
902 * 4 bits go in the "low" (but we assume the bottom 3 are zero)
903 * and the other 20 bits go in the "high"
905 NewPte
->u
.Subsect
.SubsectionAddressLow
= (Offset
& 0x78) >> 3;
906 NewPte
->u
.Subsect
.SubsectionAddressHigh
= (Offset
& 0xFFFFF80) >> 7;
911 MI_IS_MAPPED_PTE(PMMPTE PointerPte
)
913 /// \todo Make this reasonable code, this is UGLY!
914 return ((PointerPte
->u
.Long
& 0xFFFFFC01) != 0);
921 MI_MAKE_TRANSITION_PTE(_Out_ PMMPTE NewPte
,
922 _In_ PFN_NUMBER Page
,
923 _In_ ULONG Protection
)
926 NewPte
->u
.Trans
.Transition
= 1;
927 NewPte
->u
.Trans
.Protection
= Protection
;
928 NewPte
->u
.Trans
.PageFrameNumber
= Page
;
932 // Returns if the page is physically resident (ie: a large page)
933 // FIXFIX: CISC/x86 only?
937 MI_IS_PHYSICAL_ADDRESS(IN PVOID Address
)
941 /* Large pages are never paged out, always physically resident */
942 PointerPde
= MiAddressToPde(Address
);
943 return ((PointerPde
->u
.Hard
.LargePage
) && (PointerPde
->u
.Hard
.Valid
));
947 // Writes a valid PTE
951 MI_WRITE_VALID_PTE(IN PMMPTE PointerPte
,
954 /* Write the valid PTE */
955 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
956 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
957 *PointerPte
= TempPte
;
961 // Updates a valid PTE
965 MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte
,
968 /* Write the valid PTE */
969 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
970 ASSERT(TempPte
.u
.Hard
.Valid
== 1);
971 ASSERT(PointerPte
->u
.Hard
.PageFrameNumber
== TempPte
.u
.Hard
.PageFrameNumber
);
972 *PointerPte
= TempPte
;
976 // Writes an invalid PTE
980 MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte
,
983 /* Write the invalid PTE */
984 ASSERT(InvalidPte
.u
.Hard
.Valid
== 0);
985 ASSERT(InvalidPte
.u
.Long
!= 0);
986 *PointerPte
= InvalidPte
;
990 // Erase the PTE completely
994 MI_ERASE_PTE(IN PMMPTE PointerPte
)
996 /* Zero out the PTE */
997 ASSERT(PointerPte
->u
.Long
!= 0);
998 PointerPte
->u
.Long
= 0;
1002 // Writes a valid PDE
1006 MI_WRITE_VALID_PDE(IN PMMPDE PointerPde
,
1009 /* Write the valid PDE */
1010 ASSERT(PointerPde
->u
.Hard
.Valid
== 0);
1011 ASSERT(TempPde
.u
.Hard
.Valid
== 1);
1012 *PointerPde
= TempPde
;
1016 // Writes an invalid PDE
1020 MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde
,
1021 IN MMPDE InvalidPde
)
1023 /* Write the invalid PDE */
1024 ASSERT(InvalidPde
.u
.Hard
.Valid
== 0);
1025 ASSERT(InvalidPde
.u
.Long
!= 0);
1026 *PointerPde
= InvalidPde
;
1030 // Checks if the thread already owns a working set
1034 MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread
)
1036 /* If any of these are held, return TRUE */
1037 return ((Thread
->OwnsProcessWorkingSetExclusive
) ||
1038 (Thread
->OwnsProcessWorkingSetShared
) ||
1039 (Thread
->OwnsSystemWorkingSetExclusive
) ||
1040 (Thread
->OwnsSystemWorkingSetShared
) ||
1041 (Thread
->OwnsSessionWorkingSetExclusive
) ||
1042 (Thread
->OwnsSessionWorkingSetShared
));
1046 // Checks if the process owns the working set lock
1050 MI_WS_OWNER(IN PEPROCESS Process
)
1052 /* Check if this process is the owner, and that the thread owns the WS */
1053 if (PsGetCurrentThread()->OwnsProcessWorkingSetExclusive
== 0)
1055 DPRINT("Thread: %p is not an owner\n", PsGetCurrentThread());
1057 if (KeGetCurrentThread()->ApcState
.Process
!= &Process
->Pcb
)
1059 DPRINT("Current thread %p is attached to another process %p\n", PsGetCurrentThread(), Process
);
1061 return ((KeGetCurrentThread()->ApcState
.Process
== &Process
->Pcb
) &&
1062 ((PsGetCurrentThread()->OwnsProcessWorkingSetExclusive
) ||
1063 (PsGetCurrentThread()->OwnsProcessWorkingSetShared
)));
1067 // New ARM3<->RosMM PAGE Architecture
1071 MiIsRosSectionObject(IN PVOID Section
)
1073 PROS_SECTION_OBJECT RosSection
= Section
;
1074 if ((RosSection
->Type
== 'SC') && (RosSection
->Size
== 'TN')) return TRUE
;
1078 #define MI_IS_ROS_PFN(x) ((x)->u4.AweAllocation == TRUE)
1082 MiDecrementReferenceCount(
1084 IN PFN_NUMBER PageFrameIndex
1089 MI_IS_WS_UNSAFE(IN PEPROCESS Process
)
1091 return (Process
->Vm
.Flags
.AcquiredUnsafe
== TRUE
);
1095 // Locks the working set for the given process
1099 MiLockProcessWorkingSet(IN PEPROCESS Process
,
1102 /* Shouldn't already be owning the process working set */
1103 ASSERT(Thread
->OwnsProcessWorkingSetShared
== FALSE
);
1104 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1106 /* Block APCs, make sure that still nothing is already held */
1107 KeEnterGuardedRegion();
1108 ASSERT(!MM_ANY_WS_LOCK_HELD(Thread
));
1110 /* Lock the working set */
1111 ExAcquirePushLockExclusive(&Process
->Vm
.WorkingSetMutex
);
1113 /* Now claim that we own the lock */
1114 ASSERT(!MI_IS_WS_UNSAFE(Process
));
1115 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1116 Thread
->OwnsProcessWorkingSetExclusive
= TRUE
;
1121 MiLockProcessWorkingSetShared(IN PEPROCESS Process
,
1124 /* Shouldn't already be owning the process working set */
1125 ASSERT(Thread
->OwnsProcessWorkingSetShared
== FALSE
);
1126 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1128 /* Block APCs, make sure that still nothing is already held */
1129 KeEnterGuardedRegion();
1130 ASSERT(!MM_ANY_WS_LOCK_HELD(Thread
));
1132 /* Lock the working set */
1133 ExAcquirePushLockShared(&Process
->Vm
.WorkingSetMutex
);
1135 /* Now claim that we own the lock */
1136 ASSERT(!MI_IS_WS_UNSAFE(Process
));
1137 ASSERT(Thread
->OwnsProcessWorkingSetShared
== FALSE
);
1138 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1139 Thread
->OwnsProcessWorkingSetShared
= TRUE
;
1144 MiLockProcessWorkingSetUnsafe(IN PEPROCESS Process
,
1147 /* Shouldn't already be owning the process working set */
1148 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1150 /* APCs must be blocked, make sure that still nothing is already held */
1151 ASSERT(KeAreAllApcsDisabled() == TRUE
);
1152 ASSERT(!MM_ANY_WS_LOCK_HELD(Thread
));
1154 /* Lock the working set */
1155 ExAcquirePushLockExclusive(&Process
->Vm
.WorkingSetMutex
);
1157 /* Now claim that we own the lock */
1158 ASSERT(!MI_IS_WS_UNSAFE(Process
));
1159 Process
->Vm
.Flags
.AcquiredUnsafe
= 1;
1160 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1161 Thread
->OwnsProcessWorkingSetExclusive
= TRUE
;
1165 // Unlocks the working set for the given process
1169 MiUnlockProcessWorkingSet(IN PEPROCESS Process
,
1172 /* Make sure we are the owner of a safe acquisition */
1173 ASSERT(MI_WS_OWNER(Process
));
1174 ASSERT(!MI_IS_WS_UNSAFE(Process
));
1176 /* The thread doesn't own it anymore */
1177 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== TRUE
);
1178 Thread
->OwnsProcessWorkingSetExclusive
= FALSE
;
1180 /* Release the lock and re-enable APCs */
1181 ExReleasePushLockExclusive(&Process
->Vm
.WorkingSetMutex
);
1182 KeLeaveGuardedRegion();
1186 // Unlocks the working set for the given process
1190 MiUnlockProcessWorkingSetShared(IN PEPROCESS Process
,
1193 /* Make sure we are the owner of a safe acquisition (because shared) */
1194 ASSERT(MI_WS_OWNER(Process
));
1195 ASSERT(!MI_IS_WS_UNSAFE(Process
));
1197 /* Ensure we are in a shared acquisition */
1198 ASSERT(Thread
->OwnsProcessWorkingSetShared
== TRUE
);
1199 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== FALSE
);
1201 /* Don't claim the lock anylonger */
1202 Thread
->OwnsProcessWorkingSetShared
= FALSE
;
1204 /* Release the lock and re-enable APCs */
1205 ExReleasePushLockShared(&Process
->Vm
.WorkingSetMutex
);
1206 KeLeaveGuardedRegion();
1210 // Unlocks the working set for the given process
1214 MiUnlockProcessWorkingSetUnsafe(IN PEPROCESS Process
,
1217 /* Make sure we are the owner of an unsafe acquisition */
1218 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1219 ASSERT(KeAreAllApcsDisabled() == TRUE
);
1220 ASSERT(MI_WS_OWNER(Process
));
1221 ASSERT(MI_IS_WS_UNSAFE(Process
));
1223 /* No longer unsafe */
1224 Process
->Vm
.Flags
.AcquiredUnsafe
= 0;
1226 /* The thread doesn't own it anymore */
1227 ASSERT(Thread
->OwnsProcessWorkingSetExclusive
== TRUE
);
1228 Thread
->OwnsProcessWorkingSetExclusive
= FALSE
;
1230 /* Release the lock but don't touch APC state */
1231 ExReleasePushLockExclusive(&Process
->Vm
.WorkingSetMutex
);
1232 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1236 // Locks the working set
1240 MiLockWorkingSet(IN PETHREAD Thread
,
1241 IN PMMSUPPORT WorkingSet
)
1244 KeEnterGuardedRegion();
1246 /* Working set should be in global memory */
1247 ASSERT(MI_IS_SESSION_ADDRESS((PVOID
)WorkingSet
) == FALSE
);
1249 /* Thread shouldn't already be owning something */
1250 ASSERT(!MM_ANY_WS_LOCK_HELD(Thread
));
1252 /* Lock this working set */
1253 ExAcquirePushLockExclusive(&WorkingSet
->WorkingSetMutex
);
1255 /* Which working set is this? */
1256 if (WorkingSet
== &MmSystemCacheWs
)
1258 /* Own the system working set */
1259 ASSERT((Thread
->OwnsSystemWorkingSetExclusive
== FALSE
) &&
1260 (Thread
->OwnsSystemWorkingSetShared
== FALSE
));
1261 Thread
->OwnsSystemWorkingSetExclusive
= TRUE
;
1263 else if (WorkingSet
->Flags
.SessionSpace
)
1265 /* Own the session working set */
1266 ASSERT((Thread
->OwnsSessionWorkingSetExclusive
== FALSE
) &&
1267 (Thread
->OwnsSessionWorkingSetShared
== FALSE
));
1268 Thread
->OwnsSessionWorkingSetExclusive
= TRUE
;
1272 /* Own the process working set */
1273 ASSERT((Thread
->OwnsProcessWorkingSetExclusive
== FALSE
) &&
1274 (Thread
->OwnsProcessWorkingSetShared
== FALSE
));
1275 Thread
->OwnsProcessWorkingSetExclusive
= TRUE
;
1280 // Unlocks the working set
1284 MiUnlockWorkingSet(IN PETHREAD Thread
,
1285 IN PMMSUPPORT WorkingSet
)
1287 /* Working set should be in global memory */
1288 ASSERT(MI_IS_SESSION_ADDRESS((PVOID
)WorkingSet
) == FALSE
);
1290 /* Which working set is this? */
1291 if (WorkingSet
== &MmSystemCacheWs
)
1293 /* Release the system working set */
1294 ASSERT((Thread
->OwnsSystemWorkingSetExclusive
== TRUE
) ||
1295 (Thread
->OwnsSystemWorkingSetShared
== TRUE
));
1296 Thread
->OwnsSystemWorkingSetExclusive
= FALSE
;
1298 else if (WorkingSet
->Flags
.SessionSpace
)
1300 /* Release the session working set */
1301 ASSERT((Thread
->OwnsSessionWorkingSetExclusive
== TRUE
) ||
1302 (Thread
->OwnsSessionWorkingSetShared
== TRUE
));
1303 Thread
->OwnsSessionWorkingSetExclusive
= 0;
1307 /* Release the process working set */
1308 ASSERT((Thread
->OwnsProcessWorkingSetExclusive
) ||
1309 (Thread
->OwnsProcessWorkingSetShared
));
1310 Thread
->OwnsProcessWorkingSetExclusive
= FALSE
;
1313 /* Release the working set lock */
1314 ExReleasePushLockExclusive(&WorkingSet
->WorkingSetMutex
);
1317 KeLeaveGuardedRegion();
1322 MiUnlockProcessWorkingSetForFault(IN PEPROCESS Process
,
1325 OUT PBOOLEAN Shared
)
1327 ASSERT(MI_WS_OWNER(Process
));
1329 /* Check if the current owner is unsafe */
1330 if (MI_IS_WS_UNSAFE(Process
))
1332 /* Release unsafely */
1333 MiUnlockProcessWorkingSetUnsafe(Process
, Thread
);
1337 else if (Thread
->OwnsProcessWorkingSetExclusive
== 1)
1339 /* Owner is safe and exclusive, release normally */
1340 MiUnlockProcessWorkingSet(Process
, Thread
);
1346 /* Owner is shared (implies safe), release normally */
1347 MiUnlockProcessWorkingSetShared(Process
, Thread
);
1355 MiLockProcessWorkingSetForFault(IN PEPROCESS Process
,
1360 /* Check if this was a safe lock or not */
1365 /* Reacquire safely & shared */
1366 MiLockProcessWorkingSetShared(Process
, Thread
);
1370 /* Reacquire safely */
1371 MiLockProcessWorkingSet(Process
, Thread
);
1376 /* Unsafe lock cannot be shared */
1377 ASSERT(Shared
== FALSE
);
1378 /* Reacquire unsafely */
1379 MiLockProcessWorkingSetUnsafe(Process
, Thread
);
1385 MiAcquireExpansionLock(VOID
)
1389 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1390 KeAcquireSpinLock(&MmExpansionLock
, &OldIrql
);
1391 ASSERT(MiExpansionLockOwner
== NULL
);
1392 MiExpansionLockOwner
= PsGetCurrentThread();
1398 MiReleaseExpansionLock(KIRQL OldIrql
)
1400 ASSERT(MiExpansionLockOwner
== PsGetCurrentThread());
1401 MiExpansionLockOwner
= NULL
;
1402 KeReleaseSpinLock(&MmExpansionLock
, OldIrql
);
1403 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1407 // Returns the ProtoPTE inside a VAD for the given VPN
1411 MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad
,
1416 /* Find the offset within the VAD's prototype PTEs */
1417 ProtoPte
= Vad
->FirstPrototypePte
+ (Vpn
- Vad
->StartingVpn
);
1418 ASSERT(ProtoPte
<= Vad
->LastContiguousPte
);
1423 // Returns the PFN Database entry for the given page number
1424 // Warning: This is not necessarily a valid PFN database entry!
1428 MI_PFN_ELEMENT(IN PFN_NUMBER Pfn
)
1431 return &MmPfnDatabase
[Pfn
];
1435 // Drops a locked page without dereferencing it
1439 MiDropLockCount(IN PMMPFN Pfn1
)
1441 /* This page shouldn't be locked, but it should be valid */
1442 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
1443 ASSERT(Pfn1
->u2
.ShareCount
== 0);
1445 /* Is this the last reference to the page */
1446 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
1448 /* It better not be valid */
1449 ASSERT(Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
);
1451 /* Is it a prototype PTE? */
1452 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1453 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1455 /* FIXME: We should return commit */
1456 DPRINT1("Not returning commit for prototype PTE\n");
1459 /* Update the counter */
1460 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1465 // Drops a locked page and dereferences it
1469 MiDereferencePfnAndDropLockCount(IN PMMPFN Pfn1
)
1471 USHORT RefCount
, OldRefCount
;
1472 PFN_NUMBER PageFrameIndex
;
1474 /* Loop while we decrement the page successfully */
1477 /* There should be at least one reference */
1478 OldRefCount
= Pfn1
->u3
.e2
.ReferenceCount
;
1479 ASSERT(OldRefCount
!= 0);
1481 /* Are we the last one */
1482 if (OldRefCount
== 1)
1484 /* The page shoudln't be shared not active at this point */
1485 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 1);
1486 ASSERT(Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
);
1487 ASSERT(Pfn1
->u2
.ShareCount
== 0);
1489 /* Is it a prototype PTE? */
1490 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1491 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1493 /* FIXME: We should return commit */
1494 DPRINT1("Not returning commit for prototype PTE\n");
1497 /* Update the counter, and drop a reference the long way */
1498 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1499 PageFrameIndex
= MiGetPfnEntryIndex(Pfn1
);
1500 MiDecrementReferenceCount(Pfn1
, PageFrameIndex
);
1504 /* Drop a reference the short way, and that's it */
1505 RefCount
= InterlockedCompareExchange16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
,
1508 ASSERT(RefCount
!= 0);
1509 } while (OldRefCount
!= RefCount
);
1511 /* If we got here, there should be more than one reference */
1512 ASSERT(RefCount
> 1);
1515 /* Is it still being shared? */
1516 if (Pfn1
->u2
.ShareCount
>= 1)
1518 /* Then it should be valid */
1519 ASSERT(Pfn1
->u3
.e1
.PageLocation
== ActiveAndValid
);
1521 /* Is it a prototype PTE? */
1522 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1523 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1525 /* We don't handle ethis */
1529 /* Update the counter */
1530 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1536 // References a locked page and updates the counter
1537 // Used in MmProbeAndLockPages to handle different edge cases
1541 MiReferenceProbedPageAndBumpLockCount(IN PMMPFN Pfn1
)
1543 USHORT RefCount
, OldRefCount
;
1546 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
1548 /* Does ARM3 own the page? */
1549 if (MI_IS_ROS_PFN(Pfn1
))
1551 /* ReactOS Mm doesn't track share count */
1552 ASSERT(Pfn1
->u3
.e1
.PageLocation
== ActiveAndValid
);
1556 /* On ARM3 pages, we should see a valid share count */
1557 ASSERT((Pfn1
->u2
.ShareCount
!= 0) && (Pfn1
->u3
.e1
.PageLocation
== ActiveAndValid
));
1559 /* Is it a prototype PTE? */
1560 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1561 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1563 /* FIXME: We should charge commit */
1564 DPRINT1("Not charging commit for prototype PTE\n");
1568 /* More locked pages! */
1569 InterlockedIncrementSizeT(&MmSystemLockPagesCount
);
1571 /* Loop trying to update the reference count */
1574 /* Get the current reference count, make sure it's valid */
1575 OldRefCount
= Pfn1
->u3
.e2
.ReferenceCount
;
1576 ASSERT(OldRefCount
!= 0);
1577 ASSERT(OldRefCount
< 2500);
1579 /* Bump it up by one */
1580 RefCount
= InterlockedCompareExchange16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
,
1583 ASSERT(RefCount
!= 0);
1584 } while (OldRefCount
!= RefCount
);
1586 /* Was this the first lock attempt? If not, undo our bump */
1587 if (OldRefCount
!= 1) InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1591 // References a locked page and updates the counter
1592 // Used in all other cases except MmProbeAndLockPages
1596 MiReferenceUsedPageAndBumpLockCount(IN PMMPFN Pfn1
)
1600 /* Is it a prototype PTE? */
1601 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1602 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1604 /* FIXME: We should charge commit */
1605 DPRINT1("Not charging commit for prototype PTE\n");
1608 /* More locked pages! */
1609 InterlockedIncrementSizeT(&MmSystemLockPagesCount
);
1611 /* Update the reference count */
1612 NewRefCount
= InterlockedIncrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
1613 if (NewRefCount
== 2)
1615 /* Is it locked or shared? */
1616 if (Pfn1
->u2
.ShareCount
)
1618 /* It's shared, so make sure it's active */
1619 ASSERT(Pfn1
->u3
.e1
.PageLocation
== ActiveAndValid
);
1623 /* It's locked, so we shouldn't lock again */
1624 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1629 /* Someone had already locked the page, so undo our bump */
1630 ASSERT(NewRefCount
< 2500);
1631 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1636 // References a locked page and updates the counter
1637 // Used in all other cases except MmProbeAndLockPages
1641 MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1
)
1645 /* Make sure the page isn't used yet */
1646 ASSERT(Pfn1
->u2
.ShareCount
== 0);
1647 ASSERT(Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
);
1649 /* Is it a prototype PTE? */
1650 if ((Pfn1
->u3
.e1
.PrototypePte
== 1) &&
1651 (Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 1))
1653 /* FIXME: We should charge commit */
1654 DPRINT1("Not charging commit for prototype PTE\n");
1657 /* More locked pages! */
1658 InterlockedIncrementSizeT(&MmSystemLockPagesCount
);
1660 /* Update the reference count */
1661 NewRefCount
= InterlockedIncrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
1662 if (NewRefCount
!= 1)
1664 /* Someone had already locked the page, so undo our bump */
1665 ASSERT(NewRefCount
< 2500);
1666 InterlockedDecrementSizeT(&MmSystemLockPagesCount
);
1672 MiIncrementPageTableReferences(IN PVOID Address
)
1676 RefCount
= &MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)];
1679 ASSERT(*RefCount
<= PTE_PER_PAGE
);
1684 MiDecrementPageTableReferences(IN PVOID Address
)
1688 RefCount
= &MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)];
1691 ASSERT(*RefCount
< PTE_PER_PAGE
);
1696 MiQueryPageTableReferences(IN PVOID Address
)
1700 RefCount
= &MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)];
1710 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1716 MiInitializeSessionSpaceLayout(VOID
);
1721 MiInitMachineDependent(
1722 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1728 MiComputeColorInformation(
1736 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1742 MiInitializeColorTables(
1749 MiInitializePfnDatabase(
1750 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1755 MiInitializeSessionWsSupport(
1761 MiInitializeSessionIds(
1768 MiInitializeMemoryEvents(
1776 IN PFN_NUMBER PageCount
1780 PPHYSICAL_MEMORY_DESCRIPTOR
1782 MmInitializeMemoryLimits(
1783 IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
1784 IN PBOOLEAN IncludeType
1789 MiPagesInLoaderBlock(
1790 IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
1791 IN PBOOLEAN IncludeType
1797 IN PVOID AddressStart
,
1803 MiRosProtectVirtualMemory(
1804 IN PEPROCESS Process
,
1805 IN OUT PVOID
*BaseAddress
,
1806 IN OUT PSIZE_T NumberOfBytesToProtect
,
1807 IN ULONG NewAccessProtection
,
1808 OUT PULONG OldAccessProtection OPTIONAL
1816 IN KPROCESSOR_MODE Mode
,
1817 IN PVOID TrapInformation
1822 MiCheckPdeForPagedPool(
1829 MiInitializeNonPagedPool(
1836 MiInitializeNonPagedPoolThresholds(
1843 MiInitializePoolEvents(
1851 IN POOL_TYPE PoolType
,// FIXFIX: This should go in ex.h after the pool merge
1852 IN ULONG Threshold
//
1855 // FIXFIX: THIS ONE TOO
1859 ExInitializePoolDescriptor(
1860 IN PPOOL_DESCRIPTOR PoolDescriptor
,
1861 IN POOL_TYPE PoolType
,
1869 MiInitializeSessionPool(
1876 MiInitializeSystemPtes(
1877 IN PMMPTE StartingPte
,
1878 IN ULONG NumberOfPtes
,
1879 IN MMSYSTEM_PTE_POOL_TYPE PoolType
1884 MiReserveSystemPtes(
1885 IN ULONG NumberOfPtes
,
1886 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
1891 MiReleaseSystemPtes(
1892 IN PMMPTE StartingPte
,
1893 IN ULONG NumberOfPtes
,
1894 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
1900 MiFindContiguousPages(
1901 IN PFN_NUMBER LowestPfn
,
1902 IN PFN_NUMBER HighestPfn
,
1903 IN PFN_NUMBER BoundaryPfn
,
1904 IN PFN_NUMBER SizeInPages
,
1905 IN MEMORY_CACHING_TYPE CacheType
1910 MiCheckForContiguousMemory(
1911 IN PVOID BaseAddress
,
1912 IN PFN_NUMBER BaseAddressPages
,
1913 IN PFN_NUMBER SizeInPages
,
1914 IN PFN_NUMBER LowestPfn
,
1915 IN PFN_NUMBER HighestPfn
,
1916 IN PFN_NUMBER BoundaryPfn
,
1917 IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
1922 MiAllocatePagesForMdl(
1923 IN PHYSICAL_ADDRESS LowAddress
,
1924 IN PHYSICAL_ADDRESS HighAddress
,
1925 IN PHYSICAL_ADDRESS SkipBytes
,
1926 IN SIZE_T TotalBytes
,
1927 IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
,
1934 IN PMMPFNLIST ListHead
,
1935 IN PFN_NUMBER PageFrameIndex
1940 MiUnlinkFreeOrZeroedPage(
1946 MiUnlinkPageFromList(
1953 IN PFN_NUMBER PageFrameIndex
,
1954 IN PMMPTE PointerPte
,
1960 MiInitializeAndChargePfn(
1961 OUT PPFN_NUMBER PageFrameIndex
,
1962 IN PMMPDE PointerPde
,
1963 IN PFN_NUMBER ContainingPageFrame
,
1964 IN BOOLEAN SessionAllocation
1969 MiInitializePfnAndMakePteValid(
1970 IN PFN_NUMBER PageFrameIndex
,
1971 IN PMMPTE PointerPte
,
1977 MiInitializePfnForOtherProcess(
1978 IN PFN_NUMBER PageFrameIndex
,
1979 IN PVOID PteAddress
,
1980 IN PFN_NUMBER PteFrame
1985 MiDecrementShareCount(
1987 IN PFN_NUMBER PageFrameIndex
2005 IN PFN_NUMBER PageFrameIndex
2010 MiInsertPageInFreeList(
2011 IN PFN_NUMBER PageFrameIndex
2016 MiDeleteSystemPageableVm(
2017 IN PMMPTE PointerPte
,
2018 IN PFN_NUMBER PageCount
,
2020 OUT PPFN_NUMBER ValidPages
2025 MiGetPageProtection(
2026 IN PMMPTE PointerPte
2029 PLDR_DATA_TABLE_ENTRY
2031 MiLookupDataTableEntry(
2038 MiInitializeDriverLargePageList(
2045 MiInitializeLargePageSupport(
2065 IN PVOID VirtualAddress
2070 MiCheckForConflictingNode(
2071 IN ULONG_PTR StartVpn
,
2072 IN ULONG_PTR EndVpn
,
2073 IN PMM_AVL_TABLE Table
,
2074 OUT PMMADDRESS_NODE
*NodeOrParent
2079 MiFindEmptyAddressRangeDownTree(
2081 IN ULONG_PTR BoundaryAddress
,
2082 IN ULONG_PTR Alignment
,
2083 IN PMM_AVL_TABLE Table
,
2084 OUT PULONG_PTR Base
,
2085 OUT PMMADDRESS_NODE
*Parent
2090 MiFindEmptyAddressRangeDownBasedTree(
2092 IN ULONG_PTR BoundaryAddress
,
2093 IN ULONG_PTR Alignment
,
2094 IN PMM_AVL_TABLE Table
,
2100 MiFindEmptyAddressRangeInTree(
2102 IN ULONG_PTR Alignment
,
2103 IN PMM_AVL_TABLE Table
,
2104 OUT PMMADDRESS_NODE
*PreviousVad
,
2114 IN ULONG ProtectionMask
2121 _Inout_ PMM_AVL_TABLE VadRoot
);
2127 _In_ ULONG_PTR
*BaseAddress
,
2128 _In_ SIZE_T ViewSize
,
2129 _In_ ULONG_PTR HighestAddress
,
2130 _In_ ULONG_PTR Alignment
,
2131 _In_ ULONG AllocationType
);
2135 MiInsertBasedSection(
2141 MiUnmapViewOfSection(
2142 IN PEPROCESS Process
,
2143 IN PVOID BaseAddress
,
2149 MiRosUnmapViewOfSection(
2150 IN PEPROCESS Process
,
2151 IN PVOID BaseAddress
,
2152 IN BOOLEAN SkipDebuggerNotify
2158 IN PMM_AVL_TABLE Table
,
2159 IN PMMADDRESS_NODE NewNode
,
2160 PMMADDRESS_NODE Parent
,
2161 TABLE_SEARCH_RESULT Result
2167 IN PMMADDRESS_NODE Node
,
2168 IN PMM_AVL_TABLE Table
2174 IN PMMADDRESS_NODE Node
2180 IN PMMADDRESS_NODE Node
2185 MiInitializeSystemSpaceMap(
2186 IN PMMSESSION InputSession OPTIONAL
2191 MiSessionRemoveProcess(
2197 MiReleaseProcessReferenceToSessionDataPage(
2198 IN PMM_SESSION_SPACE SessionGlobal
2203 MiSessionAddProcess(
2204 IN PEPROCESS NewProcess
2209 MiSessionCommitPageTables(
2216 MiMakeProtectionMask(
2222 MiDeleteVirtualAddresses(
2224 IN ULONG_PTR EndingAddress
,
2231 IN PMMPTE PointerPte
,
2232 IN PVOID VirtualAddress
,
2233 IN PEPROCESS CurrentProcess
,
2234 IN PMMPTE PrototypePte
2239 MiMakeSystemAddressValid(
2240 IN PVOID PageTableVirtualAddress
,
2241 IN PEPROCESS CurrentProcess
2246 MiMakeSystemAddressValidPfn(
2247 IN PVOID VirtualAddress
,
2254 IN PEPROCESS CurrentProcess
,
2267 MiDeleteARM3Section(
2273 MiQueryMemorySectionName(
2274 IN HANDLE ProcessHandle
,
2275 IN PVOID BaseAddress
,
2276 OUT PVOID MemoryInformation
,
2277 IN SIZE_T MemoryInformationLength
,
2278 OUT PSIZE_T ReturnLength
2283 MiRosUnmapViewInSystemSpace(
2289 MmDeterminePoolType(
2290 IN PVOID PoolAddress
2295 MiMakePdeExistAndMakeValid(
2296 IN PMMPDE PointerPde
,
2297 IN PEPROCESS TargetProcess
,
2303 MiWriteProtectSystemImage(
2304 _In_ PVOID ImageBase
);
2307 // MiRemoveZeroPage will use inline code to zero out the page manually if only
2308 // free pages are available. In some scenarios, we don't/can't run that piece of
2309 // code and would rather only have a real zero page. If we can't have a zero page,
2310 // then we'd like to have our own code to grab a free page and zero it out, by
2311 // using MiRemoveAnyPage. This macro implements this.
2315 MiRemoveZeroPageSafe(IN ULONG Color
)
2317 if (MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
!= LIST_HEAD
) return MiRemoveZeroPage(Color
);
2321 #if (_MI_PAGING_LEVELS == 2)
2324 MiSynchronizeSystemPde(PMMPDE PointerPde
)
2329 /* Get the Index from the PDE */
2330 Index
= ((ULONG_PTR
)PointerPde
& (SYSTEM_PD_SIZE
- 1)) / sizeof(MMPTE
);
2332 /* Copy the PDE from the double-mapped system page directory */
2333 SystemPde
= MmSystemPagePtes
[Index
];
2334 *PointerPde
= SystemPde
;
2336 /* Make sure we re-read the PDE and PTE */
2337 KeMemoryBarrierWithoutFence();
2339 /* Return, if we had success */
2340 return SystemPde
.u
.Hard
.Valid
!= 0;