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