- Fix compilation with GCC 4.0-20041219.
[reactos.git] / reactos / ntoskrnl / mm / rmap.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: rmap.c,v 1.32 2004/12/24 17:06:59 navaraf Exp $
20 *
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)
26 * UPDATE HISTORY:
27 * Created 27/12/01
28 */
29
30 /* INCLUDES *****************************************************************/
31
32 #include <ntoskrnl.h>
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* TYPES ********************************************************************/
37
38 typedef struct _MM_RMAP_ENTRY
39 {
40 struct _MM_RMAP_ENTRY* Next;
41 PEPROCESS Process;
42 PVOID Address;
43 }
44 MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
45
46 #define TAG_RMAP TAG('R', 'M', 'A', 'P')
47
48 /* GLOBALS ******************************************************************/
49
50 static FAST_MUTEX RmapListLock;
51 static NPAGED_LOOKASIDE_LIST RmapLookasideList;
52
53 /* FUNCTIONS ****************************************************************/
54
55 VOID INIT_FUNCTION
56 MmInitializeRmapList(VOID)
57 {
58 ExInitializeFastMutex(&RmapListLock);
59 ExInitializeNPagedLookasideList (&RmapLookasideList,
60 NULL,
61 NULL,
62 0,
63 sizeof(MM_RMAP_ENTRY),
64 TAG_RMAP,
65 50);
66 }
67
68 NTSTATUS
69 MmWritePagePhysicalAddress(PFN_TYPE Page)
70 {
71 PMM_RMAP_ENTRY entry;
72 PMEMORY_AREA MemoryArea;
73 PMADDRESS_SPACE AddressSpace;
74 ULONG Type;
75 PVOID Address;
76 PEPROCESS Process;
77 PMM_PAGEOP PageOp;
78 ULONG Offset;
79 NTSTATUS Status = STATUS_SUCCESS;
80
81 /*
82 * Check that the address still has a valid rmap; then reference the
83 * process so it isn't freed while we are working.
84 */
85 ExAcquireFastMutex(&RmapListLock);
86 entry = MmGetRmapListHeadPage(Page);
87 if (entry == NULL)
88 {
89 ExReleaseFastMutex(&RmapListLock);
90 return(STATUS_UNSUCCESSFUL);
91 }
92 Process = entry->Process;
93 Address = entry->Address;
94 if ((((ULONG)Address) & 0xFFF) != 0)
95 {
96 KEBUGCHECK(0);
97 }
98 if (Address < (PVOID)KERNEL_BASE)
99 {
100 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
101 ExReleaseFastMutex(&RmapListLock);
102 if (!NT_SUCCESS(Status))
103 {
104 return Status;
105 }
106 AddressSpace = &Process->AddressSpace;
107 }
108 else
109 {
110 ExReleaseFastMutex(&RmapListLock);
111 AddressSpace = MmGetKernelAddressSpace();
112 }
113
114 /*
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.)
118 */
119 MmLockAddressSpace(AddressSpace);
120 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
121 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
122 {
123 MmUnlockAddressSpace(AddressSpace);
124 if (Address < (PVOID)KERNEL_BASE)
125 {
126 ObDereferenceObject(Process);
127 }
128 return(STATUS_UNSUCCESSFUL);
129 }
130
131 Type = MemoryArea->Type;
132 if (Type == MEMORY_AREA_SECTION_VIEW)
133 {
134 Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
135
136 /*
137 * Get or create a pageop
138 */
139 PageOp = MmGetPageOp(MemoryArea, 0, 0,
140 MemoryArea->Data.SectionData.Segment,
141 Offset, MM_PAGEOP_PAGEOUT, TRUE);
142
143 if (PageOp == NULL)
144 {
145 MmUnlockAddressSpace(AddressSpace);
146 if (Address < (PVOID)KERNEL_BASE)
147 {
148 ObDereferenceObject(Process);
149 }
150 return(STATUS_UNSUCCESSFUL);
151 }
152
153 /*
154 * Release locks now we have a page op.
155 */
156 MmUnlockAddressSpace(AddressSpace);
157
158 /*
159 * Do the actual page out work.
160 */
161 Status = MmWritePageSectionView(AddressSpace, MemoryArea,
162 Address, PageOp);
163 }
164 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
165 {
166 PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
167 Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
168
169 if (PageOp == NULL)
170 {
171 MmUnlockAddressSpace(AddressSpace);
172 if (Address < (PVOID)KERNEL_BASE)
173 {
174 ObDereferenceObject(Process);
175 }
176 return(STATUS_UNSUCCESSFUL);
177 }
178
179 /*
180 * Release locks now we have a page op.
181 */
182 MmUnlockAddressSpace(AddressSpace);
183
184 /*
185 * Do the actual page out work.
186 */
187 Status = MmWritePageVirtualMemory(AddressSpace, MemoryArea,
188 Address, PageOp);
189 }
190 else
191 {
192 KEBUGCHECK(0);
193 }
194 if (Address < (PVOID)KERNEL_BASE)
195 {
196 ObDereferenceObject(Process);
197 }
198 return(Status);
199 }
200
201 NTSTATUS
202 MmPageOutPhysicalAddress(PFN_TYPE Page)
203 {
204 PMM_RMAP_ENTRY entry;
205 PMEMORY_AREA MemoryArea;
206 PMADDRESS_SPACE AddressSpace;
207 ULONG Type;
208 PVOID Address;
209 PEPROCESS Process;
210 PMM_PAGEOP PageOp;
211 ULONG Offset;
212 NTSTATUS Status = STATUS_SUCCESS;
213
214 ExAcquireFastMutex(&RmapListLock);
215 entry = MmGetRmapListHeadPage(Page);
216 if (entry == NULL || MmGetLockCountPage(Page) != 0)
217 {
218 ExReleaseFastMutex(&RmapListLock);
219 return(STATUS_UNSUCCESSFUL);
220 }
221 Process = entry->Process;
222 Address = entry->Address;
223 if ((((ULONG)Address) & 0xFFF) != 0)
224 {
225 KEBUGCHECK(0);
226 }
227
228 if (Address < (PVOID)KERNEL_BASE)
229 {
230 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
231 ExReleaseFastMutex(&RmapListLock);
232 if (!NT_SUCCESS(Status))
233 {
234 return Status;
235 }
236 AddressSpace = &Process->AddressSpace;
237 }
238 else
239 {
240 ExReleaseFastMutex(&RmapListLock);
241 AddressSpace = MmGetKernelAddressSpace();
242 }
243
244 MmLockAddressSpace(AddressSpace);
245 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, Address);
246 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
247 {
248 MmUnlockAddressSpace(AddressSpace);
249 if (Address < (PVOID)KERNEL_BASE)
250 {
251 ObDereferenceObject(Process);
252 }
253 return(STATUS_UNSUCCESSFUL);
254 }
255 Type = MemoryArea->Type;
256 if (Type == MEMORY_AREA_SECTION_VIEW)
257 {
258 Offset = (ULONG)((char*)Address - (ULONG)MemoryArea->BaseAddress);
259
260 /*
261 * Get or create a pageop
262 */
263 PageOp = MmGetPageOp(MemoryArea, 0, 0,
264 MemoryArea->Data.SectionData.Segment,
265 Offset, MM_PAGEOP_PAGEOUT, TRUE);
266 if (PageOp == NULL)
267 {
268 MmUnlockAddressSpace(AddressSpace);
269 if (Address < (PVOID)KERNEL_BASE)
270 {
271 ObDereferenceObject(Process);
272 }
273 return(STATUS_UNSUCCESSFUL);
274 }
275
276 /*
277 * Release locks now we have a page op.
278 */
279 MmUnlockAddressSpace(AddressSpace);
280
281 /*
282 * Do the actual page out work.
283 */
284 Status = MmPageOutSectionView(AddressSpace, MemoryArea,
285 Address, PageOp);
286 }
287 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
288 {
289 PageOp = MmGetPageOp(MemoryArea, Address < (PVOID)KERNEL_BASE ? Process->UniqueProcessId : 0,
290 Address, NULL, 0, MM_PAGEOP_PAGEOUT, TRUE);
291 if (PageOp == NULL)
292 {
293 MmUnlockAddressSpace(AddressSpace);
294 if (Address < (PVOID)KERNEL_BASE)
295 {
296 ObDereferenceObject(Process);
297 }
298 return(STATUS_UNSUCCESSFUL);
299 }
300
301 /*
302 * Release locks now we have a page op.
303 */
304 MmUnlockAddressSpace(AddressSpace);
305
306 /*
307 * Do the actual page out work.
308 */
309 Status = MmPageOutVirtualMemory(AddressSpace, MemoryArea,
310 Address, PageOp);
311 }
312 else
313 {
314 KEBUGCHECK(0);
315 }
316 if (Address < (PVOID)KERNEL_BASE)
317 {
318 ObDereferenceObject(Process);
319 }
320 return(Status);
321 }
322
323 VOID
324 MmSetCleanAllRmaps(PFN_TYPE Page)
325 {
326 PMM_RMAP_ENTRY current_entry;
327
328 ExAcquireFastMutex(&RmapListLock);
329 current_entry = MmGetRmapListHeadPage(Page);
330 if (current_entry == NULL)
331 {
332 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
333 KEBUGCHECK(0);
334 }
335 while (current_entry != NULL)
336 {
337 MmSetCleanPage(current_entry->Process, current_entry->Address);
338 current_entry = current_entry->Next;
339 }
340 ExReleaseFastMutex(&RmapListLock);
341 }
342
343 VOID
344 MmSetDirtyAllRmaps(PFN_TYPE Page)
345 {
346 PMM_RMAP_ENTRY current_entry;
347
348 ExAcquireFastMutex(&RmapListLock);
349 current_entry = MmGetRmapListHeadPage(Page);
350 if (current_entry == NULL)
351 {
352 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
353 KEBUGCHECK(0);
354 }
355 while (current_entry != NULL)
356 {
357 MmSetDirtyPage(current_entry->Process, current_entry->Address);
358 current_entry = current_entry->Next;
359 }
360 ExReleaseFastMutex(&RmapListLock);
361 }
362
363 BOOL
364 MmIsDirtyPageRmap(PFN_TYPE Page)
365 {
366 PMM_RMAP_ENTRY current_entry;
367
368 ExAcquireFastMutex(&RmapListLock);
369 current_entry = MmGetRmapListHeadPage(Page);
370 if (current_entry == NULL)
371 {
372 ExReleaseFastMutex(&RmapListLock);
373 return(FALSE);
374 }
375 while (current_entry != NULL)
376 {
377 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
378 {
379 ExReleaseFastMutex(&RmapListLock);
380 return(TRUE);
381 }
382 current_entry = current_entry->Next;
383 }
384 ExReleaseFastMutex(&RmapListLock);
385 return(FALSE);
386 }
387
388 VOID
389 MmInsertRmap(PFN_TYPE Page, PEPROCESS Process,
390 PVOID Address)
391 {
392 PMM_RMAP_ENTRY current_entry;
393 PMM_RMAP_ENTRY new_entry;
394 ULONG PrevSize;
395
396 Address = (PVOID)PAGE_ROUND_DOWN(Address);
397
398 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
399 if (new_entry == NULL)
400 {
401 KEBUGCHECK(0);
402 }
403 new_entry->Address = Address;
404 new_entry->Process = Process;
405
406 if (MmGetPfnForProcess(Process, Address) != Page)
407 {
408 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
409 "address 0x%.8X\n", Process->UniqueProcessId, Address,
410 MmGetPfnForProcess(Process, Address) << PAGE_SHIFT,
411 Page << PAGE_SHIFT);
412 KEBUGCHECK(0);
413 }
414
415 ExAcquireFastMutex(&RmapListLock);
416 current_entry = MmGetRmapListHeadPage(Page);
417 new_entry->Next = current_entry;
418 MmSetRmapListHeadPage(Page, new_entry);
419 ExReleaseFastMutex(&RmapListLock);
420 if (Process == NULL)
421 {
422 Process = PsInitialSystemProcess;
423 }
424 if (Process)
425 {
426 PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
427 if (PrevSize >= Process->Vm.PeakWorkingSetSize)
428 {
429 Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
430 }
431 }
432 }
433
434 VOID
435 MmDeleteAllRmaps(PFN_TYPE Page, PVOID Context,
436 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
437 PVOID Address))
438 {
439 PMM_RMAP_ENTRY current_entry;
440 PMM_RMAP_ENTRY previous_entry;
441 PEPROCESS Process;
442
443 ExAcquireFastMutex(&RmapListLock);
444 current_entry = MmGetRmapListHeadPage(Page);
445 if (current_entry == NULL)
446 {
447 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
448 KEBUGCHECK(0);
449 }
450 MmSetRmapListHeadPage(Page, NULL);
451 while (current_entry != NULL)
452 {
453 previous_entry = current_entry;
454 current_entry = current_entry->Next;
455 if (DeleteMapping)
456 {
457 DeleteMapping(Context, previous_entry->Process,
458 previous_entry->Address);
459 }
460 Process = previous_entry->Process;
461 ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
462 if (Process == NULL)
463 {
464 Process = PsInitialSystemProcess;
465 }
466 if (Process)
467 {
468 InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
469 }
470 }
471 ExReleaseFastMutex(&RmapListLock);
472 }
473
474 VOID
475 MmDeleteRmap(PFN_TYPE Page, PEPROCESS Process,
476 PVOID Address)
477 {
478 PMM_RMAP_ENTRY current_entry, previous_entry;
479
480 ExAcquireFastMutex(&RmapListLock);
481 previous_entry = NULL;
482 current_entry = MmGetRmapListHeadPage(Page);
483 while (current_entry != NULL)
484 {
485 if (current_entry->Process == Process &&
486 current_entry->Address == Address)
487 {
488 if (previous_entry == NULL)
489 {
490 MmSetRmapListHeadPage(Page, current_entry->Next);
491 }
492 else
493 {
494 previous_entry->Next = current_entry->Next;
495 }
496 ExReleaseFastMutex(&RmapListLock);
497 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
498 if (Process == NULL)
499 {
500 Process = PsInitialSystemProcess;
501 }
502 if (Process)
503 {
504 InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
505 }
506 return;
507 }
508 previous_entry = current_entry;
509 current_entry = current_entry->Next;
510 }
511 KEBUGCHECK(0);
512 }