- Replace MODULE_OBJECT with LDR_DATA_TABLE_ENTRY.
[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 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 MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
32 {
33 NTSTATUS Status;
34
35 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
36
37 DPRINT("Releasing %x between %x %x (type %d)\n",
38 Marea, Marea->StartingAddress, Marea->EndingAddress,
39 Marea->Type);
40
41 switch (Marea->Type)
42 {
43 case MEMORY_AREA_SECTION_VIEW:
44 Status = MmUnmapViewOfSection(Process, (PVOID)Marea->StartingAddress);
45 ASSERT(Status == STATUS_SUCCESS);
46 return(STATUS_SUCCESS);
47
48 case MEMORY_AREA_VIRTUAL_MEMORY:
49 case MEMORY_AREA_PEB_OR_TEB:
50 MmFreeVirtualMemory(Process, Marea);
51 break;
52
53 case MEMORY_AREA_SHARED_DATA:
54 case MEMORY_AREA_NO_ACCESS:
55 Status = MmFreeMemoryArea(&Process->AddressSpace,
56 Marea,
57 NULL,
58 NULL);
59 break;
60
61 case MEMORY_AREA_MDL_MAPPING:
62 KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES);
63 break;
64
65 default:
66 KEBUGCHECK(0);
67 }
68
69 return(STATUS_SUCCESS);
70 }
71
72 NTSTATUS MmReleaseMmInfo(PEPROCESS Process)
73 {
74 DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
75 Process->ImageFileName);
76
77 MmLockAddressSpace(&Process->AddressSpace);
78
79 while (Process->AddressSpace.MemoryAreaRoot != NULL)
80 MmReleaseMemoryArea(Process, Process->AddressSpace.MemoryAreaRoot);
81
82 Mmi386ReleaseMmInfo(Process);
83
84 MmUnlockAddressSpace(&Process->AddressSpace);
85 MmDestroyAddressSpace(&Process->AddressSpace);
86
87 DPRINT("Finished MmReleaseMmInfo()\n");
88 return(STATUS_SUCCESS);
89 }
90
91 /*
92 * @implemented
93 */
94 BOOLEAN STDCALL MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
95 {
96 return MmIsAddressValid(VirtualAddress);
97 }
98
99 /*
100 * @implemented
101 */
102 BOOLEAN STDCALL MmIsAddressValid(PVOID VirtualAddress)
103 /*
104 * FUNCTION: Checks whether the given address is valid for a read or write
105 * ARGUMENTS:
106 * VirtualAddress = address to check
107 * RETURNS: True if the access would be valid
108 * False if the access would cause a page fault
109 * NOTES: This function checks whether a byte access to the page would
110 * succeed. Is this realistic for RISC processors which don't
111 * allow byte granular access?
112 */
113 {
114 MEMORY_AREA* MemoryArea;
115 PMADDRESS_SPACE AddressSpace;
116
117 if (VirtualAddress >= MmSystemRangeStart)
118 {
119 AddressSpace = MmGetKernelAddressSpace();
120 }
121 else
122 {
123 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
124 }
125
126 MmLockAddressSpace(AddressSpace);
127 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
128 VirtualAddress);
129
130 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
131 {
132 MmUnlockAddressSpace(AddressSpace);
133 return(FALSE);
134 }
135 MmUnlockAddressSpace(AddressSpace);
136 return(TRUE);
137 }
138
139 NTSTATUS MmAccessFault(KPROCESSOR_MODE Mode,
140 ULONG_PTR Address,
141 BOOLEAN FromMdl)
142 {
143 PMADDRESS_SPACE AddressSpace;
144 MEMORY_AREA* MemoryArea;
145 NTSTATUS Status;
146 BOOLEAN Locked = FromMdl;
147
148 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
149
150 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
151 {
152 CPRINT("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
153 return(STATUS_UNSUCCESSFUL);
154 }
155 if (PsGetCurrentProcess() == NULL)
156 {
157 CPRINT("No current process\n");
158 return(STATUS_UNSUCCESSFUL);
159 }
160
161 /*
162 * Find the memory area for the faulting address
163 */
164 if (Address >= (ULONG_PTR)MmSystemRangeStart)
165 {
166 /*
167 * Check permissions
168 */
169 if (Mode != KernelMode)
170 {
171 DbgPrint("%s:%d\n",__FILE__,__LINE__);
172 return(STATUS_UNSUCCESSFUL);
173 }
174 AddressSpace = MmGetKernelAddressSpace();
175 }
176 else
177 {
178 AddressSpace = &PsGetCurrentProcess()->AddressSpace;
179 }
180
181 if (!FromMdl)
182 {
183 MmLockAddressSpace(AddressSpace);
184 }
185 do
186 {
187 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
188 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
189 {
190 if (!FromMdl)
191 {
192 MmUnlockAddressSpace(AddressSpace);
193 }
194 return (STATUS_UNSUCCESSFUL);
195 }
196
197 switch (MemoryArea->Type)
198 {
199 case MEMORY_AREA_SYSTEM:
200 Status = STATUS_UNSUCCESSFUL;
201 break;
202
203 case MEMORY_AREA_PAGED_POOL:
204 Status = STATUS_SUCCESS;
205 break;
206
207 case MEMORY_AREA_SECTION_VIEW:
208 Status = MmAccessFaultSectionView(AddressSpace,
209 MemoryArea,
210 (PVOID)Address,
211 Locked);
212 break;
213
214 case MEMORY_AREA_VIRTUAL_MEMORY:
215 Status = STATUS_UNSUCCESSFUL;
216 break;
217
218 case MEMORY_AREA_SHARED_DATA:
219 Status = STATUS_UNSUCCESSFUL;
220 break;
221
222 default:
223 Status = STATUS_UNSUCCESSFUL;
224 break;
225 }
226 }
227 while (Status == STATUS_MM_RESTART_OPERATION);
228
229 DPRINT("Completed page fault handling\n");
230 if (!FromMdl)
231 {
232 MmUnlockAddressSpace(AddressSpace);
233 }
234 return(Status);
235 }
236
237 NTSTATUS MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
238 {
239 NTSTATUS Status;
240 PFN_TYPE AllocatedPage;
241 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
242 if (!NT_SUCCESS(Status))
243 {
244 MmUnlockAddressSpace(MmGetKernelAddressSpace());
245 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
246 MmLockAddressSpace(MmGetKernelAddressSpace());
247 }
248 Status =
249 MmCreateVirtualMapping(NULL,
250 (PVOID)PAGE_ROUND_DOWN(Address),
251 PAGE_READWRITE,
252 &AllocatedPage,
253 1);
254 if (Locked)
255 {
256 MmLockPage(AllocatedPage);
257 }
258 return(Status);
259 }
260
261 NTSTATUS 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 */