xref: /reactos/ntoskrnl/mm/rmap.c (revision 6db0d24f)
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