Use W32API for NTOSKRNL.
[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 CPRINT("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
197 return(STATUS_UNSUCCESSFUL);
198 }
199 if (PsGetCurrentProcess() == NULL)
200 {
201 CPRINT("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 CPRINT("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
320 return(STATUS_UNSUCCESSFUL);
321 }
322 if (PsGetCurrentProcess() == NULL)
323 {
324 /* Allow this! It lets us page alloc much earlier! It won't be needed
325 * after my init patch anyways
326 */
327 CPRINT("No current process\n");
328 if (Address < KERNEL_BASE)
329 {
330 return(STATUS_UNSUCCESSFUL);
331 }
332 }
333
334 /*
335 * Find the memory area for the faulting address
336 */
337 if (Address >= KERNEL_BASE)
338 {
339 /*
340 * Check permissions
341 */
342 if (Mode != KernelMode)
343 {
344 CPRINT("Address: %x\n", Address);
345 return(STATUS_UNSUCCESSFUL);
346 }
347 AddressSpace = MmGetKernelAddressSpace();
348 }
349 else
350 {
351 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
352 }
353
354 if (!FromMdl)
355 {
356 MmLockAddressSpace(AddressSpace);
357 }
358
359 /*
360 * Call the memory area specific fault handler
361 */
362 do
363 {
364 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
365 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
366 {
367 if (!FromMdl)
368 {
369 MmUnlockAddressSpace(AddressSpace);
370 }
371 return (STATUS_UNSUCCESSFUL);
372 }
373
374 switch (MemoryArea->Type)
375 {
376 case MEMORY_AREA_PAGED_POOL:
377 {
378 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
379 break;
380 }
381
382 case MEMORY_AREA_SYSTEM:
383 Status = STATUS_UNSUCCESSFUL;
384 break;
385
386 case MEMORY_AREA_SECTION_VIEW:
387 Status = MmNotPresentFaultSectionView(AddressSpace,
388 MemoryArea,
389 (PVOID)Address,
390 Locked);
391 break;
392
393 case MEMORY_AREA_VIRTUAL_MEMORY:
394 case MEMORY_AREA_PEB_OR_TEB:
395 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
396 MemoryArea,
397 (PVOID)Address,
398 Locked);
399 break;
400
401 case MEMORY_AREA_SHARED_DATA:
402 Pfn = MmSharedDataPagePhysicalAddress.QuadPart >> PAGE_SHIFT;
403 Status =
404 MmCreateVirtualMapping(PsGetCurrentProcess(),
405 (PVOID)PAGE_ROUND_DOWN(Address),
406 PAGE_READONLY,
407 &Pfn,
408 1);
409 break;
410
411 default:
412 Status = STATUS_UNSUCCESSFUL;
413 break;
414 }
415 }
416 while (Status == STATUS_MM_RESTART_OPERATION);
417
418 DPRINT("Completed page fault handling\n");
419 if (!FromMdl)
420 {
421 MmUnlockAddressSpace(AddressSpace);
422 }
423 return(Status);
424 }
425
426 /* Miscellanea functions: they may fit somewhere else */
427
428 /*
429 * @unimplemented
430 */
431 DWORD STDCALL
432 MmAdjustWorkingSetSize (DWORD Unknown0,
433 DWORD Unknown1,
434 DWORD Unknown2)
435 {
436 UNIMPLEMENTED;
437 return (0);
438 }
439
440
441 DWORD
442 STDCALL
443 MmDbgTranslatePhysicalAddress (
444 DWORD Unknown0,
445 DWORD Unknown1
446 )
447 {
448 UNIMPLEMENTED;
449 return (0);
450 }
451
452
453 /*
454 * @unimplemented
455 */
456 NTSTATUS
457 STDCALL
458 MmGrowKernelStack (
459 DWORD Unknown0
460 )
461 {
462 UNIMPLEMENTED;
463 return (STATUS_NOT_IMPLEMENTED);
464 }
465
466
467 /*
468 * @unimplemented
469 */
470 BOOLEAN
471 STDCALL
472 MmSetAddressRangeModified (
473 IN PVOID Address,
474 IN ULONG Length
475 )
476 {
477 UNIMPLEMENTED;
478 return (FALSE);
479 }
480
481 /*
482 * @implemented
483 */
484 PVOID
485 STDCALL
486 MmGetSystemRoutineAddress (
487 IN PUNICODE_STRING SystemRoutineName
488 )
489 {
490 PVOID ProcAddress;
491 ANSI_STRING AnsiRoutineName;
492 NTSTATUS Status;
493
494 if(!NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiRoutineName,
495 SystemRoutineName,
496 TRUE)))
497 {
498 return NULL;
499 }
500
501 Status = LdrGetProcedureAddress(NtoskrnlModuleObject.Base,
502 &AnsiRoutineName,
503 0,
504 &ProcAddress);
505
506 if(!NT_SUCCESS(Status))
507 {
508 Status = LdrGetProcedureAddress(HalModuleObject.Base,
509 &AnsiRoutineName,
510 0,
511 &ProcAddress);
512 }
513
514 RtlFreeAnsiString(&AnsiRoutineName);
515
516 return (NT_SUCCESS(Status) ? ProcAddress : NULL);
517 }
518
519 /* EOF */