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