xref: /reactos/ntoskrnl/mm/rmap.c (revision 11eee4ee)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top directory
3c2c66affSColin Finck  * PROJECT:         ReactOS kernel
4c2c66affSColin Finck  * FILE:            ntoskrnl/mm/rmap.c
5c2c66affSColin Finck  * PURPOSE:         Kernel memory managment 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;
56c2c66affSColin Finck     PVOID Address;
57c2c66affSColin Finck     PEPROCESS Process;
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 
63d8cdb89fSJérôme Gardou     OldIrql = MiAcquirePfnLock();
64d8cdb89fSJérôme Gardou 
65c2c66affSColin Finck     entry = MmGetRmapListHeadPage(Page);
66c2c66affSColin Finck 
67c2c66affSColin Finck     while (entry && RMAP_IS_SEGMENT(entry->Address))
68c2c66affSColin Finck         entry = entry->Next;
69c2c66affSColin Finck 
70c2c66affSColin Finck     if (entry == NULL)
71c2c66affSColin Finck     {
72d8cdb89fSJérôme Gardou         MiReleasePfnLock(OldIrql);
73d932bdb9SJérôme Gardou         goto WriteSegment;
74c2c66affSColin Finck     }
75c2c66affSColin Finck 
76c2c66affSColin Finck     Process = entry->Process;
77c2c66affSColin Finck     Address = entry->Address;
78c2c66affSColin Finck 
79c2c66affSColin Finck     if ((((ULONG_PTR)Address) & 0xFFF) != 0)
80c2c66affSColin Finck     {
81c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
82c2c66affSColin Finck     }
83c2c66affSColin Finck 
84c2c66affSColin Finck     if (Address < MmSystemRangeStart)
85c2c66affSColin Finck     {
86c2c66affSColin Finck         if (!ExAcquireRundownProtection(&Process->RundownProtect))
87c2c66affSColin Finck         {
88d8cdb89fSJérôme Gardou             MiReleasePfnLock(OldIrql);
89c2c66affSColin Finck             return STATUS_PROCESS_IS_TERMINATING;
90c2c66affSColin Finck         }
91c2c66affSColin Finck 
92c2c66affSColin Finck         Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
93d8cdb89fSJérôme Gardou         MiReleasePfnLock(OldIrql);
94c2c66affSColin Finck         if (!NT_SUCCESS(Status))
95c2c66affSColin Finck         {
96c2c66affSColin Finck             ExReleaseRundownProtection(&Process->RundownProtect);
97c2c66affSColin Finck             return Status;
98c2c66affSColin Finck         }
99c2c66affSColin Finck         AddressSpace = &Process->Vm;
100c2c66affSColin Finck     }
101c2c66affSColin Finck     else
102c2c66affSColin Finck     {
103d8cdb89fSJérôme Gardou         MiReleasePfnLock(OldIrql);
104c2c66affSColin Finck         AddressSpace = MmGetKernelAddressSpace();
105c2c66affSColin Finck     }
106c2c66affSColin Finck 
107c2c66affSColin Finck     MmLockAddressSpace(AddressSpace);
108d8cdb89fSJérôme Gardou 
109c2c66affSColin Finck     MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
110c2c66affSColin Finck     if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
111c2c66affSColin Finck     {
112c2c66affSColin Finck         MmUnlockAddressSpace(AddressSpace);
113c2c66affSColin Finck         if (Address < MmSystemRangeStart)
114c2c66affSColin Finck         {
115c2c66affSColin Finck             ExReleaseRundownProtection(&Process->RundownProtect);
116c2c66affSColin Finck             ObDereferenceObject(Process);
117c2c66affSColin Finck         }
118c2c66affSColin Finck         return(STATUS_UNSUCCESSFUL);
119c2c66affSColin Finck     }
120d8cdb89fSJérôme Gardou 
121d8cdb89fSJérôme Gardou     if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
122c2c66affSColin Finck     {
123c2c66affSColin Finck         ULONG_PTR Entry;
124d8cdb89fSJérôme Gardou         BOOLEAN Dirty;
125d8cdb89fSJérôme Gardou         PFN_NUMBER MapPage;
126d8cdb89fSJérôme Gardou         LARGE_INTEGER Offset;
127d8cdb89fSJérôme Gardou         BOOLEAN Released;
128d8cdb89fSJérôme Gardou 
129d8cdb89fSJérôme Gardou         Offset.QuadPart = MemoryArea->SectionData.ViewOffset.QuadPart +
130c2c66affSColin Finck                  ((ULONG_PTR)Address - MA_GetStartingAddress(MemoryArea));
131c2c66affSColin Finck 
132d8cdb89fSJérôme Gardou         Segment = MemoryArea->SectionData.Segment;
133c2c66affSColin Finck 
134d8cdb89fSJérôme Gardou         MmLockSectionSegment(Segment);
135d8cdb89fSJérôme Gardou 
136d8cdb89fSJérôme Gardou         Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
137c2c66affSColin Finck         if (Entry && MM_IS_WAIT_PTE(Entry))
138c2c66affSColin Finck         {
139d8cdb89fSJérôme Gardou             /* The segment is being read or something. Give up */
140d8cdb89fSJérôme Gardou             MmUnlockSectionSegment(Segment);
141c2c66affSColin Finck             MmUnlockAddressSpace(AddressSpace);
142c2c66affSColin Finck             if (Address < MmSystemRangeStart)
143c2c66affSColin Finck             {
144c2c66affSColin Finck                 ExReleaseRundownProtection(&Process->RundownProtect);
145c2c66affSColin Finck                 ObDereferenceObject(Process);
146c2c66affSColin Finck             }
147c2c66affSColin Finck             return(STATUS_UNSUCCESSFUL);
148c2c66affSColin Finck         }
149c2c66affSColin Finck 
150d8cdb89fSJérôme Gardou         /* Delete this virtual mapping in the process */
151d8cdb89fSJérôme Gardou         MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage);
152d8cdb89fSJérôme Gardou         ASSERT(MapPage == Page);
153c2c66affSColin Finck 
154d8cdb89fSJérôme Gardou         if (Page != PFN_FROM_SSE(Entry))
155d8cdb89fSJérôme Gardou         {
156d8cdb89fSJérôme Gardou             SWAPENTRY SwapEntry;
157d8cdb89fSJérôme Gardou 
158d8cdb89fSJérôme Gardou             /* This page is private to the process */
159d8cdb89fSJérôme Gardou             MmUnlockSectionSegment(Segment);
160d8cdb89fSJérôme Gardou 
161d8cdb89fSJérôme Gardou             /* Check if we should write it back to the page file */
162d8cdb89fSJérôme Gardou             SwapEntry = MmGetSavedSwapEntryPage(Page);
163d8cdb89fSJérôme Gardou 
164d8cdb89fSJérôme Gardou             if ((SwapEntry == 0) && Dirty)
165d8cdb89fSJérôme Gardou             {
166d8cdb89fSJérôme Gardou                 /* We don't have a Swap entry, yet the page is dirty. Get one */
167d8cdb89fSJérôme Gardou                 SwapEntry = MmAllocSwapPage();
168d8cdb89fSJérôme Gardou                 if (!SwapEntry)
169d8cdb89fSJérôme Gardou                 {
170d8cdb89fSJérôme Gardou                     PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
171d8cdb89fSJérôme Gardou                             &MemoryArea->SectionData.RegionListHead,
172d8cdb89fSJérôme Gardou                             Address, NULL);
173d8cdb89fSJérôme Gardou 
174d8cdb89fSJérôme Gardou                     /* We can't, so let this page in the Process VM */
175d8cdb89fSJérôme Gardou                     MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1);
176d8cdb89fSJérôme Gardou                     MmSetDirtyPage(Process, Address);
177d8cdb89fSJérôme Gardou 
178d8cdb89fSJérôme Gardou                     MmUnlockAddressSpace(AddressSpace);
179d932bdb9SJérôme Gardou                     if (Address < MmSystemRangeStart)
180d932bdb9SJérôme Gardou                     {
181d932bdb9SJérôme Gardou                         ExReleaseRundownProtection(&Process->RundownProtect);
182d932bdb9SJérôme Gardou                         ObDereferenceObject(Process);
183d932bdb9SJérôme Gardou                     }
184d932bdb9SJérôme Gardou 
185d8cdb89fSJérôme Gardou                     return STATUS_UNSUCCESSFUL;
186d8cdb89fSJérôme Gardou                 }
187d8cdb89fSJérôme Gardou             }
188d8cdb89fSJérôme Gardou 
189d8cdb89fSJérôme Gardou             if (Dirty)
190d8cdb89fSJérôme Gardou             {
191d8cdb89fSJérôme Gardou                 Status = MmWriteToSwapPage(SwapEntry, Page);
192d8cdb89fSJérôme Gardou                 if (!NT_SUCCESS(Status))
193d8cdb89fSJérôme Gardou                 {
194d8cdb89fSJérôme Gardou                     /* We failed at saving the content of this page. Keep it in */
195d8cdb89fSJérôme Gardou                     PMM_REGION Region = MmFindRegion((PVOID)MA_GetStartingAddress(MemoryArea),
196d8cdb89fSJérôme Gardou                             &MemoryArea->SectionData.RegionListHead,
197d8cdb89fSJérôme Gardou                             Address, NULL);
198d8cdb89fSJérôme Gardou 
199d8cdb89fSJérôme Gardou                     /* This Swap Entry is useless to us */
200d8cdb89fSJérôme Gardou                     MmSetSavedSwapEntryPage(Page, 0);
201d8cdb89fSJérôme Gardou                     MmFreeSwapPage(SwapEntry);
202d8cdb89fSJérôme Gardou 
203d8cdb89fSJérôme Gardou                     /* We can't, so let this page in the Process VM */
204d8cdb89fSJérôme Gardou                     MmCreateVirtualMapping(Process, Address, Region->Protect, &Page, 1);
205d8cdb89fSJérôme Gardou                     MmSetDirtyPage(Process, Address);
206d8cdb89fSJérôme Gardou 
207d8cdb89fSJérôme Gardou                     MmUnlockAddressSpace(AddressSpace);
208d932bdb9SJérôme Gardou                     if (Address < MmSystemRangeStart)
209d932bdb9SJérôme Gardou                     {
210d932bdb9SJérôme Gardou                         ExReleaseRundownProtection(&Process->RundownProtect);
211d932bdb9SJérôme Gardou                         ObDereferenceObject(Process);
212d932bdb9SJérôme Gardou                     }
213d8cdb89fSJérôme Gardou                     return STATUS_UNSUCCESSFUL;
214d8cdb89fSJérôme Gardou                 }
215d8cdb89fSJérôme Gardou             }
216d8cdb89fSJérôme Gardou 
217d8cdb89fSJérôme Gardou             if (SwapEntry)
218d8cdb89fSJérôme Gardou             {
219d8cdb89fSJérôme Gardou                 /* Keep this in the process VM */
220d8cdb89fSJérôme Gardou                 MmCreatePageFileMapping(Process, Address, SwapEntry);
221d8cdb89fSJérôme Gardou                 MmSetSavedSwapEntryPage(Page, 0);
222d8cdb89fSJérôme Gardou             }
223d8cdb89fSJérôme Gardou 
224c2c66affSColin Finck             MmUnlockAddressSpace(AddressSpace);
225c2c66affSColin Finck 
226d8cdb89fSJérôme Gardou             /* We can finally let this page go */
227d8cdb89fSJérôme Gardou             MmDeleteRmap(Page, Process, Address);
228d8cdb89fSJérôme Gardou             ASSERT(MmGetRmapListHeadPage(Page) == NULL);
229ba49c390SJérôme Gardou             MmReleasePageMemoryConsumer(MC_USER, Page);
230d8cdb89fSJérôme Gardou 
231d8cdb89fSJérôme Gardou             if (Address < MmSystemRangeStart)
232d8cdb89fSJérôme Gardou             {
233d8cdb89fSJérôme Gardou                 ExReleaseRundownProtection(&Process->RundownProtect);
234d8cdb89fSJérôme Gardou                 ObDereferenceObject(Process);
235d8cdb89fSJérôme Gardou             }
236d8cdb89fSJérôme Gardou             return STATUS_SUCCESS;
237d8cdb89fSJérôme Gardou         }
238d8cdb89fSJérôme Gardou 
239d8cdb89fSJérôme Gardou         /* Delete this RMAP */
240d8cdb89fSJérôme Gardou         MmDeleteRmap(Page, Process, Address);
241d8cdb89fSJérôme Gardou 
242d8cdb89fSJérôme Gardou         /* One less mapping referencing this segment */
243d8cdb89fSJérôme Gardou         Released = MmUnsharePageEntrySectionSegment(MemoryArea, Segment, &Offset, Dirty, FALSE, NULL);
244d8cdb89fSJérôme Gardou 
245d8cdb89fSJérôme Gardou         MmUnlockSectionSegment(Segment);
246d8cdb89fSJérôme Gardou         MmUnlockAddressSpace(AddressSpace);
247d8cdb89fSJérôme Gardou 
248d8cdb89fSJérôme Gardou         if (Address < MmSystemRangeStart)
249d8cdb89fSJérôme Gardou         {
250d8cdb89fSJérôme Gardou             ExReleaseRundownProtection(&Process->RundownProtect);
251d8cdb89fSJérôme Gardou             ObDereferenceObject(Process);
252d8cdb89fSJérôme Gardou         }
253d8cdb89fSJérôme Gardou 
254d8cdb89fSJérôme Gardou         if (Released) return STATUS_SUCCESS;
255c2c66affSColin Finck     }
256462d9a09SJérôme Gardou #ifdef NEWCC
257c2c66affSColin Finck     else if (Type == MEMORY_AREA_CACHE)
258c2c66affSColin Finck     {
259c2c66affSColin Finck         /* NEWCC does locking itself */
260c2c66affSColin Finck         MmUnlockAddressSpace(AddressSpace);
261c2c66affSColin Finck         Status = MmpPageOutPhysicalAddress(Page);
262c2c66affSColin Finck     }
263462d9a09SJérôme Gardou #endif
264c2c66affSColin Finck     else
265c2c66affSColin Finck     {
266c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
267c2c66affSColin Finck     }
268c2c66affSColin Finck 
269d932bdb9SJérôme Gardou WriteSegment:
270d8cdb89fSJérôme Gardou     /* Now write this page to file, if needed */
271d8cdb89fSJérôme Gardou     Segment = MmGetSectionAssociation(Page, &SegmentOffset);
272d8cdb89fSJérôme Gardou     if (Segment)
273d8cdb89fSJérôme Gardou     {
274d8cdb89fSJérôme Gardou         BOOLEAN Released;
275d8cdb89fSJérôme Gardou 
276d8cdb89fSJérôme Gardou         MmLockSectionSegment(Segment);
277d8cdb89fSJérôme Gardou 
278d8cdb89fSJérôme Gardou         Released = MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE);
279d8cdb89fSJérôme Gardou 
280d8cdb89fSJérôme Gardou         MmUnlockSectionSegment(Segment);
281d8cdb89fSJérôme Gardou 
282d8cdb89fSJérôme Gardou         MmDereferenceSegment(Segment);
283d8cdb89fSJérôme Gardou 
284d8cdb89fSJérôme Gardou         if (Released)
285d8cdb89fSJérôme Gardou         {
286d8cdb89fSJérôme Gardou             return STATUS_SUCCESS;
287d8cdb89fSJérôme Gardou         }
288d8cdb89fSJérôme Gardou     }
289d8cdb89fSJérôme Gardou 
290d8cdb89fSJérôme Gardou     /* If we are here, then we didn't release the page */
291d8cdb89fSJérôme Gardou     return STATUS_UNSUCCESSFUL;
292c2c66affSColin Finck }
293c2c66affSColin Finck 
294c2c66affSColin Finck VOID
295c2c66affSColin Finck NTAPI
296c2c66affSColin Finck MmSetCleanAllRmaps(PFN_NUMBER Page)
297c2c66affSColin Finck {
298c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry;
299d8cdb89fSJérôme Gardou     KIRQL OldIrql;
300c2c66affSColin Finck 
301d8cdb89fSJérôme Gardou     OldIrql = MiAcquirePfnLock();
302c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
303c2c66affSColin Finck     if (current_entry == NULL)
304c2c66affSColin Finck     {
305d8cdb89fSJérôme Gardou         DPRINT1("MmSetCleanAllRmaps: No rmaps.\n");
306c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
307c2c66affSColin Finck     }
308c2c66affSColin Finck     while (current_entry != NULL)
309c2c66affSColin Finck     {
310c2c66affSColin Finck         if (!RMAP_IS_SEGMENT(current_entry->Address))
311c2c66affSColin Finck             MmSetCleanPage(current_entry->Process, current_entry->Address);
312c2c66affSColin Finck         current_entry = current_entry->Next;
313c2c66affSColin Finck     }
314d8cdb89fSJérôme Gardou     MiReleasePfnLock(OldIrql);
315c2c66affSColin Finck }
316c2c66affSColin Finck 
317c2c66affSColin Finck BOOLEAN
318c2c66affSColin Finck NTAPI
319c2c66affSColin Finck MmIsDirtyPageRmap(PFN_NUMBER Page)
320c2c66affSColin Finck {
321c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry;
322d8cdb89fSJérôme Gardou     KIRQL OldIrql;
323d8cdb89fSJérôme Gardou     BOOLEAN Dirty = FALSE;
324c2c66affSColin Finck 
325d8cdb89fSJérôme Gardou     OldIrql = MiAcquirePfnLock();
326c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
327c2c66affSColin Finck     if (current_entry == NULL)
328c2c66affSColin Finck     {
329d8cdb89fSJérôme Gardou         DPRINT1("MmIsDirtyPageRmap: No rmaps.\n");
330d8cdb89fSJérôme Gardou         KeBugCheck(MEMORY_MANAGEMENT);
331c2c66affSColin Finck     }
332c2c66affSColin Finck     while (current_entry != NULL)
333c2c66affSColin Finck     {
334d8cdb89fSJérôme Gardou         if (!RMAP_IS_SEGMENT(current_entry->Address))
335c2c66affSColin Finck         {
336d8cdb89fSJérôme Gardou             if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
337d8cdb89fSJérôme Gardou             {
338d8cdb89fSJérôme Gardou                 Dirty = TRUE;
339d8cdb89fSJérôme Gardou                 break;
340d8cdb89fSJérôme Gardou             }
341c2c66affSColin Finck         }
342c2c66affSColin Finck         current_entry = current_entry->Next;
343c2c66affSColin Finck     }
344d8cdb89fSJérôme Gardou     MiReleasePfnLock(OldIrql);
345d8cdb89fSJérôme Gardou 
346d8cdb89fSJérôme Gardou     return Dirty;
347c2c66affSColin Finck }
348c2c66affSColin Finck 
349c2c66affSColin Finck VOID
350c2c66affSColin Finck NTAPI
351c2c66affSColin Finck MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
352c2c66affSColin Finck              PVOID Address)
353c2c66affSColin Finck {
354c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry;
355c2c66affSColin Finck     PMM_RMAP_ENTRY new_entry;
356c2c66affSColin Finck     ULONG PrevSize;
357d8cdb89fSJérôme Gardou     KIRQL OldIrql;
358d8cdb89fSJérôme Gardou 
359c2c66affSColin Finck     if (!RMAP_IS_SEGMENT(Address))
360c2c66affSColin Finck         Address = (PVOID)PAGE_ROUND_DOWN(Address);
361c2c66affSColin Finck 
362c2c66affSColin Finck     new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
363c2c66affSColin Finck     if (new_entry == NULL)
364c2c66affSColin Finck     {
365c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
366c2c66affSColin Finck     }
367c2c66affSColin Finck     new_entry->Address = Address;
368c2c66affSColin Finck     new_entry->Process = (PEPROCESS)Process;
369c2c66affSColin Finck #if DBG
370c2c66affSColin Finck #ifdef __GNUC__
371c2c66affSColin Finck     new_entry->Caller = __builtin_return_address(0);
372c2c66affSColin Finck #else
373c2c66affSColin Finck     new_entry->Caller = _ReturnAddress();
374c2c66affSColin Finck #endif
375c2c66affSColin Finck #endif
376c2c66affSColin Finck 
377c2c66affSColin Finck     if (
378c2c66affSColin Finck         !RMAP_IS_SEGMENT(Address) &&
379c2c66affSColin Finck         MmGetPfnForProcess(Process, Address) != Page)
380c2c66affSColin Finck     {
381c2c66affSColin Finck         DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
382c2c66affSColin Finck                 "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0,
383c2c66affSColin Finck                 Address,
384c2c66affSColin Finck                 MmGetPfnForProcess(Process, Address) << PAGE_SHIFT,
385c2c66affSColin Finck                 Page << PAGE_SHIFT);
386c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
387c2c66affSColin Finck     }
388c2c66affSColin Finck 
389d8cdb89fSJérôme Gardou     OldIrql = MiAcquirePfnLock();
390c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
391c2c66affSColin Finck     new_entry->Next = current_entry;
392c2c66affSColin Finck #if DBG
393c2c66affSColin Finck     while (current_entry)
394c2c66affSColin Finck     {
395c2c66affSColin Finck         if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
396c2c66affSColin Finck         {
397c2c66affSColin Finck             DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n    current caller ",
398c2c66affSColin Finck                      current_entry->Address);
399c2c66affSColin Finck             DbgPrint("%p", new_entry->Caller);
400c2c66affSColin Finck             DbgPrint("\n    previous caller ");
401c2c66affSColin Finck             DbgPrint("%p", current_entry->Caller);
402c2c66affSColin Finck             DbgPrint("\n");
403c2c66affSColin Finck             KeBugCheck(MEMORY_MANAGEMENT);
404c2c66affSColin Finck         }
405c2c66affSColin Finck         current_entry = current_entry->Next;
406c2c66affSColin Finck     }
407c2c66affSColin Finck #endif
408c2c66affSColin Finck     MmSetRmapListHeadPage(Page, new_entry);
409d8cdb89fSJérôme Gardou     MiReleasePfnLock(OldIrql);
410d8cdb89fSJérôme Gardou 
411c2c66affSColin Finck     if (!RMAP_IS_SEGMENT(Address))
412c2c66affSColin Finck     {
413*11eee4eeSJérôme Gardou         ASSERT(Process != NULL);
414c2c66affSColin Finck         PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
415c2c66affSColin Finck         if (PrevSize >= Process->Vm.PeakWorkingSetSize)
416c2c66affSColin Finck         {
417c2c66affSColin Finck             Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
418c2c66affSColin Finck         }
419c2c66affSColin Finck     }
420c2c66affSColin Finck }
421c2c66affSColin Finck 
422c2c66affSColin Finck VOID
423c2c66affSColin Finck NTAPI
424c2c66affSColin Finck MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
425c2c66affSColin Finck              PVOID Address)
426c2c66affSColin Finck {
427c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry, previous_entry;
428d8cdb89fSJérôme Gardou     KIRQL OldIrql;
429c2c66affSColin Finck 
430d8cdb89fSJérôme Gardou     OldIrql = MiAcquirePfnLock();
431c2c66affSColin Finck     previous_entry = NULL;
432c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
433c2c66affSColin Finck 
434c2c66affSColin Finck     while (current_entry != NULL)
435c2c66affSColin Finck     {
436c2c66affSColin Finck         if (current_entry->Process == (PEPROCESS)Process &&
437c2c66affSColin Finck                 current_entry->Address == Address)
438c2c66affSColin Finck         {
439c2c66affSColin Finck             if (previous_entry == NULL)
440c2c66affSColin Finck             {
441c2c66affSColin Finck                 MmSetRmapListHeadPage(Page, current_entry->Next);
442c2c66affSColin Finck             }
443c2c66affSColin Finck             else
444c2c66affSColin Finck             {
445c2c66affSColin Finck                 previous_entry->Next = current_entry->Next;
446c2c66affSColin Finck             }
447d8cdb89fSJérôme Gardou             MiReleasePfnLock(OldIrql);
448d8cdb89fSJérôme Gardou 
449c2c66affSColin Finck             ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
450c2c66affSColin Finck             if (!RMAP_IS_SEGMENT(Address))
451c2c66affSColin Finck             {
452*11eee4eeSJérôme Gardou                 ASSERT(Process != NULL);
453c2c66affSColin Finck                 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
454c2c66affSColin Finck             }
455c2c66affSColin Finck             return;
456c2c66affSColin Finck         }
457c2c66affSColin Finck         previous_entry = current_entry;
458c2c66affSColin Finck         current_entry = current_entry->Next;
459c2c66affSColin Finck     }
460c2c66affSColin Finck     KeBugCheck(MEMORY_MANAGEMENT);
461c2c66affSColin Finck }
462c2c66affSColin Finck 
463c2c66affSColin Finck /*
464c2c66affSColin Finck 
465c2c66affSColin Finck Return the process pointer given when a previous call to MmInsertRmap was
466c2c66affSColin Finck called with a process and address pointer that conform to the segment rmap
467c2c66affSColin Finck schema.  In short, this requires the address part to be 0xffffff00 + n
468c2c66affSColin Finck where n is between 0 and 255.  When such an rmap exists, it specifies a
469c2c66affSColin Finck segment rmap in which the process part is a pointer to a slice of a section
470c2c66affSColin Finck page table, and the low 8 bits of the address represent a page index in the
471c2c66affSColin Finck page table slice.  Together, this information is used by
472c2c66affSColin Finck MmGetSectionAssociation to determine which page entry points to this page in
473c2c66affSColin Finck the segment page table.
474c2c66affSColin Finck 
475c2c66affSColin Finck */
476c2c66affSColin Finck 
477c2c66affSColin Finck PVOID
478c2c66affSColin Finck NTAPI
479c2c66affSColin Finck MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
480c2c66affSColin Finck {
481c2c66affSColin Finck     PCACHE_SECTION_PAGE_TABLE Result = NULL;
482c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry;//, previous_entry;
483d8cdb89fSJérôme Gardou     KIRQL OldIrql = MiAcquirePfnLock();
484c2c66affSColin Finck 
485c2c66affSColin Finck     //previous_entry = NULL;
486c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
487c2c66affSColin Finck     while (current_entry != NULL)
488c2c66affSColin Finck     {
489c2c66affSColin Finck         if (RMAP_IS_SEGMENT(current_entry->Address))
490c2c66affSColin Finck         {
491c2c66affSColin Finck             Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
492c2c66affSColin Finck             *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
493d8cdb89fSJérôme Gardou             if (*Result->Segment->Flags & MM_SEGMENT_INDELETE)
494d8cdb89fSJérôme Gardou             {
495d8cdb89fSJérôme Gardou                 MiReleasePfnLock(OldIrql);
496d8cdb89fSJérôme Gardou                 return NULL;
497d8cdb89fSJérôme Gardou             }
498d8cdb89fSJérôme Gardou 
499d8cdb89fSJérôme Gardou             InterlockedIncrementUL(Result->Segment->ReferenceCount);
500d8cdb89fSJérôme Gardou             MiReleasePfnLock(OldIrql);
501c2c66affSColin Finck             return Result;
502c2c66affSColin Finck         }
503c2c66affSColin Finck         //previous_entry = current_entry;
504c2c66affSColin Finck         current_entry = current_entry->Next;
505c2c66affSColin Finck     }
506d8cdb89fSJérôme Gardou     MiReleasePfnLock(OldIrql);
507c2c66affSColin Finck     return NULL;
508c2c66affSColin Finck }
509c2c66affSColin Finck 
510c2c66affSColin Finck /*
511c2c66affSColin Finck 
512c2c66affSColin Finck Remove the section rmap associated with the indicated page, if it exists.
513c2c66affSColin Finck 
514c2c66affSColin Finck */
515c2c66affSColin Finck 
516c2c66affSColin Finck VOID
517c2c66affSColin Finck NTAPI
518c2c66affSColin Finck MmDeleteSectionAssociation(PFN_NUMBER Page)
519c2c66affSColin Finck {
520c2c66affSColin Finck     PMM_RMAP_ENTRY current_entry, previous_entry;
521d8cdb89fSJérôme Gardou     KIRQL OldIrql = MiAcquirePfnLock();
522c2c66affSColin Finck 
523c2c66affSColin Finck     previous_entry = NULL;
524c2c66affSColin Finck     current_entry = MmGetRmapListHeadPage(Page);
525c2c66affSColin Finck     while (current_entry != NULL)
526c2c66affSColin Finck     {
527c2c66affSColin Finck         if (RMAP_IS_SEGMENT(current_entry->Address))
528c2c66affSColin Finck         {
529c2c66affSColin Finck             if (previous_entry == NULL)
530c2c66affSColin Finck             {
531c2c66affSColin Finck                 MmSetRmapListHeadPage(Page, current_entry->Next);
532c2c66affSColin Finck             }
533c2c66affSColin Finck             else
534c2c66affSColin Finck             {
535c2c66affSColin Finck                 previous_entry->Next = current_entry->Next;
536c2c66affSColin Finck             }
537d8cdb89fSJérôme Gardou             MiReleasePfnLock(OldIrql);
538c2c66affSColin Finck             ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
539c2c66affSColin Finck             return;
540c2c66affSColin Finck         }
541c2c66affSColin Finck         previous_entry = current_entry;
542c2c66affSColin Finck         current_entry = current_entry->Next;
543c2c66affSColin Finck     }
544d8cdb89fSJérôme Gardou     MiReleasePfnLock(OldIrql);
545c2c66affSColin Finck }
546