3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/rmap.c
6 * PURPOSE: Kernel memory managment functions
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* TYPES ********************************************************************/
19 typedef struct _MM_RMAP_ENTRY
21 struct _MM_RMAP_ENTRY
* Next
;
28 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
30 /* GLOBALS ******************************************************************/
32 static FAST_MUTEX RmapListLock
;
33 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
35 /* FUNCTIONS ****************************************************************/
38 MmInitializeRmapList(VOID
)
40 ExInitializeFastMutex(&RmapListLock
);
41 ExInitializeNPagedLookasideList (&RmapLookasideList
,
45 sizeof(MM_RMAP_ENTRY
),
51 MmWritePagePhysicalAddress(PFN_TYPE Page
)
54 PMEMORY_AREA MemoryArea
;
55 PMADDRESS_SPACE AddressSpace
;
61 NTSTATUS Status
= STATUS_SUCCESS
;
64 * Check that the address still has a valid rmap; then reference the
65 * process so it isn't freed while we are working.
67 ExAcquireFastMutex(&RmapListLock
);
68 entry
= MmGetRmapListHeadPage(Page
);
71 ExReleaseFastMutex(&RmapListLock
);
72 return(STATUS_UNSUCCESSFUL
);
74 Process
= entry
->Process
;
75 Address
= entry
->Address
;
76 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
80 if (Address
< MmSystemRangeStart
)
82 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
83 ExReleaseFastMutex(&RmapListLock
);
84 if (!NT_SUCCESS(Status
))
88 AddressSpace
= &Process
->AddressSpace
;
92 ExReleaseFastMutex(&RmapListLock
);
93 AddressSpace
= MmGetKernelAddressSpace();
97 * Lock the address space; then check that the address we are using
98 * still corresponds to a valid memory area (the page might have been
99 * freed or paged out after we read the rmap entry.)
101 MmLockAddressSpace(AddressSpace
);
102 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
103 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
105 MmUnlockAddressSpace(AddressSpace
);
106 if (Address
< MmSystemRangeStart
)
108 ObDereferenceObject(Process
);
110 return(STATUS_UNSUCCESSFUL
);
113 Type
= MemoryArea
->Type
;
114 if (Type
== MEMORY_AREA_SECTION_VIEW
)
116 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
117 + 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
);
127 MmUnlockAddressSpace(AddressSpace
);
128 if (Address
< MmSystemRangeStart
)
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
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
146 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
148 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
149 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
153 MmUnlockAddressSpace(AddressSpace
);
154 if (Address
< MmSystemRangeStart
)
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
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
176 if (Address
< MmSystemRangeStart
)
178 ObDereferenceObject(Process
);
184 MmPageOutPhysicalAddress(PFN_TYPE Page
)
186 PMM_RMAP_ENTRY entry
;
187 PMEMORY_AREA MemoryArea
;
188 PMADDRESS_SPACE AddressSpace
;
194 NTSTATUS Status
= STATUS_SUCCESS
;
196 ExAcquireFastMutex(&RmapListLock
);
197 entry
= MmGetRmapListHeadPage(Page
);
198 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
200 ExReleaseFastMutex(&RmapListLock
);
201 return(STATUS_UNSUCCESSFUL
);
203 Process
= entry
->Process
;
204 Address
= entry
->Address
;
205 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
210 if (Address
< MmSystemRangeStart
)
212 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
213 ExReleaseFastMutex(&RmapListLock
);
214 if (!NT_SUCCESS(Status
))
218 AddressSpace
= &Process
->AddressSpace
;
222 ExReleaseFastMutex(&RmapListLock
);
223 AddressSpace
= MmGetKernelAddressSpace();
226 MmLockAddressSpace(AddressSpace
);
227 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
228 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
230 MmUnlockAddressSpace(AddressSpace
);
231 if (Address
< MmSystemRangeStart
)
233 ObDereferenceObject(Process
);
235 return(STATUS_UNSUCCESSFUL
);
237 Type
= MemoryArea
->Type
;
238 if (Type
== MEMORY_AREA_SECTION_VIEW
)
240 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
241 + MemoryArea
->Data
.SectionData
.ViewOffset
;;
244 * Get or create a pageop
246 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
247 MemoryArea
->Data
.SectionData
.Segment
,
248 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
251 MmUnlockAddressSpace(AddressSpace
);
252 if (Address
< MmSystemRangeStart
)
254 ObDereferenceObject(Process
);
256 return(STATUS_UNSUCCESSFUL
);
260 * Release locks now we have a page op.
262 MmUnlockAddressSpace(AddressSpace
);
265 * Do the actual page out work.
267 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
270 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
272 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
273 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
276 MmUnlockAddressSpace(AddressSpace
);
277 if (Address
< MmSystemRangeStart
)
279 ObDereferenceObject(Process
);
281 return(STATUS_UNSUCCESSFUL
);
285 * Release locks now we have a page op.
287 MmUnlockAddressSpace(AddressSpace
);
290 * Do the actual page out work.
292 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
299 if (Address
< MmSystemRangeStart
)
301 ObDereferenceObject(Process
);
307 MmSetCleanAllRmaps(PFN_TYPE Page
)
309 PMM_RMAP_ENTRY current_entry
;
311 ExAcquireFastMutex(&RmapListLock
);
312 current_entry
= MmGetRmapListHeadPage(Page
);
313 if (current_entry
== NULL
)
315 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
318 while (current_entry
!= NULL
)
320 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
321 current_entry
= current_entry
->Next
;
323 ExReleaseFastMutex(&RmapListLock
);
327 MmSetDirtyAllRmaps(PFN_TYPE Page
)
329 PMM_RMAP_ENTRY current_entry
;
331 ExAcquireFastMutex(&RmapListLock
);
332 current_entry
= MmGetRmapListHeadPage(Page
);
333 if (current_entry
== NULL
)
335 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
338 while (current_entry
!= NULL
)
340 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
341 current_entry
= current_entry
->Next
;
343 ExReleaseFastMutex(&RmapListLock
);
347 MmIsDirtyPageRmap(PFN_TYPE Page
)
349 PMM_RMAP_ENTRY current_entry
;
351 ExAcquireFastMutex(&RmapListLock
);
352 current_entry
= MmGetRmapListHeadPage(Page
);
353 if (current_entry
== NULL
)
355 ExReleaseFastMutex(&RmapListLock
);
358 while (current_entry
!= NULL
)
360 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
362 ExReleaseFastMutex(&RmapListLock
);
365 current_entry
= current_entry
->Next
;
367 ExReleaseFastMutex(&RmapListLock
);
372 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
375 PMM_RMAP_ENTRY current_entry
;
376 PMM_RMAP_ENTRY new_entry
;
379 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
381 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
382 if (new_entry
== NULL
)
386 new_entry
->Address
= Address
;
387 new_entry
->Process
= Process
;
389 new_entry
->Caller
= __builtin_return_address(0);
392 if (MmGetPfnForProcess(Process
, Address
) != Page
)
394 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
395 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
396 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
401 ExAcquireFastMutex(&RmapListLock
);
402 current_entry
= MmGetRmapListHeadPage(Page
);
403 new_entry
->Next
= current_entry
;
405 while (current_entry
)
407 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
409 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
410 current_entry
->Address
);
411 KeRosPrintAddress(new_entry
->Caller
);
412 DbgPrint("\n previous caller ");
413 KeRosPrintAddress(current_entry
->Caller
);
417 current_entry
= current_entry
->Next
;
420 MmSetRmapListHeadPage(Page
, new_entry
);
421 ExReleaseFastMutex(&RmapListLock
);
424 Process
= PsInitialSystemProcess
;
428 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
429 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
431 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
437 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
438 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
441 PMM_RMAP_ENTRY current_entry
;
442 PMM_RMAP_ENTRY previous_entry
;
445 ExAcquireFastMutex(&RmapListLock
);
446 current_entry
= MmGetRmapListHeadPage(Page
);
447 if (current_entry
== NULL
)
449 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
452 MmSetRmapListHeadPage(Page
, NULL
);
453 while (current_entry
!= NULL
)
455 previous_entry
= current_entry
;
456 current_entry
= current_entry
->Next
;
459 DeleteMapping(Context
, previous_entry
->Process
,
460 previous_entry
->Address
);
462 Process
= previous_entry
->Process
;
463 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
466 Process
= PsInitialSystemProcess
;
470 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
473 ExReleaseFastMutex(&RmapListLock
);
477 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
480 PMM_RMAP_ENTRY current_entry
, previous_entry
;
482 ExAcquireFastMutex(&RmapListLock
);
483 previous_entry
= NULL
;
484 current_entry
= MmGetRmapListHeadPage(Page
);
485 while (current_entry
!= NULL
)
487 if (current_entry
->Process
== Process
&&
488 current_entry
->Address
== Address
)
490 if (previous_entry
== NULL
)
492 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
496 previous_entry
->Next
= current_entry
->Next
;
498 ExReleaseFastMutex(&RmapListLock
);
499 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
502 Process
= PsInitialSystemProcess
;
506 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
510 previous_entry
= current_entry
;
511 current_entry
= current_entry
->Next
;