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 *****************************************************************/
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, MmInitializeRmapList)
20 /* TYPES ********************************************************************/
22 typedef struct _MM_RMAP_ENTRY
24 struct _MM_RMAP_ENTRY
* Next
;
31 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
33 /* GLOBALS ******************************************************************/
35 static FAST_MUTEX RmapListLock
;
36 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
38 /* FUNCTIONS ****************************************************************/
43 MmInitializeRmapList(VOID
)
45 ExInitializeFastMutex(&RmapListLock
);
46 ExInitializeNPagedLookasideList (&RmapLookasideList
,
50 sizeof(MM_RMAP_ENTRY
),
57 MmWritePagePhysicalAddress(PFN_TYPE Page
)
60 PMEMORY_AREA MemoryArea
;
61 PMMSUPPORT AddressSpace
;
67 NTSTATUS Status
= STATUS_SUCCESS
;
70 * Check that the address still has a valid rmap; then reference the
71 * process so it isn't freed while we are working.
73 ExAcquireFastMutex(&RmapListLock
);
74 entry
= MmGetRmapListHeadPage(Page
);
77 ExReleaseFastMutex(&RmapListLock
);
78 return(STATUS_UNSUCCESSFUL
);
80 Process
= entry
->Process
;
81 Address
= entry
->Address
;
82 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
84 KeBugCheck(MEMORY_MANAGEMENT
);
86 if (Address
< MmSystemRangeStart
)
88 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
89 ExReleaseFastMutex(&RmapListLock
);
90 if (!NT_SUCCESS(Status
))
94 AddressSpace
= &Process
->Vm
;
98 ExReleaseFastMutex(&RmapListLock
);
99 AddressSpace
= MmGetKernelAddressSpace();
103 * Lock the address space; then check that the address we are using
104 * still corresponds to a valid memory area (the page might have been
105 * freed or paged out after we read the rmap entry.)
107 MmLockAddressSpace(AddressSpace
);
108 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
109 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
111 MmUnlockAddressSpace(AddressSpace
);
112 if (Address
< MmSystemRangeStart
)
114 ObDereferenceObject(Process
);
116 return(STATUS_UNSUCCESSFUL
);
119 Type
= MemoryArea
->Type
;
120 if (Type
== MEMORY_AREA_SECTION_VIEW
)
122 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
123 + MemoryArea
->Data
.SectionData
.ViewOffset
;
125 * Get or create a pageop
127 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
128 MemoryArea
->Data
.SectionData
.Segment
,
129 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
133 MmUnlockAddressSpace(AddressSpace
);
134 if (Address
< MmSystemRangeStart
)
136 ObDereferenceObject(Process
);
138 return(STATUS_UNSUCCESSFUL
);
142 * Release locks now we have a page op.
144 MmUnlockAddressSpace(AddressSpace
);
147 * Do the actual page out work.
149 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
152 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
154 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
155 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
159 MmUnlockAddressSpace(AddressSpace
);
160 if (Address
< MmSystemRangeStart
)
162 ObDereferenceObject(Process
);
164 return(STATUS_UNSUCCESSFUL
);
168 * Release locks now we have a page op.
170 MmUnlockAddressSpace(AddressSpace
);
173 * Do the actual page out work.
175 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
180 KeBugCheck(MEMORY_MANAGEMENT
);
182 if (Address
< MmSystemRangeStart
)
184 ObDereferenceObject(Process
);
191 MmPageOutPhysicalAddress(PFN_TYPE Page
)
193 PMM_RMAP_ENTRY entry
;
194 PMEMORY_AREA MemoryArea
;
195 PMMSUPPORT AddressSpace
;
201 NTSTATUS Status
= STATUS_SUCCESS
;
203 ExAcquireFastMutex(&RmapListLock
);
204 entry
= MmGetRmapListHeadPage(Page
);
207 ExReleaseFastMutex(&RmapListLock
);
208 return(STATUS_UNSUCCESSFUL
);
210 Process
= entry
->Process
;
211 Address
= entry
->Address
;
212 if ((((ULONG_PTR
)Address
) & 0xFFF) != 0)
214 KeBugCheck(MEMORY_MANAGEMENT
);
217 if (Address
< MmSystemRangeStart
)
219 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
220 ExReleaseFastMutex(&RmapListLock
);
221 if (!NT_SUCCESS(Status
))
225 AddressSpace
= &Process
->Vm
;
229 ExReleaseFastMutex(&RmapListLock
);
230 AddressSpace
= MmGetKernelAddressSpace();
233 MmLockAddressSpace(AddressSpace
);
234 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
235 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
237 MmUnlockAddressSpace(AddressSpace
);
238 if (Address
< MmSystemRangeStart
)
240 ObDereferenceObject(Process
);
242 return(STATUS_UNSUCCESSFUL
);
244 Type
= MemoryArea
->Type
;
245 if (Type
== MEMORY_AREA_SECTION_VIEW
)
247 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
248 + MemoryArea
->Data
.SectionData
.ViewOffset
;
251 * Get or create a pageop
253 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0,
254 MemoryArea
->Data
.SectionData
.Segment
,
255 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
258 MmUnlockAddressSpace(AddressSpace
);
259 if (Address
< MmSystemRangeStart
)
261 ObDereferenceObject(Process
);
263 return(STATUS_UNSUCCESSFUL
);
267 * Release locks now we have a page op.
269 MmUnlockAddressSpace(AddressSpace
);
272 * Do the actual page out work.
274 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
277 else if ((Type
== MEMORY_AREA_VIRTUAL_MEMORY
) || (Type
== MEMORY_AREA_PEB_OR_TEB
))
279 PageOp
= MmGetPageOp(MemoryArea
, Address
< MmSystemRangeStart
? Process
->UniqueProcessId
: NULL
,
280 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
283 MmUnlockAddressSpace(AddressSpace
);
284 if (Address
< MmSystemRangeStart
)
286 ObDereferenceObject(Process
);
288 return(STATUS_UNSUCCESSFUL
);
292 * Release locks now we have a page op.
294 MmUnlockAddressSpace(AddressSpace
);
297 * Do the actual page out work.
299 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
304 KeBugCheck(MEMORY_MANAGEMENT
);
306 if (Address
< MmSystemRangeStart
)
308 ObDereferenceObject(Process
);
315 MmSetCleanAllRmaps(PFN_TYPE Page
)
317 PMM_RMAP_ENTRY current_entry
;
319 ExAcquireFastMutex(&RmapListLock
);
320 current_entry
= MmGetRmapListHeadPage(Page
);
321 if (current_entry
== NULL
)
323 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
324 KeBugCheck(MEMORY_MANAGEMENT
);
326 while (current_entry
!= NULL
)
328 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
329 current_entry
= current_entry
->Next
;
331 ExReleaseFastMutex(&RmapListLock
);
336 MmSetDirtyAllRmaps(PFN_TYPE Page
)
338 PMM_RMAP_ENTRY current_entry
;
340 ExAcquireFastMutex(&RmapListLock
);
341 current_entry
= MmGetRmapListHeadPage(Page
);
342 if (current_entry
== NULL
)
344 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
345 KeBugCheck(MEMORY_MANAGEMENT
);
347 while (current_entry
!= NULL
)
349 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
350 current_entry
= current_entry
->Next
;
352 ExReleaseFastMutex(&RmapListLock
);
357 MmIsDirtyPageRmap(PFN_TYPE Page
)
359 PMM_RMAP_ENTRY current_entry
;
361 ExAcquireFastMutex(&RmapListLock
);
362 current_entry
= MmGetRmapListHeadPage(Page
);
363 if (current_entry
== NULL
)
365 ExReleaseFastMutex(&RmapListLock
);
368 while (current_entry
!= NULL
)
370 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
372 ExReleaseFastMutex(&RmapListLock
);
375 current_entry
= current_entry
->Next
;
377 ExReleaseFastMutex(&RmapListLock
);
383 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
386 PMM_RMAP_ENTRY current_entry
;
387 PMM_RMAP_ENTRY new_entry
;
390 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
392 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
393 if (new_entry
== NULL
)
395 KeBugCheck(MEMORY_MANAGEMENT
);
397 new_entry
->Address
= Address
;
398 new_entry
->Process
= (PEPROCESS
)Process
;
401 new_entry
->Caller
= __builtin_return_address(0);
403 new_entry
->Caller
= _ReturnAddress();
407 if (MmGetPfnForProcess(Process
, Address
) != Page
)
409 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
410 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
411 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
413 KeBugCheck(MEMORY_MANAGEMENT
);
416 ExAcquireFastMutex(&RmapListLock
);
417 current_entry
= MmGetRmapListHeadPage(Page
);
418 new_entry
->Next
= current_entry
;
420 while (current_entry
)
422 if (current_entry
->Address
== new_entry
->Address
&& current_entry
->Process
== new_entry
->Process
)
424 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
425 current_entry
->Address
);
426 DbgPrint("%p", new_entry
->Caller
);
427 DbgPrint("\n previous caller ");
428 DbgPrint("%p", current_entry
->Caller
);
430 KeBugCheck(MEMORY_MANAGEMENT
);
432 current_entry
= current_entry
->Next
;
435 MmSetRmapListHeadPage(Page
, new_entry
);
436 ExReleaseFastMutex(&RmapListLock
);
439 Process
= PsInitialSystemProcess
;
443 PrevSize
= InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, PAGE_SIZE
);
444 if (PrevSize
>= Process
->Vm
.PeakWorkingSetSize
)
446 Process
->Vm
.PeakWorkingSetSize
= PrevSize
+ PAGE_SIZE
;
453 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
454 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
457 PMM_RMAP_ENTRY current_entry
;
458 PMM_RMAP_ENTRY previous_entry
;
461 ExAcquireFastMutex(&RmapListLock
);
462 current_entry
= MmGetRmapListHeadPage(Page
);
463 if (current_entry
== NULL
)
465 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
466 KeBugCheck(MEMORY_MANAGEMENT
);
468 MmSetRmapListHeadPage(Page
, NULL
);
469 ExReleaseFastMutex(&RmapListLock
);
470 while (current_entry
!= NULL
)
472 previous_entry
= current_entry
;
473 current_entry
= current_entry
->Next
;
476 DeleteMapping(Context
, previous_entry
->Process
,
477 previous_entry
->Address
);
479 Process
= previous_entry
->Process
;
480 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
483 Process
= PsInitialSystemProcess
;
487 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
494 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
497 PMM_RMAP_ENTRY current_entry
, previous_entry
;
499 ExAcquireFastMutex(&RmapListLock
);
500 previous_entry
= NULL
;
501 current_entry
= MmGetRmapListHeadPage(Page
);
502 while (current_entry
!= NULL
)
504 if (current_entry
->Process
== (PEPROCESS
)Process
&&
505 current_entry
->Address
== Address
)
507 if (previous_entry
== NULL
)
509 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
513 previous_entry
->Next
= current_entry
->Next
;
515 ExReleaseFastMutex(&RmapListLock
);
516 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
519 Process
= PsInitialSystemProcess
;
523 (void)InterlockedExchangeAddUL(&Process
->Vm
.WorkingSetSize
, -PAGE_SIZE
);
527 previous_entry
= current_entry
;
528 current_entry
= current_entry
->Next
;
530 KeBugCheck(MEMORY_MANAGEMENT
);