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