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 *****************************************************************/
14 #include "../cache/section/newmm.h"
19 #if defined (ALLOC_PRAGMA)
20 #pragma alloc_text(INIT, MmInitializeRmapList)
23 /* TYPES ********************************************************************/
25 /* GLOBALS ******************************************************************/
27 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
28 FAST_MUTEX RmapListLock
;
30 /* FUNCTIONS ****************************************************************/
35 MmInitializeRmapList(VOID
)
37 ExInitializeFastMutex(&RmapListLock
);
38 ExInitializeNPagedLookasideList (&RmapLookasideList
,
42 sizeof(MM_RMAP_ENTRY
),
49 MmPageOutPhysicalAddress(PFN_NUMBER Page
)
52 PMEMORY_AREA MemoryArea
;
53 PMMSUPPORT AddressSpace
;
59 NTSTATUS Status
= STATUS_SUCCESS
;
61 ExAcquireFastMutex(&RmapListLock
);
62 entry
= MmGetRmapListHeadPage(Page
);
65 ExReleaseFastMutex(&RmapListLock
);
66 return(STATUS_UNSUCCESSFUL
);
68 Process
= entry
->Process
;
70 Address
= entry
->Address
;
72 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
74 KeBugCheck(MEMORY_MANAGEMENT
);
77 if (Address
< MmSystemRangeStart
)
79 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
81 ExReleaseFastMutex(&RmapListLock
);
82 return STATUS_PROCESS_IS_TERMINATING
;
85 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
86 ExReleaseFastMutex(&RmapListLock
);
87 if (!NT_SUCCESS(Status
))
89 ExReleaseRundownProtection(&Process
->RundownProtect
);
92 AddressSpace
= &Process
->Vm
;
96 ExReleaseFastMutex(&RmapListLock
);
97 AddressSpace
= MmGetKernelAddressSpace();
100 MmLockAddressSpace(AddressSpace
);
101 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
102 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
104 MmUnlockAddressSpace(AddressSpace
);
105 if (Address
< MmSystemRangeStart
)
107 ExReleaseRundownProtection(&Process
->RundownProtect
);
108 ObDereferenceObject(Process
);
110 return(STATUS_UNSUCCESSFUL
);
112 Type
= MemoryArea
->Type
;
113 if (Type
== MEMORY_AREA_SECTION_VIEW
)
115 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
116 + MemoryArea
->Data
.SectionData
.ViewOffset
;
119 * Get or create a pageop
121 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
122 MemoryArea
->Data
.SectionData
.Segment
,
123 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
126 MmUnlockAddressSpace(AddressSpace
);
127 if (Address
< MmSystemRangeStart
)
129 ExReleaseRundownProtection(&Process
->RundownProtect
);
130 ObDereferenceObject(Process
);
132 return(STATUS_UNSUCCESSFUL
);
136 * Release locks now we have a page op.
138 MmUnlockAddressSpace(AddressSpace
);
141 * Do the actual page out work.
143 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
146 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
148 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
149 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
152 MmUnlockAddressSpace(AddressSpace
);
153 if (Address
< MmSystemRangeStart
)
155 ExReleaseRundownProtection(&Process
->RundownProtect
);
156 ObDereferenceObject(Process
);
158 return(STATUS_UNSUCCESSFUL
);
162 * Release locks now we have a page op.
164 MmUnlockAddressSpace(AddressSpace
);
167 * Do the actual page out work.
169 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
174 KeBugCheck(MEMORY_MANAGEMENT
);
177 if (Address
< MmSystemRangeStart
)
179 ExReleaseRundownProtection(&Process
->RundownProtect
);
180 ObDereferenceObject(Process
);
187 MmSetCleanAllRmaps(PFN_NUMBER Page
)
189 PMM_RMAP_ENTRY current_entry
;
191 ExAcquireFastMutex(&RmapListLock
);
192 current_entry
= MmGetRmapListHeadPage(Page
);
193 if (current_entry
== NULL
)
195 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
196 KeBugCheck(MEMORY_MANAGEMENT
);
198 while (current_entry
!= NULL
)
201 if (!RMAP_IS_SEGMENT(current_entry
->Address
))
203 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
204 current_entry
= current_entry
->Next
;
206 ExReleaseFastMutex(&RmapListLock
);
211 MmSetDirtyAllRmaps(PFN_NUMBER Page
)
213 PMM_RMAP_ENTRY current_entry
;
215 ExAcquireFastMutex(&RmapListLock
);
216 current_entry
= MmGetRmapListHeadPage(Page
);
217 if (current_entry
== NULL
)
219 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
220 KeBugCheck(MEMORY_MANAGEMENT
);
222 while (current_entry
!= NULL
)
225 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
)
250 !RMAP_IS_SEGMENT(current_entry
->Address
) &&
252 MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
254 ExReleaseFastMutex(&RmapListLock
);
257 current_entry
= current_entry
->Next
;
259 ExReleaseFastMutex(&RmapListLock
);
265 MmInsertRmap(PFN_NUMBER Page
, PEPROCESS Process
,
268 PMM_RMAP_ENTRY current_entry
;
269 PMM_RMAP_ENTRY new_entry
;
272 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();
293 !RMAP_IS_SEGMENT(Address
) &&
295 MmGetPfnForProcess(Process
, Address
) != Page
)
297 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
298 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
299 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
301 KeBugCheck(MEMORY_MANAGEMENT
);
304 ExAcquireFastMutex(&RmapListLock
);
305 current_entry
= MmGetRmapListHeadPage(Page
);
306 new_entry
->Next
= current_entry
;
308 while (current_entry
)
310 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
312 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
313 current_entry
->Address
);
314 DbgPrint("%p", new_entry
->Caller
);
315 DbgPrint("\n previous caller ");
316 DbgPrint("%p", current_entry
->Caller
);
318 KeBugCheck(MEMORY_MANAGEMENT
);
320 current_entry
= current_entry
->Next
;
323 MmSetRmapListHeadPage(Page
, new_entry
);
324 ExReleaseFastMutex(&RmapListLock
);
326 if (!RMAP_IS_SEGMENT(Address
))
331 Process
= PsInitialSystemProcess
;
335 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
336 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
338 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
346 MmDeleteAllRmaps(PFN_NUMBER Page
, PVOID Context
,
347 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
350 PMM_RMAP_ENTRY current_entry
;
351 PMM_RMAP_ENTRY previous_entry
;
354 ExAcquireFastMutex(&RmapListLock
);
355 current_entry
= MmGetRmapListHeadPage(Page
);
356 if (current_entry
== NULL
)
358 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
359 KeBugCheck(MEMORY_MANAGEMENT
);
361 MmSetRmapListHeadPage(Page
, NULL
);
362 ExReleaseFastMutex(&RmapListLock
);
363 while (current_entry
!= NULL
)
365 previous_entry
= current_entry
;
366 current_entry
= current_entry
->Next
;
368 if (!RMAP_IS_SEGMENT(previous_entry
->Address
))
373 DeleteMapping(Context
, previous_entry
->Process
,
374 previous_entry
->Address
);
376 Process
= previous_entry
->Process
;
377 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
380 Process
= PsInitialSystemProcess
;
384 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
390 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
398 MmDeleteRmap(PFN_NUMBER Page
, PEPROCESS Process
,
401 PMM_RMAP_ENTRY current_entry
, previous_entry
;
403 ExAcquireFastMutex(&RmapListLock
);
404 previous_entry
= NULL
;
405 current_entry
= MmGetRmapListHeadPage(Page
);
407 while (current_entry
!= NULL
)
409 if (current_entry
->Process
== (PEPROCESS
)Process
&&
410 current_entry
->Address
== Address
)
412 if (previous_entry
== NULL
)
414 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
418 previous_entry
->Next
= current_entry
->Next
;
420 ExReleaseFastMutex(&RmapListLock
);
421 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
423 if (!RMAP_IS_SEGMENT(Address
))
428 Process
= PsInitialSystemProcess
;
432 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
437 previous_entry
= current_entry
;
438 current_entry
= current_entry
->Next
;
440 KeBugCheck(MEMORY_MANAGEMENT
);
446 MmGetSegmentRmap(PFN_NUMBER Page
, PULONG RawOffset
)
448 PCACHE_SECTION_PAGE_TABLE Result
= NULL
;
449 PMM_RMAP_ENTRY current_entry
, previous_entry
;
451 ExAcquireFastMutex(&RmapListLock
);
452 previous_entry
= NULL
;
453 current_entry
= MmGetRmapListHeadPage(Page
);
454 while (current_entry
!= NULL
)
456 if (RMAP_IS_SEGMENT(current_entry
->Address
))
458 Result
= (PCACHE_SECTION_PAGE_TABLE
)current_entry
->Process
;
459 *RawOffset
= (ULONG_PTR
)current_entry
->Address
& ~RMAP_SEGMENT_MASK
;
460 InterlockedIncrementUL(&Result
->Segment
->ReferenceCount
);
461 ExReleaseFastMutex(&RmapListLock
);
464 previous_entry
= current_entry
;
465 current_entry
= current_entry
->Next
;
467 ExReleaseFastMutex(&RmapListLock
);
473 MmDeleteSectionAssociation(PFN_NUMBER Page
)
475 PMM_RMAP_ENTRY current_entry
, previous_entry
;
477 ExAcquireFastMutex(&RmapListLock
);
478 previous_entry
= NULL
;
479 current_entry
= MmGetRmapListHeadPage(Page
);
480 while (current_entry
!= NULL
)
482 if (RMAP_IS_SEGMENT(current_entry
->Address
))
484 if (previous_entry
== NULL
)
486 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
490 previous_entry
->Next
= current_entry
->Next
;
492 ExReleaseFastMutex(&RmapListLock
);
493 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
496 previous_entry
= current_entry
;
497 current_entry
= current_entry
->Next
;
499 ExReleaseFastMutex(&RmapListLock
);