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