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