3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/mm/rmap.c
24 * PURPOSE: kernel memory managment functions
25 * PROGRAMMER: David Welch (welch@cwcom.net)
30 /* INCLUDES *****************************************************************/
32 #include <ddk/ntddk.h>
33 #include <internal/mm.h>
34 #include <internal/ps.h>
37 #include <internal/debug.h>
39 /* TYPES ********************************************************************/
41 typedef struct _MM_RMAP_ENTRY
43 struct _MM_RMAP_ENTRY* Next;
46 } MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
48 #define TAG_RMAP TAG('R', 'M', 'A', 'P')
50 /* GLOBALS ******************************************************************/
52 static FAST_MUTEX RmapListLock;
53 static NPAGED_LOOKASIDE_LIST RmapLookasideList;
55 /* FUNCTIONS ****************************************************************/
58 MmInitializeRmapList(VOID)
60 ExInitializeFastMutex(&RmapListLock);
61 ExInitializeNPagedLookasideList (&RmapLookasideList,
65 sizeof(MM_RMAP_ENTRY),
71 MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
74 PMEMORY_AREA MemoryArea;
75 PMADDRESS_SPACE AddressSpace;
81 NTSTATUS Status = STATUS_SUCCESS;
84 * Check that the address still has a valid rmap; then reference the
85 * process so it isn't freed while we are working.
87 ExAcquireFastMutex(&RmapListLock);
88 entry = MmGetRmapListHeadPage(PhysicalAddress);
91 ExReleaseFastMutex(&RmapListLock);
92 return(STATUS_UNSUCCESSFUL);
94 Process = entry->Process;
95 Address = entry->Address;
96 if ((((ULONG)Address) & 0xFFF) != 0)
100 if (Address < (PVOID)KERNEL_BASE)
102 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
103 ExReleaseFastMutex(&RmapListLock);
104 if (!NT_SUCCESS(Status))
108 AddressSpace = &Process->AddressSpace;
112 ExReleaseFastMutex(&RmapListLock);
113 AddressSpace = MmGetKernelAddressSpace();
117 * Lock the address space; then check that the address we are using
118 * still corresponds to a valid memory area (the page might have been
119 * freed or paged out after we read the rmap entry.)
121 MmLockAddressSpace(AddressSpace);
122 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
123 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
125 MmUnlockAddressSpace(AddressSpace);
126 if (Address < (PVOID)KERNEL_BASE)
128 ObDereferenceObject(Process);
130 return(STATUS_UNSUCCESSFUL);
133 Type = MemoryArea->Type;
134 if (Type == MEMORY_AREA_SECTION_VIEW)
136 Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
139 * Get or create a pageop
141 PageOp = MmGetPageOp(MemoryArea, 0, 0,
142 MemoryArea->Data.SectionData.Segment,
143 Offset, MM_PAGEOP_PAGEOUT);
146 DPRINT1("MmGetPageOp failed\n");
151 if (PageOp->Thread != PsGetCurrentThread())
153 MmUnlockAddressSpace(AddressSpace);
154 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
159 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
160 MmReleasePageOp(PageOp);
161 if (Address < (PVOID)KERNEL_BASE)
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 = MmWritePageSectionView(AddressSpace, MemoryArea,
179 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
181 PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
182 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
184 if (PageOp->Thread != PsGetCurrentThread())
186 MmReleasePageOp(PageOp);
187 MmUnlockAddressSpace(AddressSpace);
188 if (Address < (PVOID)KERNEL_BASE)
190 ObDereferenceObject(Process);
192 return(STATUS_UNSUCCESSFUL);
196 * Release locks now we have a page op.
198 MmUnlockAddressSpace(AddressSpace);
201 * Do the actual page out work.
203 Status = MmWritePageVirtualMemory(AddressSpace, MemoryArea,
210 if (Address < (PVOID)KERNEL_BASE)
212 ObDereferenceObject(Process);
218 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
220 PMM_RMAP_ENTRY entry;
221 PMEMORY_AREA MemoryArea;
222 PMADDRESS_SPACE AddressSpace;
228 NTSTATUS Status = STATUS_SUCCESS;
230 ExAcquireFastMutex(&RmapListLock);
231 entry = MmGetRmapListHeadPage(PhysicalAddress);
234 ExReleaseFastMutex(&RmapListLock);
235 return(STATUS_UNSUCCESSFUL);
237 Process = entry->Process;
238 Address = entry->Address;
239 if ((((ULONG)Address) & 0xFFF) != 0)
244 if (Address < (PVOID)KERNEL_BASE)
246 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
247 ExReleaseFastMutex(&RmapListLock);
248 if (!NT_SUCCESS(Status))
252 AddressSpace = &Process->AddressSpace;
256 ExReleaseFastMutex(&RmapListLock);
257 AddressSpace = MmGetKernelAddressSpace();
260 MmLockAddressSpace(AddressSpace);
261 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
262 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
264 MmUnlockAddressSpace(AddressSpace);
265 if (Address < (PVOID)KERNEL_BASE)
267 ObDereferenceObject(Process);
269 return(STATUS_UNSUCCESSFUL);
271 Type = MemoryArea->Type;
272 if (Type == MEMORY_AREA_SECTION_VIEW)
274 Offset = (ULONG)(Address - (ULONG)MemoryArea->BaseAddress);
277 * Get or create a pageop
279 PageOp = MmGetPageOp(MemoryArea, 0, 0,
280 MemoryArea->Data.SectionData.Segment,
281 Offset, MM_PAGEOP_PAGEOUT);
284 DPRINT1("MmGetPageOp failed\n");
288 if (PageOp->Thread != PsGetCurrentThread())
290 MmReleasePageOp(PageOp);
291 MmUnlockAddressSpace(AddressSpace);
292 if (Address < (PVOID)KERNEL_BASE)
294 ObDereferenceObject(Process);
296 return(STATUS_UNSUCCESSFUL);
300 * Release locks now we have a page op.
302 MmUnlockAddressSpace(AddressSpace);
305 * Do the actual page out work.
307 Status = MmPageOutSectionView(AddressSpace, MemoryArea,
310 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
312 PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
313 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
314 if (PageOp->Thread != PsGetCurrentThread())
316 MmUnlockAddressSpace(AddressSpace);
317 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
322 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
323 MmReleasePageOp(PageOp);
324 if (Address < (PVOID)KERNEL_BASE)
326 ObDereferenceObject(Process);
328 return(STATUS_UNSUCCESSFUL);
332 * Release locks now we have a page op.
334 MmUnlockAddressSpace(AddressSpace);
337 * Do the actual page out work.
339 Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea,
346 if (Address < (PVOID)KERNEL_BASE)
348 ObDereferenceObject(Process);
354 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
356 PMM_RMAP_ENTRY current_entry;
358 ExAcquireFastMutex(&RmapListLock);
359 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
360 if (current_entry == NULL)
362 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
365 while (current_entry != NULL)
367 MmSetCleanPage(current_entry->Process, current_entry->Address);
368 current_entry = current_entry->Next;
370 ExReleaseFastMutex(&RmapListLock);
374 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
376 PMM_RMAP_ENTRY current_entry;
378 ExAcquireFastMutex(&RmapListLock);
379 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
380 if (current_entry == NULL)
382 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
385 while (current_entry != NULL)
387 MmSetDirtyPage(current_entry->Process, current_entry->Address);
388 current_entry = current_entry->Next;
390 ExReleaseFastMutex(&RmapListLock);
394 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress)
396 PMM_RMAP_ENTRY current_entry;
398 ExAcquireFastMutex(&RmapListLock);
399 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
400 if (current_entry == NULL)
402 ExReleaseFastMutex(&RmapListLock);
405 while (current_entry != NULL)
407 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
409 ExReleaseFastMutex(&RmapListLock);
412 current_entry = current_entry->Next;
414 ExReleaseFastMutex(&RmapListLock);
419 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
422 PMM_RMAP_ENTRY current_entry;
423 PMM_RMAP_ENTRY new_entry;
425 Address = (PVOID)PAGE_ROUND_DOWN(Address);
427 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
428 if (new_entry == NULL)
432 new_entry->Address = Address;
433 new_entry->Process = Process;
435 if (MmGetPhysicalAddressForProcess(Process, Address).QuadPart !=
436 PhysicalAddress.QuadPart)
438 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
439 "address 0x%.8X\n", Process->UniqueProcessId, Address,
440 MmGetPhysicalAddressForProcess(Process, Address),
445 ExAcquireFastMutex(&RmapListLock);
446 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
447 new_entry->Next = current_entry;
448 MmSetRmapListHeadPage(PhysicalAddress, new_entry);
449 ExReleaseFastMutex(&RmapListLock);
453 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
454 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
457 PMM_RMAP_ENTRY current_entry;
458 PMM_RMAP_ENTRY previous_entry;
460 ExAcquireFastMutex(&RmapListLock);
461 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
462 if (current_entry == NULL)
464 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
467 MmSetRmapListHeadPage(PhysicalAddress, NULL);
468 while (current_entry != NULL)
470 previous_entry = current_entry;
471 current_entry = current_entry->Next;
474 DeleteMapping(Context, previous_entry->Process,
475 previous_entry->Address);
477 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
479 ExReleaseFastMutex(&RmapListLock);
483 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
486 PMM_RMAP_ENTRY current_entry, previous_entry;
488 ExAcquireFastMutex(&RmapListLock);
489 previous_entry = NULL;
490 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
491 while (current_entry != NULL)
493 if (current_entry->Process == Process &&
494 current_entry->Address == Address)
496 if (previous_entry == NULL)
498 MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
502 previous_entry->Next = current_entry->Next;
504 ExReleaseFastMutex(&RmapListLock);
505 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
508 previous_entry = current_entry;
509 current_entry = current_entry->Next;