sync with trunk head (34904)
[reactos.git] / reactos / ntoskrnl / mm / mm.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/mm.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 <internal/debug.h>
14
15 /* GLOBALS *****************************************************************/
16
17 ULONG MmUserProbeAddress = 0;
18 PVOID MmHighestUserAddress = NULL;
19 PBOOLEAN Mm64BitPhysicalAddress = FALSE;
20 PVOID MmSystemRangeStart = NULL;
21 ULONG MmReadClusterSize;
22
23 MM_STATS MmStats;
24
25 /* FUNCTIONS ****************************************************************/
26
27 /*
28 * @implemented
29 */
30 BOOLEAN NTAPI MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
31 {
32 return MmIsAddressValid(VirtualAddress);
33 }
34
35 /*
36 * @implemented
37 */
38 BOOLEAN NTAPI MmIsAddressValid(PVOID VirtualAddress)
39 /*
40 * FUNCTION: Checks whether the given address is valid for a read or write
41 * ARGUMENTS:
42 * VirtualAddress = address to check
43 * RETURNS: True if the access would be valid
44 * False if the access would cause a page fault
45 * NOTES: This function checks whether a byte access to the page would
46 * succeed. Is this realistic for RISC processors which don't
47 * allow byte granular access?
48 */
49 {
50 MEMORY_AREA* MemoryArea;
51 PMM_AVL_TABLE AddressSpace;
52
53 if (VirtualAddress >= MmSystemRangeStart)
54 {
55 AddressSpace = MmGetKernelAddressSpace();
56 }
57 else
58 {
59 AddressSpace = &PsGetCurrentProcess()->VadRoot;
60 }
61
62 MmLockAddressSpace(AddressSpace);
63 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
64 VirtualAddress);
65
66 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
67 {
68 MmUnlockAddressSpace(AddressSpace);
69 return(FALSE);
70 }
71 MmUnlockAddressSpace(AddressSpace);
72 return(TRUE);
73 }
74
75 NTSTATUS
76 NTAPI
77 MmpAccessFault(KPROCESSOR_MODE Mode,
78 ULONG_PTR Address,
79 BOOLEAN FromMdl)
80 {
81 PMM_AVL_TABLE AddressSpace;
82 MEMORY_AREA* MemoryArea;
83 NTSTATUS Status;
84 BOOLEAN Locked = FromMdl;
85
86 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
87
88 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
89 {
90 CPRINT("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
91 return(STATUS_UNSUCCESSFUL);
92 }
93 if (PsGetCurrentProcess() == NULL)
94 {
95 DPRINT("No current process\n");
96 return(STATUS_UNSUCCESSFUL);
97 }
98
99 /*
100 * Find the memory area for the faulting address
101 */
102 if (Address >= (ULONG_PTR)MmSystemRangeStart)
103 {
104 /*
105 * Check permissions
106 */
107 if (Mode != KernelMode)
108 {
109 DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
110 DbgPrint("%s:%d\n",__FILE__,__LINE__);
111 return(STATUS_ACCESS_VIOLATION);
112 }
113 AddressSpace = MmGetKernelAddressSpace();
114 }
115 else
116 {
117 AddressSpace = &PsGetCurrentProcess()->VadRoot;
118 }
119
120 if (!FromMdl)
121 {
122 MmLockAddressSpace(AddressSpace);
123 }
124 do
125 {
126 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
127 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
128 {
129 if (!FromMdl)
130 {
131 MmUnlockAddressSpace(AddressSpace);
132 }
133 return (STATUS_ACCESS_VIOLATION);
134 }
135
136 switch (MemoryArea->Type)
137 {
138 case MEMORY_AREA_SYSTEM:
139 Status = STATUS_ACCESS_VIOLATION;
140 break;
141
142 case MEMORY_AREA_PAGED_POOL:
143 Status = STATUS_SUCCESS;
144 break;
145
146 case MEMORY_AREA_SECTION_VIEW:
147 Status = MmAccessFaultSectionView(AddressSpace,
148 MemoryArea,
149 (PVOID)Address,
150 Locked);
151 break;
152
153 case MEMORY_AREA_VIRTUAL_MEMORY:
154 Status = STATUS_ACCESS_VIOLATION;
155 break;
156
157 case MEMORY_AREA_SHARED_DATA:
158 Status = STATUS_ACCESS_VIOLATION;
159 break;
160
161 default:
162 Status = STATUS_ACCESS_VIOLATION;
163 break;
164 }
165 }
166 while (Status == STATUS_MM_RESTART_OPERATION);
167
168 DPRINT("Completed page fault handling\n");
169 if (!FromMdl)
170 {
171 MmUnlockAddressSpace(AddressSpace);
172 }
173 return(Status);
174 }
175
176 NTSTATUS
177 NTAPI
178 MmNotPresentFault(KPROCESSOR_MODE Mode,
179 ULONG_PTR Address,
180 BOOLEAN FromMdl)
181 {
182 PMM_AVL_TABLE AddressSpace;
183 MEMORY_AREA* MemoryArea;
184 NTSTATUS Status;
185 BOOLEAN Locked = FromMdl;
186 PFN_TYPE Pfn;
187
188 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
189
190 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
191 {
192 CPRINT("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address);
193 return(STATUS_UNSUCCESSFUL);
194 }
195
196 /*
197 * Find the memory area for the faulting address
198 */
199 if (Address >= (ULONG_PTR)MmSystemRangeStart)
200 {
201 /*
202 * Check permissions
203 */
204 if (Mode != KernelMode)
205 {
206 CPRINT("Address: %x\n", Address);
207 return(STATUS_ACCESS_VIOLATION);
208 }
209 AddressSpace = MmGetKernelAddressSpace();
210 }
211 else
212 {
213 AddressSpace = &PsGetCurrentProcess()->VadRoot;
214 }
215
216 if (!FromMdl)
217 {
218 MmLockAddressSpace(AddressSpace);
219 }
220
221 /*
222 * Call the memory area specific fault handler
223 */
224 do
225 {
226 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
227 if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
228 {
229 if (!FromMdl)
230 {
231 MmUnlockAddressSpace(AddressSpace);
232 }
233 return (STATUS_ACCESS_VIOLATION);
234 }
235
236 switch (MemoryArea->Type)
237 {
238 case MEMORY_AREA_PAGED_POOL:
239 {
240 Status = MmCommitPagedPoolAddress((PVOID)Address, Locked);
241 break;
242 }
243
244 case MEMORY_AREA_SYSTEM:
245 Status = STATUS_ACCESS_VIOLATION;
246 break;
247
248 case MEMORY_AREA_SECTION_VIEW:
249 Status = MmNotPresentFaultSectionView(AddressSpace,
250 MemoryArea,
251 (PVOID)Address,
252 Locked);
253 break;
254
255 case MEMORY_AREA_VIRTUAL_MEMORY:
256 case MEMORY_AREA_PEB_OR_TEB:
257 Status = MmNotPresentFaultVirtualMemory(AddressSpace,
258 MemoryArea,
259 (PVOID)Address,
260 Locked);
261 break;
262
263 case MEMORY_AREA_SHARED_DATA:
264 Pfn = MmSharedDataPagePhysicalAddress.LowPart >> PAGE_SHIFT;
265 Status =
266 MmCreateVirtualMapping(PsGetCurrentProcess(),
267 (PVOID)PAGE_ROUND_DOWN(Address),
268 PAGE_READONLY,
269 &Pfn,
270 1);
271 break;
272
273 default:
274 Status = STATUS_ACCESS_VIOLATION;
275 break;
276 }
277 }
278 while (Status == STATUS_MM_RESTART_OPERATION);
279
280 DPRINT("Completed page fault handling\n");
281 if (!FromMdl)
282 {
283 MmUnlockAddressSpace(AddressSpace);
284 }
285 return(Status);
286 }
287
288 extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address);
289
290 NTSTATUS
291 NTAPI
292 MmAccessFault(IN BOOLEAN StoreInstruction,
293 IN PVOID Address,
294 IN KPROCESSOR_MODE Mode,
295 IN PVOID TrapInformation)
296 {
297 /* Cute little hack for ROS */
298 if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart)
299 {
300 #ifdef _M_IX86
301 /* Check for an invalid page directory in kernel mode */
302 if (Mmi386MakeKernelPageTableGlobal(Address))
303 {
304 /* All is well with the world */
305 return STATUS_SUCCESS;
306 }
307 #endif
308 }
309
310 /* Keep same old ReactOS Behaviour */
311 if (StoreInstruction)
312 {
313 /* Call access fault */
314 return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
315 }
316 else
317 {
318 /* Call not present */
319 return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE);
320 }
321 }
322
323 NTSTATUS
324 NTAPI
325 MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked)
326 {
327 NTSTATUS Status;
328 PFN_TYPE AllocatedPage;
329 Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
330 if (!NT_SUCCESS(Status))
331 {
332 MmUnlockAddressSpace(MmGetKernelAddressSpace());
333 Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
334 MmLockAddressSpace(MmGetKernelAddressSpace());
335 }
336 Status =
337 MmCreateVirtualMapping(NULL,
338 (PVOID)PAGE_ROUND_DOWN(Address),
339 PAGE_READWRITE,
340 &AllocatedPage,
341 1);
342 if (Locked)
343 {
344 MmLockPage(AllocatedPage);
345 }
346 return(Status);
347 }
348
349
350
351 /* Miscellanea functions: they may fit somewhere else */
352
353 /*
354 * @unimplemented
355 */
356 ULONG NTAPI
357 MmAdjustWorkingSetSize (ULONG Unknown0,
358 ULONG Unknown1,
359 ULONG Unknown2)
360 {
361 UNIMPLEMENTED;
362 return (0);
363 }
364
365 /*
366 * @unimplemented
367 */
368 BOOLEAN
369 NTAPI
370 MmSetAddressRangeModified (
371 IN PVOID Address,
372 IN ULONG Length
373 )
374 {
375 UNIMPLEMENTED;
376 return (FALSE);
377 }
378
379 NTSTATUS
380 NTAPI
381 NtGetWriteWatch(IN HANDLE ProcessHandle,
382 IN ULONG Flags,
383 IN PVOID BaseAddress,
384 IN ULONG RegionSize,
385 IN PVOID *UserAddressArray,
386 OUT PULONG EntriesInUserAddressArray,
387 OUT PULONG Granularity)
388 {
389 UNIMPLEMENTED;
390 return STATUS_NOT_IMPLEMENTED;
391 }
392
393 NTSTATUS
394 NTAPI
395 NtResetWriteWatch(IN HANDLE ProcessHandle,
396 IN PVOID BaseAddress,
397 IN ULONG RegionSize)
398 {
399 UNIMPLEMENTED;
400 return STATUS_NOT_IMPLEMENTED;
401 }
402
403 /* EOF */