xref: /reactos/ntoskrnl/mm/mmfault.c (revision 96c65e94)
1 /*
2  * COPYRIGHT:       See COPYING in the top directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/mm/mmfault.c
5  * PURPOSE:         Kernel memory management functions
6  * PROGRAMMERS:     David Welch (welch@cwcom.net)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #include <cache/section/newmm.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "ARM3/miarm.h"
18 
19 /* PRIVATE FUNCTIONS **********************************************************/
20 
21 NTSTATUS
22 NTAPI
MmpAccessFault(KPROCESSOR_MODE Mode,ULONG_PTR Address,BOOLEAN FromMdl,ULONG FaultCode)23 MmpAccessFault(KPROCESSOR_MODE Mode,
24                ULONG_PTR Address,
25                BOOLEAN FromMdl,
26                ULONG FaultCode)
27 {
28     PMMSUPPORT AddressSpace;
29     MEMORY_AREA* MemoryArea;
30     NTSTATUS Status;
31 
32     DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
33 
34     if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
35     {
36         DPRINT1("Page fault at high IRQL was %u\n", KeGetCurrentIrql());
37         return(STATUS_UNSUCCESSFUL);
38     }
39 
40     /* Instruction fetch and the page is present.
41        This means the page is NX and we cannot do anything to "fix" it. */
42     if (MI_IS_INSTRUCTION_FETCH(FaultCode))
43     {
44         DPRINT1("Page fault instruction fetch at %p\n", Address);
45         return STATUS_ACCESS_VIOLATION;
46     }
47 
48     /*
49      * Find the memory area for the faulting address
50      */
51     if (Address >= (ULONG_PTR)MmSystemRangeStart)
52     {
53         /*
54          * Check permissions
55          */
56         if (Mode != KernelMode)
57         {
58             DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
59             return(STATUS_ACCESS_VIOLATION);
60         }
61         AddressSpace = MmGetKernelAddressSpace();
62     }
63     else
64     {
65         AddressSpace = &PsGetCurrentProcess()->Vm;
66     }
67 
68     if (!FromMdl)
69     {
70         MmLockAddressSpace(AddressSpace);
71     }
72     do
73     {
74         MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
75         if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
76         {
77             if (!FromMdl)
78             {
79                 MmUnlockAddressSpace(AddressSpace);
80             }
81             return (STATUS_ACCESS_VIOLATION);
82         }
83 
84         switch (MemoryArea->Type)
85         {
86         case MEMORY_AREA_SECTION_VIEW:
87             Status = MmAccessFaultSectionView(AddressSpace,
88                                               MemoryArea,
89                                               (PVOID)Address,
90                                               !FromMdl);
91             break;
92 #ifdef NEWCC
93         case MEMORY_AREA_CACHE:
94             // This code locks for itself to keep from having to break a lock
95             // passed in.
96             if (!FromMdl)
97                 MmUnlockAddressSpace(AddressSpace);
98             Status = MmAccessFaultCacheSection(Mode, Address, FromMdl);
99             if (!FromMdl)
100                 MmLockAddressSpace(AddressSpace);
101             break;
102 #endif
103         default:
104             Status = STATUS_ACCESS_VIOLATION;
105             break;
106         }
107     }
108     while (Status == STATUS_MM_RESTART_OPERATION);
109 
110     DPRINT("Completed page fault handling\n");
111     if (!FromMdl)
112     {
113         MmUnlockAddressSpace(AddressSpace);
114     }
115     return(Status);
116 }
117 
118 NTSTATUS
119 NTAPI
MmNotPresentFault(KPROCESSOR_MODE Mode,ULONG_PTR Address,BOOLEAN FromMdl)120 MmNotPresentFault(KPROCESSOR_MODE Mode,
121                   ULONG_PTR Address,
122                   BOOLEAN FromMdl)
123 {
124     PMMSUPPORT AddressSpace;
125     MEMORY_AREA* MemoryArea;
126     NTSTATUS Status;
127 
128     DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
129 
130     if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
131     {
132         DPRINT1("Page fault at high IRQL was %u, address %x\n", KeGetCurrentIrql(), Address);
133         return(STATUS_UNSUCCESSFUL);
134     }
135 
136     /*
137      * Find the memory area for the faulting address
138      */
139     if (Address >= (ULONG_PTR)MmSystemRangeStart)
140     {
141         /*
142          * Check permissions
143          */
144         if (Mode != KernelMode)
145         {
146             DPRINT1("Address: %x\n", Address);
147             return(STATUS_ACCESS_VIOLATION);
148         }
149         AddressSpace = MmGetKernelAddressSpace();
150     }
151     else
152     {
153         AddressSpace = &PsGetCurrentProcess()->Vm;
154     }
155 
156     if (!FromMdl)
157     {
158         MmLockAddressSpace(AddressSpace);
159     }
160 
161     /*
162      * Call the memory area specific fault handler
163      */
164     do
165     {
166         MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
167         if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
168         {
169             if (!FromMdl)
170             {
171                 MmUnlockAddressSpace(AddressSpace);
172             }
173             return (STATUS_ACCESS_VIOLATION);
174         }
175 
176         switch (MemoryArea->Type)
177         {
178         case MEMORY_AREA_SECTION_VIEW:
179             Status = MmNotPresentFaultSectionView(AddressSpace,
180                                                   MemoryArea,
181                                                   (PVOID)Address,
182                                                   !FromMdl);
183             break;
184 #ifdef NEWCC
185         case MEMORY_AREA_CACHE:
186             // This code locks for itself to keep from having to break a lock
187             // passed in.
188             if (!FromMdl)
189                 MmUnlockAddressSpace(AddressSpace);
190             Status = MmNotPresentFaultCacheSection(Mode, Address, FromMdl);
191             if (!FromMdl)
192                 MmLockAddressSpace(AddressSpace);
193             break;
194 #endif
195         default:
196             Status = STATUS_ACCESS_VIOLATION;
197             break;
198         }
199     }
200     while (Status == STATUS_MM_RESTART_OPERATION);
201 
202     DPRINT("Completed page fault handling\n");
203     if (!FromMdl)
204     {
205         MmUnlockAddressSpace(AddressSpace);
206     }
207     return(Status);
208 }
209 
210 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
211 
212 VOID
213 NTAPI
214 MmRebalanceMemoryConsumersAndWait(VOID);
215 
216 NTSTATUS
217 NTAPI
MmAccessFault(IN ULONG FaultCode,IN PVOID Address,IN KPROCESSOR_MODE Mode,IN PVOID TrapInformation)218 MmAccessFault(IN ULONG FaultCode,
219               IN PVOID Address,
220               IN KPROCESSOR_MODE Mode,
221               IN PVOID TrapInformation)
222 {
223     PMEMORY_AREA MemoryArea = NULL;
224     NTSTATUS Status;
225     BOOLEAN IsArm3Fault = FALSE;
226 
227     /* Cute little hack for ROS */
228     if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
229     {
230 #ifdef _M_IX86
231         /* Check for an invalid page directory in kernel mode */
232         if (Mmi386MakeKernelPageTableGlobal(Address))
233         {
234             /* All is well with the world */
235             return STATUS_SUCCESS;
236         }
237 #endif
238     }
239 
240     /* Handle shared user page / page table, which don't have a VAD / MemoryArea */
241     if ((PAGE_ALIGN(Address) == (PVOID)MM_SHARED_USER_DATA_VA) ||
242         MI_IS_PAGE_TABLE_ADDRESS(Address))
243     {
244         /* This is an ARM3 fault */
245         DPRINT("ARM3 fault %p\n", Address);
246         return MmArmAccessFault(FaultCode, Address, Mode, TrapInformation);
247     }
248 
249     /* Is there a ReactOS address space yet? */
250     if (MmGetKernelAddressSpace())
251     {
252         if (Address > MM_HIGHEST_USER_ADDRESS)
253         {
254             /* Check if this is an ARM3 memory area */
255             MiLockWorkingSetShared(PsGetCurrentThread(), &MmSystemCacheWs);
256             MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), Address);
257 
258             if ((MemoryArea != NULL) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3))
259             {
260                 IsArm3Fault = TRUE;
261             }
262 
263             MiUnlockWorkingSetShared(PsGetCurrentThread(), &MmSystemCacheWs);
264         }
265         else
266         {
267             /* Could this be a VAD fault from user-mode? */
268             MiLockProcessWorkingSetShared(PsGetCurrentProcess(), PsGetCurrentThread());
269             MemoryArea = MmLocateMemoryAreaByAddress(MmGetCurrentAddressSpace(), Address);
270 
271             if ((MemoryArea != NULL) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3))
272             {
273                 IsArm3Fault = TRUE;
274             }
275 
276             MiUnlockProcessWorkingSetShared(PsGetCurrentProcess(), PsGetCurrentThread());
277         }
278     }
279 
280     /* Is this an ARM3 memory area, or is there no address space yet? */
281     if (IsArm3Fault ||
282         ((MemoryArea == NULL) &&
283          ((ULONG_PTR)Address >= (ULONG_PTR)MmPagedPoolStart) &&
284          ((ULONG_PTR)Address < (ULONG_PTR)MmPagedPoolEnd)) ||
285         (!MmGetKernelAddressSpace()))
286     {
287         /* This is an ARM3 fault */
288         DPRINT("ARM3 fault %p\n", MemoryArea);
289         return MmArmAccessFault(FaultCode, Address, Mode, TrapInformation);
290     }
291 
292 Retry:
293     /* Keep same old ReactOS Behaviour */
294     if (!MI_IS_NOT_PRESENT_FAULT(FaultCode))
295     {
296         /* Call access fault */
297         Status = MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE, FaultCode);
298     }
299     else
300     {
301         /* Call not present */
302         Status = MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
303     }
304 
305     if (Status == STATUS_NO_MEMORY)
306     {
307         MmRebalanceMemoryConsumersAndWait();
308         goto Retry;
309     }
310 
311     return Status;
312 }
313 
314