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.30 2004/08/15 16:39:08 chorns 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 *****************************************************************/
34 #include <internal/debug.h>
36 /* TYPES ********************************************************************/
38 typedef struct _MM_RMAP_ENTRY
40 struct _MM_RMAP_ENTRY
* Next
;
44 MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
46 #define TAG_RMAP TAG('R', 'M', 'A', 'P')
48 /* GLOBALS ******************************************************************/
50 static FAST_MUTEX RmapListLock
;
51 static NPAGED_LOOKASIDE_LIST RmapLookasideList
;
53 /* FUNCTIONS ****************************************************************/
56 MmInitializeRmapList(VOID
)
58 ExInitializeFastMutex(&RmapListLock
);
59 ExInitializeNPagedLookasideList (&RmapLookasideList
,
63 sizeof(MM_RMAP_ENTRY
),
69 MmWritePagePhysicalAddress(PFN_TYPE Page
)
72 PMEMORY_AREA MemoryArea
;
73 PMADDRESS_SPACE AddressSpace
;
79 NTSTATUS Status
= STATUS_SUCCESS
;
82 * Check that the address still has a valid rmap; then reference the
83 * process so it isn't freed while we are working.
85 ExAcquireFastMutex(&RmapListLock
);
86 entry
= MmGetRmapListHeadPage(Page
);
89 ExReleaseFastMutex(&RmapListLock
);
90 return(STATUS_UNSUCCESSFUL
);
92 Process
= entry
->Process
;
93 Address
= entry
->Address
;
94 if ((((ULONG
)Address
) & 0xFFF) != 0)
98 if (Address
< (PVOID
)KERNEL_BASE
)
100 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
101 ExReleaseFastMutex(&RmapListLock
);
102 if (!NT_SUCCESS(Status
))
106 AddressSpace
= &Process
->AddressSpace
;
110 ExReleaseFastMutex(&RmapListLock
);
111 AddressSpace
= MmGetKernelAddressSpace();
115 * Lock the address space; then check that the address we are using
116 * still corresponds to a valid memory area (the page might have been
117 * freed or paged out after we read the rmap entry.)
119 MmLockAddressSpace(AddressSpace
);
120 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
121 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
123 MmUnlockAddressSpace(AddressSpace
);
124 if (Address
< (PVOID
)KERNEL_BASE
)
126 ObDereferenceObject(Process
);
128 return(STATUS_UNSUCCESSFUL
);
131 Type
= MemoryArea
->Type
;
132 if (Type
== MEMORY_AREA_SECTION_VIEW
)
134 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
137 * Get or create a pageop
139 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
140 MemoryArea
->Data
.SectionData
.Segment
,
141 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
145 MmUnlockAddressSpace(AddressSpace
);
146 if (Address
< (PVOID
)KERNEL_BASE
)
148 ObDereferenceObject(Process
);
150 return(STATUS_UNSUCCESSFUL
);
154 * Release locks now we have a page op.
156 MmUnlockAddressSpace(AddressSpace
);
159 * Do the actual page out work.
161 Status
= MmWritePageSectionView(AddressSpace
, MemoryArea
,
164 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
166 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
167 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
171 MmUnlockAddressSpace(AddressSpace
);
172 if (Address
< (PVOID
)KERNEL_BASE
)
174 ObDereferenceObject(Process
);
176 return(STATUS_UNSUCCESSFUL
);
180 * Release locks now we have a page op.
182 MmUnlockAddressSpace(AddressSpace
);
185 * Do the actual page out work.
187 Status
= MmWritePageVirtualMemory(AddressSpace
, MemoryArea
,
194 if (Address
< (PVOID
)KERNEL_BASE
)
196 ObDereferenceObject(Process
);
202 MmPageOutPhysicalAddress(PFN_TYPE Page
)
204 PMM_RMAP_ENTRY entry
;
205 PMEMORY_AREA MemoryArea
;
206 PMADDRESS_SPACE AddressSpace
;
212 NTSTATUS Status
= STATUS_SUCCESS
;
214 ExAcquireFastMutex(&RmapListLock
);
215 entry
= MmGetRmapListHeadPage(Page
);
216 if (entry
== NULL
|| MmGetLockCountPage(Page
) != 0)
218 ExReleaseFastMutex(&RmapListLock
);
219 return(STATUS_UNSUCCESSFUL
);
221 Process
= entry
->Process
;
222 Address
= entry
->Address
;
223 if ((((ULONG
)Address
) & 0xFFF) != 0)
228 if (Address
< (PVOID
)KERNEL_BASE
)
230 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
231 ExReleaseFastMutex(&RmapListLock
);
232 if (!NT_SUCCESS(Status
))
236 AddressSpace
= &Process
->AddressSpace
;
240 ExReleaseFastMutex(&RmapListLock
);
241 AddressSpace
= MmGetKernelAddressSpace();
244 MmLockAddressSpace(AddressSpace
);
245 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, Address
);
246 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
248 MmUnlockAddressSpace(AddressSpace
);
249 if (Address
< (PVOID
)KERNEL_BASE
)
251 ObDereferenceObject(Process
);
253 return(STATUS_UNSUCCESSFUL
);
255 Type
= MemoryArea
->Type
;
256 if (Type
== MEMORY_AREA_SECTION_VIEW
)
258 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
261 * Get or create a pageop
263 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
264 MemoryArea
->Data
.SectionData
.Segment
,
265 Offset
, MM_PAGEOP_PAGEOUT
, TRUE
);
268 MmUnlockAddressSpace(AddressSpace
);
269 if (Address
< (PVOID
)KERNEL_BASE
)
271 ObDereferenceObject(Process
);
273 return(STATUS_UNSUCCESSFUL
);
277 * Release locks now we have a page op.
279 MmUnlockAddressSpace(AddressSpace
);
282 * Do the actual page out work.
284 Status
= MmPageOutSectionView(AddressSpace
, MemoryArea
,
287 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
289 PageOp
= MmGetPageOp(MemoryArea
, Address
< (PVOID
)KERNEL_BASE
? Process
->UniqueProcessId
: 0,
290 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
, TRUE
);
293 MmUnlockAddressSpace(AddressSpace
);
294 if (Address
< (PVOID
)KERNEL_BASE
)
296 ObDereferenceObject(Process
);
298 return(STATUS_UNSUCCESSFUL
);
302 * Release locks now we have a page op.
304 MmUnlockAddressSpace(AddressSpace
);
307 * Do the actual page out work.
309 Status
= MmPageOutVirtualMemory(AddressSpace
, MemoryArea
,
316 if (Address
< (PVOID
)KERNEL_BASE
)
318 ObDereferenceObject(Process
);
324 MmSetCleanAllRmaps(PFN_TYPE Page
)
326 PMM_RMAP_ENTRY current_entry
;
328 ExAcquireFastMutex(&RmapListLock
);
329 current_entry
= MmGetRmapListHeadPage(Page
);
330 if (current_entry
== NULL
)
332 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
335 while (current_entry
!= NULL
)
337 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
338 current_entry
= current_entry
->Next
;
340 ExReleaseFastMutex(&RmapListLock
);
344 MmSetDirtyAllRmaps(PFN_TYPE Page
)
346 PMM_RMAP_ENTRY current_entry
;
348 ExAcquireFastMutex(&RmapListLock
);
349 current_entry
= MmGetRmapListHeadPage(Page
);
350 if (current_entry
== NULL
)
352 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
355 while (current_entry
!= NULL
)
357 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
358 current_entry
= current_entry
->Next
;
360 ExReleaseFastMutex(&RmapListLock
);
364 MmIsDirtyPageRmap(PFN_TYPE Page
)
366 PMM_RMAP_ENTRY current_entry
;
368 ExAcquireFastMutex(&RmapListLock
);
369 current_entry
= MmGetRmapListHeadPage(Page
);
370 if (current_entry
== NULL
)
372 ExReleaseFastMutex(&RmapListLock
);
375 while (current_entry
!= NULL
)
377 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
379 ExReleaseFastMutex(&RmapListLock
);
382 current_entry
= current_entry
->Next
;
384 ExReleaseFastMutex(&RmapListLock
);
389 MmInsertRmap(PFN_TYPE Page
, PEPROCESS Process
,
392 PMM_RMAP_ENTRY current_entry
;
393 PMM_RMAP_ENTRY new_entry
;
395 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
397 new_entry
= ExAllocateFromNPagedLookasideList(&RmapLookasideList
);
398 if (new_entry
== NULL
)
402 new_entry
->Address
= Address
;
403 new_entry
->Process
= Process
;
405 if (MmGetPfnForProcess(Process
, Address
) != Page
)
407 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
408 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
409 MmGetPfnForProcess(Process
, Address
) << PAGE_SHIFT
,
414 ExAcquireFastMutex(&RmapListLock
);
415 current_entry
= MmGetRmapListHeadPage(Page
);
416 new_entry
->Next
= current_entry
;
417 MmSetRmapListHeadPage(Page
, new_entry
);
418 ExReleaseFastMutex(&RmapListLock
);
422 MmDeleteAllRmaps(PFN_TYPE Page
, PVOID Context
,
423 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
426 PMM_RMAP_ENTRY current_entry
;
427 PMM_RMAP_ENTRY previous_entry
;
429 ExAcquireFastMutex(&RmapListLock
);
430 current_entry
= MmGetRmapListHeadPage(Page
);
431 if (current_entry
== NULL
)
433 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
436 MmSetRmapListHeadPage(Page
, NULL
);
437 while (current_entry
!= NULL
)
439 previous_entry
= current_entry
;
440 current_entry
= current_entry
->Next
;
443 DeleteMapping(Context
, previous_entry
->Process
,
444 previous_entry
->Address
);
446 ExFreeToNPagedLookasideList(&RmapLookasideList
, previous_entry
);
448 ExReleaseFastMutex(&RmapListLock
);
452 MmDeleteRmap(PFN_TYPE Page
, PEPROCESS Process
,
455 PMM_RMAP_ENTRY current_entry
, previous_entry
;
457 ExAcquireFastMutex(&RmapListLock
);
458 previous_entry
= NULL
;
459 current_entry
= MmGetRmapListHeadPage(Page
);
460 while (current_entry
!= NULL
)
462 if (current_entry
->Process
== Process
&&
463 current_entry
->Address
== Address
)
465 if (previous_entry
== NULL
)
467 MmSetRmapListHeadPage(Page
, current_entry
->Next
);
471 previous_entry
->Next
= current_entry
->Next
;
473 ExReleaseFastMutex(&RmapListLock
);
474 ExFreeToNPagedLookasideList(&RmapLookasideList
, current_entry
);
477 previous_entry
= current_entry
;
478 current_entry
= current_entry
->Next
;