1c2c66affSColin Finck /* 2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top directory 3c2c66affSColin Finck * PROJECT: ReactOS kernel 4c2c66affSColin Finck * FILE: ntoskrnl/mm/rmap.c 5*6db0d24fSHermès Bélusca-Maïto * PURPOSE: Kernel memory management functions 6c2c66affSColin Finck * 7c2c66affSColin Finck * PROGRAMMERS: David Welch (welch@cwcom.net) 8c2c66affSColin Finck */ 9c2c66affSColin Finck 10c2c66affSColin Finck /* INCLUDES *****************************************************************/ 11c2c66affSColin Finck 12c2c66affSColin Finck #include <ntoskrnl.h> 13c2c66affSColin Finck #include <cache/section/newmm.h> 14c2c66affSColin Finck #define NDEBUG 15c2c66affSColin Finck #include <debug.h> 16c2c66affSColin Finck 17c2c66affSColin Finck /* TYPES ********************************************************************/ 18c2c66affSColin Finck 19c2c66affSColin Finck /* GLOBALS ******************************************************************/ 20c2c66affSColin Finck 21c2c66affSColin Finck static NPAGED_LOOKASIDE_LIST RmapLookasideList; 22c2c66affSColin Finck 23c2c66affSColin Finck /* FUNCTIONS ****************************************************************/ 24c2c66affSColin Finck 25c2c66affSColin Finck _IRQL_requires_max_(DISPATCH_LEVEL) 26c2c66affSColin Finck static 27c2c66affSColin Finck VOID 28c2c66affSColin Finck NTAPI 29c2c66affSColin Finck RmapListFree( 30c2c66affSColin Finck _In_ __drv_freesMem(Mem) PVOID P) 31c2c66affSColin Finck { 32c2c66affSColin Finck ExFreePoolWithTag(P, TAG_RMAP); 33c2c66affSColin Finck } 34c2c66affSColin Finck 355c7ce447SVictor Perevertkin CODE_SEG("INIT") 36b20f8151SSerge Gautherie VOID 37c2c66affSColin Finck NTAPI 38c2c66affSColin Finck MmInitializeRmapList(VOID) 39c2c66affSColin Finck { 40c2c66affSColin Finck ExInitializeNPagedLookasideList (&RmapLookasideList, 41c2c66affSColin Finck NULL, 42c2c66affSColin Finck RmapListFree, 43c2c66affSColin Finck 0, 44c2c66affSColin Finck sizeof(MM_RMAP_ENTRY), 45c2c66affSColin Finck TAG_RMAP, 46c2c66affSColin Finck 50); 47c2c66affSColin Finck } 48c2c66affSColin Finck 49c2c66affSColin Finck NTSTATUS 50c2c66affSColin Finck NTAPI 51c2c66affSColin Finck MmPageOutPhysicalAddress(PFN_NUMBER Page) 52c2c66affSColin Finck { 53c2c66affSColin Finck PMM_RMAP_ENTRY entry; 54c2c66affSColin Finck PMEMORY_AREA MemoryArea; 55c2c66affSColin Finck PMMSUPPORT AddressSpace; 5641475dfcSJérôme Gardou PVOID Address = NULL; 5741475dfcSJérôme Gardou PEPROCESS Process = NULL; 58c2c66affSColin Finck NTSTATUS Status = STATUS_SUCCESS; 59d8cdb89fSJérôme Gardou PMM_SECTION_SEGMENT Segment; 60d8cdb89fSJérôme Gardou LARGE_INTEGER SegmentOffset; 61d8cdb89fSJérôme Gardou KIRQL OldIrql; 62c2c66affSColin Finck 6341475dfcSJérôme Gardou GetEntry: 64d8cdb89fSJérôme Gardou OldIrql = MiAcquirePfnLock(); 65d8cdb89fSJérôme Gardou 66c2c66affSColin Finck entry = MmGetRmapListHeadPage(Page); 67c2c66affSColin Finck 68c2c66affSColin Finck while (entry && RMAP_IS_SEGMENT(entry->Address)) 69c2c66affSColin Finck entry = entry->Next; 70c2c66affSColin Finck 71c2c66affSColin Finck if (entry == NULL) 72c2c66affSColin Finck { 73d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 74d932bdb9SJérôme Gardou goto WriteSegment; 75c2c66affSColin Finck } 76c2c66affSColin Finck 77c2c66affSColin Finck Process = entry->Process; 78c2c66affSColin Finck Address = entry->Address; 79c2c66affSColin Finck 80c2c66affSColin Finck if ((((ULONG_PTR)Address) & 0xFFF) != 0) 81c2c66affSColin Finck { 82c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 83c2c66affSColin Finck } 84c2c66affSColin Finck 8541475dfcSJérôme Gardou /* This is for user-mode address only */ 8641475dfcSJérôme Gardou ASSERT(Address < MmSystemRangeStart); 8741475dfcSJérôme Gardou 88c2c66affSColin Finck if (!ExAcquireRundownProtection(&Process->RundownProtect)) 89c2c66affSColin Finck { 90d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 91c2c66affSColin Finck return STATUS_PROCESS_IS_TERMINATING; 92c2c66affSColin Finck } 93c2c66affSColin Finck 94c2c66affSColin Finck Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode); 95d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 96c2c66affSColin Finck if (!NT_SUCCESS(Status)) 97c2c66affSColin Finck { 98c2c66affSColin Finck ExReleaseRundownProtection(&Process->RundownProtect); 99c2c66affSColin Finck return Status; 100c2c66affSColin Finck } 101c2c66affSColin Finck AddressSpace = &Process->Vm; 102c2c66affSColin Finck 103c2c66affSColin Finck MmLockAddressSpace(AddressSpace); 104d8cdb89fSJérôme Gardou 10543378411SJérôme Gardou MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); 10643378411SJérôme Gardou if (MemoryArea == NULL || MemoryArea->DeleteInProgress) 10741475dfcSJérôme Gardou { 10841475dfcSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 10941475dfcSJérôme Gardou ExReleaseRundownProtection(&Process->RundownProtect); 11041475dfcSJérôme Gardou ObDereferenceObject(Process); 11141475dfcSJérôme Gardou goto GetEntry; 11241475dfcSJérôme Gardou } 11341475dfcSJérôme Gardou 11443378411SJérôme Gardou 11543378411SJérôme Gardou /* Attach to it, if needed */ 11643378411SJérôme Gardou ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess); 11743378411SJérôme Gardou if (Process != PsInitialSystemProcess) 11843378411SJérôme Gardou KeAttachProcess(&Process->Pcb); 11943378411SJérôme Gardou 12043378411SJérôme Gardou if (MmGetPfnForProcess(Process, Address) != Page) 121c2c66affSColin Finck { 12243378411SJérôme Gardou /* This changed in the short window where we didn't have any locks */ 12343378411SJérôme Gardou if (Process != PsInitialSystemProcess) 12443378411SJérôme Gardou KeDetachProcess(); 125c2c66affSColin Finck MmUnlockAddressSpace(AddressSpace); 126c2c66affSColin Finck ExReleaseRundownProtection(&Process->RundownProtect); 127c2c66affSColin Finck ObDereferenceObject(Process); 12841475dfcSJérôme Gardou goto GetEntry; 129c2c66affSColin Finck } 130d8cdb89fSJérôme Gardou 131d8cdb89fSJérôme Gardou if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) 132c2c66affSColin Finck { 133c2c66affSColin Finck ULONG_PTR Entry; 134d8cdb89fSJérôme Gardou BOOLEAN Dirty; 135d8cdb89fSJérôme Gardou PFN_NUMBER MapPage; 136d8cdb89fSJérôme Gardou LARGE_INTEGER Offset; 137d8cdb89fSJérôme Gardou BOOLEAN Released; 13875125228SJérôme Gardou BOOLEAN Unmapped; 139d8cdb89fSJérôme Gardou 140b7eb0fddSJérôme Gardou Offset.QuadPart = MemoryArea->SectionData.ViewOffset + 141c2c66affSColin Finck ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea)); 142c2c66affSColin Finck 143d8cdb89fSJérôme Gardou Segment = MemoryArea->SectionData.Segment; 144c2c66affSColin Finck 145d8cdb89fSJérôme Gardou MmLockSectionSegment(Segment); 146d8cdb89fSJérôme Gardou 147d8cdb89fSJérôme Gardou Entry = MmGetPageEntrySectionSegment(Segment, &Offset); 148c2c66affSColin Finck if (Entry && MM_IS_WAIT_PTE(Entry)) 149c2c66affSColin Finck { 150d8cdb89fSJérôme Gardou /* The segment is being read or something. Give up */ 151d8cdb89fSJérôme Gardou MmUnlockSectionSegment(Segment); 15243378411SJérôme Gardou if (Process != PsInitialSystemProcess) 15343378411SJérôme Gardou KeDetachProcess(); 154c2c66affSColin Finck MmUnlockAddressSpace(AddressSpace); 155c2c66affSColin Finck ExReleaseRundownProtection(&Process->RundownProtect); 156c2c66affSColin Finck ObDereferenceObject(Process); 157c2c66affSColin Finck return(STATUS_UNSUCCESSFUL); 158c2c66affSColin Finck } 159c2c66affSColin Finck 160d8cdb89fSJérôme Gardou /* Delete this virtual mapping in the process */ 16136a92e6eSJérôme Gardou MmDeleteRmap(Page, Process, Address); 16275125228SJérôme Gardou Unmapped = MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage); 16375125228SJérôme Gardou if (!Unmapped || (MapPage != Page)) 16475125228SJérôme Gardou { 16575125228SJérôme Gardou /* 16675125228SJérôme Gardou * Something's corrupted, we got there because this process is 16775125228SJérôme Gardou * supposed to be mapping this page there. 16875125228SJérôme Gardou */ 16975125228SJérôme Gardou KeBugCheckEx(MEMORY_MANAGEMENT, 17075125228SJérôme Gardou (ULONG_PTR)Process, 17175125228SJérôme Gardou (ULONG_PTR)Address, 17275125228SJérôme Gardou (ULONG_PTR)__FILE__, 17375125228SJérôme Gardou __LINE__); 17475125228SJérôme Gardou } 175c2c66affSColin Finck 176d8cdb89fSJérôme Gardou if (Page != PFN_FROM_SSE(Entry)) 177d8cdb89fSJérôme Gardou { 178d8cdb89fSJérôme Gardou SWAPENTRY SwapEntry; 179d8cdb89fSJérôme Gardou 180d8cdb89fSJérôme Gardou /* This page is private to the process */ 181d8cdb89fSJérôme Gardou MmUnlockSectionSegment(Segment); 182d8cdb89fSJérôme Gardou 183d8cdb89fSJérôme Gardou /* Check if we should write it back to the page file */ 184d8cdb89fSJérôme Gardou SwapEntry = MmGetSavedSwapEntryPage(Page); 185d8cdb89fSJérôme Gardou 186d8cdb89fSJérôme Gardou if ((SwapEntry == 0) && Dirty) 187d8cdb89fSJérôme Gardou { 188d8cdb89fSJérôme Gardou /* We don't have a Swap entry, yet the page is dirty. Get one */ 189d8cdb89fSJérôme Gardou SwapEntry = MmAllocSwapPage(); 190d8cdb89fSJérôme Gardou if (!SwapEntry) 191d8cdb89fSJérôme Gardou { 192d8cdb89fSJérôme Gardou PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 193d8cdb89fSJérôme Gardou &MemoryArea->SectionData.RegionListHead, 194d8cdb89fSJérôme Gardou Address, NULL); 195d8cdb89fSJérôme Gardou 196d8cdb89fSJérôme Gardou /* We can't, so let this page in the Process VM */ 19743378411SJérôme Gardou MmCreateVirtualMapping(Process, Address, Region->Protect, Page); 19836a92e6eSJérôme Gardou MmInsertRmap(Page, Process, Address); 199d8cdb89fSJérôme Gardou MmSetDirtyPage(Process, Address); 200d8cdb89fSJérôme Gardou 201d8cdb89fSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 20236a92e6eSJérôme Gardou if (Process != PsInitialSystemProcess) 20336a92e6eSJérôme Gardou KeDetachProcess(); 204d932bdb9SJérôme Gardou ExReleaseRundownProtection(&Process->RundownProtect); 205d932bdb9SJérôme Gardou ObDereferenceObject(Process); 206d932bdb9SJérôme Gardou 207d8cdb89fSJérôme Gardou return STATUS_UNSUCCESSFUL; 208d8cdb89fSJérôme Gardou } 209d8cdb89fSJérôme Gardou } 210d8cdb89fSJérôme Gardou 211d8cdb89fSJérôme Gardou if (Dirty) 212d8cdb89fSJérôme Gardou { 21336a92e6eSJérôme Gardou SWAPENTRY Dummy; 21436a92e6eSJérôme Gardou 21536a92e6eSJérôme Gardou /* Put a wait entry into the process and unlock */ 21636a92e6eSJérôme Gardou MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY); 21736a92e6eSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 21836a92e6eSJérôme Gardou 219d8cdb89fSJérôme Gardou Status = MmWriteToSwapPage(SwapEntry, Page); 22036a92e6eSJérôme Gardou 22136a92e6eSJérôme Gardou MmLockAddressSpace(AddressSpace); 22236a92e6eSJérôme Gardou MmDeletePageFileMapping(Process, Address, &Dummy); 22336a92e6eSJérôme Gardou ASSERT(Dummy == MM_WAIT_ENTRY); 22436a92e6eSJérôme Gardou 225d8cdb89fSJérôme Gardou if (!NT_SUCCESS(Status)) 226d8cdb89fSJérôme Gardou { 227d8cdb89fSJérôme Gardou /* We failed at saving the content of this page. Keep it in */ 228d8cdb89fSJérôme Gardou PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea), 229d8cdb89fSJérôme Gardou &MemoryArea->SectionData.RegionListHead, 230d8cdb89fSJérôme Gardou Address, NULL); 231d8cdb89fSJérôme Gardou 232d8cdb89fSJérôme Gardou /* This Swap Entry is useless to us */ 233d8cdb89fSJérôme Gardou MmSetSavedSwapEntryPage(Page, 0); 234d8cdb89fSJérôme Gardou MmFreeSwapPage(SwapEntry); 235d8cdb89fSJérôme Gardou 236d8cdb89fSJérôme Gardou /* We can't, so let this page in the Process VM */ 23743378411SJérôme Gardou MmCreateVirtualMapping(Process, Address, Region->Protect, Page); 23836a92e6eSJérôme Gardou MmInsertRmap(Page, Process, Address); 239d8cdb89fSJérôme Gardou MmSetDirtyPage(Process, Address); 240d8cdb89fSJérôme Gardou 241d8cdb89fSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 24236a92e6eSJérôme Gardou if (Process != PsInitialSystemProcess) 24336a92e6eSJérôme Gardou KeDetachProcess(); 244d932bdb9SJérôme Gardou ExReleaseRundownProtection(&Process->RundownProtect); 245d932bdb9SJérôme Gardou ObDereferenceObject(Process); 2467f7abc98SJérôme Gardou 247d8cdb89fSJérôme Gardou return STATUS_UNSUCCESSFUL; 248d8cdb89fSJérôme Gardou } 249d8cdb89fSJérôme Gardou } 250d8cdb89fSJérôme Gardou 251d8cdb89fSJérôme Gardou if (SwapEntry) 252d8cdb89fSJérôme Gardou { 253d8cdb89fSJérôme Gardou /* Keep this in the process VM */ 254d8cdb89fSJérôme Gardou MmCreatePageFileMapping(Process, Address, SwapEntry); 255d8cdb89fSJérôme Gardou MmSetSavedSwapEntryPage(Page, 0); 256d8cdb89fSJérôme Gardou } 257d8cdb89fSJérôme Gardou 258d8cdb89fSJérôme Gardou /* We can finally let this page go */ 25936a92e6eSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 26036a92e6eSJérôme Gardou if (Process != PsInitialSystemProcess) 26136a92e6eSJérôme Gardou KeDetachProcess(); 262f201b8afSJérôme Gardou #if DBG 263f201b8afSJérôme Gardou OldIrql = MiAcquirePfnLock(); 264d8cdb89fSJérôme Gardou ASSERT(MmGetRmapListHeadPage(Page) == NULL); 265f201b8afSJérôme Gardou MiReleasePfnLock(OldIrql); 266f201b8afSJérôme Gardou #endif 267ba49c390SJérôme Gardou MmReleasePageMemoryConsumer(MC_USER, Page); 268d8cdb89fSJérôme Gardou 269d8cdb89fSJérôme Gardou ExReleaseRundownProtection(&Process->RundownProtect); 270d8cdb89fSJérôme Gardou ObDereferenceObject(Process); 2717f7abc98SJérôme Gardou 272d8cdb89fSJérôme Gardou return STATUS_SUCCESS; 273d8cdb89fSJérôme Gardou } 274d8cdb89fSJérôme Gardou 275d8cdb89fSJérôme Gardou /* One less mapping referencing this segment */ 27641475dfcSJérôme Gardou Released = MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, TRUE, NULL); 277d8cdb89fSJérôme Gardou 278d8cdb89fSJérôme Gardou MmUnlockSectionSegment(Segment); 27943378411SJérôme Gardou if (Process != PsInitialSystemProcess) 28043378411SJérôme Gardou KeDetachProcess(); 281d8cdb89fSJérôme Gardou MmUnlockAddressSpace(AddressSpace); 282d8cdb89fSJérôme Gardou 283d8cdb89fSJérôme Gardou ExReleaseRundownProtection(&Process->RundownProtect); 284d8cdb89fSJérôme Gardou ObDereferenceObject(Process); 285d8cdb89fSJérôme Gardou 286d8cdb89fSJérôme Gardou if (Released) return STATUS_SUCCESS; 287c2c66affSColin Finck } 288462d9a09SJérôme Gardou #ifdef NEWCC 289c2c66affSColin Finck else if (Type == MEMORY_AREA_CACHE) 290c2c66affSColin Finck { 291c2c66affSColin Finck /* NEWCC does locking itself */ 292c2c66affSColin Finck MmUnlockAddressSpace(AddressSpace); 293c2c66affSColin Finck Status = MmpPageOutPhysicalAddress(Page); 294c2c66affSColin Finck } 295462d9a09SJérôme Gardou #endif 296c2c66affSColin Finck else 297c2c66affSColin Finck { 298c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 299c2c66affSColin Finck } 300c2c66affSColin Finck 301d932bdb9SJérôme Gardou WriteSegment: 302d8cdb89fSJérôme Gardou /* Now write this page to file, if needed */ 303d8cdb89fSJérôme Gardou Segment = MmGetSectionAssociation(Page, &SegmentOffset); 304d8cdb89fSJérôme Gardou if (Segment) 305d8cdb89fSJérôme Gardou { 306d8cdb89fSJérôme Gardou BOOLEAN Released; 307d8cdb89fSJérôme Gardou 308d8cdb89fSJérôme Gardou MmLockSectionSegment(Segment); 309d8cdb89fSJérôme Gardou 310d8cdb89fSJérôme Gardou Released = MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE); 311d8cdb89fSJérôme Gardou 312d8cdb89fSJérôme Gardou MmUnlockSectionSegment(Segment); 313d8cdb89fSJérôme Gardou MmDereferenceSegment(Segment); 314d8cdb89fSJérôme Gardou 315d8cdb89fSJérôme Gardou if (Released) 316d8cdb89fSJérôme Gardou { 317d8cdb89fSJérôme Gardou return STATUS_SUCCESS; 318d8cdb89fSJérôme Gardou } 319d8cdb89fSJérôme Gardou } 320d8cdb89fSJérôme Gardou 321d8cdb89fSJérôme Gardou /* If we are here, then we didn't release the page */ 322d8cdb89fSJérôme Gardou return STATUS_UNSUCCESSFUL; 323c2c66affSColin Finck } 324c2c66affSColin Finck 325c2c66affSColin Finck VOID 326c2c66affSColin Finck NTAPI 327c2c66affSColin Finck MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, 328c2c66affSColin Finck PVOID Address) 329c2c66affSColin Finck { 330c2c66affSColin Finck PMM_RMAP_ENTRY current_entry; 331c2c66affSColin Finck PMM_RMAP_ENTRY new_entry; 332c2c66affSColin Finck ULONG PrevSize; 333d8cdb89fSJérôme Gardou KIRQL OldIrql; 334d8cdb89fSJérôme Gardou 335c2c66affSColin Finck if (!RMAP_IS_SEGMENT(Address)) 336c2c66affSColin Finck Address = (PVOID)PAGE_ROUND_DOWN(Address); 337c2c66affSColin Finck 338c2c66affSColin Finck new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList); 339c2c66affSColin Finck if (new_entry == NULL) 340c2c66affSColin Finck { 341c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 342c2c66affSColin Finck } 343c2c66affSColin Finck new_entry->Address = Address; 344c2c66affSColin Finck new_entry->Process = (PEPROCESS)Process; 345c2c66affSColin Finck #if DBG 346c2c66affSColin Finck new_entry->Caller = _ReturnAddress(); 347c2c66affSColin Finck #endif 348c2c66affSColin Finck 349c2c66affSColin Finck if ( 350c2c66affSColin Finck !RMAP_IS_SEGMENT(Address) && 351c2c66affSColin Finck MmGetPfnForProcess(Process, Address) != Page) 352c2c66affSColin Finck { 353c2c66affSColin Finck DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical " 354c2c66affSColin Finck "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0, 355c2c66affSColin Finck Address, 356c2c66affSColin Finck MmGetPfnForProcess(Process, Address) << PAGE_SHIFT, 357c2c66affSColin Finck Page << PAGE_SHIFT); 358c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 359c2c66affSColin Finck } 360c2c66affSColin Finck 361d8cdb89fSJérôme Gardou OldIrql = MiAcquirePfnLock(); 362c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page); 36341475dfcSJérôme Gardou 36441475dfcSJérôme Gardou PMM_RMAP_ENTRY previous_entry = NULL; 36541475dfcSJérôme Gardou /* Keep the list sorted */ 36641475dfcSJérôme Gardou while (current_entry && (current_entry->Address < Address)) 367c2c66affSColin Finck { 36841475dfcSJérôme Gardou previous_entry = current_entry; 369c2c66affSColin Finck current_entry = current_entry->Next; 370c2c66affSColin Finck } 37141475dfcSJérôme Gardou 37241475dfcSJérôme Gardou /* In case of clash in the address, sort by process */ 37341475dfcSJérôme Gardou if (current_entry && (current_entry->Address == Address)) 37441475dfcSJérôme Gardou { 37541475dfcSJérôme Gardou while (current_entry && (current_entry->Process < Process)) 37641475dfcSJérôme Gardou { 37741475dfcSJérôme Gardou previous_entry = current_entry; 37841475dfcSJérôme Gardou current_entry = current_entry->Next; 37941475dfcSJérôme Gardou } 38041475dfcSJérôme Gardou } 38141475dfcSJérôme Gardou 38241475dfcSJérôme Gardou if (current_entry && (current_entry->Address == Address) && (current_entry->Process == Process)) 38341475dfcSJérôme Gardou { 384b705df73SVictor Perevertkin #if DBG 38541475dfcSJérôme Gardou DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n", current_entry->Address); 38641475dfcSJérôme Gardou DbgPrint(" current caller %p\n", new_entry->Caller); 38741475dfcSJérôme Gardou DbgPrint(" previous caller %p\n", current_entry->Caller); 388b705df73SVictor Perevertkin #endif 38941475dfcSJérôme Gardou KeBugCheck(MEMORY_MANAGEMENT); 39041475dfcSJérôme Gardou } 39141475dfcSJérôme Gardou 39241475dfcSJérôme Gardou new_entry->Next = current_entry; 39341475dfcSJérôme Gardou if (previous_entry) 39441475dfcSJérôme Gardou previous_entry->Next = new_entry; 39541475dfcSJérôme Gardou else 396c2c66affSColin Finck MmSetRmapListHeadPage(Page, new_entry); 39741475dfcSJérôme Gardou 398d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 399d8cdb89fSJérôme Gardou 400c2c66affSColin Finck if (!RMAP_IS_SEGMENT(Address)) 401c2c66affSColin Finck { 40211eee4eeSJérôme Gardou ASSERT(Process != NULL); 403c2c66affSColin Finck PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE); 404c2c66affSColin Finck if (PrevSize >= Process->Vm.PeakWorkingSetSize) 405c2c66affSColin Finck { 406c2c66affSColin Finck Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE; 407c2c66affSColin Finck } 408c2c66affSColin Finck } 409c2c66affSColin Finck } 410c2c66affSColin Finck 411c2c66affSColin Finck VOID 412c2c66affSColin Finck NTAPI 413c2c66affSColin Finck MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, 414c2c66affSColin Finck PVOID Address) 415c2c66affSColin Finck { 416c2c66affSColin Finck PMM_RMAP_ENTRY current_entry, previous_entry; 417d8cdb89fSJérôme Gardou KIRQL OldIrql; 418c2c66affSColin Finck 419d8cdb89fSJérôme Gardou OldIrql = MiAcquirePfnLock(); 420c2c66affSColin Finck previous_entry = NULL; 421c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page); 422c2c66affSColin Finck 423c2c66affSColin Finck while (current_entry != NULL) 424c2c66affSColin Finck { 425c2c66affSColin Finck if (current_entry->Process == (PEPROCESS)Process && 426c2c66affSColin Finck current_entry->Address == Address) 427c2c66affSColin Finck { 428c2c66affSColin Finck if (previous_entry == NULL) 429c2c66affSColin Finck { 430c2c66affSColin Finck MmSetRmapListHeadPage(Page, current_entry->Next); 431c2c66affSColin Finck } 432c2c66affSColin Finck else 433c2c66affSColin Finck { 434c2c66affSColin Finck previous_entry->Next = current_entry->Next; 435c2c66affSColin Finck } 436d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 437d8cdb89fSJérôme Gardou 438c2c66affSColin Finck ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry); 439c2c66affSColin Finck if (!RMAP_IS_SEGMENT(Address)) 440c2c66affSColin Finck { 44111eee4eeSJérôme Gardou ASSERT(Process != NULL); 442c2c66affSColin Finck (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE); 443c2c66affSColin Finck } 444c2c66affSColin Finck return; 445c2c66affSColin Finck } 446c2c66affSColin Finck previous_entry = current_entry; 447c2c66affSColin Finck current_entry = current_entry->Next; 448c2c66affSColin Finck } 449c2c66affSColin Finck KeBugCheck(MEMORY_MANAGEMENT); 450c2c66affSColin Finck } 451c2c66affSColin Finck 452c2c66affSColin Finck /* 453c2c66affSColin Finck 454c2c66affSColin Finck Return the process pointer given when a previous call to MmInsertRmap was 455c2c66affSColin Finck called with a process and address pointer that conform to the segment rmap 456c2c66affSColin Finck schema. In short, this requires the address part to be 0xffffff00 + n 457c2c66affSColin Finck where n is between 0 and 255. When such an rmap exists, it specifies a 458c2c66affSColin Finck segment rmap in which the process part is a pointer to a slice of a section 459c2c66affSColin Finck page table, and the low 8 bits of the address represent a page index in the 460c2c66affSColin Finck page table slice. Together, this information is used by 461c2c66affSColin Finck MmGetSectionAssociation to determine which page entry points to this page in 462c2c66affSColin Finck the segment page table. 463c2c66affSColin Finck 464c2c66affSColin Finck */ 465c2c66affSColin Finck 466c2c66affSColin Finck PVOID 467c2c66affSColin Finck NTAPI 468c2c66affSColin Finck MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset) 469c2c66affSColin Finck { 470c2c66affSColin Finck PCACHE_SECTION_PAGE_TABLE Result = NULL; 471c2c66affSColin Finck PMM_RMAP_ENTRY current_entry;//, previous_entry; 472d8cdb89fSJérôme Gardou KIRQL OldIrql = MiAcquirePfnLock(); 473c2c66affSColin Finck 474c2c66affSColin Finck //previous_entry = NULL; 475c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page); 476c2c66affSColin Finck while (current_entry != NULL) 477c2c66affSColin Finck { 478c2c66affSColin Finck if (RMAP_IS_SEGMENT(current_entry->Address)) 479c2c66affSColin Finck { 480c2c66affSColin Finck Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process; 481c2c66affSColin Finck *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK; 482d8cdb89fSJérôme Gardou if (*Result->Segment->Flags & MM_SEGMENT_INDELETE) 483d8cdb89fSJérôme Gardou { 484d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 485d8cdb89fSJérôme Gardou return NULL; 486d8cdb89fSJérôme Gardou } 487d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 488c2c66affSColin Finck return Result; 489c2c66affSColin Finck } 490c2c66affSColin Finck //previous_entry = current_entry; 491c2c66affSColin Finck current_entry = current_entry->Next; 492c2c66affSColin Finck } 493d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 494c2c66affSColin Finck return NULL; 495c2c66affSColin Finck } 496c2c66affSColin Finck 497c2c66affSColin Finck /* 498c2c66affSColin Finck 499c2c66affSColin Finck Remove the section rmap associated with the indicated page, if it exists. 500c2c66affSColin Finck 501c2c66affSColin Finck */ 502c2c66affSColin Finck 503c2c66affSColin Finck VOID 504c2c66affSColin Finck NTAPI 505c2c66affSColin Finck MmDeleteSectionAssociation(PFN_NUMBER Page) 506c2c66affSColin Finck { 507c2c66affSColin Finck PMM_RMAP_ENTRY current_entry, previous_entry; 508d8cdb89fSJérôme Gardou KIRQL OldIrql = MiAcquirePfnLock(); 509c2c66affSColin Finck 510c2c66affSColin Finck previous_entry = NULL; 511c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page); 512c2c66affSColin Finck while (current_entry != NULL) 513c2c66affSColin Finck { 514c2c66affSColin Finck if (RMAP_IS_SEGMENT(current_entry->Address)) 515c2c66affSColin Finck { 516c2c66affSColin Finck if (previous_entry == NULL) 517c2c66affSColin Finck { 518c2c66affSColin Finck MmSetRmapListHeadPage(Page, current_entry->Next); 519c2c66affSColin Finck } 520c2c66affSColin Finck else 521c2c66affSColin Finck { 522c2c66affSColin Finck previous_entry->Next = current_entry->Next; 523c2c66affSColin Finck } 524d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 525c2c66affSColin Finck ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry); 526c2c66affSColin Finck return; 527c2c66affSColin Finck } 528c2c66affSColin Finck previous_entry = current_entry; 529c2c66affSColin Finck current_entry = current_entry->Next; 530c2c66affSColin Finck } 531d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql); 532c2c66affSColin Finck } 533