Sync with trunk (48237)
[reactos.git] / ntoskrnl / mm / mmfault.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/mmfault.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 #define MODULE_INVOLVED_IN_ARM3
16 #include "ARM3/miarm.h"
17
18 /* PRIVATE FUNCTIONS **********************************************************/
19
20 VOID
21 FASTCALL
22 MiSyncForProcessAttach(IN PKTHREAD Thread,
23 IN PEPROCESS Process)
24 {
25 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
26
27 /* Hack Sync because Mm is broken */
28 MmUpdatePageDir(Process, Ethread, sizeof(ETHREAD));
29 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
30 MmUpdatePageDir(Process,
31 (PVOID)Thread->StackLimit,
32 Thread->LargeStack ?
33 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
34 }
35
36 VOID
37 FASTCALL
38 MiSyncForContextSwitch(IN PKTHREAD Thread)
39 {
40 PVOID Process = PsGetCurrentProcess();
41 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
42
43 /* Hack Sync because Mm is broken */
44 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
45 MmUpdatePageDir(Process,
46 (PVOID)Thread->StackLimit,
47 Thread->LargeStack ?
48 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
49 }
50
51 NTSTATUS
52 NTAPI
53 MmpAccessFault(KPROCESSOR_MODE Mode,
54 ULONG_PTR Address,
55 BOOLEAN FromMdl)
56 {
57 PMMSUPPORT AddressSpace;
58 MEMORY_AREA* MemoryArea;
59 NTSTATUS Status;
60 BOOLEAN Locked = FromMdl;
61
62 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
63
64 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
65 {
66 DPRINT1("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
67 return(STATUS_UNSUCCESSFUL);
68 }
69
70 /*
71 * Find the memory area for the faulting address
72 */
73 if (Address >= (ULONG_PTR)MmSystemRangeStart)
74 {
75 /*
76 * Check permissions
77 */
78 if (Mode != KernelMode)
79 {
80 DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
81 return(STATUS_ACCESS_VIOLATION);
82 }
83 AddressSpace = MmGetKernelAddressSpace();
84 }
85 else
86 {
87 AddressSpace = &PsGetCurrentProcess()->Vm;
88 }
89
90 if (!FromMdl)
91 {
92 MmLockAddressSpace(AddressSpace);
93 }
94 do
95 {
96 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
97 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
98 {
99 if (!FromMdl)
100 {
101 MmUnlockAddressSpace(AddressSpace);
102 }
103 return (STATUS_ACCESS_VIOLATION);
104 }
105
106 switch (MemoryArea->Type)
107 {
108 case MEMORY_AREA_PAGED_POOL:
109 Status = STATUS_SUCCESS;
110 break;
111
112 case MEMORY_AREA_SECTION_VIEW:
113 Status = MmAccessFaultSectionView(AddressSpace,
114 MemoryArea,
115 (PVOID)Address,
116 Locked);
117 break;
118
119 case MEMORY_AREA_VIRTUAL_MEMORY:
120 Status = STATUS_ACCESS_VIOLATION;
121 break;
122
123 default:
124 Status = STATUS_ACCESS_VIOLATION;
125 break;
126 }
127 }
128 while (Status == STATUS_MM_RESTART_OPERATION);
129
130 DPRINT("Completed page fault handling\n");
131 if (!FromMdl)
132 {
133 MmUnlockAddressSpace(AddressSpace);
134 }
135 return(Status);
136 }
137
138 NTSTATUS
139 NTAPI
140 MmNotPresentFault(KPROCESSOR_MODE Mode,
141 ULONG_PTR Address,
142 BOOLEAN FromMdl)
143 {
144 PMMSUPPORT AddressSpace;
145 MEMORY_AREA* MemoryArea;
146 NTSTATUS Status;
147 BOOLEAN Locked = FromMdl;
148
149 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
150
151 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
152 {
153 DPRINT1("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
154 return(STATUS_UNSUCCESSFUL);
155 }
156
157 /*
158 * Find the memory area for the faulting address
159 */
160 if (Address >= (ULONG_PTR)MmSystemRangeStart)
161 {
162 /*
163 * Check permissions
164 */
165 if (Mode != KernelMode)
166 {
167 DPRINT1("Address: %x\n", Address);
168 return(STATUS_ACCESS_VIOLATION);
169 }
170 AddressSpace = MmGetKernelAddressSpace();
171 }
172 else
173 {
174 AddressSpace = &PsGetCurrentProcess()->Vm;
175 }
176
177 if (!FromMdl)
178 {
179 MmLockAddressSpace(AddressSpace);
180 }
181
182 /*
183 * Call the memory area specific fault handler
184 */
185 do
186 {
187 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
188 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
189 {
190 if (!FromMdl)
191 {
192 MmUnlockAddressSpace(AddressSpace);
193 }
194 return (STATUS_ACCESS_VIOLATION);
195 }
196
197 switch (MemoryArea->Type)
198 {
199 case MEMORY_AREA_PAGED_POOL:
200 {
201 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
202 break;
203 }
204
205 case MEMORY_AREA_SECTION_VIEW:
206 Status = MmNotPresentFaultSectionView(AddressSpace,
207 MemoryArea,
208 (PVOID)Address,
209 Locked);
210 break;
211
212 case MEMORY_AREA_VIRTUAL_MEMORY:
213 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
214 MemoryArea,
215 (PVOID)Address,
216 Locked);
217 break;
218
219 default:
220 Status = STATUS_ACCESS_VIOLATION;
221 break;
222 }
223 }
224 while (Status == STATUS_MM_RESTART_OPERATION);
225
226 DPRINT("Completed page fault handling\n");
227 if (!FromMdl)
228 {
229 MmUnlockAddressSpace(AddressSpace);
230 }
231 return(Status);
232 }
233
234 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
235
236 NTSTATUS
237 NTAPI
238 MmAccessFault(IN BOOLEAN StoreInstruction,
239 IN PVOID Address,
240 IN KPROCESSOR_MODE Mode,
241 IN PVOID TrapInformation)
242 {
243 PMEMORY_AREA MemoryArea;
244
245 /* Cute little hack for ROS */
246 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
247 {
248 #ifdef _M_IX86
249 /* Check for an invalid page directory in kernel mode */
250 if (Mmi386MakeKernelPageTableGlobal(Address))
251 {
252 /* All is well with the world */
253 return STATUS_SUCCESS;
254 }
255 #endif
256 }
257
258 /*
259 * Check if this is an ARM3 memory area or if there's no memory area at all.
260 * The latter can happen early in the boot cycle when ARM3 paged pool is in
261 * use before having defined the memory areas proper.
262 * A proper fix would be to define memory areas in the ARM3 code, but we want
263 * to avoid adding this ReactOS-specific construct to ARM3 code.
264 * Either way, in the future, as ReactOS-paged pool is eliminated, this hack
265 * can go away.
266 */
267 MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), Address);
268 if (!(MemoryArea) && (Address <= MM_HIGHEST_USER_ADDRESS))
269 {
270 /* Could this be a VAD fault from user-mode? */
271 MemoryArea = MmLocateMemoryAreaByAddress(MmGetCurrentAddressSpace(), Address);
272 }
273 if ((!(MemoryArea) && ((ULONG_PTR)Address >= (ULONG_PTR)MmPagedPoolStart)) ||
274 ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)))
275 {
276 //
277 // Hand it off to more competent hands...
278 //
279 DPRINT("ARM3 fault %p\n", MemoryArea);
280 return MmArmAccessFault(StoreInstruction, Address, Mode, TrapInformation);
281 }
282
283 /* Keep same old ReactOS Behaviour */
284 if (StoreInstruction)
285 {
286 /* Call access fault */
287 return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
288 }
289 else
290 {
291 /* Call not present */
292 return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
293 }
294 }
295
296 NTSTATUS
297 NTAPI
298 MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
299 {
300 NTSTATUS Status;
301 PFN_NUMBER AllocatedPage;
302
303 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
304 if (!NT_SUCCESS(Status))
305 {
306 MmUnlockAddressSpace(MmGetKernelAddressSpace());
307 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
308 MmLockAddressSpace(MmGetKernelAddressSpace());
309 }
310 Status =
311 MmCreateVirtualMapping(NULL,
312 (PVOID)PAGE_ROUND_DOWN(Address),
313 PAGE_READWRITE,
314 &AllocatedPage,
315 1);
316 return(Status);
317 }