eafada883d2c3a5db60732868be3699a9fa4de90
[reactos.git] / reactos / ntoskrnl / mm / mm.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/mm.c
6 * PURPOSE: Kernel memory managment functions
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* GLOBALS *****************************************************************/
17
18 extern MODULE_OBJECT NtoskrnlModuleObject;
19 extern MODULE_OBJECT HalModuleObject;
20
21 ULONG EXPORTED MmUserProbeAddress = 0;
22 PVOID EXPORTED MmHighestUserAddress = NULL;
23 PBOOLEAN EXPORTED Mm64BitPhysicalAddress = FALSE;
24 PVOID EXPORTED MmSystemRangeStart = NULL;
25
26 MM_STATS MmStats;
27
28 /* FUNCTIONS ****************************************************************/
29
30
31 NTSTATUS STDCALL
32 MmCopyToCaller(PVOID Dest, const VOID *Src, ULONG NumberOfBytes)
33 {
34 NTSTATUS Status;
35
36 if (ExGetPreviousMode() == UserMode)
37 {
38 if ((ULONG_PTR)Dest >= KERNEL_BASE)
39 {
40 return(STATUS_ACCESS_VIOLATION);
41 }
42 Status = MmSafeCopyToUser(Dest, Src, NumberOfBytes);
43 return(Status);
44 }
45 else
46 {
47 memcpy(Dest, Src, NumberOfBytes);
48 return(STATUS_SUCCESS);
49 }
50 }
51
52 NTSTATUS STDCALL
53 MmCopyFromCaller(PVOID Dest, const VOID *Src, ULONG NumberOfBytes)
54 {
55 NTSTATUS Status;
56
57 if (ExGetPreviousMode() == UserMode)
58 {
59 if ((ULONG_PTR)Src >= KERNEL_BASE)
60 {
61 return(STATUS_ACCESS_VIOLATION);
62 }
63 Status = MmSafeCopyFromUser(Dest, Src, NumberOfBytes);
64 return(Status);
65 }
66 else
67 {
68 memcpy(Dest, Src, NumberOfBytes);
69 return(STATUS_SUCCESS);
70 }
71 }
72
73
74
75 NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
76 {
77 NTSTATUS Status;
78
79 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
80
81 DPRINT("Releasing %x between %x %x (type %d)\n",
82 Marea, Marea->StartingAddress, Marea->EndingAddress,
83 Marea->Type);
84
85 switch (Marea->Type)
86 {
87 case MEMORY_AREA_SECTION_VIEW:
88 Status = MmUnmapViewOfSection(Process, (PVOID)Marea->StartingAddress);
89 ASSERT(Status == STATUS_SUCCESS);
90 return(STATUS_SUCCESS);
91
92 case MEMORY_AREA_VIRTUAL_MEMORY:
93 case MEMORY_AREA_PEB_OR_TEB:
94 MmFreeVirtualMemory(Process, Marea);
95 break;
96
97 case MEMORY_AREA_SHARED_DATA:
98 case MEMORY_AREA_NO_ACCESS:
99 Status = MmFreeMemoryArea(&Process->AddressSpace,
100 Marea,
101 NULL,
102 NULL);
103 break;
104
105 case MEMORY_AREA_MDL_MAPPING:
106 KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES);
107 break;
108
109 default:
110 KEBUGCHECK(0);
111 }
112
113 return(STATUS_SUCCESS);
114 }
115
116 NTSTATUS MmReleaseMmInfo(PEPROCESS Process)
117 {
118 DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
119 Process->ImageFileName);
120
121 MmLockAddressSpace(&Process->AddressSpace);
122
123 while (Process->AddressSpace.MemoryAreaRoot != NULL)
124 MmReleaseMemoryArea(Process, Process->AddressSpace.MemoryAreaRoot);
125
126 Mmi386ReleaseMmInfo(Process);
127
128 MmUnlockAddressSpace(&Process->AddressSpace);
129 MmDestroyAddressSpace(&Process->AddressSpace);
130
131 DPRINT("Finished MmReleaseMmInfo()\n");
132 return(STATUS_SUCCESS);
133 }
134
135 /*
136 * @implemented
137 */
138 BOOLEAN STDCALL MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
139 {
140 return MmIsAddressValid(VirtualAddress);
141 }
142
143 /*
144 * @implemented
145 */
146 BOOLEAN STDCALL MmIsAddressValid(PVOID VirtualAddress)
147 /*
148 * FUNCTION: Checks whether the given address is valid for a read or write
149 * ARGUMENTS:
150 * VirtualAddress = address to check
151 * RETURNS: True if the access would be valid
152 * False if the access would cause a page fault
153 * NOTES: This function checks whether a byte access to the page would
154 * succeed. Is this realistic for RISC processors which don't
155 * allow byte granular access?
156 */
157 {
158 MEMORY_AREA* MemoryArea;
159 PMADDRESS_SPACE AddressSpace;
160
161 if ((ULONG_PTR)VirtualAddress >= KERNEL_BASE)
162 {
163 AddressSpace = MmGetKernelAddressSpace();
164 }
165 else
166 {
167 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
168 }
169
170 MmLockAddressSpace(AddressSpace);
171 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
172 VirtualAddress);
173
174 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
175 {
176 MmUnlockAddressSpace(AddressSpace);
177 return(FALSE);
178 }
179 MmUnlockAddressSpace(AddressSpace);
180 return(TRUE);
181 }
182
183 NTSTATUS MmAccessFault(KPROCESSOR_MODE Mode,
184 ULONG_PTR Address,
185 BOOLEAN FromMdl)
186 {
187 PMADDRESS_SPACE AddressSpace;
188 MEMORY_AREA* MemoryArea;
189 NTSTATUS Status;
190 BOOLEAN Locked = FromMdl;
191
192 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
193
194 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
195 {
196 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
197 return(STATUS_UNSUCCESSFUL);
198 }
199 if (PsGetCurrentProcess() == NULL)
200 {
201 DbgPrint("No current process\n");
202 return(STATUS_UNSUCCESSFUL);
203 }
204
205 /*
206 * Find the memory area for the faulting address
207 */
208 if (Address >= KERNEL_BASE)
209 {
210 /*
211 * Check permissions
212 */
213 if (Mode != KernelMode)
214 {
215 DbgPrint("%s:%d\n",__FILE__,__LINE__);
216 return(STATUS_UNSUCCESSFUL);
217 }
218 AddressSpace = MmGetKernelAddressSpace();
219 }
220 else
221 {
222 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
223 }
224
225 if (!FromMdl)
226 {
227 MmLockAddressSpace(AddressSpace);
228 }
229 do
230 {
231 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
232 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
233 {
234 if (!FromMdl)
235 {
236 MmUnlockAddressSpace(AddressSpace);
237 }
238 return (STATUS_UNSUCCESSFUL);
239 }
240
241 switch (MemoryArea->Type)
242 {
243 case MEMORY_AREA_SYSTEM:
244 Status = STATUS_UNSUCCESSFUL;
245 break;
246
247 case MEMORY_AREA_PAGED_POOL:
248 Status = STATUS_SUCCESS;
249 break;
250
251 case MEMORY_AREA_SECTION_VIEW:
252 Status = MmAccessFaultSectionView(AddressSpace,
253 MemoryArea,
254 (PVOID)Address,
255 Locked);
256 break;
257
258 case MEMORY_AREA_VIRTUAL_MEMORY:
259 Status = STATUS_UNSUCCESSFUL;
260 break;
261
262 case MEMORY_AREA_SHARED_DATA:
263 Status = STATUS_UNSUCCESSFUL;
264 break;
265
266 default:
267 Status = STATUS_UNSUCCESSFUL;
268 break;
269 }
270 }
271 while (Status == STATUS_MM_RESTART_OPERATION);
272
273 DPRINT("Completed page fault handling\n");
274 if (!FromMdl)
275 {
276 MmUnlockAddressSpace(AddressSpace);
277 }
278 return(Status);
279 }
280
281 NTSTATUS MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
282 {
283 NTSTATUS Status;
284 PFN_TYPE AllocatedPage;
285 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
286 if (!NT_SUCCESS(Status))
287 {
288 MmUnlockAddressSpace(MmGetKernelAddressSpace());
289 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
290 MmLockAddressSpace(MmGetKernelAddressSpace());
291 }
292 Status =
293 MmCreateVirtualMapping(NULL,
294 (PVOID)PAGE_ROUND_DOWN(Address),
295 PAGE_READWRITE,
296 &AllocatedPage,
297 1);
298 if (Locked)
299 {
300 MmLockPage(AllocatedPage);
301 }
302 return(Status);
303 }
304
305 NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode,
306 ULONG_PTR Address,
307 BOOLEAN FromMdl)
308 {
309 PMADDRESS_SPACE AddressSpace;
310 MEMORY_AREA* MemoryArea;
311 NTSTATUS Status;
312 BOOLEAN Locked = FromMdl;
313 PFN_TYPE Pfn;
314
315 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
316
317 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
318 {
319 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
320 return(STATUS_UNSUCCESSFUL);
321 }
322 if (PsGetCurrentProcess() == NULL)
323 {
324 DbgPrint("No current process\n");
325 return(STATUS_UNSUCCESSFUL);
326 }
327
328 /*
329 * Find the memory area for the faulting address
330 */
331 if (Address >= KERNEL_BASE)
332 {
333 /*
334 * Check permissions
335 */
336 if (Mode != KernelMode)
337 {
338 DbgPrint("%s:%d\n",__FILE__,__LINE__);
339 return(STATUS_UNSUCCESSFUL);
340 }
341 AddressSpace = MmGetKernelAddressSpace();
342 }
343 else
344 {
345 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
346 }
347
348 if (!FromMdl)
349 {
350 MmLockAddressSpace(AddressSpace);
351 }
352
353 /*
354 * Call the memory area specific fault handler
355 */
356 do
357 {
358 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
359 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
360 {
361 if (!FromMdl)
362 {
363 MmUnlockAddressSpace(AddressSpace);
364 }
365 return (STATUS_UNSUCCESSFUL);
366 }
367
368 switch (MemoryArea->Type)
369 {
370 case MEMORY_AREA_PAGED_POOL:
371 {
372 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
373 break;
374 }
375
376 case MEMORY_AREA_SYSTEM:
377 Status = STATUS_UNSUCCESSFUL;
378 break;
379
380 case MEMORY_AREA_SECTION_VIEW:
381 Status = MmNotPresentFaultSectionView(AddressSpace,
382 MemoryArea,
383 (PVOID)Address,
384 Locked);
385 break;
386
387 case MEMORY_AREA_VIRTUAL_MEMORY:
388 case MEMORY_AREA_PEB_OR_TEB:
389 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
390 MemoryArea,
391 (PVOID)Address,
392 Locked);
393 break;
394
395 case MEMORY_AREA_SHARED_DATA:
396 Pfn = MmSharedDataPagePhysicalAddress.QuadPart >> PAGE_SHIFT;
397 Status =
398 MmCreateVirtualMapping(PsGetCurrentProcess(),
399 (PVOID)PAGE_ROUND_DOWN(Address),
400 PAGE_READONLY,
401 &Pfn,
402 1);
403 break;
404
405 default:
406 Status = STATUS_UNSUCCESSFUL;
407 break;
408 }
409 }
410 while (Status == STATUS_MM_RESTART_OPERATION);
411
412 DPRINT("Completed page fault handling\n");
413 if (!FromMdl)
414 {
415 MmUnlockAddressSpace(AddressSpace);
416 }
417 return(Status);
418 }
419
420 /* Miscellanea functions: they may fit somewhere else */
421
422 /*
423 * @unimplemented
424 */
425 DWORD STDCALL
426 MmAdjustWorkingSetSize (DWORD Unknown0,
427 DWORD Unknown1,
428 DWORD Unknown2)
429 {
430 UNIMPLEMENTED;
431 return (0);
432 }
433
434
435 DWORD
436 STDCALL
437 MmDbgTranslatePhysicalAddress (
438 DWORD Unknown0,
439 DWORD Unknown1
440 )
441 {
442 UNIMPLEMENTED;
443 return (0);
444 }
445
446
447 /*
448 * @unimplemented
449 */
450 NTSTATUS
451 STDCALL
452 MmGrowKernelStack (
453 DWORD Unknown0
454 )
455 {
456 UNIMPLEMENTED;
457 return (STATUS_NOT_IMPLEMENTED);
458 }
459
460
461 /*
462 * @unimplemented
463 */
464 BOOLEAN
465 STDCALL
466 MmSetAddressRangeModified (
467 IN PVOID Address,
468 IN ULONG Length
469 )
470 {
471 UNIMPLEMENTED;
472 return (FALSE);
473 }
474
475 /*
476 * @implemented
477 */
478 PVOID
479 NTKERNELAPI
480 MmGetSystemRoutineAddress (
481 IN PUNICODE_STRING SystemRoutineName
482 )
483 {
484 PVOID ProcAddress;
485 ANSI_STRING AnsiRoutineName;
486 NTSTATUS Status;
487
488 if(!NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiRoutineName,
489 SystemRoutineName,
490 TRUE)))
491 {
492 return NULL;
493 }
494
495 Status = LdrGetProcedureAddress(NtoskrnlModuleObject.Base,
496 &AnsiRoutineName,
497 0,
498 &ProcAddress);
499
500 if(!NT_SUCCESS(Status))
501 {
502 Status = LdrGetProcedureAddress(HalModuleObject.Base,
503 &AnsiRoutineName,
504 0,
505 &ProcAddress);
506 }
507
508 RtlFreeAnsiString(&AnsiRoutineName);
509
510 return (NT_SUCCESS(Status) ? ProcAddress : NULL);
511 }
512
513 /* EOF */