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.29 2004/08/01 07:24:58 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
;
47 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
49 #define TAG_RMAP TAG('R', 'M', 'A', 'P')
51 /* GLOBALS ******************************************************************/
53 static FAST_MUTEX RmapListLock
;
54 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
56 /* FUNCTIONS ****************************************************************/
59 MmInitializeRmapList(VOID
)
61 ExInitializeFastMutex(&RmapListLock
);
62 ExInitializeNPagedLookasideList (&RmapLookasideList
,
66 sizeof(MM_RMAP_ENTRY
),
72 MmWritePagePhysicalAddress(PFN_TYPE Page
)
75 PMEMORY_AREA MemoryArea
;
76 PMADDRESS_SPACE AddressSpace
;
82 NTSTATUS Status
= STATUS_SUCCESS
;
85 * Check that the address still has a valid rmap; then reference the
86 * process so it isn't freed while we are working.
88 ExAcquireFastMutex(&RmapListLock
);
89 entry
= MmGetRmapListHeadPage(Page
);
92 ExReleaseFastMutex(&RmapListLock
);
93 return(STATUS_UNSUCCESSFUL
);
95 Process
= entry
->Process
;
96 Address
= entry
->Address
;
97 if ((((ULONG
)Address
) & 0xFFF) != 0)
101 if (Address
< (PVOID
)KERNEL_BASE
)
103 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
104 ExReleaseFastMutex(&RmapListLock
);
105 if (!NT_SUCCESS(Status
))
109 AddressSpace
= &Process
->AddressSpace
;
113 ExReleaseFastMutex(&RmapListLock
);
114 AddressSpace
= MmGetKernelAddressSpace();
118 * Lock the address space; then check that the address we are using
119 * still corresponds to a valid memory area (the page might have been
120 * freed or paged out after we read the rmap entry.)
122 MmLockAddressSpace(AddressSpace
);
123 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
124 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
126 MmUnlockAddressSpace(AddressSpace
);
127 if (Address
< (PVOID
)KERNEL_BASE
)
129 ObDereferenceObject(Process
);
131 return(STATUS_UNSUCCESSFUL
);
134 Type
= MemoryArea
->Type
;
135 if (Type
== MEMORY_AREA_SECTION_VIEW
)
137 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
140 * Get or create a pageop
142 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
143 MemoryArea
->Data
.SectionData
.Segment
,
144 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
148 MmUnlockAddressSpace(AddressSpace
);
149 if (Address
< (PVOID
)KERNEL_BASE
)
151 ObDereferenceObject(Process
);
153 return(STATUS_UNSUCCESSFUL
);
157 * Release locks now we have a page op.
159 MmUnlockAddressSpace(AddressSpace
);
162 * Do the actual page out work.
164 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
167 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
169 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
170 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
174 MmUnlockAddressSpace(AddressSpace
);
175 if (Address
< (PVOID
)KERNEL_BASE
)
177 ObDereferenceObject(Process
);
179 return(STATUS_UNSUCCESSFUL
);
183 * Release locks now we have a page op.
185 MmUnlockAddressSpace(AddressSpace
);
188 * Do the actual page out work.
190 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
197 if (Address
< (PVOID
)KERNEL_BASE
)
199 ObDereferenceObject(Process
);
205 MmPageOutPhysicalAddress(PFN_TYPE Page
)
207 PMM_RMAP_ENTRY entry
;
208 PMEMORY_AREA MemoryArea
;
209 PMADDRESS_SPACE AddressSpace
;
215 NTSTATUS Status
= STATUS_SUCCESS
;
217 ExAcquireFastMutex(&RmapListLock
);
218 entry
= MmGetRmapListHeadPage(Page
);
219 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
221 ExReleaseFastMutex(&RmapListLock
);
222 return(STATUS_UNSUCCESSFUL
);
224 Process
= entry
->Process
;
225 Address
= entry
->Address
;
226 if ((((ULONG
)Address
) & 0xFFF) != 0)
231 if (Address
< (PVOID
)KERNEL_BASE
)
233 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
234 ExReleaseFastMutex(&RmapListLock
);
235 if (!NT_SUCCESS(Status
))
239 AddressSpace
= &Process
->AddressSpace
;
243 ExReleaseFastMutex(&RmapListLock
);
244 AddressSpace
= MmGetKernelAddressSpace();
247 MmLockAddressSpace(AddressSpace
);
248 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
249 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
251 MmUnlockAddressSpace(AddressSpace
);
252 if (Address
< (PVOID
)KERNEL_BASE
)
254 ObDereferenceObject(Process
);
256 return(STATUS_UNSUCCESSFUL
);
258 Type
= MemoryArea
->Type
;
259 if (Type
== MEMORY_AREA_SECTION_VIEW
)
261 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
264 * Get or create a pageop
266 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
267 MemoryArea
->Data
.SectionData
.Segment
,
268 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
271 MmUnlockAddressSpace(AddressSpace
);
272 if (Address
< (PVOID
)KERNEL_BASE
)
274 ObDereferenceObject(Process
);
276 return(STATUS_UNSUCCESSFUL
);
280 * Release locks now we have a page op.
282 MmUnlockAddressSpace(AddressSpace
);
285 * Do the actual page out work.
287 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
290 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
292 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
293 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
296 MmUnlockAddressSpace(AddressSpace
);
297 if (Address
< (PVOID
)KERNEL_BASE
)
299 ObDereferenceObject(Process
);
301 return(STATUS_UNSUCCESSFUL
);
305 * Release locks now we have a page op.
307 MmUnlockAddressSpace(AddressSpace
);
310 * Do the actual page out work.
312 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
319 if (Address
< (PVOID
)KERNEL_BASE
)
321 ObDereferenceObject(Process
);
327 MmSetCleanAllRmaps(PFN_TYPE Page
)
329 PMM_RMAP_ENTRY current_entry
;
331 ExAcquireFastMutex(&RmapListLock
);
332 current_entry
= MmGetRmapListHeadPage(Page
);
333 if (current_entry
== NULL
)
335 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
338 while (current_entry
!= NULL
)
340 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
341 current_entry
= current_entry
->Next
;
343 ExReleaseFastMutex(&RmapListLock
);
347 MmSetDirtyAllRmaps(PFN_TYPE Page
)
349 PMM_RMAP_ENTRY current_entry
;
351 ExAcquireFastMutex(&RmapListLock
);
352 current_entry
= MmGetRmapListHeadPage(Page
);
353 if (current_entry
== NULL
)
355 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
358 while (current_entry
!= NULL
)
360 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
361 current_entry
= current_entry
->Next
;
363 ExReleaseFastMutex(&RmapListLock
);
367 MmIsDirtyPageRmap(PFN_TYPE Page
)
369 PMM_RMAP_ENTRY current_entry
;
371 ExAcquireFastMutex(&RmapListLock
);
372 current_entry
= MmGetRmapListHeadPage(Page
);
373 if (current_entry
== NULL
)
375 ExReleaseFastMutex(&RmapListLock
);
378 while (current_entry
!= NULL
)
380 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
382 ExReleaseFastMutex(&RmapListLock
);
385 current_entry
= current_entry
->Next
;
387 ExReleaseFastMutex(&RmapListLock
);
392 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
395 PMM_RMAP_ENTRY current_entry
;
396 PMM_RMAP_ENTRY new_entry
;
398 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
400 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
401 if (new_entry
== NULL
)
405 new_entry
->Address
= Address
;
406 new_entry
->Process
= Process
;
408 if (MmGetPfnForProcess(Process
, Address
) != Page
)
410 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
411 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
412 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
417 ExAcquireFastMutex(&RmapListLock
);
418 current_entry
= MmGetRmapListHeadPage(Page
);
419 new_entry
->Next
= current_entry
;
420 MmSetRmapListHeadPage(Page
, new_entry
);
421 ExReleaseFastMutex(&RmapListLock
);
425 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
426 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
429 PMM_RMAP_ENTRY current_entry
;
430 PMM_RMAP_ENTRY previous_entry
;
432 ExAcquireFastMutex(&RmapListLock
);
433 current_entry
= MmGetRmapListHeadPage(Page
);
434 if (current_entry
== NULL
)
436 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
439 MmSetRmapListHeadPage(Page
, NULL
);
440 while (current_entry
!= NULL
)
442 previous_entry
= current_entry
;
443 current_entry
= current_entry
->Next
;
446 DeleteMapping(Context
, previous_entry
->Process
,
447 previous_entry
->Address
);
449 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
451 ExReleaseFastMutex(&RmapListLock
);
455 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
458 PMM_RMAP_ENTRY current_entry
, previous_entry
;
460 ExAcquireFastMutex(&RmapListLock
);
461 previous_entry
= NULL
;
462 current_entry
= MmGetRmapListHeadPage(Page
);
463 while (current_entry
!= NULL
)
465 if (current_entry
->Process
== Process
&&
466 current_entry
->Address
== Address
)
468 if (previous_entry
== NULL
)
470 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
474 previous_entry
->Next
= current_entry
->Next
;
476 ExReleaseFastMutex(&RmapListLock
);
477 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
480 previous_entry
= current_entry
;
481 current_entry
= current_entry
->Next
;