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.11 2002/09/07 15:13:00 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 *****************************************************************/
35 #include <internal/debug.h>
38 /* TYPES ********************************************************************/
40 typedef struct _MM_RMAP_ENTRY
42 struct _MM_RMAP_ENTRY
* Next
;
45 } MM_RMAP_ENTRY
, *PMM_RMAP_ENTRY
;
47 /* GLOBALS ******************************************************************/
49 static FAST_MUTEX RmapListLock
;
51 /* FUNCTIONS ****************************************************************/
54 MmInitializeRmapList(VOID
)
56 ExInitializeFastMutex(&RmapListLock
);
60 MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress
)
63 PMEMORY_AREA MemoryArea
;
72 * Check that the address still has a valid rmap; then reference the
73 * process so it isn't freed while we are working.
75 ExAcquireFastMutex(&RmapListLock
);
76 entry
= MmGetRmapListHeadPage(PhysicalAddress
);
79 ExReleaseFastMutex(&RmapListLock
);
80 return(STATUS_UNSUCCESSFUL
);
82 Process
= entry
->Process
;
83 Address
= entry
->Address
;
84 if ((((ULONG
)Address
) & 0xFFF) != 0)
88 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
89 ExReleaseFastMutex(&RmapListLock
);
90 if (!NT_SUCCESS(Status
))
96 * Lock the address space; then check that the address we are using
97 * still corresponds to a valid memory area (the page might have been
98 * freed or paged out after we read the rmap entry.)
100 MmLockAddressSpace(&Process
->AddressSpace
);
101 MemoryArea
= MmOpenMemoryAreaByAddress(&Process
->AddressSpace
, Address
);
102 if (MemoryArea
== NULL
)
104 ObDereferenceObject(Process
);
105 return(STATUS_UNSUCCESSFUL
);
108 Type
= MemoryArea
->Type
;
109 if (Type
== MEMORY_AREA_SECTION_VIEW
)
111 Offset
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
112 MemoryArea
->Data
.SectionData
.ViewOffset
);
115 * Get or create a pageop
117 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
118 MemoryArea
->Data
.SectionData
.Segment
,
119 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
122 DPRINT1("MmGetPageOp failed\n");
127 if (PageOp
->Thread
!= PsGetCurrentThread())
129 MmReleasePageOp(PageOp
);
130 MmUnlockAddressSpace(&Process
->AddressSpace
);
131 ObDereferenceObject(Process
);
132 return(STATUS_UNSUCCESSFUL
);
136 * Release locks now we have a page op.
138 MmUnlockAddressSpace(&Process
->AddressSpace
);
141 * Do the actual page out work.
143 Status
= MmWritePageSectionView(&Process
->AddressSpace
, MemoryArea
,
146 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
148 PageOp
= MmGetPageOp(MemoryArea
, Process
->UniqueProcessId
,
149 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
152 if (PageOp
->Thread
!= PsGetCurrentThread())
154 MmReleasePageOp(PageOp
);
155 MmUnlockAddressSpace(&Process
->AddressSpace
);
156 ObDereferenceObject(Process
);
157 return(STATUS_UNSUCCESSFUL
);
161 * Release locks now we have a page op.
163 MmUnlockAddressSpace(&Process
->AddressSpace
);
166 * Do the actual page out work.
168 Status
= MmWritePageVirtualMemory(&Process
->AddressSpace
, MemoryArea
,
175 ObDereferenceObject(Process
);
180 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress
)
182 PMM_RMAP_ENTRY entry
;
183 PMEMORY_AREA MemoryArea
;
188 LARGE_INTEGER Offset
;
191 ExAcquireFastMutex(&RmapListLock
);
192 entry
= MmGetRmapListHeadPage(PhysicalAddress
);
195 ExReleaseFastMutex(&RmapListLock
);
196 return(STATUS_UNSUCCESSFUL
);
198 Process
= entry
->Process
;
199 Address
= entry
->Address
;
200 if ((((ULONG
)Address
) & 0xFFF) != 0)
205 Status
= ObReferenceObjectByPointer(Process
, PROCESS_ALL_ACCESS
, NULL
, KernelMode
);
206 ExReleaseFastMutex(&RmapListLock
);
207 if (!NT_SUCCESS(Status
))
211 MmLockAddressSpace(&Process
->AddressSpace
);
212 MemoryArea
= MmOpenMemoryAreaByAddress(&Process
->AddressSpace
, Address
);
213 Type
= MemoryArea
->Type
;
214 if (Type
== MEMORY_AREA_SECTION_VIEW
)
216 Offset
.QuadPart
= (ULONG
)((Address
- (ULONG
)MemoryArea
->BaseAddress
) +
217 MemoryArea
->Data
.SectionData
.ViewOffset
);
220 * Get or create a pageop
222 PageOp
= MmGetPageOp(MemoryArea
, 0, 0,
223 MemoryArea
->Data
.SectionData
.Segment
,
224 Offset
.u
.LowPart
, MM_PAGEOP_PAGEOUT
);
227 DPRINT1("MmGetPageOp failed\n");
231 if (PageOp
->Thread
!= PsGetCurrentThread())
233 MmReleasePageOp(PageOp
);
234 MmUnlockAddressSpace(&Process
->AddressSpace
);
235 ObDereferenceObject(Process
);
236 return(STATUS_UNSUCCESSFUL
);
240 * Release locks now we have a page op.
242 MmUnlockAddressSpace(&Process
->AddressSpace
);
245 * Do the actual page out work.
247 Status
= MmPageOutSectionView(&Process
->AddressSpace
, MemoryArea
,
250 else if (Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
252 PageOp
= MmGetPageOp(MemoryArea
, Process
->UniqueProcessId
,
253 Address
, NULL
, 0, MM_PAGEOP_PAGEOUT
);
254 if (PageOp
->Thread
!= PsGetCurrentThread())
256 MmReleasePageOp(PageOp
);
257 MmUnlockAddressSpace(&Process
->AddressSpace
);
258 ObDereferenceObject(Process
);
259 return(STATUS_UNSUCCESSFUL
);
263 * Release locks now we have a page op.
265 MmUnlockAddressSpace(&Process
->AddressSpace
);
268 * Do the actual page out work.
270 Status
= MmPageOutVirtualMemory(&Process
->AddressSpace
, MemoryArea
,
277 ObDereferenceObject(Process
);
282 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
284 PMM_RMAP_ENTRY current_entry
;
286 ExAcquireFastMutex(&RmapListLock
);
287 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
288 if (current_entry
== NULL
)
290 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
293 while (current_entry
!= NULL
)
295 MmSetCleanPage(current_entry
->Process
, current_entry
->Address
);
296 current_entry
= current_entry
->Next
;
298 ExReleaseFastMutex(&RmapListLock
);
302 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
)
304 PMM_RMAP_ENTRY current_entry
;
306 ExAcquireFastMutex(&RmapListLock
);
307 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
308 if (current_entry
== NULL
)
310 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
313 while (current_entry
!= NULL
)
315 MmSetDirtyPage(current_entry
->Process
, current_entry
->Address
);
316 current_entry
= current_entry
->Next
;
318 ExReleaseFastMutex(&RmapListLock
);
322 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress
)
324 PMM_RMAP_ENTRY current_entry
;
326 ExAcquireFastMutex(&RmapListLock
);
327 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
328 if (current_entry
== NULL
)
330 ExReleaseFastMutex(&RmapListLock
);
333 while (current_entry
!= NULL
)
335 if (MmIsDirtyPage(current_entry
->Process
, current_entry
->Address
))
337 ExReleaseFastMutex(&RmapListLock
);
340 current_entry
= current_entry
->Next
;
342 ExReleaseFastMutex(&RmapListLock
);
347 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
350 PMM_RMAP_ENTRY current_entry
;
351 PMM_RMAP_ENTRY new_entry
;
353 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
355 new_entry
= ExAllocatePool(NonPagedPool
, sizeof(MM_RMAP_ENTRY
));
356 if (new_entry
== NULL
)
360 new_entry
->Address
= Address
;
361 new_entry
->Process
= Process
;
363 if (MmGetPhysicalAddressForProcess(Process
, Address
).QuadPart
!=
364 PhysicalAddress
.QuadPart
)
366 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
367 "address 0x%.8X\n", Process
->UniqueProcessId
, Address
,
368 MmGetPhysicalAddressForProcess(Process
, Address
),
373 ExAcquireFastMutex(&RmapListLock
);
374 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
375 new_entry
->Next
= current_entry
;
376 MmSetRmapListHeadPage(PhysicalAddress
, new_entry
);
377 ExReleaseFastMutex(&RmapListLock
);
381 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress
, PVOID Context
,
382 VOID (*DeleteMapping
)(PVOID Context
, PEPROCESS Process
,
385 PMM_RMAP_ENTRY current_entry
;
386 PMM_RMAP_ENTRY previous_entry
;
388 ExAcquireFastMutex(&RmapListLock
);
389 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
390 if (current_entry
== NULL
)
392 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
395 while (current_entry
!= NULL
)
397 previous_entry
= current_entry
;
398 current_entry
= current_entry
->Next
;
401 DeleteMapping(Context
, previous_entry
->Process
,
402 previous_entry
->Address
);
404 ExFreePool(previous_entry
);
406 MmSetRmapListHeadPage(PhysicalAddress
, NULL
);
407 ExReleaseFastMutex(&RmapListLock
);
411 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress
, PEPROCESS Process
,
414 PMM_RMAP_ENTRY current_entry
, previous_entry
;
416 ExAcquireFastMutex(&RmapListLock
);
417 previous_entry
= NULL
;
418 current_entry
= MmGetRmapListHeadPage(PhysicalAddress
);
419 while (current_entry
!= NULL
)
421 if (current_entry
->Process
== Process
&&
422 current_entry
->Address
== Address
)
424 if (previous_entry
== NULL
)
426 MmSetRmapListHeadPage(PhysicalAddress
, current_entry
->Next
);
427 ExReleaseFastMutex(&RmapListLock
);
428 ExFreePool(current_entry
);
432 previous_entry
->Next
= current_entry
->Next
;
433 ExReleaseFastMutex(&RmapListLock
);
434 ExFreePool(current_entry
);
438 previous_entry
= current_entry
;
439 current_entry
= current_entry
->Next
;