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;
83 * Check that the address still has a valid rmap; then reference the
84 * process so it isn't freed while we are working.
86 ExAcquireFastMutex(&RmapListLock);
87 entry = MmGetRmapListHeadPage(PhysicalAddress);
90 ExReleaseFastMutex(&RmapListLock);
91 return(STATUS_UNSUCCESSFUL);
93 Process = entry->Process;
94 Address = entry->Address;
95 if ((((ULONG)Address) & 0xFFF) != 0)
99 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
100 ExReleaseFastMutex(&RmapListLock);
101 if (!NT_SUCCESS(Status))
107 * Lock the address space; then check that the address we are using
108 * still corresponds to a valid memory area (the page might have been
109 * freed or paged out after we read the rmap entry.)
111 MmLockAddressSpace(&Process->AddressSpace);
112 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
113 if (MemoryArea == NULL)
115 MmUnlockAddressSpace(&Process->AddressSpace);
116 ObDereferenceObject(Process);
117 return(STATUS_UNSUCCESSFUL);
120 Type = MemoryArea->Type;
121 if (Type == MEMORY_AREA_SECTION_VIEW)
123 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
124 MemoryArea->Data.SectionData.ViewOffset);
127 * Get or create a pageop
129 PageOp = MmGetPageOp(MemoryArea, 0, 0,
130 MemoryArea->Data.SectionData.Segment,
131 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
134 DPRINT1("MmGetPageOp failed\n");
139 if (PageOp->Thread != PsGetCurrentThread())
141 MmReleasePageOp(PageOp);
142 MmUnlockAddressSpace(&Process->AddressSpace);
143 ObDereferenceObject(Process);
144 return(STATUS_UNSUCCESSFUL);
148 * Release locks now we have a page op.
150 MmUnlockAddressSpace(&Process->AddressSpace);
153 * Do the actual page out work.
155 Status = MmWritePageSectionView(&Process->AddressSpace, MemoryArea,
158 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
160 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
161 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
164 if (PageOp->Thread != PsGetCurrentThread())
166 MmReleasePageOp(PageOp);
167 MmUnlockAddressSpace(&Process->AddressSpace);
168 ObDereferenceObject(Process);
169 return(STATUS_UNSUCCESSFUL);
173 * Release locks now we have a page op.
175 MmUnlockAddressSpace(&Process->AddressSpace);
178 * Do the actual page out work.
180 Status = MmWritePageVirtualMemory(&Process->AddressSpace, MemoryArea,
187 ObDereferenceObject(Process);
192 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
194 PMM_RMAP_ENTRY entry;
195 PMEMORY_AREA MemoryArea;
200 LARGE_INTEGER Offset;
203 ExAcquireFastMutex(&RmapListLock);
204 entry = MmGetRmapListHeadPage(PhysicalAddress);
207 ExReleaseFastMutex(&RmapListLock);
208 return(STATUS_UNSUCCESSFUL);
210 Process = entry->Process;
211 Address = entry->Address;
212 if ((((ULONG)Address) & 0xFFF) != 0)
217 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
218 ExReleaseFastMutex(&RmapListLock);
219 if (!NT_SUCCESS(Status))
223 MmLockAddressSpace(&Process->AddressSpace);
224 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
225 Type = MemoryArea->Type;
226 if (Type == MEMORY_AREA_SECTION_VIEW)
228 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
229 MemoryArea->Data.SectionData.ViewOffset);
232 * Get or create a pageop
234 PageOp = MmGetPageOp(MemoryArea, 0, 0,
235 MemoryArea->Data.SectionData.Segment,
236 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
239 DPRINT1("MmGetPageOp failed\n");
243 if (PageOp->Thread != PsGetCurrentThread())
245 MmReleasePageOp(PageOp);
246 MmUnlockAddressSpace(&Process->AddressSpace);
247 ObDereferenceObject(Process);
248 return(STATUS_UNSUCCESSFUL);
252 * Release locks now we have a page op.
254 MmUnlockAddressSpace(&Process->AddressSpace);
257 * Do the actual page out work.
259 Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea,
262 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
264 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
265 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
266 if (PageOp->Thread != PsGetCurrentThread())
268 MmReleasePageOp(PageOp);
269 MmUnlockAddressSpace(&Process->AddressSpace);
270 ObDereferenceObject(Process);
271 return(STATUS_UNSUCCESSFUL);
275 * Release locks now we have a page op.
277 MmUnlockAddressSpace(&Process->AddressSpace);
280 * Do the actual page out work.
282 Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea,
289 ObDereferenceObject(Process);
294 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
296 PMM_RMAP_ENTRY current_entry;
298 ExAcquireFastMutex(&RmapListLock);
299 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
300 if (current_entry == NULL)
302 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
305 while (current_entry != NULL)
307 MmSetCleanPage(current_entry->Process, current_entry->Address);
308 current_entry = current_entry->Next;
310 ExReleaseFastMutex(&RmapListLock);
314 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
316 PMM_RMAP_ENTRY current_entry;
318 ExAcquireFastMutex(&RmapListLock);
319 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
320 if (current_entry == NULL)
322 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
325 while (current_entry != NULL)
327 MmSetDirtyPage(current_entry->Process, current_entry->Address);
328 current_entry = current_entry->Next;
330 ExReleaseFastMutex(&RmapListLock);
334 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress)
336 PMM_RMAP_ENTRY current_entry;
338 ExAcquireFastMutex(&RmapListLock);
339 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
340 if (current_entry == NULL)
342 ExReleaseFastMutex(&RmapListLock);
345 while (current_entry != NULL)
347 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
349 ExReleaseFastMutex(&RmapListLock);
352 current_entry = current_entry->Next;
354 ExReleaseFastMutex(&RmapListLock);
359 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
362 PMM_RMAP_ENTRY current_entry;
363 PMM_RMAP_ENTRY new_entry;
365 Address = (PVOID)PAGE_ROUND_DOWN(Address);
367 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
368 if (new_entry == NULL)
372 new_entry->Address = Address;
373 new_entry->Process = Process;
375 if (MmGetPhysicalAddressForProcess(Process, Address).QuadPart !=
376 PhysicalAddress.QuadPart)
378 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
379 "address 0x%.8X\n", Process->UniqueProcessId, Address,
380 MmGetPhysicalAddressForProcess(Process, Address),
385 ExAcquireFastMutex(&RmapListLock);
386 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
387 new_entry->Next = current_entry;
388 MmSetRmapListHeadPage(PhysicalAddress, new_entry);
389 ExReleaseFastMutex(&RmapListLock);
393 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
394 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
397 PMM_RMAP_ENTRY current_entry;
398 PMM_RMAP_ENTRY previous_entry;
400 ExAcquireFastMutex(&RmapListLock);
401 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
402 if (current_entry == NULL)
404 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
407 while (current_entry != NULL)
409 previous_entry = current_entry;
410 current_entry = current_entry->Next;
413 DeleteMapping(Context, previous_entry->Process,
414 previous_entry->Address);
416 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
418 MmSetRmapListHeadPage(PhysicalAddress, NULL);
419 ExReleaseFastMutex(&RmapListLock);
423 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
426 PMM_RMAP_ENTRY current_entry, previous_entry;
428 ExAcquireFastMutex(&RmapListLock);
429 previous_entry = NULL;
430 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
431 while (current_entry != NULL)
433 if (current_entry->Process == Process &&
434 current_entry->Address == Address)
436 if (previous_entry == NULL)
438 MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
442 previous_entry->Next = current_entry->Next;
444 ExReleaseFastMutex(&RmapListLock);
445 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
448 previous_entry = current_entry;
449 current_entry = current_entry->Next;