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