2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/rmap.c
5 * PURPOSE: Kernel memory managment functions
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
10 /* INCLUDES *****************************************************************/
13 #include <cache/section/newmm.h>
17 /* TYPES ********************************************************************/
19 /* GLOBALS ******************************************************************/
21 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
22 FAST_MUTEX RmapListLock
;
24 /* FUNCTIONS ****************************************************************/
26 _IRQL_requires_max_(DISPATCH_LEVEL
)
31 _In_
__drv_freesMem(Mem
) PVOID P
)
33 ExFreePoolWithTag(P
, TAG_RMAP
);
39 MmInitializeRmapList(VOID
)
41 ExInitializeFastMutex(&RmapListLock
);
42 ExInitializeNPagedLookasideList (&RmapLookasideList
,
46 sizeof(MM_RMAP_ENTRY
),
53 MmPageOutPhysicalAddress(PFN_NUMBER Page
)
56 PMEMORY_AREA MemoryArea
;
57 PMMSUPPORT AddressSpace
;
62 NTSTATUS Status
= STATUS_SUCCESS
;
64 ExAcquireFastMutex(&RmapListLock
);
65 entry
= MmGetRmapListHeadPage(Page
);
68 // Special case for NEWCC: we can have a page that's only in a segment
70 if (entry
&& RMAP_IS_SEGMENT(entry
->Address
) && entry
->Next
== NULL
)
72 /* NEWCC does locking itself */
73 ExReleaseFastMutex(&RmapListLock
);
74 return MmpPageOutPhysicalAddress(Page
);
78 while (entry
&& RMAP_IS_SEGMENT(entry
->Address
))
83 ExReleaseFastMutex(&RmapListLock
);
84 return(STATUS_UNSUCCESSFUL
);
87 Process
= entry
->Process
;
89 Address
= entry
->Address
;
91 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
93 KeBugCheck(MEMORY_MANAGEMENT
);
96 if (Address
< MmSystemRangeStart
)
98 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
100 ExReleaseFastMutex(&RmapListLock
);
101 return STATUS_PROCESS_IS_TERMINATING
;
104 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
105 ExReleaseFastMutex(&RmapListLock
);
106 if (!NT_SUCCESS(Status
))
108 ExReleaseRundownProtection(&Process
->RundownProtect
);
111 AddressSpace
= &Process
->Vm
;
115 ExReleaseFastMutex(&RmapListLock
);
116 AddressSpace
= MmGetKernelAddressSpace();
119 MmLockAddressSpace(AddressSpace
);
120 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
121 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
123 MmUnlockAddressSpace(AddressSpace
);
124 if (Address
< MmSystemRangeStart
)
126 ExReleaseRundownProtection(&Process
->RundownProtect
);
127 ObDereferenceObject(Process
);
129 return(STATUS_UNSUCCESSFUL
);
131 Type
= MemoryArea
->Type
;
132 if (Type
== MEMORY_AREA_SECTION_VIEW
)
135 Offset
= MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
+
136 ((ULONG_PTR
)Address
- MA_GetStartingAddress(MemoryArea
));
138 MmLockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
141 * Get or create a pageop
143 Entry
= MmGetPageEntrySectionSegment(MemoryArea
->Data
.SectionData
.Segment
,
144 (PLARGE_INTEGER
)&Offset
);
145 if (Entry
&& MM_IS_WAIT_PTE(Entry
))
147 MmUnlockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
148 MmUnlockAddressSpace(AddressSpace
);
149 if (Address
< MmSystemRangeStart
)
151 ExReleaseRundownProtection(&Process
->RundownProtect
);
152 ObDereferenceObject(Process
);
154 return(STATUS_UNSUCCESSFUL
);
157 MmSetPageEntrySectionSegment(MemoryArea
->Data
.SectionData
.Segment
, (PLARGE_INTEGER
)&Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
160 * Release locks now we have a page op.
162 MmUnlockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
163 MmUnlockAddressSpace(AddressSpace
);
166 * Do the actual page out work.
168 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
, Address
, Entry
);
170 else if (Type
== MEMORY_AREA_CACHE
)
172 /* NEWCC does locking itself */
173 MmUnlockAddressSpace(AddressSpace
);
174 Status
= MmpPageOutPhysicalAddress(Page
);
178 KeBugCheck(MEMORY_MANAGEMENT
);
181 if (Address
< MmSystemRangeStart
)
183 ExReleaseRundownProtection(&Process
->RundownProtect
);
184 ObDereferenceObject(Process
);
191 MmSetCleanAllRmaps(PFN_NUMBER Page
)
193 PMM_RMAP_ENTRY current_entry
;
195 ExAcquireFastMutex(&RmapListLock
);
196 current_entry
= MmGetRmapListHeadPage(Page
);
197 if (current_entry
== NULL
)
199 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
200 KeBugCheck(MEMORY_MANAGEMENT
);
202 while (current_entry
!= NULL
)
204 if (!RMAP_IS_SEGMENT(current_entry
->Address
))
205 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
206 current_entry
= current_entry
->Next
;
208 ExReleaseFastMutex(&RmapListLock
);
213 MmSetDirtyAllRmaps(PFN_NUMBER Page
)
215 PMM_RMAP_ENTRY current_entry
;
217 ExAcquireFastMutex(&RmapListLock
);
218 current_entry
= MmGetRmapListHeadPage(Page
);
219 if (current_entry
== NULL
)
221 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
222 KeBugCheck(MEMORY_MANAGEMENT
);
224 while (current_entry
!= NULL
)
226 if (!RMAP_IS_SEGMENT(current_entry
->Address
))
227 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
228 current_entry
= current_entry
->Next
;
230 ExReleaseFastMutex(&RmapListLock
);
235 MmIsDirtyPageRmap(PFN_NUMBER Page
)
237 PMM_RMAP_ENTRY current_entry
;
239 ExAcquireFastMutex(&RmapListLock
);
240 current_entry
= MmGetRmapListHeadPage(Page
);
241 if (current_entry
== NULL
)
243 ExReleaseFastMutex(&RmapListLock
);
246 while (current_entry
!= NULL
)
249 !RMAP_IS_SEGMENT(current_entry
->Address
) &&
250 MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
252 ExReleaseFastMutex(&RmapListLock
);
255 current_entry
= current_entry
->Next
;
257 ExReleaseFastMutex(&RmapListLock
);
263 MmInsertRmap(PFN_NUMBER Page
, PEPROCESS Process
,
266 PMM_RMAP_ENTRY current_entry
;
267 PMM_RMAP_ENTRY new_entry
;
269 if (!RMAP_IS_SEGMENT(Address
))
270 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
272 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
273 if (new_entry
== NULL
)
275 KeBugCheck(MEMORY_MANAGEMENT
);
277 new_entry
->Address
= Address
;
278 new_entry
->Process
= (PEPROCESS
)Process
;
281 new_entry
->Caller
= __builtin_return_address(0);
283 new_entry
->Caller
= _ReturnAddress();
288 !RMAP_IS_SEGMENT(Address
) &&
289 MmGetPfnForProcess(Process
, Address
) != Page
)
291 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
292 "address 0x%.8X\n", Process
? Process
->UniqueProcessId
: 0,
294 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
296 KeBugCheck(MEMORY_MANAGEMENT
);
299 ExAcquireFastMutex(&RmapListLock
);
300 current_entry
= MmGetRmapListHeadPage(Page
);
301 new_entry
->Next
= current_entry
;
303 while (current_entry
)
305 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
307 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
308 current_entry
->Address
);
309 DbgPrint("%p", new_entry
->Caller
);
310 DbgPrint("\n previous caller ");
311 DbgPrint("%p", current_entry
->Caller
);
313 KeBugCheck(MEMORY_MANAGEMENT
);
315 current_entry
= current_entry
->Next
;
318 MmSetRmapListHeadPage(Page
, new_entry
);
319 ExReleaseFastMutex(&RmapListLock
);
320 if (!RMAP_IS_SEGMENT(Address
))
324 Process
= PsInitialSystemProcess
;
328 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
329 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
331 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
339 MmDeleteAllRmaps(PFN_NUMBER Page
, PVOID Context
,
340 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
343 PMM_RMAP_ENTRY current_entry
;
344 PMM_RMAP_ENTRY previous_entry
;
347 ExAcquireFastMutex(&RmapListLock
);
348 current_entry
= MmGetRmapListHeadPage(Page
);
349 if (current_entry
== NULL
)
351 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
352 KeBugCheck(MEMORY_MANAGEMENT
);
354 MmSetRmapListHeadPage(Page
, NULL
);
355 ExReleaseFastMutex(&RmapListLock
);
357 while (current_entry
!= NULL
)
359 previous_entry
= current_entry
;
360 current_entry
= current_entry
->Next
;
361 if (!RMAP_IS_SEGMENT(previous_entry
->Address
))
365 DeleteMapping(Context
, previous_entry
->Process
,
366 previous_entry
->Address
);
368 Process
= previous_entry
->Process
;
369 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
372 Process
= PsInitialSystemProcess
;
376 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
381 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
388 MmDeleteRmap(PFN_NUMBER Page
, PEPROCESS Process
,
391 PMM_RMAP_ENTRY current_entry
, previous_entry
;
393 ExAcquireFastMutex(&RmapListLock
);
394 previous_entry
= NULL
;
395 current_entry
= MmGetRmapListHeadPage(Page
);
397 while (current_entry
!= NULL
)
399 if (current_entry
->Process
== (PEPROCESS
)Process
&&
400 current_entry
->Address
== Address
)
402 if (previous_entry
== NULL
)
404 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
408 previous_entry
->Next
= current_entry
->Next
;
410 ExReleaseFastMutex(&RmapListLock
);
411 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
412 if (!RMAP_IS_SEGMENT(Address
))
416 Process
= PsInitialSystemProcess
;
420 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
425 previous_entry
= current_entry
;
426 current_entry
= current_entry
->Next
;
428 KeBugCheck(MEMORY_MANAGEMENT
);
433 Return the process pointer given when a previous call to MmInsertRmap was
434 called with a process and address pointer that conform to the segment rmap
435 schema. In short, this requires the address part to be 0xffffff00 + n
436 where n is between 0 and 255. When such an rmap exists, it specifies a
437 segment rmap in which the process part is a pointer to a slice of a section
438 page table, and the low 8 bits of the address represent a page index in the
439 page table slice. Together, this information is used by
440 MmGetSectionAssociation to determine which page entry points to this page in
441 the segment page table.
447 MmGetSegmentRmap(PFN_NUMBER Page
, PULONG RawOffset
)
449 PCACHE_SECTION_PAGE_TABLE Result
= NULL
;
450 PMM_RMAP_ENTRY current_entry
;//, previous_entry;
452 ExAcquireFastMutex(&RmapListLock
);
453 //previous_entry = NULL;
454 current_entry
= MmGetRmapListHeadPage(Page
);
455 while (current_entry
!= NULL
)
457 if (RMAP_IS_SEGMENT(current_entry
->Address
))
459 Result
= (PCACHE_SECTION_PAGE_TABLE
)current_entry
->Process
;
460 *RawOffset
= (ULONG_PTR
)current_entry
->Address
& ~RMAP_SEGMENT_MASK
;
461 InterlockedIncrementUL(&Result
->Segment
->ReferenceCount
);
462 ExReleaseFastMutex(&RmapListLock
);
465 //previous_entry = current_entry;
466 current_entry
= current_entry
->Next
;
468 ExReleaseFastMutex(&RmapListLock
);
474 Remove the section rmap associated with the indicated page, if it exists.
480 MmDeleteSectionAssociation(PFN_NUMBER Page
)
482 PMM_RMAP_ENTRY current_entry
, previous_entry
;
484 ExAcquireFastMutex(&RmapListLock
);
485 previous_entry
= NULL
;
486 current_entry
= MmGetRmapListHeadPage(Page
);
487 while (current_entry
!= NULL
)
489 if (RMAP_IS_SEGMENT(current_entry
->Address
))
491 if (previous_entry
== NULL
)
493 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
497 previous_entry
->Next
= current_entry
->Next
;
499 ExReleaseFastMutex(&RmapListLock
);
500 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
503 previous_entry
= current_entry
;
504 current_entry
= current_entry
->Next
;
506 ExReleaseFastMutex(&RmapListLock
);