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.17 2003/05/19 15:58:09 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
;
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
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
137 MemoryArea
->Data
.SectionData
.ViewOffset
);
140 * Get or create a pageop
142 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
143 MemoryArea
->Data
.SectionData
.Segment
,
144 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
147 DPRINT1("MmGetPageOp failed\n");
152 if (PageOp
->Thread
!= PsGetCurrentThread())
154 MmReleasePageOp(PageOp
);
155 MmUnlockAddressSpace(AddressSpace
);
156 if (Address
< (PVOID
)KERNEL_BASE
)
158 ObDereferenceObject(Process
);
160 return(STATUS_UNSUCCESSFUL
);
164 * Release locks now we have a page op.
166 MmUnlockAddressSpace(AddressSpace
);
169 * Do the actual page out work.
171 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
174 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
176 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
177 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
179 if (PageOp
->Thread
!= PsGetCurrentThread())
181 MmReleasePageOp(PageOp
);
182 MmUnlockAddressSpace(AddressSpace
);
183 if (Address
< (PVOID
)KERNEL_BASE
)
185 ObDereferenceObject(Process
);
187 return(STATUS_UNSUCCESSFUL
);
191 * Release locks now we have a page op.
193 MmUnlockAddressSpace(AddressSpace
);
196 * Do the actual page out work.
198 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
205 if (Address
< (PVOID
)KERNEL_BASE
)
207 ObDereferenceObject(Process
);
213 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress
)
215 PMM_RMAP_ENTRY entry
;
216 PMEMORY_AREA MemoryArea
;
217 PMADDRESS_SPACE AddressSpace
;
222 LARGE_INTEGER Offset
;
225 ExAcquireFastMutex(&RmapListLock
);
226 entry
= MmGetRmapListHeadPage(PhysicalAddress
);
229 ExReleaseFastMutex(&RmapListLock
);
230 return(STATUS_UNSUCCESSFUL
);
232 Process
= entry
->Process
;
233 Address
= entry
->Address
;
234 if ((((ULONG
)Address
) & 0xFFF) != 0)
239 if (Address
< (PVOID
)KERNEL_BASE
)
241 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
242 ExReleaseFastMutex(&RmapListLock
);
243 if (!NT_SUCCESS(Status
))
247 AddressSpace
= &Process
->AddressSpace
;
251 ExReleaseFastMutex(&RmapListLock
);
252 AddressSpace
= MmGetKernelAddressSpace();
255 MmLockAddressSpace(AddressSpace
);
256 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
257 Type
= MemoryArea
->Type
;
258 if (Type
== MEMORY_AREA_SECTION_VIEW
)
260 Offset
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
261 MemoryArea
->Data
.SectionData
.ViewOffset
);
264 * Get or create a pageop
266 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
267 MemoryArea
->Data
.SectionData
.Segment
,
268 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
271 DPRINT1("MmGetPageOp failed\n");
275 if (PageOp
->Thread
!= PsGetCurrentThread())
277 MmReleasePageOp(PageOp
);
278 MmUnlockAddressSpace(AddressSpace
);
279 if (Address
< (PVOID
)KERNEL_BASE
)
281 ObDereferenceObject(Process
);
283 return(STATUS_UNSUCCESSFUL
);
287 * Release locks now we have a page op.
289 MmUnlockAddressSpace(AddressSpace
);
292 * Do the actual page out work.
294 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
297 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
299 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
300 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
301 if (PageOp
->Thread
!= PsGetCurrentThread())
303 MmReleasePageOp(PageOp
);
304 MmUnlockAddressSpace(AddressSpace
);
305 if (Address
< (PVOID
)KERNEL_BASE
)
307 ObDereferenceObject(Process
);
309 return(STATUS_UNSUCCESSFUL
);
313 * Release locks now we have a page op.
315 MmUnlockAddressSpace(AddressSpace
);
318 * Do the actual page out work.
320 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
327 if (Address
< (PVOID
)KERNEL_BASE
)
329 ObDereferenceObject(Process
);
335 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
337 PMM_RMAP_ENTRY current_entry
;
339 ExAcquireFastMutex(&RmapListLock
);
340 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
341 if (current_entry
== NULL
)
343 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
346 while (current_entry
!= NULL
)
348 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
349 current_entry
= current_entry
->Next
;
351 ExReleaseFastMutex(&RmapListLock
);
355 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
357 PMM_RMAP_ENTRY current_entry
;
359 ExAcquireFastMutex(&RmapListLock
);
360 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
361 if (current_entry
== NULL
)
363 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
366 while (current_entry
!= NULL
)
368 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
369 current_entry
= current_entry
->Next
;
371 ExReleaseFastMutex(&RmapListLock
);
375 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress
)
377 PMM_RMAP_ENTRY current_entry
;
379 ExAcquireFastMutex(&RmapListLock
);
380 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
381 if (current_entry
== NULL
)
383 ExReleaseFastMutex(&RmapListLock
);
386 while (current_entry
!= NULL
)
388 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
390 ExReleaseFastMutex(&RmapListLock
);
393 current_entry
= current_entry
->Next
;
395 ExReleaseFastMutex(&RmapListLock
);
400 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
403 PMM_RMAP_ENTRY current_entry
;
404 PMM_RMAP_ENTRY new_entry
;
406 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
408 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
409 if (new_entry
== NULL
)
413 new_entry
->Address
= Address
;
414 new_entry
->Process
= Process
;
416 if (MmGetPhysicalAddressForProcess(Process
, Address
).QuadPart
!=
417 PhysicalAddress
.QuadPart
)
419 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
420 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
421 MmGetPhysicalAddressForProcess(Process
, Address
),
426 ExAcquireFastMutex(&RmapListLock
);
427 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
428 new_entry
->Next
= current_entry
;
429 MmSetRmapListHeadPage(PhysicalAddress
, new_entry
);
430 ExReleaseFastMutex(&RmapListLock
);
434 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
, PVOID Context
,
435 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
438 PMM_RMAP_ENTRY current_entry
;
439 PMM_RMAP_ENTRY previous_entry
;
441 ExAcquireFastMutex(&RmapListLock
);
442 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
443 if (current_entry
== NULL
)
445 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
448 while (current_entry
!= NULL
)
450 previous_entry
= current_entry
;
451 current_entry
= current_entry
->Next
;
454 DeleteMapping(Context
, previous_entry
->Process
,
455 previous_entry
->Address
);
457 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
459 MmSetRmapListHeadPage(PhysicalAddress
, NULL
);
460 ExReleaseFastMutex(&RmapListLock
);
464 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
467 PMM_RMAP_ENTRY current_entry
, previous_entry
;
469 ExAcquireFastMutex(&RmapListLock
);
470 previous_entry
= NULL
;
471 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
472 while (current_entry
!= NULL
)
474 if (current_entry
->Process
== Process
&&
475 current_entry
->Address
== Address
)
477 if (previous_entry
== NULL
)
479 MmSetRmapListHeadPage(PhysicalAddress
, current_entry
->Next
);
483 previous_entry
->Next
= current_entry
->Next
;
485 ExReleaseFastMutex(&RmapListLock
);
486 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
489 previous_entry
= current_entry
;
490 current_entry
= current_entry
->Next
;