Use free Windows DDK and compile with latest MinGW releases.
[reactos.git] / reactos / ntoskrnl / mm / mm.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: mm.c,v 1.59 2002/09/07 15:12:59 chorns Exp $
20 *
21 * COPYRIGHT: See COPYING in the top directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/mm/mm.c
24 * PURPOSE: kernel memory managment functions
25 * PROGRAMMER: David Welch (welch@cwcom.net)
26 * UPDATE HISTORY:
27 * Created 9/4/98
28 */
29
30 /* INCLUDES *****************************************************************/
31
32 #include <ntoskrnl.h>
33
34 #define NDEBUG
35 #include <internal/debug.h>
36
37
38 /* GLOBALS *****************************************************************/
39
40 MM_STATS MmStats;
41
42 /* FUNCTIONS ****************************************************************/
43
44 NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
45 {
46 NTSTATUS Status;
47
48 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
49
50 DPRINT("Releasing %x between %x %x (type %d)\n",
51 Marea, Marea->BaseAddress, Marea->BaseAddress + Marea->Length,
52 Marea->Type);
53
54 switch (Marea->Type)
55 {
56 case MEMORY_AREA_SECTION_VIEW:
57 Status = MmUnmapViewOfSection(Process, Marea->BaseAddress);
58 assert(Status == STATUS_SUCCESS);
59 return(STATUS_SUCCESS);
60
61 case MEMORY_AREA_VIRTUAL_MEMORY:
62 MmFreeVirtualMemory(Process, Marea);
63 break;
64
65 case MEMORY_AREA_SHARED_DATA:
66 Status = MmFreeMemoryArea(&Process->AddressSpace,
67 Marea->BaseAddress,
68 0,
69 NULL,
70 NULL);
71 break;
72
73 default:
74 KeBugCheck(0);
75 }
76
77 return(STATUS_SUCCESS);
78 }
79
80 NTSTATUS MmReleaseMmInfo(PEPROCESS Process)
81 {
82 PLIST_ENTRY CurrentEntry;
83 PMEMORY_AREA Current;
84
85 DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
86 Process->ImageFileName);
87
88 MmLockAddressSpace(&Process->AddressSpace);
89
90 CurrentEntry = Process->AddressSpace.MAreaListHead.Flink;
91 while (CurrentEntry != &Process->AddressSpace.MAreaListHead)
92 {
93 Current = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Entry);
94 CurrentEntry = CurrentEntry->Flink;
95
96 MmReleaseMemoryArea(Process, Current);
97 }
98
99 Mmi386ReleaseMmInfo(Process);
100
101 MmUnlockAddressSpace(&Process->AddressSpace);
102 MmDestroyAddressSpace(&Process->AddressSpace);
103
104 DPRINT("Finished MmReleaseMmInfo()\n");
105 return(STATUS_SUCCESS);
106 }
107
108 BOOLEAN STDCALL MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
109 {
110 UNIMPLEMENTED;
111 }
112
113 BOOLEAN STDCALL MmIsAddressValid(PVOID VirtualAddress)
114 /*
115 * FUNCTION: Checks whether the given address is valid for a read or write
116 * ARGUMENTS:
117 * VirtualAddress = address to check
118 * RETURNS: True if the access would be valid
119 * False if the access would cause a page fault
120 * NOTES: This function checks whether a byte access to the page would
121 * succeed. Is this realistic for RISC processors which don't
122 * allow byte granular access?
123 */
124 {
125 MEMORY_AREA* MemoryArea;
126 PMADDRESS_SPACE AddressSpace;
127
128 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
129
130 MmLockAddressSpace(AddressSpace);
131 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
132 VirtualAddress);
133
134 if (MemoryArea == NULL)
135 {
136 MmUnlockAddressSpace(AddressSpace);
137 return(FALSE);
138 }
139 MmUnlockAddressSpace(AddressSpace);
140 return(TRUE);
141 }
142
143 NTSTATUS MmAccessFault(KPROCESSOR_MODE Mode,
144 ULONG Address,
145 BOOLEAN FromMdl)
146 {
147 PMADDRESS_SPACE AddressSpace;
148 MEMORY_AREA* MemoryArea;
149 NTSTATUS Status;
150 BOOLEAN Locked = FromMdl;
151
152 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
153
154 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
155 {
156 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
157 KeDumpStackFrames((PULONG)__builtin_frame_address(0));
158 return(STATUS_UNSUCCESSFUL);
159 }
160 if (PsGetCurrentProcess() == NULL)
161 {
162 DbgPrint("No current process\n");
163 return(STATUS_UNSUCCESSFUL);
164 }
165
166 /*
167 * Find the memory area for the faulting address
168 */
169 if (Address >= KERNEL_BASE)
170 {
171 /*
172 * Check permissions
173 */
174 if (Mode != KernelMode)
175 {
176 DbgPrint("%s:%d\n",__FILE__,__LINE__);
177 return(STATUS_UNSUCCESSFUL);
178 }
179 AddressSpace = MmGetKernelAddressSpace();
180 }
181 else
182 {
183 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
184 }
185
186 if (!FromMdl)
187 {
188 MmLockAddressSpace(AddressSpace);
189 }
190 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, (PVOID)Address);
191 if (MemoryArea == NULL)
192 {
193 DbgPrint("%s:%d\n",__FILE__,__LINE__);
194 if (!FromMdl)
195 {
196 MmUnlockAddressSpace(AddressSpace);
197 }
198 return(STATUS_UNSUCCESSFUL);
199 }
200
201 switch (MemoryArea->Type)
202 {
203 case MEMORY_AREA_SYSTEM:
204 Status = STATUS_UNSUCCESSFUL;
205 break;
206
207 case MEMORY_AREA_PAGED_POOL:
208 Status = STATUS_SUCCESS;
209 break;
210
211 case MEMORY_AREA_SECTION_VIEW:
212 Status = MmAccessFaultSectionView(AddressSpace,
213 MemoryArea,
214 (PVOID)Address,
215 Locked);
216 break;
217
218 case MEMORY_AREA_VIRTUAL_MEMORY:
219 Status = STATUS_UNSUCCESSFUL;
220 break;
221
222 case MEMORY_AREA_SHARED_DATA:
223 Status = STATUS_UNSUCCESSFUL;
224 break;
225
226 default:
227 Status = STATUS_UNSUCCESSFUL;
228 break;
229 }
230 DPRINT("Completed page fault handling\n");
231 if (!FromMdl)
232 {
233 MmUnlockAddressSpace(AddressSpace);
234 }
235 return(Status);
236 }
237
238 NTSTATUS MmCommitPagedPoolAddress(PVOID Address)
239 {
240 NTSTATUS Status;
241 PHYSICAL_ADDRESS AllocatedPage;
242 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
243 if (!NT_SUCCESS(Status))
244 {
245 MmUnlockAddressSpace(MmGetKernelAddressSpace());
246 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
247 MmLockAddressSpace(MmGetKernelAddressSpace());
248 }
249 Status =
250 MmCreateVirtualMapping(NULL,
251 (PVOID)PAGE_ROUND_DOWN(Address),
252 PAGE_READWRITE,
253 AllocatedPage,
254 FALSE);
255 if (!NT_SUCCESS(Status))
256 {
257 MmUnlockAddressSpace(MmGetKernelAddressSpace());
258 Status =
259 MmCreateVirtualMapping(NULL,
260 (PVOID)PAGE_ROUND_DOWN(Address),
261 PAGE_READWRITE,
262 AllocatedPage,
263 FALSE);
264 MmLockAddressSpace(MmGetKernelAddressSpace());
265 }
266 return(Status);
267 }
268
269 NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode,
270 ULONG Address,
271 BOOLEAN FromMdl)
272 {
273 PMADDRESS_SPACE AddressSpace;
274 MEMORY_AREA* MemoryArea;
275 NTSTATUS Status;
276 BOOLEAN Locked = FromMdl;
277
278 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
279
280 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
281 {
282 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
283 return(STATUS_UNSUCCESSFUL);
284 }
285 if (PsGetCurrentProcess() == NULL)
286 {
287 DbgPrint("No current process\n");
288 return(STATUS_UNSUCCESSFUL);
289 }
290
291 /*
292 * Find the memory area for the faulting address
293 */
294 if (Address >= KERNEL_BASE)
295 {
296 /*
297 * Check permissions
298 */
299 if (Mode != KernelMode)
300 {
301 DbgPrint("%s:%d\n",__FILE__,__LINE__);
302 return(STATUS_UNSUCCESSFUL);
303 }
304 AddressSpace = MmGetKernelAddressSpace();
305 }
306 else
307 {
308 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
309 }
310
311 if (!FromMdl)
312 {
313 MmLockAddressSpace(AddressSpace);
314 }
315
316 /*
317 * Call the memory area specific fault handler
318 */
319 do
320 {
321 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, (PVOID)Address);
322 if (MemoryArea == NULL)
323 {
324 if (!FromMdl)
325 {
326 MmUnlockAddressSpace(AddressSpace);
327 }
328 return (STATUS_UNSUCCESSFUL);
329 }
330
331 switch (MemoryArea->Type)
332 {
333 case MEMORY_AREA_PAGED_POOL:
334 {
335 Status = MmCommitPagedPoolAddress((PVOID)Address);
336 break;
337 }
338
339 case MEMORY_AREA_SYSTEM:
340 Status = STATUS_UNSUCCESSFUL;
341 break;
342
343 case MEMORY_AREA_SECTION_VIEW:
344 Status = MmNotPresentFaultSectionView(AddressSpace,
345 MemoryArea,
346 (PVOID)Address,
347 Locked);
348 break;
349
350 case MEMORY_AREA_VIRTUAL_MEMORY:
351 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
352 MemoryArea,
353 (PVOID)Address,
354 Locked);
355 break;
356
357 case MEMORY_AREA_SHARED_DATA:
358 Status =
359 MmCreateVirtualMapping(PsGetCurrentProcess(),
360 (PVOID)PAGE_ROUND_DOWN(Address),
361 PAGE_READONLY,
362 MmSharedDataPagePhysicalAddress,
363 FALSE);
364 if (!NT_SUCCESS(Status))
365 {
366 MmUnlockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
367 Status =
368 MmCreateVirtualMapping(PsGetCurrentProcess(),
369 (PVOID)PAGE_ROUND_DOWN(Address),
370 PAGE_READONLY,
371 MmSharedDataPagePhysicalAddress,
372 TRUE);
373 MmLockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
374 }
375 break;
376
377 default:
378 Status = STATUS_UNSUCCESSFUL;
379 break;
380 }
381 }
382 while (Status == STATUS_MM_RESTART_OPERATION);
383
384 DPRINT("Completed page fault handling\n");
385 if (!FromMdl)
386 {
387 MmUnlockAddressSpace(AddressSpace);
388 }
389 return(Status);
390 }
391
392 /* Miscellanea functions: they may fit somewhere else */
393
394 DWORD STDCALL
395 MmAdjustWorkingSetSize (DWORD Unknown0,
396 DWORD Unknown1,
397 DWORD Unknown2)
398 {
399 UNIMPLEMENTED;
400 return (0);
401 }
402
403
404 DWORD
405 STDCALL
406 MmDbgTranslatePhysicalAddress (
407 DWORD Unknown0,
408 DWORD Unknown1
409 )
410 {
411 UNIMPLEMENTED;
412 return (0);
413 }
414
415
416 NTSTATUS
417 STDCALL
418 MmGrowKernelStack (
419 DWORD Unknown0
420 )
421 {
422 UNIMPLEMENTED;
423 return (STATUS_NOT_IMPLEMENTED);
424 }
425
426
427 BOOLEAN
428 STDCALL
429 MmSetAddressRangeModified (
430 IN PVOID Address,
431 IN ULONG Length
432 )
433 {
434 UNIMPLEMENTED;
435 return (FALSE);
436 }
437
438 /* EOF */