1c2c66affSColin Finck /*
2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top directory
3c2c66affSColin Finck * PROJECT: ReactOS kernel
4c2c66affSColin Finck * FILE: ntoskrnl/mm/rmap.c
56db0d24fSHermè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
_IRQL_requires_max_(DISPATCH_LEVEL)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
MmInitializeRmapList(VOID)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
MmPageOutPhysicalAddress(PFN_NUMBER Page)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
MmInsertRmap(PFN_NUMBER Page,PEPROCESS Process,PVOID Address)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
MmDeleteRmap(PFN_NUMBER Page,PEPROCESS Process,PVOID Address)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
MmGetSegmentRmap(PFN_NUMBER Page,PULONG RawOffset)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;
472*54d1b396STimo Kreuzer
473*54d1b396STimo Kreuzer /* Must hold the PFN lock */
474*54d1b396STimo Kreuzer ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
475c2c66affSColin Finck
476c2c66affSColin Finck //previous_entry = NULL;
477c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page);
478c2c66affSColin Finck while (current_entry != NULL)
479c2c66affSColin Finck {
480c2c66affSColin Finck if (RMAP_IS_SEGMENT(current_entry->Address))
481c2c66affSColin Finck {
482c2c66affSColin Finck Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
483c2c66affSColin Finck *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
484d8cdb89fSJérôme Gardou if (*Result->Segment->Flags & MM_SEGMENT_INDELETE)
485d8cdb89fSJérôme Gardou {
486d8cdb89fSJérôme Gardou return NULL;
487d8cdb89fSJérôme Gardou }
488*54d1b396STimo Kreuzer
489c2c66affSColin Finck return Result;
490c2c66affSColin Finck }
491c2c66affSColin Finck //previous_entry = current_entry;
492c2c66affSColin Finck current_entry = current_entry->Next;
493c2c66affSColin Finck }
494*54d1b396STimo Kreuzer
495c2c66affSColin Finck return NULL;
496c2c66affSColin Finck }
497c2c66affSColin Finck
498c2c66affSColin Finck /*
499c2c66affSColin Finck
500c2c66affSColin Finck Remove the section rmap associated with the indicated page, if it exists.
501c2c66affSColin Finck
502c2c66affSColin Finck */
503c2c66affSColin Finck
504c2c66affSColin Finck VOID
505c2c66affSColin Finck NTAPI
MmDeleteSectionAssociation(PFN_NUMBER Page)506c2c66affSColin Finck MmDeleteSectionAssociation(PFN_NUMBER Page)
507c2c66affSColin Finck {
508c2c66affSColin Finck PMM_RMAP_ENTRY current_entry, previous_entry;
509d8cdb89fSJérôme Gardou KIRQL OldIrql = MiAcquirePfnLock();
510c2c66affSColin Finck
511c2c66affSColin Finck previous_entry = NULL;
512c2c66affSColin Finck current_entry = MmGetRmapListHeadPage(Page);
513c2c66affSColin Finck while (current_entry != NULL)
514c2c66affSColin Finck {
515c2c66affSColin Finck if (RMAP_IS_SEGMENT(current_entry->Address))
516c2c66affSColin Finck {
517c2c66affSColin Finck if (previous_entry == NULL)
518c2c66affSColin Finck {
519c2c66affSColin Finck MmSetRmapListHeadPage(Page, current_entry->Next);
520c2c66affSColin Finck }
521c2c66affSColin Finck else
522c2c66affSColin Finck {
523c2c66affSColin Finck previous_entry->Next = current_entry->Next;
524c2c66affSColin Finck }
525d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql);
526c2c66affSColin Finck ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
527c2c66affSColin Finck return;
528c2c66affSColin Finck }
529c2c66affSColin Finck previous_entry = current_entry;
530c2c66affSColin Finck current_entry = current_entry->Next;
531c2c66affSColin Finck }
532d8cdb89fSJérôme Gardou MiReleasePfnLock(OldIrql);
533c2c66affSColin Finck }
534