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 ****************************************************************/
40 MmInitializeRmapList(VOID
)
42 ExInitializeFastMutex(&RmapListLock
);
43 ExInitializeNPagedLookasideList (&RmapLookasideList
,
47 sizeof(MM_RMAP_ENTRY
),
54 MmWritePagePhysicalAddress(PFN_TYPE Page
)
57 PMEMORY_AREA MemoryArea
;
58 PMADDRESS_SPACE AddressSpace
;
64 NTSTATUS Status
= STATUS_SUCCESS
;
67 * Check that the address still has a valid rmap; then reference the
68 * process so it isn't freed while we are working.
70 ExAcquireFastMutex(&RmapListLock
);
71 entry
= MmGetRmapListHeadPage(Page
);
74 ExReleaseFastMutex(&RmapListLock
);
75 return(STATUS_UNSUCCESSFUL
);
77 Process
= entry
->Process
;
78 Address
= entry
->Address
;
79 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
83 if (Address
< MmSystemRangeStart
)
85 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
86 ExReleaseFastMutex(&RmapListLock
);
87 if (!NT_SUCCESS(Status
))
91 AddressSpace
= &Process
->AddressSpace
;
95 ExReleaseFastMutex(&RmapListLock
);
96 AddressSpace
= MmGetKernelAddressSpace();
100 * Lock the address space; then check that the address we are using
101 * still corresponds to a valid memory area (the page might have been
102 * freed or paged out after we read the rmap entry.)
104 MmLockAddressSpace(AddressSpace
);
105 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
106 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
108 MmUnlockAddressSpace(AddressSpace
);
109 if (Address
< MmSystemRangeStart
)
111 ObDereferenceObject(Process
);
113 return(STATUS_UNSUCCESSFUL
);
116 Type
= MemoryArea
->Type
;
117 if (Type
== MEMORY_AREA_SECTION_VIEW
)
119 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
120 + MemoryArea
->Data
.SectionData
.ViewOffset
;
122 * Get or create a pageop
124 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
125 MemoryArea
->Data
.SectionData
.Segment
,
126 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
130 MmUnlockAddressSpace(AddressSpace
);
131 if (Address
< MmSystemRangeStart
)
133 ObDereferenceObject(Process
);
135 return(STATUS_UNSUCCESSFUL
);
139 * Release locks now we have a page op.
141 MmUnlockAddressSpace(AddressSpace
);
144 * Do the actual page out work.
146 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
149 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
151 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
152 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
156 MmUnlockAddressSpace(AddressSpace
);
157 if (Address
< MmSystemRangeStart
)
159 ObDereferenceObject(Process
);
161 return(STATUS_UNSUCCESSFUL
);
165 * Release locks now we have a page op.
167 MmUnlockAddressSpace(AddressSpace
);
170 * Do the actual page out work.
172 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
179 if (Address
< MmSystemRangeStart
)
181 ObDereferenceObject(Process
);
188 MmPageOutPhysicalAddress(PFN_TYPE Page
)
190 PMM_RMAP_ENTRY entry
;
191 PMEMORY_AREA MemoryArea
;
192 PMADDRESS_SPACE AddressSpace
;
198 NTSTATUS Status
= STATUS_SUCCESS
;
200 ExAcquireFastMutex(&RmapListLock
);
201 entry
= MmGetRmapListHeadPage(Page
);
202 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
204 ExReleaseFastMutex(&RmapListLock
);
205 return(STATUS_UNSUCCESSFUL
);
207 Process
= entry
->Process
;
208 Address
= entry
->Address
;
209 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
214 if (Address
< MmSystemRangeStart
)
216 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
217 ExReleaseFastMutex(&RmapListLock
);
218 if (!NT_SUCCESS(Status
))
222 AddressSpace
= &Process
->AddressSpace
;
226 ExReleaseFastMutex(&RmapListLock
);
227 AddressSpace
= MmGetKernelAddressSpace();
230 MmLockAddressSpace(AddressSpace
);
231 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
232 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
234 MmUnlockAddressSpace(AddressSpace
);
235 if (Address
< MmSystemRangeStart
)
237 ObDereferenceObject(Process
);
239 return(STATUS_UNSUCCESSFUL
);
241 Type
= MemoryArea
->Type
;
242 if (Type
== MEMORY_AREA_SECTION_VIEW
)
244 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
245 + MemoryArea
->Data
.SectionData
.ViewOffset
;;
248 * Get or create a pageop
250 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
251 MemoryArea
->Data
.SectionData
.Segment
,
252 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
255 MmUnlockAddressSpace(AddressSpace
);
256 if (Address
< MmSystemRangeStart
)
258 ObDereferenceObject(Process
);
260 return(STATUS_UNSUCCESSFUL
);
264 * Release locks now we have a page op.
266 MmUnlockAddressSpace(AddressSpace
);
269 * Do the actual page out work.
271 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
274 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
276 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
277 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
280 MmUnlockAddressSpace(AddressSpace
);
281 if (Address
< MmSystemRangeStart
)
283 ObDereferenceObject(Process
);
285 return(STATUS_UNSUCCESSFUL
);
289 * Release locks now we have a page op.
291 MmUnlockAddressSpace(AddressSpace
);
294 * Do the actual page out work.
296 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
303 if (Address
< MmSystemRangeStart
)
305 ObDereferenceObject(Process
);
312 MmSetCleanAllRmaps(PFN_TYPE Page
)
314 PMM_RMAP_ENTRY current_entry
;
316 ExAcquireFastMutex(&RmapListLock
);
317 current_entry
= MmGetRmapListHeadPage(Page
);
318 if (current_entry
== NULL
)
320 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
323 while (current_entry
!= NULL
)
325 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
326 current_entry
= current_entry
->Next
;
328 ExReleaseFastMutex(&RmapListLock
);
333 MmSetDirtyAllRmaps(PFN_TYPE Page
)
335 PMM_RMAP_ENTRY current_entry
;
337 ExAcquireFastMutex(&RmapListLock
);
338 current_entry
= MmGetRmapListHeadPage(Page
);
339 if (current_entry
== NULL
)
341 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
344 while (current_entry
!= NULL
)
346 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
347 current_entry
= current_entry
->Next
;
349 ExReleaseFastMutex(&RmapListLock
);
354 MmIsDirtyPageRmap(PFN_TYPE Page
)
356 PMM_RMAP_ENTRY current_entry
;
358 ExAcquireFastMutex(&RmapListLock
);
359 current_entry
= MmGetRmapListHeadPage(Page
);
360 if (current_entry
== NULL
)
362 ExReleaseFastMutex(&RmapListLock
);
365 while (current_entry
!= NULL
)
367 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
369 ExReleaseFastMutex(&RmapListLock
);
372 current_entry
= current_entry
->Next
;
374 ExReleaseFastMutex(&RmapListLock
);
380 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
383 PMM_RMAP_ENTRY current_entry
;
384 PMM_RMAP_ENTRY new_entry
;
387 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
389 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
390 if (new_entry
== NULL
)
394 new_entry
->Address
= Address
;
395 new_entry
->Process
= Process
;
397 new_entry
->Caller
= __builtin_return_address(0);
400 if (MmGetPfnForProcess(Process
, Address
) != Page
)
402 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
403 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
404 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
409 ExAcquireFastMutex(&RmapListLock
);
410 current_entry
= MmGetRmapListHeadPage(Page
);
411 new_entry
->Next
= current_entry
;
413 while (current_entry
)
415 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
417 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
418 current_entry
->Address
);
419 KeRosPrintAddress(new_entry
->Caller
);
420 DbgPrint("\n previous caller ");
421 KeRosPrintAddress(current_entry
->Caller
);
425 current_entry
= current_entry
->Next
;
428 MmSetRmapListHeadPage(Page
, new_entry
);
429 ExReleaseFastMutex(&RmapListLock
);
432 Process
= PsInitialSystemProcess
;
436 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
437 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
439 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
446 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
447 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
450 PMM_RMAP_ENTRY current_entry
;
451 PMM_RMAP_ENTRY previous_entry
;
454 ExAcquireFastMutex(&RmapListLock
);
455 current_entry
= MmGetRmapListHeadPage(Page
);
456 if (current_entry
== NULL
)
458 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
461 MmSetRmapListHeadPage(Page
, NULL
);
462 while (current_entry
!= NULL
)
464 previous_entry
= current_entry
;
465 current_entry
= current_entry
->Next
;
468 DeleteMapping(Context
, previous_entry
->Process
,
469 previous_entry
->Address
);
471 Process
= previous_entry
->Process
;
472 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
475 Process
= PsInitialSystemProcess
;
479 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
482 ExReleaseFastMutex(&RmapListLock
);
487 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
490 PMM_RMAP_ENTRY current_entry
, previous_entry
;
492 ExAcquireFastMutex(&RmapListLock
);
493 previous_entry
= NULL
;
494 current_entry
= MmGetRmapListHeadPage(Page
);
495 while (current_entry
!= NULL
)
497 if (current_entry
->Process
== Process
&&
498 current_entry
->Address
== Address
)
500 if (previous_entry
== NULL
)
502 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
506 previous_entry
->Next
= current_entry
->Next
;
508 ExReleaseFastMutex(&RmapListLock
);
509 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
512 Process
= PsInitialSystemProcess
;
516 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
520 previous_entry
= current_entry
;
521 current_entry
= current_entry
->Next
;