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 /* GLOBALS ******************************************************************/
50 static FAST_MUTEX RmapListLock;
52 /* FUNCTIONS ****************************************************************/
55 MmInitializeRmapList(VOID)
57 ExInitializeFastMutex(&RmapListLock);
61 MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
64 PMEMORY_AREA MemoryArea;
73 * Check that the address still has a valid rmap; then reference the
74 * process so it isn't freed while we are working.
76 ExAcquireFastMutex(&RmapListLock);
77 entry = MmGetRmapListHeadPage(PhysicalAddress);
80 ExReleaseFastMutex(&RmapListLock);
81 return(STATUS_UNSUCCESSFUL);
83 Process = entry->Process;
84 Address = entry->Address;
85 if ((((ULONG)Address) & 0xFFF) != 0)
89 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
90 ExReleaseFastMutex(&RmapListLock);
91 if (!NT_SUCCESS(Status))
97 * Lock the address space; then check that the address we are using
98 * still corresponds to a valid memory area (the page might have been
99 * freed or paged out after we read the rmap entry.)
101 MmLockAddressSpace(&Process->AddressSpace);
102 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
103 if (MemoryArea == NULL)
105 ObDereferenceObject(Process);
106 return(STATUS_UNSUCCESSFUL);
109 Type = MemoryArea->Type;
110 if (Type == MEMORY_AREA_SECTION_VIEW)
112 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
113 MemoryArea->Data.SectionData.ViewOffset);
116 * Get or create a pageop
118 PageOp = MmGetPageOp(MemoryArea, 0, 0,
119 MemoryArea->Data.SectionData.Segment,
120 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
123 DPRINT1("MmGetPageOp failed\n");
128 if (PageOp->Thread != PsGetCurrentThread())
130 MmReleasePageOp(PageOp);
131 MmUnlockAddressSpace(&Process->AddressSpace);
132 ObDereferenceObject(Process);
133 return(STATUS_UNSUCCESSFUL);
137 * Release locks now we have a page op.
139 MmUnlockAddressSpace(&Process->AddressSpace);
142 * Do the actual page out work.
144 Status = MmWritePageSectionView(&Process->AddressSpace, MemoryArea,
147 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
149 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
150 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
153 if (PageOp->Thread != PsGetCurrentThread())
155 MmReleasePageOp(PageOp);
156 MmUnlockAddressSpace(&Process->AddressSpace);
157 ObDereferenceObject(Process);
158 return(STATUS_UNSUCCESSFUL);
162 * Release locks now we have a page op.
164 MmUnlockAddressSpace(&Process->AddressSpace);
167 * Do the actual page out work.
169 Status = MmWritePageVirtualMemory(&Process->AddressSpace, MemoryArea,
176 ObDereferenceObject(Process);
181 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
183 PMM_RMAP_ENTRY entry;
184 PMEMORY_AREA MemoryArea;
189 LARGE_INTEGER Offset;
192 ExAcquireFastMutex(&RmapListLock);
193 entry = MmGetRmapListHeadPage(PhysicalAddress);
196 ExReleaseFastMutex(&RmapListLock);
197 return(STATUS_UNSUCCESSFUL);
199 Process = entry->Process;
200 Address = entry->Address;
201 if ((((ULONG)Address) & 0xFFF) != 0)
206 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
207 ExReleaseFastMutex(&RmapListLock);
208 if (!NT_SUCCESS(Status))
212 MmLockAddressSpace(&Process->AddressSpace);
213 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
214 Type = MemoryArea->Type;
215 if (Type == MEMORY_AREA_SECTION_VIEW)
217 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
218 MemoryArea->Data.SectionData.ViewOffset);
221 * Get or create a pageop
223 PageOp = MmGetPageOp(MemoryArea, 0, 0,
224 MemoryArea->Data.SectionData.Segment,
225 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
228 DPRINT1("MmGetPageOp failed\n");
232 if (PageOp->Thread != PsGetCurrentThread())
234 MmReleasePageOp(PageOp);
235 MmUnlockAddressSpace(&Process->AddressSpace);
236 ObDereferenceObject(Process);
237 return(STATUS_UNSUCCESSFUL);
241 * Release locks now we have a page op.
243 MmUnlockAddressSpace(&Process->AddressSpace);
246 * Do the actual page out work.
248 Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea,
251 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
253 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
254 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
255 if (PageOp->Thread != PsGetCurrentThread())
257 MmReleasePageOp(PageOp);
258 MmUnlockAddressSpace(&Process->AddressSpace);
259 ObDereferenceObject(Process);
260 return(STATUS_UNSUCCESSFUL);
264 * Release locks now we have a page op.
266 MmUnlockAddressSpace(&Process->AddressSpace);
269 * Do the actual page out work.
271 Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea,
278 ObDereferenceObject(Process);
283 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
285 PMM_RMAP_ENTRY current_entry;
287 ExAcquireFastMutex(&RmapListLock);
288 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
289 if (current_entry == NULL)
291 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
294 while (current_entry != NULL)
296 MmSetCleanPage(current_entry->Process, current_entry->Address);
297 current_entry = current_entry->Next;
299 ExReleaseFastMutex(&RmapListLock);
303 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
305 PMM_RMAP_ENTRY current_entry;
307 ExAcquireFastMutex(&RmapListLock);
308 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
309 if (current_entry == NULL)
311 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
314 while (current_entry != NULL)
316 MmSetDirtyPage(current_entry->Process, current_entry->Address);
317 current_entry = current_entry->Next;
319 ExReleaseFastMutex(&RmapListLock);
323 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress)
325 PMM_RMAP_ENTRY current_entry;
327 ExAcquireFastMutex(&RmapListLock);
328 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
329 if (current_entry == NULL)
331 ExReleaseFastMutex(&RmapListLock);
334 while (current_entry != NULL)
336 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
338 ExReleaseFastMutex(&RmapListLock);
341 current_entry = current_entry->Next;
343 ExReleaseFastMutex(&RmapListLock);
348 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
351 PMM_RMAP_ENTRY current_entry;
352 PMM_RMAP_ENTRY new_entry;
354 Address = (PVOID)PAGE_ROUND_DOWN(Address);
356 new_entry = ExAllocatePool(NonPagedPool, sizeof(MM_RMAP_ENTRY));
357 if (new_entry == NULL)
361 new_entry->Address = Address;
362 new_entry->Process = Process;
364 if (MmGetPhysicalAddressForProcess(Process, Address).QuadPart !=
365 PhysicalAddress.QuadPart)
367 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
368 "address 0x%.8X\n", Process->UniqueProcessId, Address,
369 MmGetPhysicalAddressForProcess(Process, Address),
374 ExAcquireFastMutex(&RmapListLock);
375 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
376 new_entry->Next = current_entry;
377 MmSetRmapListHeadPage(PhysicalAddress, new_entry);
378 ExReleaseFastMutex(&RmapListLock);
382 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
383 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
386 PMM_RMAP_ENTRY current_entry;
387 PMM_RMAP_ENTRY previous_entry;
389 ExAcquireFastMutex(&RmapListLock);
390 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
391 if (current_entry == NULL)
393 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
396 while (current_entry != NULL)
398 previous_entry = current_entry;
399 current_entry = current_entry->Next;
402 DeleteMapping(Context, previous_entry->Process,
403 previous_entry->Address);
405 ExFreePool(previous_entry);
407 MmSetRmapListHeadPage(PhysicalAddress, NULL);
408 ExReleaseFastMutex(&RmapListLock);
412 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
415 PMM_RMAP_ENTRY current_entry, previous_entry;
417 ExAcquireFastMutex(&RmapListLock);
418 previous_entry = NULL;
419 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
420 while (current_entry != NULL)
422 if (current_entry->Process == Process &&
423 current_entry->Address == Address)
425 if (previous_entry == NULL)
427 MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
428 ExReleaseFastMutex(&RmapListLock);
429 ExFreePool(current_entry);
433 previous_entry->Next = current_entry->Next;
434 ExReleaseFastMutex(&RmapListLock);
435 ExFreePool(current_entry);
439 previous_entry = current_entry;
440 current_entry = current_entry->Next;