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.
19 /* $Id: rmap.c,v 1.18 2003/06/06 21:01:36 hbirr Exp $
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
)
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 MmReleasePageOp(PageOp
);
154 MmUnlockAddressSpace(AddressSpace
);
155 if (Address
< (PVOID
)KERNEL_BASE
)
157 ObDereferenceObject(Process
);
159 return(STATUS_UNSUCCESSFUL
);
163 * Release locks now we have a page op.
165 MmUnlockAddressSpace(AddressSpace
);
168 * Do the actual page out work.
170 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
173 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
175 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
176 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
178 if (PageOp
->Thread
!= PsGetCurrentThread())
180 MmReleasePageOp(PageOp
);
181 MmUnlockAddressSpace(AddressSpace
);
182 if (Address
< (PVOID
)KERNEL_BASE
)
184 ObDereferenceObject(Process
);
186 return(STATUS_UNSUCCESSFUL
);
190 * Release locks now we have a page op.
192 MmUnlockAddressSpace(AddressSpace
);
195 * Do the actual page out work.
197 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
204 if (Address
< (PVOID
)KERNEL_BASE
)
206 ObDereferenceObject(Process
);
212 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress
)
214 PMM_RMAP_ENTRY entry
;
215 PMEMORY_AREA MemoryArea
;
216 PMADDRESS_SPACE AddressSpace
;
222 NTSTATUS Status
= STATUS_SUCCESS
;
224 ExAcquireFastMutex(&RmapListLock
);
225 entry
= MmGetRmapListHeadPage(PhysicalAddress
);
228 ExReleaseFastMutex(&RmapListLock
);
229 return(STATUS_UNSUCCESSFUL
);
231 Process
= entry
->Process
;
232 Address
= entry
->Address
;
233 if ((((ULONG
)Address
) & 0xFFF) != 0)
238 if (Address
< (PVOID
)KERNEL_BASE
)
240 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
241 ExReleaseFastMutex(&RmapListLock
);
242 if (!NT_SUCCESS(Status
))
246 AddressSpace
= &Process
->AddressSpace
;
250 ExReleaseFastMutex(&RmapListLock
);
251 AddressSpace
= MmGetKernelAddressSpace();
254 MmLockAddressSpace(AddressSpace
);
255 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
256 Type
= MemoryArea
->Type
;
257 if (Type
== MEMORY_AREA_SECTION_VIEW
)
259 Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
262 * Get or create a pageop
264 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
265 MemoryArea
->Data
.SectionData
.Segment
,
266 Offset
, MM_PAGEOP_PAGEOUT
);
269 DPRINT1("MmGetPageOp failed\n");
273 if (PageOp
->Thread
!= PsGetCurrentThread())
275 MmReleasePageOp(PageOp
);
276 MmUnlockAddressSpace(AddressSpace
);
277 if (Address
< (PVOID
)KERNEL_BASE
)
279 ObDereferenceObject(Process
);
281 return(STATUS_UNSUCCESSFUL
);
285 * Release locks now we have a page op.
287 MmUnlockAddressSpace(AddressSpace
);
290 * Do the actual page out work.
292 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
295 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
297 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
298 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
299 if (PageOp
->Thread
!= PsGetCurrentThread())
301 MmReleasePageOp(PageOp
);
302 MmUnlockAddressSpace(AddressSpace
);
303 if (Address
< (PVOID
)KERNEL_BASE
)
305 ObDereferenceObject(Process
);
307 return(STATUS_UNSUCCESSFUL
);
311 * Release locks now we have a page op.
313 MmUnlockAddressSpace(AddressSpace
);
316 * Do the actual page out work.
318 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
325 if (Address
< (PVOID
)KERNEL_BASE
)
327 ObDereferenceObject(Process
);
333 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
335 PMM_RMAP_ENTRY current_entry
;
337 ExAcquireFastMutex(&RmapListLock
);
338 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
339 if (current_entry
== NULL
)
341 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
344 while (current_entry
!= NULL
)
346 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
347 current_entry
= current_entry
->Next
;
349 ExReleaseFastMutex(&RmapListLock
);
353 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
355 PMM_RMAP_ENTRY current_entry
;
357 ExAcquireFastMutex(&RmapListLock
);
358 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
359 if (current_entry
== NULL
)
361 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
364 while (current_entry
!= NULL
)
366 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
367 current_entry
= current_entry
->Next
;
369 ExReleaseFastMutex(&RmapListLock
);
373 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress
)
375 PMM_RMAP_ENTRY current_entry
;
377 ExAcquireFastMutex(&RmapListLock
);
378 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
379 if (current_entry
== NULL
)
381 ExReleaseFastMutex(&RmapListLock
);
384 while (current_entry
!= NULL
)
386 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
388 ExReleaseFastMutex(&RmapListLock
);
391 current_entry
= current_entry
->Next
;
393 ExReleaseFastMutex(&RmapListLock
);
398 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
401 PMM_RMAP_ENTRY current_entry
;
402 PMM_RMAP_ENTRY new_entry
;
404 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
406 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
407 if (new_entry
== NULL
)
411 new_entry
->Address
= Address
;
412 new_entry
->Process
= Process
;
414 if (MmGetPhysicalAddressForProcess(Process
, Address
).QuadPart
!=
415 PhysicalAddress
.QuadPart
)
417 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
418 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
419 MmGetPhysicalAddressForProcess(Process
, Address
),
424 ExAcquireFastMutex(&RmapListLock
);
425 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
426 new_entry
->Next
= current_entry
;
427 MmSetRmapListHeadPage(PhysicalAddress
, new_entry
);
428 ExReleaseFastMutex(&RmapListLock
);
432 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
, PVOID Context
,
433 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
436 PMM_RMAP_ENTRY current_entry
;
437 PMM_RMAP_ENTRY previous_entry
;
439 ExAcquireFastMutex(&RmapListLock
);
440 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
441 if (current_entry
== NULL
)
443 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
446 while (current_entry
!= NULL
)
448 previous_entry
= current_entry
;
449 current_entry
= current_entry
->Next
;
452 DeleteMapping(Context
, previous_entry
->Process
,
453 previous_entry
->Address
);
455 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
457 MmSetRmapListHeadPage(PhysicalAddress
, NULL
);
458 ExReleaseFastMutex(&RmapListLock
);
462 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
465 PMM_RMAP_ENTRY current_entry
, previous_entry
;
467 ExAcquireFastMutex(&RmapListLock
);
468 previous_entry
= NULL
;
469 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
470 while (current_entry
!= NULL
)
472 if (current_entry
->Process
== Process
&&
473 current_entry
->Address
== Address
)
475 if (previous_entry
== NULL
)
477 MmSetRmapListHeadPage(PhysicalAddress
, current_entry
->Next
);
481 previous_entry
->Next
= current_entry
->Next
;
483 ExReleaseFastMutex(&RmapListLock
);
484 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
487 previous_entry
= current_entry
;
488 current_entry
= current_entry
->Next
;