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