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
;
25 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
27 #define TAG_RMAP TAG('R', 'M', 'A', 'P')
29 /* GLOBALS ******************************************************************/
31 static FAST_MUTEX RmapListLock
;
32 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
34 /* FUNCTIONS ****************************************************************/
37 MmInitializeRmapList(VOID
)
39 ExInitializeFastMutex(&RmapListLock
);
40 ExInitializeNPagedLookasideList (&RmapLookasideList
,
44 sizeof(MM_RMAP_ENTRY
),
50 MmWritePagePhysicalAddress(PFN_TYPE Page
)
53 PMEMORY_AREA MemoryArea
;
54 PMADDRESS_SPACE AddressSpace
;
60 NTSTATUS Status
= STATUS_SUCCESS
;
63 * Check that the address still has a valid rmap; then reference the
64 * process so it isn't freed while we are working.
66 ExAcquireFastMutex(&RmapListLock
);
67 entry
= MmGetRmapListHeadPage(Page
);
70 ExReleaseFastMutex(&RmapListLock
);
71 return(STATUS_UNSUCCESSFUL
);
73 Process
= entry
->Process
;
74 Address
= entry
->Address
;
75 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
79 if (Address
< (PVOID
)KERNEL_BASE
)
81 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
82 ExReleaseFastMutex(&RmapListLock
);
83 if (!NT_SUCCESS(Status
))
87 AddressSpace
= &Process
->AddressSpace
;
91 ExReleaseFastMutex(&RmapListLock
);
92 AddressSpace
= MmGetKernelAddressSpace();
96 * Lock the address space; then check that the address we are using
97 * still corresponds to a valid memory area (the page might have been
98 * freed or paged out after we read the rmap entry.)
100 MmLockAddressSpace(AddressSpace
);
101 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
102 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
104 MmUnlockAddressSpace(AddressSpace
);
105 if (Address
< (PVOID
)KERNEL_BASE
)
107 ObDereferenceObject(Process
);
109 return(STATUS_UNSUCCESSFUL
);
112 Type
= MemoryArea
->Type
;
113 if (Type
== MEMORY_AREA_SECTION_VIEW
)
115 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
118 * Get or create a pageop
120 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
121 MemoryArea
->Data
.SectionData
.Segment
,
122 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
126 MmUnlockAddressSpace(AddressSpace
);
127 if (Address
< (PVOID
)KERNEL_BASE
)
129 ObDereferenceObject(Process
);
131 return(STATUS_UNSUCCESSFUL
);
135 * Release locks now we have a page op.
137 MmUnlockAddressSpace(AddressSpace
);
140 * Do the actual page out work.
142 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
145 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
147 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: NULL
,
148 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
152 MmUnlockAddressSpace(AddressSpace
);
153 if (Address
< (PVOID
)KERNEL_BASE
)
155 ObDereferenceObject(Process
);
157 return(STATUS_UNSUCCESSFUL
);
161 * Release locks now we have a page op.
163 MmUnlockAddressSpace(AddressSpace
);
166 * Do the actual page out work.
168 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
175 if (Address
< (PVOID
)KERNEL_BASE
)
177 ObDereferenceObject(Process
);
183 MmPageOutPhysicalAddress(PFN_TYPE Page
)
185 PMM_RMAP_ENTRY entry
;
186 PMEMORY_AREA MemoryArea
;
187 PMADDRESS_SPACE AddressSpace
;
193 NTSTATUS Status
= STATUS_SUCCESS
;
195 ExAcquireFastMutex(&RmapListLock
);
196 entry
= MmGetRmapListHeadPage(Page
);
197 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
199 ExReleaseFastMutex(&RmapListLock
);
200 return(STATUS_UNSUCCESSFUL
);
202 Process
= entry
->Process
;
203 Address
= entry
->Address
;
204 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
209 if (Address
< (PVOID
)KERNEL_BASE
)
211 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
212 ExReleaseFastMutex(&RmapListLock
);
213 if (!NT_SUCCESS(Status
))
217 AddressSpace
= &Process
->AddressSpace
;
221 ExReleaseFastMutex(&RmapListLock
);
222 AddressSpace
= MmGetKernelAddressSpace();
225 MmLockAddressSpace(AddressSpace
);
226 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
227 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
229 MmUnlockAddressSpace(AddressSpace
);
230 if (Address
< (PVOID
)KERNEL_BASE
)
232 ObDereferenceObject(Process
);
234 return(STATUS_UNSUCCESSFUL
);
236 Type
= MemoryArea
->Type
;
237 if (Type
== MEMORY_AREA_SECTION_VIEW
)
239 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
242 * Get or create a pageop
244 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
245 MemoryArea
->Data
.SectionData
.Segment
,
246 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
249 MmUnlockAddressSpace(AddressSpace
);
250 if (Address
< (PVOID
)KERNEL_BASE
)
252 ObDereferenceObject(Process
);
254 return(STATUS_UNSUCCESSFUL
);
258 * Release locks now we have a page op.
260 MmUnlockAddressSpace(AddressSpace
);
263 * Do the actual page out work.
265 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
268 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
270 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: NULL
,
271 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
274 MmUnlockAddressSpace(AddressSpace
);
275 if (Address
< (PVOID
)KERNEL_BASE
)
277 ObDereferenceObject(Process
);
279 return(STATUS_UNSUCCESSFUL
);
283 * Release locks now we have a page op.
285 MmUnlockAddressSpace(AddressSpace
);
288 * Do the actual page out work.
290 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
297 if (Address
< (PVOID
)KERNEL_BASE
)
299 ObDereferenceObject(Process
);
305 MmSetCleanAllRmaps(PFN_TYPE Page
)
307 PMM_RMAP_ENTRY current_entry
;
309 ExAcquireFastMutex(&RmapListLock
);
310 current_entry
= MmGetRmapListHeadPage(Page
);
311 if (current_entry
== NULL
)
313 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
316 while (current_entry
!= NULL
)
318 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
319 current_entry
= current_entry
->Next
;
321 ExReleaseFastMutex(&RmapListLock
);
325 MmSetDirtyAllRmaps(PFN_TYPE Page
)
327 PMM_RMAP_ENTRY current_entry
;
329 ExAcquireFastMutex(&RmapListLock
);
330 current_entry
= MmGetRmapListHeadPage(Page
);
331 if (current_entry
== NULL
)
333 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
336 while (current_entry
!= NULL
)
338 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
339 current_entry
= current_entry
->Next
;
341 ExReleaseFastMutex(&RmapListLock
);
345 MmIsDirtyPageRmap(PFN_TYPE Page
)
347 PMM_RMAP_ENTRY current_entry
;
349 ExAcquireFastMutex(&RmapListLock
);
350 current_entry
= MmGetRmapListHeadPage(Page
);
351 if (current_entry
== NULL
)
353 ExReleaseFastMutex(&RmapListLock
);
356 while (current_entry
!= NULL
)
358 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
360 ExReleaseFastMutex(&RmapListLock
);
363 current_entry
= current_entry
->Next
;
365 ExReleaseFastMutex(&RmapListLock
);
370 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
373 PMM_RMAP_ENTRY current_entry
;
374 PMM_RMAP_ENTRY new_entry
;
377 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
379 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
380 if (new_entry
== NULL
)
384 new_entry
->Address
= Address
;
385 new_entry
->Process
= Process
;
387 if (MmGetPfnForProcess(Process
, Address
) != Page
)
389 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
390 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
391 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
396 ExAcquireFastMutex(&RmapListLock
);
397 current_entry
= MmGetRmapListHeadPage(Page
);
398 new_entry
->Next
= current_entry
;
399 MmSetRmapListHeadPage(Page
, new_entry
);
400 ExReleaseFastMutex(&RmapListLock
);
403 Process
= PsInitialSystemProcess
;
407 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
408 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
410 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
416 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
417 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
420 PMM_RMAP_ENTRY current_entry
;
421 PMM_RMAP_ENTRY previous_entry
;
424 ExAcquireFastMutex(&RmapListLock
);
425 current_entry
= MmGetRmapListHeadPage(Page
);
426 if (current_entry
== NULL
)
428 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
431 MmSetRmapListHeadPage(Page
, NULL
);
432 while (current_entry
!= NULL
)
434 previous_entry
= current_entry
;
435 current_entry
= current_entry
->Next
;
438 DeleteMapping(Context
, previous_entry
->Process
,
439 previous_entry
->Address
);
441 Process
= previous_entry
->Process
;
442 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
445 Process
= PsInitialSystemProcess
;
449 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
452 ExReleaseFastMutex(&RmapListLock
);
456 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
459 PMM_RMAP_ENTRY current_entry
, previous_entry
;
461 ExAcquireFastMutex(&RmapListLock
);
462 previous_entry
= NULL
;
463 current_entry
= MmGetRmapListHeadPage(Page
);
464 while (current_entry
!= NULL
)
466 if (current_entry
->Process
== Process
&&
467 current_entry
->Address
== Address
)
469 if (previous_entry
== NULL
)
471 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
475 previous_entry
->Next
= current_entry
->Next
;
477 ExReleaseFastMutex(&RmapListLock
);
478 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
481 Process
= PsInitialSystemProcess
;
485 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
489 previous_entry
= current_entry
;
490 current_entry
= current_entry
->Next
;