Use free Windows DDK and compile with latest MinGW releases.
[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.11 2002/09/07 15:13:00 chorns 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
34 #define NDEBUG
35 #include <internal/debug.h>
36
37
38 /* TYPES ********************************************************************/
39
40 typedef struct _MM_RMAP_ENTRY
41 {
42 struct _MM_RMAP_ENTRY* Next;
43 PEPROCESS Process;
44 PVOID Address;
45 } MM_RMAP_ENTRY, *PMM_RMAP_ENTRY;
46
47 /* GLOBALS ******************************************************************/
48
49 static FAST_MUTEX RmapListLock;
50
51 /* FUNCTIONS ****************************************************************/
52
53 VOID
54 MmInitializeRmapList(VOID)
55 {
56 ExInitializeFastMutex(&RmapListLock);
57 }
58
59 NTSTATUS
60 MmWritePagePhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
61 {
62 PMM_RMAP_ENTRY entry;
63 PMEMORY_AREA MemoryArea;
64 ULONG Type;
65 PVOID Address;
66 PEPROCESS Process;
67 PMM_PAGEOP PageOp;
68 LARGE_INTEGER Offset;
69 NTSTATUS Status;
70
71 /*
72 * Check that the address still has a valid rmap; then reference the
73 * process so it isn't freed while we are working.
74 */
75 ExAcquireFastMutex(&RmapListLock);
76 entry = MmGetRmapListHeadPage(PhysicalAddress);
77 if (entry == NULL)
78 {
79 ExReleaseFastMutex(&RmapListLock);
80 return(STATUS_UNSUCCESSFUL);
81 }
82 Process = entry->Process;
83 Address = entry->Address;
84 if ((((ULONG)Address) & 0xFFF) != 0)
85 {
86 KeBugCheck(0);
87 }
88 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
89 ExReleaseFastMutex(&RmapListLock);
90 if (!NT_SUCCESS(Status))
91 {
92 return Status;
93 }
94
95 /*
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.)
99 */
100 MmLockAddressSpace(&Process->AddressSpace);
101 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
102 if (MemoryArea == NULL)
103 {
104 ObDereferenceObject(Process);
105 return(STATUS_UNSUCCESSFUL);
106 }
107
108 Type = MemoryArea->Type;
109 if (Type == MEMORY_AREA_SECTION_VIEW)
110 {
111 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
112 MemoryArea->Data.SectionData.ViewOffset);
113
114 /*
115 * Get or create a pageop
116 */
117 PageOp = MmGetPageOp(MemoryArea, 0, 0,
118 MemoryArea->Data.SectionData.Segment,
119 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
120 if (PageOp == NULL)
121 {
122 DPRINT1("MmGetPageOp failed\n");
123 KeBugCheck(0);
124 }
125
126
127 if (PageOp->Thread != PsGetCurrentThread())
128 {
129 MmReleasePageOp(PageOp);
130 MmUnlockAddressSpace(&Process->AddressSpace);
131 ObDereferenceObject(Process);
132 return(STATUS_UNSUCCESSFUL);
133 }
134
135 /*
136 * Release locks now we have a page op.
137 */
138 MmUnlockAddressSpace(&Process->AddressSpace);
139
140 /*
141 * Do the actual page out work.
142 */
143 Status = MmWritePageSectionView(&Process->AddressSpace, MemoryArea,
144 Address, PageOp);
145 }
146 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
147 {
148 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
149 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
150
151
152 if (PageOp->Thread != PsGetCurrentThread())
153 {
154 MmReleasePageOp(PageOp);
155 MmUnlockAddressSpace(&Process->AddressSpace);
156 ObDereferenceObject(Process);
157 return(STATUS_UNSUCCESSFUL);
158 }
159
160 /*
161 * Release locks now we have a page op.
162 */
163 MmUnlockAddressSpace(&Process->AddressSpace);
164
165 /*
166 * Do the actual page out work.
167 */
168 Status = MmWritePageVirtualMemory(&Process->AddressSpace, MemoryArea,
169 Address, PageOp);
170 }
171 else
172 {
173 KeBugCheck(0);
174 }
175 ObDereferenceObject(Process);
176 return(Status);
177 }
178
179 NTSTATUS
180 MmPageOutPhysicalAddress(PHYSICAL_ADDRESS PhysicalAddress)
181 {
182 PMM_RMAP_ENTRY entry;
183 PMEMORY_AREA MemoryArea;
184 ULONG Type;
185 PVOID Address;
186 PEPROCESS Process;
187 PMM_PAGEOP PageOp;
188 LARGE_INTEGER Offset;
189 NTSTATUS Status;
190
191 ExAcquireFastMutex(&RmapListLock);
192 entry = MmGetRmapListHeadPage(PhysicalAddress);
193 if (entry == NULL)
194 {
195 ExReleaseFastMutex(&RmapListLock);
196 return(STATUS_UNSUCCESSFUL);
197 }
198 Process = entry->Process;
199 Address = entry->Address;
200 if ((((ULONG)Address) & 0xFFF) != 0)
201 {
202 KeBugCheck(0);
203 }
204
205 Status = ObReferenceObjectByPointer(Process, PROCESS_ALL_ACCESS, NULL, KernelMode);
206 ExReleaseFastMutex(&RmapListLock);
207 if (!NT_SUCCESS(Status))
208 {
209 return Status;
210 }
211 MmLockAddressSpace(&Process->AddressSpace);
212 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace, Address);
213 Type = MemoryArea->Type;
214 if (Type == MEMORY_AREA_SECTION_VIEW)
215 {
216 Offset.QuadPart = (ULONG)((Address - (ULONG)MemoryArea->BaseAddress) +
217 MemoryArea->Data.SectionData.ViewOffset);
218
219 /*
220 * Get or create a pageop
221 */
222 PageOp = MmGetPageOp(MemoryArea, 0, 0,
223 MemoryArea->Data.SectionData.Segment,
224 Offset.u.LowPart, MM_PAGEOP_PAGEOUT);
225 if (PageOp == NULL)
226 {
227 DPRINT1("MmGetPageOp failed\n");
228 KeBugCheck(0);
229 }
230
231 if (PageOp->Thread != PsGetCurrentThread())
232 {
233 MmReleasePageOp(PageOp);
234 MmUnlockAddressSpace(&Process->AddressSpace);
235 ObDereferenceObject(Process);
236 return(STATUS_UNSUCCESSFUL);
237 }
238
239 /*
240 * Release locks now we have a page op.
241 */
242 MmUnlockAddressSpace(&Process->AddressSpace);
243
244 /*
245 * Do the actual page out work.
246 */
247 Status = MmPageOutSectionView(&Process->AddressSpace, MemoryArea,
248 Address, PageOp);
249 }
250 else if (Type == MEMORY_AREA_VIRTUAL_MEMORY)
251 {
252 PageOp = MmGetPageOp(MemoryArea, Process->UniqueProcessId,
253 Address, NULL, 0, MM_PAGEOP_PAGEOUT);
254 if (PageOp->Thread != PsGetCurrentThread())
255 {
256 MmReleasePageOp(PageOp);
257 MmUnlockAddressSpace(&Process->AddressSpace);
258 ObDereferenceObject(Process);
259 return(STATUS_UNSUCCESSFUL);
260 }
261
262 /*
263 * Release locks now we have a page op.
264 */
265 MmUnlockAddressSpace(&Process->AddressSpace);
266
267 /*
268 * Do the actual page out work.
269 */
270 Status = MmPageOutVirtualMemory(&Process->AddressSpace, MemoryArea,
271 Address, PageOp);
272 }
273 else
274 {
275 KeBugCheck(0);
276 }
277 ObDereferenceObject(Process);
278 return(Status);
279 }
280
281 VOID
282 MmSetCleanAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
283 {
284 PMM_RMAP_ENTRY current_entry;
285
286 ExAcquireFastMutex(&RmapListLock);
287 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
288 if (current_entry == NULL)
289 {
290 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
291 KeBugCheck(0);
292 }
293 while (current_entry != NULL)
294 {
295 MmSetCleanPage(current_entry->Process, current_entry->Address);
296 current_entry = current_entry->Next;
297 }
298 ExReleaseFastMutex(&RmapListLock);
299 }
300
301 VOID
302 MmSetDirtyAllRmaps(PHYSICAL_ADDRESS PhysicalAddress)
303 {
304 PMM_RMAP_ENTRY current_entry;
305
306 ExAcquireFastMutex(&RmapListLock);
307 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
308 if (current_entry == NULL)
309 {
310 DPRINT1("MmIsDirtyRmap: No rmaps.\n");
311 KeBugCheck(0);
312 }
313 while (current_entry != NULL)
314 {
315 MmSetDirtyPage(current_entry->Process, current_entry->Address);
316 current_entry = current_entry->Next;
317 }
318 ExReleaseFastMutex(&RmapListLock);
319 }
320
321 BOOL
322 MmIsDirtyPageRmap(PHYSICAL_ADDRESS PhysicalAddress)
323 {
324 PMM_RMAP_ENTRY current_entry;
325
326 ExAcquireFastMutex(&RmapListLock);
327 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
328 if (current_entry == NULL)
329 {
330 ExReleaseFastMutex(&RmapListLock);
331 return(FALSE);
332 }
333 while (current_entry != NULL)
334 {
335 if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
336 {
337 ExReleaseFastMutex(&RmapListLock);
338 return(TRUE);
339 }
340 current_entry = current_entry->Next;
341 }
342 ExReleaseFastMutex(&RmapListLock);
343 return(FALSE);
344 }
345
346 VOID
347 MmInsertRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
348 PVOID Address)
349 {
350 PMM_RMAP_ENTRY current_entry;
351 PMM_RMAP_ENTRY new_entry;
352
353 Address = (PVOID)PAGE_ROUND_DOWN(Address);
354
355 new_entry = ExAllocatePool(NonPagedPool, sizeof(MM_RMAP_ENTRY));
356 if (new_entry == NULL)
357 {
358 KeBugCheck(0);
359 }
360 new_entry->Address = Address;
361 new_entry->Process = Process;
362
363 if (MmGetPhysicalAddressForProcess(Process, Address).QuadPart !=
364 PhysicalAddress.QuadPart)
365 {
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),
369 PhysicalAddress)
370 KeBugCheck(0);
371 }
372
373 ExAcquireFastMutex(&RmapListLock);
374 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
375 new_entry->Next = current_entry;
376 MmSetRmapListHeadPage(PhysicalAddress, new_entry);
377 ExReleaseFastMutex(&RmapListLock);
378 }
379
380 VOID
381 MmDeleteAllRmaps(PHYSICAL_ADDRESS PhysicalAddress, PVOID Context,
382 VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
383 PVOID Address))
384 {
385 PMM_RMAP_ENTRY current_entry;
386 PMM_RMAP_ENTRY previous_entry;
387
388 ExAcquireFastMutex(&RmapListLock);
389 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
390 if (current_entry == NULL)
391 {
392 DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
393 KeBugCheck(0);
394 }
395 while (current_entry != NULL)
396 {
397 previous_entry = current_entry;
398 current_entry = current_entry->Next;
399 if (DeleteMapping)
400 {
401 DeleteMapping(Context, previous_entry->Process,
402 previous_entry->Address);
403 }
404 ExFreePool(previous_entry);
405 }
406 MmSetRmapListHeadPage(PhysicalAddress, NULL);
407 ExReleaseFastMutex(&RmapListLock);
408 }
409
410 VOID
411 MmDeleteRmap(PHYSICAL_ADDRESS PhysicalAddress, PEPROCESS Process,
412 PVOID Address)
413 {
414 PMM_RMAP_ENTRY current_entry, previous_entry;
415
416 ExAcquireFastMutex(&RmapListLock);
417 previous_entry = NULL;
418 current_entry = MmGetRmapListHeadPage(PhysicalAddress);
419 while (current_entry != NULL)
420 {
421 if (current_entry->Process == Process &&
422 current_entry->Address == Address)
423 {
424 if (previous_entry == NULL)
425 {
426 MmSetRmapListHeadPage(PhysicalAddress, current_entry->Next);
427 ExReleaseFastMutex(&RmapListLock);
428 ExFreePool(current_entry);
429 }
430 else
431 {
432 previous_entry->Next = current_entry->Next;
433 ExReleaseFastMutex(&RmapListLock);
434 ExFreePool(current_entry);
435 }
436 return;
437 }
438 previous_entry = current_entry;
439 current_entry = current_entry->Next;
440 }
441 KeBugCheck(0);
442 }