ab3f28fc665acaf5c4379e8f8eaed8c9705934ec
[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_SYSTEM:
109 Status = STATUS_ACCESS_VIOLATION;
110 break;
111
112 case MEMORY_AREA_PAGED_POOL:
113 Status = STATUS_SUCCESS;
114 break;
115
116 case MEMORY_AREA_SECTION_VIEW:
117 Status = MmAccessFaultSectionView(AddressSpace,
118 MemoryArea,
119 (PVOID)Address,
120 Locked);
121 break;
122
123 case MEMORY_AREA_VIRTUAL_MEMORY:
124 Status = STATUS_ACCESS_VIOLATION;
125 break;
126
127 case MEMORY_AREA_SHARED_DATA:
128 Status = STATUS_ACCESS_VIOLATION;
129 break;
130
131 default:
132 Status = STATUS_ACCESS_VIOLATION;
133 break;
134 }
135 }
136 while (Status == STATUS_MM_RESTART_OPERATION);
137
138 DPRINT("Completed page fault handling\n");
139 if (!FromMdl)
140 {
141 MmUnlockAddressSpace(AddressSpace);
142 }
143 return(Status);
144 }
145
146 NTSTATUS
147 NTAPI
148 MmNotPresentFault(KPROCESSOR_MODE Mode,
149 ULONG_PTR Address,
150 BOOLEAN FromMdl)
151 {
152 PMMSUPPORT AddressSpace;
153 MEMORY_AREA* MemoryArea;
154 NTSTATUS Status;
155 BOOLEAN Locked = FromMdl;
156 extern PMMPTE MmSharedUserDataPte;
157
158 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
159
160 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
161 {
162 DPRINT1("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
163 return(STATUS_UNSUCCESSFUL);
164 }
165
166 /*
167 * Find the memory area for the faulting address
168 */
169 if (Address >= (ULONG_PTR)MmSystemRangeStart)
170 {
171 /*
172 * Check permissions
173 */
174 if (Mode != KernelMode)
175 {
176 DPRINT1("Address: %x\n", Address);
177 return(STATUS_ACCESS_VIOLATION);
178 }
179 AddressSpace = MmGetKernelAddressSpace();
180 }
181 else
182 {
183 AddressSpace = &PsGetCurrentProcess()->Vm;
184 }
185
186 if (!FromMdl)
187 {
188 MmLockAddressSpace(AddressSpace);
189 }
190
191 /*
192 * Call the memory area specific fault handler
193 */
194 do
195 {
196 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
197 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
198 {
199 if (!FromMdl)
200 {
201 MmUnlockAddressSpace(AddressSpace);
202 }
203 return (STATUS_ACCESS_VIOLATION);
204 }
205
206 switch (MemoryArea->Type)
207 {
208 case MEMORY_AREA_PAGED_POOL:
209 {
210 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
211 break;
212 }
213
214 case MEMORY_AREA_SYSTEM:
215 Status = STATUS_ACCESS_VIOLATION;
216 break;
217
218 case MEMORY_AREA_SECTION_VIEW:
219 Status = MmNotPresentFaultSectionView(AddressSpace,
220 MemoryArea,
221 (PVOID)Address,
222 Locked);
223 break;
224
225 case MEMORY_AREA_VIRTUAL_MEMORY:
226 case MEMORY_AREA_PEB_OR_TEB:
227 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
228 MemoryArea,
229 (PVOID)Address,
230 Locked);
231 break;
232
233 case MEMORY_AREA_SHARED_DATA:
234 *MiAddressToPte(USER_SHARED_DATA) = *MmSharedUserDataPte;
235 Status = STATUS_SUCCESS;
236 break;
237
238 default:
239 Status = STATUS_ACCESS_VIOLATION;
240 break;
241 }
242 }
243 while (Status == STATUS_MM_RESTART_OPERATION);
244
245 DPRINT("Completed page fault handling\n");
246 if (!FromMdl)
247 {
248 MmUnlockAddressSpace(AddressSpace);
249 }
250 return(Status);
251 }
252
253 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
254
255 NTSTATUS
256 NTAPI
257 MmAccessFault(IN BOOLEAN StoreInstruction,
258 IN PVOID Address,
259 IN KPROCESSOR_MODE Mode,
260 IN PVOID TrapInformation)
261 {
262 PMEMORY_AREA MemoryArea;
263
264 /* Cute little hack for ROS */
265 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
266 {
267 #ifdef _M_IX86
268 /* Check for an invalid page directory in kernel mode */
269 if (Mmi386MakeKernelPageTableGlobal(Address))
270 {
271 /* All is well with the world */
272 return STATUS_SUCCESS;
273 }
274 #endif
275 }
276
277 /*
278 * Check if this is an ARM3 memory area or if there's no memory area at all.
279 * The latter can happen early in the boot cycle when ARM3 paged pool is in
280 * use before having defined the memory areas proper.
281 * A proper fix would be to define memory areas in the ARM3 code, but we want
282 * to avoid adding this ReactOS-specific construct to ARM3 code.
283 * Either way, in the future, as ReactOS-paged pool is eliminated, this hack
284 * can go away.
285 */
286 MemoryArea = MmLocateMemoryAreaByAddress(MmGetKernelAddressSpace(), Address);
287 if ((!(MemoryArea) && ((ULONG_PTR)Address >= (ULONG_PTR)MmPagedPoolStart)) ||
288 ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3)))
289 {
290 //
291 // Hand it off to more competent hands...
292 //
293 DPRINT("ARM3 fault %p\n", MemoryArea);
294 return MmArmAccessFault(StoreInstruction, Address, Mode, TrapInformation);
295 }
296
297 /* Keep same old ReactOS Behaviour */
298 if (StoreInstruction)
299 {
300 /* Call access fault */
301 return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
302 }
303 else
304 {
305 /* Call not present */
306 return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
307 }
308 }
309
310 NTSTATUS
311 NTAPI
312 MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
313 {
314 NTSTATUS Status;
315 PFN_NUMBER AllocatedPage;
316
317 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
318 if (!NT_SUCCESS(Status))
319 {
320 MmUnlockAddressSpace(MmGetKernelAddressSpace());
321 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
322 MmLockAddressSpace(MmGetKernelAddressSpace());
323 }
324 Status =
325 MmCreateVirtualMapping(NULL,
326 (PVOID)PAGE_ROUND_DOWN(Address),
327 PAGE_READWRITE,
328 &AllocatedPage,
329 1);
330 return(Status);
331 }