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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitializeRmapList)
21 /* TYPES ********************************************************************/
23 /* GLOBALS ******************************************************************/
25 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
26 FAST_MUTEX RmapListLock
;
28 /* FUNCTIONS ****************************************************************/
30 _IRQL_requires_max_(DISPATCH_LEVEL
)
35 _In_
__drv_freesMem(Mem
) PVOID P
)
37 ExFreePoolWithTag(P
, TAG_RMAP
);
43 MmInitializeRmapList(VOID
)
45 ExInitializeFastMutex(&RmapListLock
);
46 ExInitializeNPagedLookasideList (&RmapLookasideList
,
50 sizeof(MM_RMAP_ENTRY
),
57 MmPageOutPhysicalAddress(PFN_NUMBER Page
)
60 PMEMORY_AREA MemoryArea
;
61 PMMSUPPORT AddressSpace
;
66 NTSTATUS Status
= STATUS_SUCCESS
;
68 ExAcquireFastMutex(&RmapListLock
);
69 entry
= MmGetRmapListHeadPage(Page
);
72 // Special case for NEWCC: we can have a page that's only in a segment
74 if (entry
&& RMAP_IS_SEGMENT(entry
->Address
) && entry
->Next
== NULL
)
76 /* NEWCC does locking itself */
77 ExReleaseFastMutex(&RmapListLock
);
78 return MmpPageOutPhysicalAddress(Page
);
82 while (entry
&& RMAP_IS_SEGMENT(entry
->Address
))
87 ExReleaseFastMutex(&RmapListLock
);
88 return(STATUS_UNSUCCESSFUL
);
91 Process
= entry
->Process
;
93 Address
= entry
->Address
;
95 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
97 KeBugCheck(MEMORY_MANAGEMENT
);
100 if (Address
< MmSystemRangeStart
)
102 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
104 ExReleaseFastMutex(&RmapListLock
);
105 return STATUS_PROCESS_IS_TERMINATING
;
108 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
109 ExReleaseFastMutex(&RmapListLock
);
110 if (!NT_SUCCESS(Status
))
112 ExReleaseRundownProtection(&Process
->RundownProtect
);
115 AddressSpace
= &Process
->Vm
;
119 ExReleaseFastMutex(&RmapListLock
);
120 AddressSpace
= MmGetKernelAddressSpace();
123 MmLockAddressSpace(AddressSpace
);
124 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
125 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
127 MmUnlockAddressSpace(AddressSpace
);
128 if (Address
< MmSystemRangeStart
)
130 ExReleaseRundownProtection(&Process
->RundownProtect
);
131 ObDereferenceObject(Process
);
133 return(STATUS_UNSUCCESSFUL
);
135 Type
= MemoryArea
->Type
;
136 if (Type
== MEMORY_AREA_SECTION_VIEW
)
139 Offset
= MemoryArea
->Data
.SectionData
.ViewOffset
.QuadPart
+
140 ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
142 MmLockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
145 * Get or create a pageop
147 Entry
= MmGetPageEntrySectionSegment(MemoryArea
->Data
.SectionData
.Segment
,
148 (PLARGE_INTEGER
)&Offset
);
149 if (Entry
&& IS_SWAP_FROM_SSE(Entry
) && SWAPENTRY_FROM_SSE(Entry
) == MM_WAIT_ENTRY
)
151 MmUnlockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
152 MmUnlockAddressSpace(AddressSpace
);
153 if (Address
< MmSystemRangeStart
)
155 ExReleaseRundownProtection(&Process
->RundownProtect
);
156 ObDereferenceObject(Process
);
158 return(STATUS_UNSUCCESSFUL
);
161 MmSetPageEntrySectionSegment(MemoryArea
->Data
.SectionData
.Segment
, (PLARGE_INTEGER
)&Offset
, MAKE_SWAP_SSE(MM_WAIT_ENTRY
));
164 * Release locks now we have a page op.
166 MmUnlockSectionSegment(MemoryArea
->Data
.SectionData
.Segment
);
167 MmUnlockAddressSpace(AddressSpace
);
170 * Do the actual page out work.
172 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
, Address
, Entry
);
174 else if (Type
== MEMORY_AREA_CACHE
)
176 /* NEWCC does locking itself */
177 MmUnlockAddressSpace(AddressSpace
);
178 Status
= MmpPageOutPhysicalAddress(Page
);
182 KeBugCheck(MEMORY_MANAGEMENT
);
185 if (Address
< MmSystemRangeStart
)
187 ExReleaseRundownProtection(&Process
->RundownProtect
);
188 ObDereferenceObject(Process
);
195 MmSetCleanAllRmaps(PFN_NUMBER Page
)
197 PMM_RMAP_ENTRY current_entry
;
199 ExAcquireFastMutex(&RmapListLock
);
200 current_entry
= MmGetRmapListHeadPage(Page
);
201 if (current_entry
== NULL
)
203 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
204 KeBugCheck(MEMORY_MANAGEMENT
);
206 while (current_entry
!= NULL
)
208 if (!RMAP_IS_SEGMENT(current_entry
->Address
))
209 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
210 current_entry
= current_entry
->Next
;
212 ExReleaseFastMutex(&RmapListLock
);
217 MmSetDirtyAllRmaps(PFN_NUMBER Page
)
219 PMM_RMAP_ENTRY current_entry
;
221 ExAcquireFastMutex(&RmapListLock
);
222 current_entry
= MmGetRmapListHeadPage(Page
);
223 if (current_entry
== NULL
)
225 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
226 KeBugCheck(MEMORY_MANAGEMENT
);
228 while (current_entry
!= NULL
)
230 if (!RMAP_IS_SEGMENT(current_entry
->Address
))
231 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
232 current_entry
= current_entry
->Next
;
234 ExReleaseFastMutex(&RmapListLock
);
239 MmIsDirtyPageRmap(PFN_NUMBER Page
)
241 PMM_RMAP_ENTRY current_entry
;
243 ExAcquireFastMutex(&RmapListLock
);
244 current_entry
= MmGetRmapListHeadPage(Page
);
245 if (current_entry
== NULL
)
247 ExReleaseFastMutex(&RmapListLock
);
250 while (current_entry
!= NULL
)
253 !RMAP_IS_SEGMENT(current_entry
->Address
) &&
254 MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
256 ExReleaseFastMutex(&RmapListLock
);
259 current_entry
= current_entry
->Next
;
261 ExReleaseFastMutex(&RmapListLock
);
267 MmInsertRmap(PFN_NUMBER Page
, PEPROCESS Process
,
270 PMM_RMAP_ENTRY current_entry
;
271 PMM_RMAP_ENTRY new_entry
;
273 if (!RMAP_IS_SEGMENT(Address
))
274 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
276 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
277 if (new_entry
== NULL
)
279 KeBugCheck(MEMORY_MANAGEMENT
);
281 new_entry
->Address
= Address
;
282 new_entry
->Process
= (PEPROCESS
)Process
;
285 new_entry
->Caller
= __builtin_return_address(0);
287 new_entry
->Caller
= _ReturnAddress();
292 !RMAP_IS_SEGMENT(Address
) &&
293 MmGetPfnForProcess(Process
, Address
) != Page
)
295 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
296 "address 0x%.8X\n", Process
? Process
->UniqueProcessId
: 0,
298 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
300 KeBugCheck(MEMORY_MANAGEMENT
);
303 ExAcquireFastMutex(&RmapListLock
);
304 current_entry
= MmGetRmapListHeadPage(Page
);
305 new_entry
->Next
= current_entry
;
307 while (current_entry
)
309 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
311 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
312 current_entry
->Address
);
313 DbgPrint("%p", new_entry
->Caller
);
314 DbgPrint("\n previous caller ");
315 DbgPrint("%p", current_entry
->Caller
);
317 KeBugCheck(MEMORY_MANAGEMENT
);
319 current_entry
= current_entry
->Next
;
322 MmSetRmapListHeadPage(Page
, new_entry
);
323 ExReleaseFastMutex(&RmapListLock
);
324 if (!RMAP_IS_SEGMENT(Address
))
328 Process
= PsInitialSystemProcess
;
332 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
333 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
335 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
343 MmDeleteAllRmaps(PFN_NUMBER Page
, PVOID Context
,
344 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
347 PMM_RMAP_ENTRY current_entry
;
348 PMM_RMAP_ENTRY previous_entry
;
351 ExAcquireFastMutex(&RmapListLock
);
352 current_entry
= MmGetRmapListHeadPage(Page
);
353 if (current_entry
== NULL
)
355 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
356 KeBugCheck(MEMORY_MANAGEMENT
);
358 MmSetRmapListHeadPage(Page
, NULL
);
359 ExReleaseFastMutex(&RmapListLock
);
361 while (current_entry
!= NULL
)
363 previous_entry
= current_entry
;
364 current_entry
= current_entry
->Next
;
365 if (!RMAP_IS_SEGMENT(previous_entry
->Address
))
369 DeleteMapping(Context
, previous_entry
->Process
,
370 previous_entry
->Address
);
372 Process
= previous_entry
->Process
;
373 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
376 Process
= PsInitialSystemProcess
;
380 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
385 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
392 MmDeleteRmap(PFN_NUMBER Page
, PEPROCESS Process
,
395 PMM_RMAP_ENTRY current_entry
, previous_entry
;
397 ExAcquireFastMutex(&RmapListLock
);
398 previous_entry
= NULL
;
399 current_entry
= MmGetRmapListHeadPage(Page
);
401 while (current_entry
!= NULL
)
403 if (current_entry
->Process
== (PEPROCESS
)Process
&&
404 current_entry
->Address
== Address
)
406 if (previous_entry
== NULL
)
408 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
412 previous_entry
->Next
= current_entry
->Next
;
414 ExReleaseFastMutex(&RmapListLock
);
415 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
416 if (!RMAP_IS_SEGMENT(Address
))
420 Process
= PsInitialSystemProcess
;
424 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
429 previous_entry
= current_entry
;
430 current_entry
= current_entry
->Next
;
432 KeBugCheck(MEMORY_MANAGEMENT
);
437 Return the process pointer given when a previous call to MmInsertRmap was
438 called with a process and address pointer that conform to the segment rmap
439 schema. In short, this requires the address part to be 0xffffff00 + n
440 where n is between 0 and 255. When such an rmap exists, it specifies a
441 segment rmap in which the process part is a pointer to a slice of a section
442 page table, and the low 8 bits of the address represent a page index in the
443 page table slice. Together, this information is used by
444 MmGetSectionAssociation to determine which page entry points to this page in
445 the segment page table.
451 MmGetSegmentRmap(PFN_NUMBER Page
, PULONG RawOffset
)
453 PCACHE_SECTION_PAGE_TABLE Result
= NULL
;
454 PMM_RMAP_ENTRY current_entry
, previous_entry
;
456 ExAcquireFastMutex(&RmapListLock
);
457 previous_entry
= NULL
;
458 current_entry
= MmGetRmapListHeadPage(Page
);
459 while (current_entry
!= NULL
)
461 if (RMAP_IS_SEGMENT(current_entry
->Address
))
463 Result
= (PCACHE_SECTION_PAGE_TABLE
)current_entry
->Process
;
464 *RawOffset
= (ULONG_PTR
)current_entry
->Address
& ~RMAP_SEGMENT_MASK
;
465 InterlockedIncrementUL(&Result
->Segment
->ReferenceCount
);
466 ExReleaseFastMutex(&RmapListLock
);
469 previous_entry
= current_entry
;
470 current_entry
= current_entry
->Next
;
472 ExReleaseFastMutex(&RmapListLock
);
478 Remove the section rmap associated with the indicated page, if it exists.
484 MmDeleteSectionAssociation(PFN_NUMBER Page
)
486 PMM_RMAP_ENTRY current_entry
, previous_entry
;
488 ExAcquireFastMutex(&RmapListLock
);
489 previous_entry
= NULL
;
490 current_entry
= MmGetRmapListHeadPage(Page
);
491 while (current_entry
!= NULL
)
493 if (RMAP_IS_SEGMENT(current_entry
->Address
))
495 if (previous_entry
== NULL
)
497 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
501 previous_entry
->Next
= current_entry
->Next
;
503 ExReleaseFastMutex(&RmapListLock
);
504 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
507 previous_entry
= current_entry
;
508 current_entry
= current_entry
->Next
;
510 ExReleaseFastMutex(&RmapListLock
);