Sync to trunk head(r38096)
[reactos.git] / reactos / ntoskrnl / mm / mm.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/mm.c
5 * PURPOSE: Kernel memory managment functions
6 * PROGRAMMERS: David Welch (welch@cwcom.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *****************************************************************/
16
17 ULONG_PTR MmUserProbeAddress = 0;
18 PVOID MmHighestUserAddress = NULL;
19 PBOOLEAN Mm64BitPhysicalAddress = FALSE;
20 PVOID MmSystemRangeStart = NULL;
21 ULONG MmReadClusterSize;
22
23 MM_STATS MmStats;
24
25 PMM_AVL_TABLE MmKernelAddressSpace;
26
27 /* FUNCTIONS ****************************************************************/
28
29 VOID
30 FASTCALL
31 MiSyncForProcessAttach(IN PKTHREAD Thread,
32 IN PEPROCESS Process)
33 {
34 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
35
36 /* Hack Sync because Mm is broken */
37 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
38 MmUpdatePageDir(Process,
39 (PVOID)Thread->StackLimit,
40 Thread->LargeStack ?
41 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
42 }
43
44 VOID
45 FASTCALL
46 MiSyncForContextSwitch(IN PKTHREAD Thread)
47 {
48 PVOID Process = PsGetCurrentProcess();
49 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
50
51 /* Hack Sync because Mm is broken */
52 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
53 MmUpdatePageDir(Process,
54 (PVOID)Thread->StackLimit,
55 Thread->LargeStack ?
56 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
57 }
58
59 /*
60 * @implemented
61 */
62 BOOLEAN NTAPI MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
63 {
64 return MmIsAddressValid(VirtualAddress);
65 }
66
67 /*
68 * @implemented
69 */
70 BOOLEAN NTAPI MmIsAddressValid(PVOID VirtualAddress)
71 /*
72 * FUNCTION: Checks whether the given address is valid for a read or write
73 * ARGUMENTS:
74 * VirtualAddress = address to check
75 * RETURNS: True if the access would be valid
76 * False if the access would cause a page fault
77 * NOTES: This function checks whether a byte access to the page would
78 * succeed. Is this realistic for RISC processors which don't
79 * allow byte granular access?
80 */
81 {
82 MEMORY_AREA* MemoryArea;
83 PMM_AVL_TABLE AddressSpace;
84
85 if (VirtualAddress >= MmSystemRangeStart)
86 {
87 AddressSpace = MmGetKernelAddressSpace();
88 }
89 else
90 {
91 AddressSpace = &PsGetCurrentProcess()->VadRoot;
92 }
93
94 MmLockAddressSpace(AddressSpace);
95 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
96 VirtualAddress);
97
98 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
99 {
100 MmUnlockAddressSpace(AddressSpace);
101 return(FALSE);
102 }
103 MmUnlockAddressSpace(AddressSpace);
104 return(TRUE);
105 }
106
107 NTSTATUS
108 NTAPI
109 MmpAccessFault(KPROCESSOR_MODE Mode,
110 ULONG_PTR Address,
111 BOOLEAN FromMdl)
112 {
113 PMM_AVL_TABLE AddressSpace;
114 MEMORY_AREA* MemoryArea;
115 NTSTATUS Status;
116 BOOLEAN Locked = FromMdl;
117
118 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
119
120 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
121 {
122 DPRINT1("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
123 return(STATUS_UNSUCCESSFUL);
124 }
125 if (PsGetCurrentProcess() == NULL)
126 {
127 DPRINT("No current process\n");
128 return(STATUS_UNSUCCESSFUL);
129 }
130
131 /*
132 * Find the memory area for the faulting address
133 */
134 if (Address >= (ULONG_PTR)MmSystemRangeStart)
135 {
136 /*
137 * Check permissions
138 */
139 if (Mode != KernelMode)
140 {
141 DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
142 return(STATUS_ACCESS_VIOLATION);
143 }
144 AddressSpace = MmGetKernelAddressSpace();
145 }
146 else
147 {
148 AddressSpace = &PsGetCurrentProcess()->VadRoot;
149 }
150
151 if (!FromMdl)
152 {
153 MmLockAddressSpace(AddressSpace);
154 }
155 do
156 {
157 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
158 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
159 {
160 if (!FromMdl)
161 {
162 MmUnlockAddressSpace(AddressSpace);
163 }
164 return (STATUS_ACCESS_VIOLATION);
165 }
166
167 switch (MemoryArea->Type)
168 {
169 case MEMORY_AREA_SYSTEM:
170 Status = STATUS_ACCESS_VIOLATION;
171 break;
172
173 case MEMORY_AREA_PAGED_POOL:
174 Status = STATUS_SUCCESS;
175 break;
176
177 case MEMORY_AREA_SECTION_VIEW:
178 Status = MmAccessFaultSectionView(AddressSpace,
179 MemoryArea,
180 (PVOID)Address,
181 Locked);
182 break;
183
184 case MEMORY_AREA_VIRTUAL_MEMORY:
185 Status = STATUS_ACCESS_VIOLATION;
186 break;
187
188 case MEMORY_AREA_SHARED_DATA:
189 Status = STATUS_ACCESS_VIOLATION;
190 break;
191
192 default:
193 Status = STATUS_ACCESS_VIOLATION;
194 break;
195 }
196 }
197 while (Status == STATUS_MM_RESTART_OPERATION);
198
199 DPRINT("Completed page fault handling\n");
200 if (!FromMdl)
201 {
202 MmUnlockAddressSpace(AddressSpace);
203 }
204 return(Status);
205 }
206
207 NTSTATUS
208 NTAPI
209 MmNotPresentFault(KPROCESSOR_MODE Mode,
210 ULONG_PTR Address,
211 BOOLEAN FromMdl)
212 {
213 PMM_AVL_TABLE AddressSpace;
214 MEMORY_AREA* MemoryArea;
215 NTSTATUS Status;
216 BOOLEAN Locked = FromMdl;
217 PFN_TYPE Pfn;
218
219 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
220
221 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
222 {
223 DPRINT1("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
224 return(STATUS_UNSUCCESSFUL);
225 }
226
227 /*
228 * Find the memory area for the faulting address
229 */
230 if (Address >= (ULONG_PTR)MmSystemRangeStart)
231 {
232 /*
233 * Check permissions
234 */
235 if (Mode != KernelMode)
236 {
237 DPRINT1("Address: %x\n", Address);
238 return(STATUS_ACCESS_VIOLATION);
239 }
240 AddressSpace = MmGetKernelAddressSpace();
241 }
242 else
243 {
244 AddressSpace = &PsGetCurrentProcess()->VadRoot;
245 }
246
247 if (!FromMdl)
248 {
249 MmLockAddressSpace(AddressSpace);
250 }
251
252 /*
253 * Call the memory area specific fault handler
254 */
255 do
256 {
257 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
258 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
259 {
260 if (!FromMdl)
261 {
262 MmUnlockAddressSpace(AddressSpace);
263 }
264 return (STATUS_ACCESS_VIOLATION);
265 }
266
267 switch (MemoryArea->Type)
268 {
269 case MEMORY_AREA_PAGED_POOL:
270 {
271 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
272 break;
273 }
274
275 case MEMORY_AREA_SYSTEM:
276 Status = STATUS_ACCESS_VIOLATION;
277 break;
278
279 case MEMORY_AREA_SECTION_VIEW:
280 Status = MmNotPresentFaultSectionView(AddressSpace,
281 MemoryArea,
282 (PVOID)Address,
283 Locked);
284 break;
285
286 case MEMORY_AREA_VIRTUAL_MEMORY:
287 case MEMORY_AREA_PEB_OR_TEB:
288 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
289 MemoryArea,
290 (PVOID)Address,
291 Locked);
292 break;
293
294 case MEMORY_AREA_SHARED_DATA:
295 Pfn = MmSharedDataPagePhysicalAddress.LowPart >> PAGE_SHIFT;
296 Status =
297 MmCreateVirtualMapping(PsGetCurrentProcess(),
298 (PVOID)PAGE_ROUND_DOWN(Address),
299 PAGE_READONLY,
300 &Pfn,
301 1);
302 break;
303
304 default:
305 Status = STATUS_ACCESS_VIOLATION;
306 break;
307 }
308 }
309 while (Status == STATUS_MM_RESTART_OPERATION);
310
311 DPRINT("Completed page fault handling\n");
312 if (!FromMdl)
313 {
314 MmUnlockAddressSpace(AddressSpace);
315 }
316 return(Status);
317 }
318
319 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
320
321 NTSTATUS
322 NTAPI
323 MmAccessFault(IN BOOLEAN StoreInstruction,
324 IN PVOID Address,
325 IN KPROCESSOR_MODE Mode,
326 IN PVOID TrapInformation)
327 {
328 /* Cute little hack for ROS */
329 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
330 {
331 #ifdef _M_IX86
332 /* Check for an invalid page directory in kernel mode */
333 if (Mmi386MakeKernelPageTableGlobal(Address))
334 {
335 /* All is well with the world */
336 return STATUS_SUCCESS;
337 }
338 #endif
339 }
340
341 /* Keep same old ReactOS Behaviour */
342 if (StoreInstruction)
343 {
344 /* Call access fault */
345 return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
346 }
347 else
348 {
349 /* Call not present */
350 return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
351 }
352 }
353
354 NTSTATUS
355 NTAPI
356 MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
357 {
358 NTSTATUS Status;
359 PFN_TYPE AllocatedPage;
360 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
361 if (!NT_SUCCESS(Status))
362 {
363 MmUnlockAddressSpace(MmGetKernelAddressSpace());
364 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
365 MmLockAddressSpace(MmGetKernelAddressSpace());
366 }
367 Status =
368 MmCreateVirtualMapping(NULL,
369 (PVOID)PAGE_ROUND_DOWN(Address),
370 PAGE_READWRITE,
371 &AllocatedPage,
372 1);
373 if (Locked)
374 {
375 MmLockPage(AllocatedPage);
376 }
377 return(Status);
378 }
379
380
381
382 /* Miscellanea functions: they may fit somewhere else */
383
384 /*
385 * @implemented
386 */
387 BOOLEAN
388 NTAPI
389 MmIsRecursiveIoFault (VOID)
390 {
391 PETHREAD Thread = PsGetCurrentThread();
392
393 return (Thread->DisablePageFaultClustering | Thread->ForwardClusterOnly);
394 }
395
396 /*
397 * @unimplemented
398 */
399 NTSTATUS
400 NTAPI
401 MmMapUserAddressesToPage(IN PVOID BaseAddress,
402 IN SIZE_T NumberOfBytes,
403 IN PVOID PageAddress)
404 {
405 UNIMPLEMENTED;
406 return STATUS_NOT_IMPLEMENTED;
407 }
408
409 /*
410 * @unimplemented
411 */
412 ULONG NTAPI
413 MmAdjustWorkingSetSize (ULONG Unknown0,
414 ULONG Unknown1,
415 ULONG Unknown2,
416 ULONG Unknown3)
417 {
418 UNIMPLEMENTED;
419 return (0);
420 }
421
422 /*
423 * @unimplemented
424 */
425 BOOLEAN
426 NTAPI
427 MmSetAddressRangeModified (
428 IN PVOID Address,
429 IN ULONG Length
430 )
431 {
432 UNIMPLEMENTED;
433 return (FALSE);
434 }
435
436 NTSTATUS
437 NTAPI
438 NtGetWriteWatch(IN HANDLE ProcessHandle,
439 IN ULONG Flags,
440 IN PVOID BaseAddress,
441 IN SIZE_T RegionSize,
442 IN PVOID *UserAddressArray,
443 OUT PULONG_PTR EntriesInUserAddressArray,
444 OUT PULONG Granularity)
445 {
446 UNIMPLEMENTED;
447 return STATUS_NOT_IMPLEMENTED;
448 }
449
450 NTSTATUS
451 NTAPI
452 NtResetWriteWatch(IN HANDLE ProcessHandle,
453 IN PVOID BaseAddress,
454 IN SIZE_T RegionSize)
455 {
456 UNIMPLEMENTED;
457 return STATUS_NOT_IMPLEMENTED;
458 }
459
460 /* EOF */