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;
54 /* FUNCTIONS ****************************************************************/
57 MmInitializeRmapList(VOID)
59 ExInitializeFastMutex(&RmapListLock);
63 MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
66 PMEMORY_AREA MemoryArea;
75 * Check that the address still has a valid rmap; then reference the
76 * process so it isn't freed while we are working.
78 ExAcquireFastMutex(&RmapListLock);
79 entry = MmGetRmapListHeadPage(PhysicalAddress);
82 ExReleaseFastMutex(&RmapListLock);
83 return(STATUS_UNSUCCESSFUL);
85 Process = entry->Process;
86 Address = entry->Address;
87 if ((((ULONG)Address) & 0xFFF) != 0)
91 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
92 ExReleaseFastMutex(&RmapListLock);
93 if (!NT_SUCCESS(Status))
99 * Lock the address space; then check that the address we are using
100 * still corresponds to a valid memory area (the page might have been
101 * freed or paged out after we read the rmap entry.)
103 MmLockAddressSpace(&Process->AddressSpace);
104 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
105 if (MemoryArea == NULL)
107 ObDereferenceObject(Process);
108 return(STATUS_UNSUCCESSFUL);
111 Type = MemoryArea->Type;
112 if (Type == MEMORY_AREA_SECTION_VIEW)
114 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
115 MemoryArea->Data.SectionData.ViewOffset);
118 * Get or create a pageop
120 PageOp = MmGetPageOp(MemoryArea, 0, 0,
121 MemoryArea->Data.SectionData.Segment,
122 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
125 DPRINT1("MmGetPageOp failed\n");
130 if (PageOp->Thread != PsGetCurrentThread())
132 MmReleasePageOp(PageOp);
133 MmUnlockAddressSpace(&Process->AddressSpace);
134 ObDereferenceObject(Process);
135 return(STATUS_UNSUCCESSFUL);
139 * Release locks now we have a page op.
141 MmUnlockAddressSpace(&Process->AddressSpace);
144 * Do the actual page out work.
146 Status = MmWritePageSectionView(&Process->AddressSpace, MemoryArea,
149 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
151 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
152 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
155 if (PageOp->Thread != PsGetCurrentThread())
157 MmReleasePageOp(PageOp);
158 MmUnlockAddressSpace(&Process->AddressSpace);
159 ObDereferenceObject(Process);
160 return(STATUS_UNSUCCESSFUL);
164 * Release locks now we have a page op.
166 MmUnlockAddressSpace(&Process->AddressSpace);
169 * Do the actual page out work.
171 Status = MmWritePageVirtualMemory(&Process->AddressSpace, MemoryArea,
178 ObDereferenceObject(Process);
183 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
185 PMM_RMAP_ENTRY entry;
186 PMEMORY_AREA MemoryArea;
191 LARGE_INTEGER Offset;
194 ExAcquireFastMutex(&RmapListLock);
195 entry = MmGetRmapListHeadPage(PhysicalAddress);
198 ExReleaseFastMutex(&RmapListLock);
199 return(STATUS_UNSUCCESSFUL);
201 Process = entry->Process;
202 Address = entry->Address;
203 if ((((ULONG)Address) & 0xFFF) != 0)
208 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
209 ExReleaseFastMutex(&RmapListLock);
210 if (!NT_SUCCESS(Status))
214 MmLockAddressSpace(&Process->AddressSpace);
215 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
216 Type = MemoryArea->Type;
217 if (Type == MEMORY_AREA_SECTION_VIEW)
219 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
220 MemoryArea->Data.SectionData.ViewOffset);
223 * Get or create a pageop
225 PageOp = MmGetPageOp(MemoryArea, 0, 0,
226 MemoryArea->Data.SectionData.Segment,
227 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
230 DPRINT1("MmGetPageOp failed\n");
234 if (PageOp->Thread != PsGetCurrentThread())
236 MmReleasePageOp(PageOp);
237 MmUnlockAddressSpace(&Process->AddressSpace);
238 ObDereferenceObject(Process);
239 return(STATUS_UNSUCCESSFUL);
243 * Release locks now we have a page op.
245 MmUnlockAddressSpace(&Process->AddressSpace);
248 * Do the actual page out work.
250 Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea,
253 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
255 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
256 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
257 if (PageOp->Thread != PsGetCurrentThread())
259 MmReleasePageOp(PageOp);
260 MmUnlockAddressSpace(&Process->AddressSpace);
261 ObDereferenceObject(Process);
262 return(STATUS_UNSUCCESSFUL);
266 * Release locks now we have a page op.
268 MmUnlockAddressSpace(&Process->AddressSpace);
271 * Do the actual page out work.
273 Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea,
280 ObDereferenceObject(Process);
285 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
287 PMM_RMAP_ENTRY current_entry;
289 ExAcquireFastMutex(&RmapListLock);
290 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
291 if (current_entry == NULL)
293 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
296 while (current_entry != NULL)
298 MmSetCleanPage(current_entry->Process, current_entry->Address);
299 current_entry = current_entry->Next;
301 ExReleaseFastMutex(&RmapListLock);
305 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
307 PMM_RMAP_ENTRY current_entry;
309 ExAcquireFastMutex(&RmapListLock);
310 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
311 if (current_entry == NULL)
313 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
316 while (current_entry != NULL)
318 MmSetDirtyPage(current_entry->Process, current_entry->Address);
319 current_entry = current_entry->Next;
321 ExReleaseFastMutex(&RmapListLock);
325 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress)
327 PMM_RMAP_ENTRY current_entry;
329 ExAcquireFastMutex(&RmapListLock);
330 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
331 if (current_entry == NULL)
333 ExReleaseFastMutex(&RmapListLock);
336 while (current_entry != NULL)
338 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
340 ExReleaseFastMutex(&RmapListLock);
343 current_entry = current_entry->Next;
345 ExReleaseFastMutex(&RmapListLock);
350 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
353 PMM_RMAP_ENTRY current_entry;
354 PMM_RMAP_ENTRY new_entry;
356 Address = (PVOID)PAGE_ROUND_DOWN(Address);
358 new_entry = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_RMAP_ENTRY), TAG_RMAP);
359 if (new_entry == NULL)
363 new_entry->Address = Address;
364 new_entry->Process = Process;
366 if (MmGetPhysicalAddressForProcess(Process, Address).QuadPart !=
367 PhysicalAddress.QuadPart)
369 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
370 "address 0x%.8X\n", Process->UniqueProcessId, Address,
371 MmGetPhysicalAddressForProcess(Process, Address),
376 ExAcquireFastMutex(&RmapListLock);
377 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
378 new_entry->Next = current_entry;
379 MmSetRmapListHeadPage(PhysicalAddress, new_entry);
380 ExReleaseFastMutex(&RmapListLock);
384 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
385 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
388 PMM_RMAP_ENTRY current_entry;
389 PMM_RMAP_ENTRY previous_entry;
391 ExAcquireFastMutex(&RmapListLock);
392 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
393 if (current_entry == NULL)
395 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
398 while (current_entry != NULL)
400 previous_entry = current_entry;
401 current_entry = current_entry->Next;
404 DeleteMapping(Context, previous_entry->Process,
405 previous_entry->Address);
407 ExFreePool(previous_entry);
409 MmSetRmapListHeadPage(PhysicalAddress, NULL);
410 ExReleaseFastMutex(&RmapListLock);
414 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
417 PMM_RMAP_ENTRY current_entry, previous_entry;
419 ExAcquireFastMutex(&RmapListLock);
420 previous_entry = NULL;
421 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
422 while (current_entry != NULL)
424 if (current_entry->Process == Process &&
425 current_entry->Address == Address)
427 if (previous_entry == NULL)
429 MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
430 ExReleaseFastMutex(&RmapListLock);
431 ExFreePool(current_entry);
435 previous_entry->Next = current_entry->Next;
436 ExReleaseFastMutex(&RmapListLock);
437 ExFreePool(current_entry);
441 previous_entry = current_entry;
442 current_entry = current_entry->Next;