-Import tkreuzer's time implementation from AMD64 branch
[reactos.git] / reactos / 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 /* PRIVATE FUNCTIONS **********************************************************/
16
17 VOID
18 FASTCALL
19 MiSyncForProcessAttach(IN PKTHREAD Thread,
20 IN PEPROCESS Process)
21 {
22 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
23
24 /* Hack Sync because Mm is broken */
25 MmUpdatePageDir(Process, Ethread, sizeof(ETHREAD));
26 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
27 MmUpdatePageDir(Process,
28 (PVOID)Thread->StackLimit,
29 Thread->LargeStack ?
30 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
31 }
32
33 VOID
34 FASTCALL
35 MiSyncForContextSwitch(IN PKTHREAD Thread)
36 {
37 PVOID Process = PsGetCurrentProcess();
38 PETHREAD Ethread = CONTAINING_RECORD(Thread, ETHREAD, Tcb);
39
40 /* Hack Sync because Mm is broken */
41 MmUpdatePageDir(Process, Ethread->ThreadsProcess, sizeof(EPROCESS));
42 MmUpdatePageDir(Process,
43 (PVOID)Thread->StackLimit,
44 Thread->LargeStack ?
45 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
46 }
47
48 NTSTATUS
49 NTAPI
50 MmpAccessFault(KPROCESSOR_MODE Mode,
51 ULONG_PTR Address,
52 BOOLEAN FromMdl)
53 {
54 PMMSUPPORT AddressSpace;
55 MEMORY_AREA* MemoryArea;
56 NTSTATUS Status;
57 BOOLEAN Locked = FromMdl;
58
59 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
60
61 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
62 {
63 DPRINT1("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
64 return(STATUS_UNSUCCESSFUL);
65 }
66
67 /*
68 * Find the memory area for the faulting address
69 */
70 if (Address >= (ULONG_PTR)MmSystemRangeStart)
71 {
72 /*
73 * Check permissions
74 */
75 if (Mode != KernelMode)
76 {
77 DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
78 return(STATUS_ACCESS_VIOLATION);
79 }
80 AddressSpace = MmGetKernelAddressSpace();
81 }
82 else
83 {
84 AddressSpace = &PsGetCurrentProcess()->Vm;
85 }
86
87 if (!FromMdl)
88 {
89 MmLockAddressSpace(AddressSpace);
90 }
91 do
92 {
93 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
94 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
95 {
96 if (!FromMdl)
97 {
98 MmUnlockAddressSpace(AddressSpace);
99 }
100 return (STATUS_ACCESS_VIOLATION);
101 }
102
103 switch (MemoryArea->Type)
104 {
105 case MEMORY_AREA_SYSTEM:
106 Status = STATUS_ACCESS_VIOLATION;
107 break;
108
109 case MEMORY_AREA_PAGED_POOL:
110 Status = STATUS_SUCCESS;
111 break;
112
113 case MEMORY_AREA_SECTION_VIEW:
114 Status = MmAccessFaultSectionView(AddressSpace,
115 MemoryArea,
116 (PVOID)Address,
117 Locked);
118 break;
119
120 case MEMORY_AREA_VIRTUAL_MEMORY:
121 Status = STATUS_ACCESS_VIOLATION;
122 break;
123
124 case MEMORY_AREA_SHARED_DATA:
125 Status = STATUS_ACCESS_VIOLATION;
126 break;
127
128 default:
129 Status = STATUS_ACCESS_VIOLATION;
130 break;
131 }
132 }
133 while (Status == STATUS_MM_RESTART_OPERATION);
134
135 DPRINT("Completed page fault handling\n");
136 if (!FromMdl)
137 {
138 MmUnlockAddressSpace(AddressSpace);
139 }
140 return(Status);
141 }
142
143 NTSTATUS
144 NTAPI
145 MmNotPresentFault(KPROCESSOR_MODE Mode,
146 ULONG_PTR Address,
147 BOOLEAN FromMdl)
148 {
149 PMMSUPPORT AddressSpace;
150 MEMORY_AREA* MemoryArea;
151 NTSTATUS Status;
152 BOOLEAN Locked = FromMdl;
153 extern PMMPTE MmSharedUserDataPte;
154
155 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
156
157 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
158 {
159 DPRINT1("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
160 return(STATUS_UNSUCCESSFUL);
161 }
162
163 /*
164 * Find the memory area for the faulting address
165 */
166 if (Address >= (ULONG_PTR)MmSystemRangeStart)
167 {
168 /*
169 * Check permissions
170 */
171 if (Mode != KernelMode)
172 {
173 DPRINT1("Address: %x\n", Address);
174 return(STATUS_ACCESS_VIOLATION);
175 }
176 AddressSpace = MmGetKernelAddressSpace();
177 }
178 else
179 {
180 AddressSpace = &PsGetCurrentProcess()->Vm;
181 }
182
183 if (!FromMdl)
184 {
185 MmLockAddressSpace(AddressSpace);
186 }
187
188 /*
189 * Call the memory area specific fault handler
190 */
191 do
192 {
193 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
194 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
195 {
196 if (!FromMdl)
197 {
198 MmUnlockAddressSpace(AddressSpace);
199 }
200 return (STATUS_ACCESS_VIOLATION);
201 }
202
203 switch (MemoryArea->Type)
204 {
205 case MEMORY_AREA_PAGED_POOL:
206 {
207 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
208 break;
209 }
210
211 case MEMORY_AREA_SYSTEM:
212 Status = STATUS_ACCESS_VIOLATION;
213 break;
214
215 case MEMORY_AREA_SECTION_VIEW:
216 Status = MmNotPresentFaultSectionView(AddressSpace,
217 MemoryArea,
218 (PVOID)Address,
219 Locked);
220 break;
221
222 case MEMORY_AREA_VIRTUAL_MEMORY:
223 case MEMORY_AREA_PEB_OR_TEB:
224 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
225 MemoryArea,
226 (PVOID)Address,
227 Locked);
228 break;
229
230 case MEMORY_AREA_SHARED_DATA:
231 *MiAddressToPte(USER_SHARED_DATA) = *MmSharedUserDataPte;
232 Status = STATUS_SUCCESS;
233 break;
234
235 default:
236 Status = STATUS_ACCESS_VIOLATION;
237 break;
238 }
239 }
240 while (Status == STATUS_MM_RESTART_OPERATION);
241
242 DPRINT("Completed page fault handling\n");
243 if (!FromMdl)
244 {
245 MmUnlockAddressSpace(AddressSpace);
246 }
247 return(Status);
248 }
249
250 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
251
252 NTSTATUS
253 NTAPI
254 MmAccessFault(IN BOOLEAN StoreInstruction,
255 IN PVOID Address,
256 IN KPROCESSOR_MODE Mode,
257 IN PVOID TrapInformation)
258 {
259 /* Cute little hack for ROS */
260 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
261 {
262 #ifdef _M_IX86
263 /* Check for an invalid page directory in kernel mode */
264 if (Mmi386MakeKernelPageTableGlobal(Address))
265 {
266 /* All is well with the world */
267 return STATUS_SUCCESS;
268 }
269 #endif
270 }
271
272 /* Keep same old ReactOS Behaviour */
273 if (StoreInstruction)
274 {
275 /* Call access fault */
276 return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
277 }
278 else
279 {
280 /* Call not present */
281 return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
282 }
283 }
284
285 NTSTATUS
286 NTAPI
287 MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
288 {
289 NTSTATUS Status;
290 PFN_TYPE AllocatedPage;
291 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
292 if (!NT_SUCCESS(Status))
293 {
294 MmUnlockAddressSpace(MmGetKernelAddressSpace());
295 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
296 MmLockAddressSpace(MmGetKernelAddressSpace());
297 }
298 Status =
299 MmCreateVirtualMapping(NULL,
300 (PVOID)PAGE_ROUND_DOWN(Address),
301 PAGE_READWRITE,
302 &AllocatedPage,
303 1);
304 if (Locked)
305 {
306 MmLockPage(AllocatedPage);
307 }
308 return(Status);
309 }
310
311 /* PUBLIC FUNCTIONS ***********************************************************/
312
313 /*
314 * @implemented
315 */
316 BOOLEAN
317 NTAPI
318 MmIsAddressValid(IN PVOID VirtualAddress)
319 {
320 MEMORY_AREA* MemoryArea;
321 PMMSUPPORT AddressSpace;
322
323 DPRINT1("WARNING: %s returns bogus result\n", __FUNCTION__);
324
325 if (VirtualAddress >= MmSystemRangeStart)
326 {
327 AddressSpace = MmGetKernelAddressSpace();
328 }
329 else
330 {
331 AddressSpace = &PsGetCurrentProcess()->Vm;
332 }
333
334 MmLockAddressSpace(AddressSpace);
335 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
336 VirtualAddress);
337
338 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
339 {
340 MmUnlockAddressSpace(AddressSpace);
341 return(FALSE);
342 }
343 MmUnlockAddressSpace(AddressSpace);
344 return(TRUE);
345 }
346
347 /* EOF */