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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitializeRmapList)
21 /* TYPES ********************************************************************/
23 typedef struct _MM_RMAP_ENTRY
25 struct _MM_RMAP_ENTRY
* Next
;
32 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
34 /* GLOBALS ******************************************************************/
36 static FAST_MUTEX RmapListLock
;
37 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
39 /* FUNCTIONS ****************************************************************/
44 MmInitializeRmapList(VOID
)
46 ExInitializeFastMutex(&RmapListLock
);
47 ExInitializeNPagedLookasideList (&RmapLookasideList
,
51 sizeof(MM_RMAP_ENTRY
),
58 MmWritePagePhysicalAddress(PFN_TYPE Page
)
61 PMEMORY_AREA MemoryArea
;
62 PMADDRESS_SPACE AddressSpace
;
68 NTSTATUS Status
= STATUS_SUCCESS
;
71 * Check that the address still has a valid rmap; then reference the
72 * process so it isn't freed while we are working.
74 ExAcquireFastMutex(&RmapListLock
);
75 entry
= MmGetRmapListHeadPage(Page
);
78 ExReleaseFastMutex(&RmapListLock
);
79 return(STATUS_UNSUCCESSFUL
);
81 Process
= entry
->Process
;
82 Address
= entry
->Address
;
83 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
87 if (Address
< MmSystemRangeStart
)
89 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
90 ExReleaseFastMutex(&RmapListLock
);
91 if (!NT_SUCCESS(Status
))
95 AddressSpace
= &Process
->AddressSpace
;
99 ExReleaseFastMutex(&RmapListLock
);
100 AddressSpace
= MmGetKernelAddressSpace();
104 * Lock the address space; then check that the address we are using
105 * still corresponds to a valid memory area (the page might have been
106 * freed or paged out after we read the rmap entry.)
108 MmLockAddressSpace(AddressSpace
);
109 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
110 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
112 MmUnlockAddressSpace(AddressSpace
);
113 if (Address
< MmSystemRangeStart
)
115 ObDereferenceObject(Process
);
117 return(STATUS_UNSUCCESSFUL
);
120 Type
= MemoryArea
->Type
;
121 if (Type
== MEMORY_AREA_SECTION_VIEW
)
123 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
124 + MemoryArea
->Data
.SectionData
.ViewOffset
;
126 * Get or create a pageop
128 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
129 MemoryArea
->Data
.SectionData
.Segment
,
130 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
134 MmUnlockAddressSpace(AddressSpace
);
135 if (Address
< MmSystemRangeStart
)
137 ObDereferenceObject(Process
);
139 return(STATUS_UNSUCCESSFUL
);
143 * Release locks now we have a page op.
145 MmUnlockAddressSpace(AddressSpace
);
148 * Do the actual page out work.
150 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
153 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
155 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
156 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
160 MmUnlockAddressSpace(AddressSpace
);
161 if (Address
< MmSystemRangeStart
)
163 ObDereferenceObject(Process
);
165 return(STATUS_UNSUCCESSFUL
);
169 * Release locks now we have a page op.
171 MmUnlockAddressSpace(AddressSpace
);
174 * Do the actual page out work.
176 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
183 if (Address
< MmSystemRangeStart
)
185 ObDereferenceObject(Process
);
192 MmPageOutPhysicalAddress(PFN_TYPE Page
)
194 PMM_RMAP_ENTRY entry
;
195 PMEMORY_AREA MemoryArea
;
196 PMADDRESS_SPACE AddressSpace
;
202 NTSTATUS Status
= STATUS_SUCCESS
;
204 ExAcquireFastMutex(&RmapListLock
);
205 entry
= MmGetRmapListHeadPage(Page
);
206 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
208 ExReleaseFastMutex(&RmapListLock
);
209 return(STATUS_UNSUCCESSFUL
);
211 Process
= entry
->Process
;
212 Address
= entry
->Address
;
213 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
218 if (Address
< MmSystemRangeStart
)
220 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
221 ExReleaseFastMutex(&RmapListLock
);
222 if (!NT_SUCCESS(Status
))
226 AddressSpace
= &Process
->AddressSpace
;
230 ExReleaseFastMutex(&RmapListLock
);
231 AddressSpace
= MmGetKernelAddressSpace();
234 MmLockAddressSpace(AddressSpace
);
235 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
236 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
238 MmUnlockAddressSpace(AddressSpace
);
239 if (Address
< MmSystemRangeStart
)
241 ObDereferenceObject(Process
);
243 return(STATUS_UNSUCCESSFUL
);
245 Type
= MemoryArea
->Type
;
246 if (Type
== MEMORY_AREA_SECTION_VIEW
)
248 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
249 + MemoryArea
->Data
.SectionData
.ViewOffset
;;
252 * Get or create a pageop
254 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
255 MemoryArea
->Data
.SectionData
.Segment
,
256 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
259 MmUnlockAddressSpace(AddressSpace
);
260 if (Address
< MmSystemRangeStart
)
262 ObDereferenceObject(Process
);
264 return(STATUS_UNSUCCESSFUL
);
268 * Release locks now we have a page op.
270 MmUnlockAddressSpace(AddressSpace
);
273 * Do the actual page out work.
275 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
278 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
280 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
281 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
284 MmUnlockAddressSpace(AddressSpace
);
285 if (Address
< MmSystemRangeStart
)
287 ObDereferenceObject(Process
);
289 return(STATUS_UNSUCCESSFUL
);
293 * Release locks now we have a page op.
295 MmUnlockAddressSpace(AddressSpace
);
298 * Do the actual page out work.
300 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
307 if (Address
< MmSystemRangeStart
)
309 ObDereferenceObject(Process
);
316 MmSetCleanAllRmaps(PFN_TYPE Page
)
318 PMM_RMAP_ENTRY current_entry
;
320 ExAcquireFastMutex(&RmapListLock
);
321 current_entry
= MmGetRmapListHeadPage(Page
);
322 if (current_entry
== NULL
)
324 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
327 while (current_entry
!= NULL
)
329 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
330 current_entry
= current_entry
->Next
;
332 ExReleaseFastMutex(&RmapListLock
);
337 MmSetDirtyAllRmaps(PFN_TYPE Page
)
339 PMM_RMAP_ENTRY current_entry
;
341 ExAcquireFastMutex(&RmapListLock
);
342 current_entry
= MmGetRmapListHeadPage(Page
);
343 if (current_entry
== NULL
)
345 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
348 while (current_entry
!= NULL
)
350 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
351 current_entry
= current_entry
->Next
;
353 ExReleaseFastMutex(&RmapListLock
);
358 MmIsDirtyPageRmap(PFN_TYPE Page
)
360 PMM_RMAP_ENTRY current_entry
;
362 ExAcquireFastMutex(&RmapListLock
);
363 current_entry
= MmGetRmapListHeadPage(Page
);
364 if (current_entry
== NULL
)
366 ExReleaseFastMutex(&RmapListLock
);
369 while (current_entry
!= NULL
)
371 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
373 ExReleaseFastMutex(&RmapListLock
);
376 current_entry
= current_entry
->Next
;
378 ExReleaseFastMutex(&RmapListLock
);
384 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
387 PMM_RMAP_ENTRY current_entry
;
388 PMM_RMAP_ENTRY new_entry
;
391 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
393 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
394 if (new_entry
== NULL
)
398 new_entry
->Address
= Address
;
399 new_entry
->Process
= Process
;
401 new_entry
->Caller
= __builtin_return_address(0);
404 if (MmGetPfnForProcess(Process
, Address
) != Page
)
406 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
407 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
408 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
413 ExAcquireFastMutex(&RmapListLock
);
414 current_entry
= MmGetRmapListHeadPage(Page
);
415 new_entry
->Next
= current_entry
;
417 while (current_entry
)
419 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
421 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
422 current_entry
->Address
);
423 KeRosPrintAddress(new_entry
->Caller
);
424 DbgPrint("\n previous caller ");
425 KeRosPrintAddress(current_entry
->Caller
);
429 current_entry
= current_entry
->Next
;
432 MmSetRmapListHeadPage(Page
, new_entry
);
433 ExReleaseFastMutex(&RmapListLock
);
436 Process
= PsInitialSystemProcess
;
440 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
441 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
443 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
450 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
451 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
454 PMM_RMAP_ENTRY current_entry
;
455 PMM_RMAP_ENTRY previous_entry
;
458 ExAcquireFastMutex(&RmapListLock
);
459 current_entry
= MmGetRmapListHeadPage(Page
);
460 if (current_entry
== NULL
)
462 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
465 MmSetRmapListHeadPage(Page
, NULL
);
466 ExReleaseFastMutex(&RmapListLock
);
467 while (current_entry
!= NULL
)
469 previous_entry
= current_entry
;
470 current_entry
= current_entry
->Next
;
473 DeleteMapping(Context
, previous_entry
->Process
,
474 previous_entry
->Address
);
476 Process
= previous_entry
->Process
;
477 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
480 Process
= PsInitialSystemProcess
;
484 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
491 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
494 PMM_RMAP_ENTRY current_entry
, previous_entry
;
496 ExAcquireFastMutex(&RmapListLock
);
497 previous_entry
= NULL
;
498 current_entry
= MmGetRmapListHeadPage(Page
);
499 while (current_entry
!= NULL
)
501 if (current_entry
->Process
== Process
&&
502 current_entry
->Address
== Address
)
504 if (previous_entry
== NULL
)
506 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
510 previous_entry
->Next
= current_entry
->Next
;
512 ExReleaseFastMutex(&RmapListLock
);
513 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
516 Process
= PsInitialSystemProcess
;
520 InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
524 previous_entry
= current_entry
;
525 current_entry
= current_entry
->Next
;