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