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.14 2002/11/09 20:27:03 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
;
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 MmUnlockAddressSpace(&Process
->AddressSpace
);
108 ObDereferenceObject(Process
);
109 return(STATUS_UNSUCCESSFUL
);
112 Type
= MemoryArea
->Type
;
113 if (Type
== MEMORY_AREA_SECTION_VIEW
)
115 Offset
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
116 MemoryArea
->Data
.SectionData
.ViewOffset
);
119 * Get or create a pageop
121 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
122 MemoryArea
->Data
.SectionData
.Segment
,
123 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
126 DPRINT1("MmGetPageOp failed\n");
131 if (PageOp
->Thread
!= PsGetCurrentThread())
133 MmReleasePageOp(PageOp
);
134 MmUnlockAddressSpace(&Process
->AddressSpace
);
135 ObDereferenceObject(Process
);
136 return(STATUS_UNSUCCESSFUL
);
140 * Release locks now we have a page op.
142 MmUnlockAddressSpace(&Process
->AddressSpace
);
145 * Do the actual page out work.
147 Status
= MmWritePageSectionView(&Process
->AddressSpace
, MemoryArea
,
150 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
152 PageOp
= MmGetPageOp(MemoryArea
, Process
->UniqueProcessId
,
153 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
156 if (PageOp
->Thread
!= PsGetCurrentThread())
158 MmReleasePageOp(PageOp
);
159 MmUnlockAddressSpace(&Process
->AddressSpace
);
160 ObDereferenceObject(Process
);
161 return(STATUS_UNSUCCESSFUL
);
165 * Release locks now we have a page op.
167 MmUnlockAddressSpace(&Process
->AddressSpace
);
170 * Do the actual page out work.
172 Status
= MmWritePageVirtualMemory(&Process
->AddressSpace
, MemoryArea
,
179 ObDereferenceObject(Process
);
184 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress
)
186 PMM_RMAP_ENTRY entry
;
187 PMEMORY_AREA MemoryArea
;
192 LARGE_INTEGER Offset
;
195 ExAcquireFastMutex(&RmapListLock
);
196 entry
= MmGetRmapListHeadPage(PhysicalAddress
);
199 ExReleaseFastMutex(&RmapListLock
);
200 return(STATUS_UNSUCCESSFUL
);
202 Process
= entry
->Process
;
203 Address
= entry
->Address
;
204 if ((((ULONG
)Address
) & 0xFFF) != 0)
209 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
210 ExReleaseFastMutex(&RmapListLock
);
211 if (!NT_SUCCESS(Status
))
215 MmLockAddressSpace(&Process
->AddressSpace
);
216 MemoryArea
= MmOpenMemoryAreaByAddress(&Process
->AddressSpace
, Address
);
217 Type
= MemoryArea
->Type
;
218 if (Type
== MEMORY_AREA_SECTION_VIEW
)
220 Offset
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
221 MemoryArea
->Data
.SectionData
.ViewOffset
);
224 * Get or create a pageop
226 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
227 MemoryArea
->Data
.SectionData
.Segment
,
228 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
231 DPRINT1("MmGetPageOp failed\n");
235 if (PageOp
->Thread
!= PsGetCurrentThread())
237 MmReleasePageOp(PageOp
);
238 MmUnlockAddressSpace(&Process
->AddressSpace
);
239 ObDereferenceObject(Process
);
240 return(STATUS_UNSUCCESSFUL
);
244 * Release locks now we have a page op.
246 MmUnlockAddressSpace(&Process
->AddressSpace
);
249 * Do the actual page out work.
251 Status
= MmPageOutSectionView(&Process
->AddressSpace
, MemoryArea
,
254 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
256 PageOp
= MmGetPageOp(MemoryArea
, Process
->UniqueProcessId
,
257 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
258 if (PageOp
->Thread
!= PsGetCurrentThread())
260 MmReleasePageOp(PageOp
);
261 MmUnlockAddressSpace(&Process
->AddressSpace
);
262 ObDereferenceObject(Process
);
263 return(STATUS_UNSUCCESSFUL
);
267 * Release locks now we have a page op.
269 MmUnlockAddressSpace(&Process
->AddressSpace
);
272 * Do the actual page out work.
274 Status
= MmPageOutVirtualMemory(&Process
->AddressSpace
, MemoryArea
,
281 ObDereferenceObject(Process
);
286 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
288 PMM_RMAP_ENTRY current_entry
;
290 ExAcquireFastMutex(&RmapListLock
);
291 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
292 if (current_entry
== NULL
)
294 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
297 while (current_entry
!= NULL
)
299 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
300 current_entry
= current_entry
->Next
;
302 ExReleaseFastMutex(&RmapListLock
);
306 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
308 PMM_RMAP_ENTRY current_entry
;
310 ExAcquireFastMutex(&RmapListLock
);
311 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
312 if (current_entry
== NULL
)
314 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
317 while (current_entry
!= NULL
)
319 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
320 current_entry
= current_entry
->Next
;
322 ExReleaseFastMutex(&RmapListLock
);
326 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress
)
328 PMM_RMAP_ENTRY current_entry
;
330 ExAcquireFastMutex(&RmapListLock
);
331 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
332 if (current_entry
== NULL
)
334 ExReleaseFastMutex(&RmapListLock
);
337 while (current_entry
!= NULL
)
339 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
341 ExReleaseFastMutex(&RmapListLock
);
344 current_entry
= current_entry
->Next
;
346 ExReleaseFastMutex(&RmapListLock
);
351 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
354 PMM_RMAP_ENTRY current_entry
;
355 PMM_RMAP_ENTRY new_entry
;
357 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
359 new_entry
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_RMAP_ENTRY
), TAG_RMAP
);
360 if (new_entry
== NULL
)
364 new_entry
->Address
= Address
;
365 new_entry
->Process
= Process
;
367 if (MmGetPhysicalAddressForProcess(Process
, Address
).QuadPart
!=
368 PhysicalAddress
.QuadPart
)
370 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
371 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
372 MmGetPhysicalAddressForProcess(Process
, Address
),
377 ExAcquireFastMutex(&RmapListLock
);
378 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
379 new_entry
->Next
= current_entry
;
380 MmSetRmapListHeadPage(PhysicalAddress
, new_entry
);
381 ExReleaseFastMutex(&RmapListLock
);
385 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
, PVOID Context
,
386 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
389 PMM_RMAP_ENTRY current_entry
;
390 PMM_RMAP_ENTRY previous_entry
;
392 ExAcquireFastMutex(&RmapListLock
);
393 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
394 if (current_entry
== NULL
)
396 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
399 while (current_entry
!= NULL
)
401 previous_entry
= current_entry
;
402 current_entry
= current_entry
->Next
;
405 DeleteMapping(Context
, previous_entry
->Process
,
406 previous_entry
->Address
);
408 ExFreePool(previous_entry
);
410 MmSetRmapListHeadPage(PhysicalAddress
, NULL
);
411 ExReleaseFastMutex(&RmapListLock
);
415 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
418 PMM_RMAP_ENTRY current_entry
, previous_entry
;
420 ExAcquireFastMutex(&RmapListLock
);
421 previous_entry
= NULL
;
422 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
423 while (current_entry
!= NULL
)
425 if (current_entry
->Process
== Process
&&
426 current_entry
->Address
== Address
)
428 if (previous_entry
== NULL
)
430 MmSetRmapListHeadPage(PhysicalAddress
, current_entry
->Next
);
431 ExReleaseFastMutex(&RmapListLock
);
432 ExFreePool(current_entry
);
436 previous_entry
->Next
= current_entry
->Next
;
437 ExReleaseFastMutex(&RmapListLock
);
438 ExFreePool(current_entry
);
442 previous_entry
= current_entry
;
443 current_entry
= current_entry
->Next
;