Synchronize with trunk.
[reactos.git] / ntoskrnl / mm / mminit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/mm/mminit.c
5 * PURPOSE: Memory Manager Initialization
6 * PROGRAMMERS:
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 /* GLOBALS *******************************************************************/
19
20 VOID NTAPI MiInitializeUserPfnBitmap(VOID);
21
22 HANDLE MpwThreadHandle;
23 KEVENT MpwThreadEvent;
24
25 BOOLEAN Mm64BitPhysicalAddress = FALSE;
26 ULONG MmReadClusterSize;
27 //
28 // 0 | 1 is on/off paging, 2 is undocumented
29 //
30 UCHAR MmDisablePagingExecutive = 1; // Forced to off
31 PMMPTE MmSharedUserDataPte;
32 PMMSUPPORT MmKernelAddressSpace;
33
34 extern KEVENT MmWaitPageEvent;
35 extern FAST_MUTEX MiGlobalPageOperation;
36 extern LIST_ENTRY MiSegmentList;
37 extern NTSTATUS MiRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed);
38
39 /* PRIVATE FUNCTIONS *********************************************************/
40
41 VOID
42 INIT_FUNCTION
43 NTAPI
44 MiInitSystemMemoryAreas()
45 {
46 PVOID BaseAddress;
47 PHYSICAL_ADDRESS BoundaryAddressMultiple;
48 PMEMORY_AREA MArea;
49 NTSTATUS Status;
50 BoundaryAddressMultiple.QuadPart = 0;
51
52 //
53 // Create the memory area to define the loader mappings
54 //
55 BaseAddress = (PVOID)KSEG0_BASE;
56 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
57 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
58 &BaseAddress,
59 MmBootImageSize,
60 PAGE_EXECUTE_READWRITE,
61 &MArea,
62 TRUE,
63 0,
64 BoundaryAddressMultiple);
65 ASSERT(Status == STATUS_SUCCESS);
66
67 //
68 // Create the memory area to define the PTE base
69 //
70 BaseAddress = (PVOID)PTE_BASE;
71 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
72 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
73 &BaseAddress,
74 PTE_TOP - PTE_BASE + 1,
75 PAGE_READWRITE,
76 &MArea,
77 TRUE,
78 0,
79 BoundaryAddressMultiple);
80 ASSERT(Status == STATUS_SUCCESS);
81
82 //
83 // Create the memory area to define Hyperspace
84 //
85 BaseAddress = (PVOID)HYPER_SPACE;
86 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
87 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
88 &BaseAddress,
89 HYPER_SPACE_END - HYPER_SPACE + 1,
90 PAGE_READWRITE,
91 &MArea,
92 TRUE,
93 0,
94 BoundaryAddressMultiple);
95 ASSERT(Status == STATUS_SUCCESS);
96
97 //
98 // Protect the PFN database
99 //
100 BaseAddress = MmPfnDatabase;
101 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
102 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
103 &BaseAddress,
104 (MxPfnAllocation << PAGE_SHIFT),
105 PAGE_READWRITE,
106 &MArea,
107 TRUE,
108 0,
109 BoundaryAddressMultiple);
110 ASSERT(Status == STATUS_SUCCESS);
111
112 //
113 // ReactOS requires a memory area to keep the initial NP area off-bounds
114 //
115 BaseAddress = MmNonPagedPoolStart;
116 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
117 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
118 &BaseAddress,
119 MmSizeOfNonPagedPoolInBytes,
120 PAGE_READWRITE,
121 &MArea,
122 TRUE,
123 0,
124 BoundaryAddressMultiple);
125 ASSERT(Status == STATUS_SUCCESS);
126
127 //
128 // And we need one more for the system NP
129 //
130 BaseAddress = MmNonPagedSystemStart;
131 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
132 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
133 &BaseAddress,
134 MiNonPagedSystemSize,
135 PAGE_READWRITE,
136 &MArea,
137 TRUE,
138 0,
139 BoundaryAddressMultiple);
140 ASSERT(Status == STATUS_SUCCESS);
141
142 //
143 // We also need one for system view space
144 //
145 BaseAddress = MiSystemViewStart;
146 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
147 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
148 &BaseAddress,
149 MmSystemViewSize,
150 PAGE_READWRITE,
151 &MArea,
152 TRUE,
153 0,
154 BoundaryAddressMultiple);
155 ASSERT(Status == STATUS_SUCCESS);
156
157 //
158 // And another for session space
159 //
160 BaseAddress = MmSessionBase;
161 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
162 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
163 &BaseAddress,
164 (ULONG_PTR)MiSessionSpaceEnd -
165 (ULONG_PTR)MmSessionBase,
166 PAGE_READWRITE,
167 &MArea,
168 TRUE,
169 0,
170 BoundaryAddressMultiple);
171 ASSERT(Status == STATUS_SUCCESS);
172
173 //
174 // One more for ARM paged pool
175 //
176 BaseAddress = MmPagedPoolStart;
177 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
178 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
179 &BaseAddress,
180 MmSizeOfPagedPoolInBytes,
181 PAGE_READWRITE,
182 &MArea,
183 TRUE,
184 0,
185 BoundaryAddressMultiple);
186 ASSERT(Status == STATUS_SUCCESS);
187 #ifndef _M_AMD64
188 //
189 // Next, the KPCR
190 //
191 BaseAddress = (PVOID)PCR;
192 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
193 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
194 &BaseAddress,
195 PAGE_SIZE * KeNumberProcessors,
196 PAGE_READWRITE,
197 &MArea,
198 TRUE,
199 0,
200 BoundaryAddressMultiple);
201 ASSERT(Status == STATUS_SUCCESS);
202 #endif
203 //
204 // Now the KUSER_SHARED_DATA
205 //
206 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
207 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
208 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
209 &BaseAddress,
210 PAGE_SIZE,
211 PAGE_READWRITE,
212 &MArea,
213 TRUE,
214 0,
215 BoundaryAddressMultiple);
216 ASSERT(Status == STATUS_SUCCESS);
217
218 //
219 // And the debugger mapping
220 //
221 BaseAddress = MI_DEBUG_MAPPING;
222 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
223 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
224 &BaseAddress,
225 PAGE_SIZE,
226 PAGE_READWRITE,
227 &MArea,
228 TRUE,
229 0,
230 BoundaryAddressMultiple);
231 ASSERT(Status == STATUS_SUCCESS);
232
233 #if defined(_X86_)
234 //
235 // Finally, reserve the 2 pages we currently make use of for HAL mappings
236 //
237 BaseAddress = (PVOID)0xFFC00000;
238 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
239 MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC,
240 &BaseAddress,
241 PAGE_SIZE * 2,
242 PAGE_READWRITE,
243 &MArea,
244 TRUE,
245 0,
246 BoundaryAddressMultiple);
247 ASSERT(Status == STATUS_SUCCESS);
248 #endif
249 }
250
251 VOID
252 NTAPI
253 INIT_FUNCTION
254 MiDbgDumpAddressSpace(VOID)
255 {
256 //
257 // Print the memory layout
258 //
259 DPRINT1(" 0x%p - 0x%p\t%s\n",
260 KSEG0_BASE,
261 (ULONG_PTR)KSEG0_BASE + MmBootImageSize,
262 "Boot Loaded Image");
263 DPRINT1(" 0x%p - 0x%p\t%s\n",
264 MmPfnDatabase,
265 (ULONG_PTR)MmPfnDatabase + (MxPfnAllocation << PAGE_SHIFT),
266 "PFN Database");
267 DPRINT1(" 0x%p - 0x%p\t%s\n",
268 MmNonPagedPoolStart,
269 (ULONG_PTR)MmNonPagedPoolStart + MmSizeOfNonPagedPoolInBytes,
270 "ARM3 Non Paged Pool");
271 DPRINT1(" 0x%p - 0x%p\t%s\n",
272 MiSystemViewStart,
273 (ULONG_PTR)MiSystemViewStart + MmSystemViewSize,
274 "System View Space");
275 DPRINT1(" 0x%p - 0x%p\t%s\n",
276 MmSessionBase,
277 MiSessionSpaceEnd,
278 "Session Space");
279 DPRINT1(" 0x%p - 0x%p\t%s\n",
280 PTE_BASE, PTE_TOP,
281 "Page Tables");
282 DPRINT1(" 0x%p - 0x%p\t%s\n",
283 PDE_BASE, PDE_TOP,
284 "Page Directories");
285 DPRINT1(" 0x%p - 0x%p\t%s\n",
286 HYPER_SPACE, HYPER_SPACE_END,
287 "Hyperspace");
288 DPRINT1(" 0x%p - 0x%p\t%s\n",
289 MmPagedPoolStart,
290 (ULONG_PTR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes,
291 "ARM3 Paged Pool");
292 DPRINT1(" 0x%p - 0x%p\t%s\n",
293 MmNonPagedSystemStart, MmNonPagedPoolExpansionStart,
294 "System PTE Space");
295 DPRINT1(" 0x%p - 0x%p\t%s\n",
296 MmNonPagedPoolExpansionStart, MmNonPagedPoolEnd,
297 "Non Paged Pool Expansion PTE Space");
298 }
299
300 NTSTATUS NTAPI
301 MmMpwThreadMain(PVOID Ignored)
302 {
303 NTSTATUS Status;
304 ULONG PagesWritten;
305 LARGE_INTEGER Timeout;
306
307 Timeout.QuadPart = -50000000;
308
309 for(;;)
310 {
311 Status = KeWaitForSingleObject(&MpwThreadEvent,
312 0,
313 KernelMode,
314 FALSE,
315 &Timeout);
316 if (!NT_SUCCESS(Status))
317 {
318 DbgPrint("MpwThread: Wait failed\n");
319 KeBugCheck(MEMORY_MANAGEMENT);
320 return(STATUS_UNSUCCESSFUL);
321 }
322
323 PagesWritten = 0;
324
325 #ifndef NEWCC
326 // XXX arty -- we flush when evicting pages or destorying cache
327 // sections.
328 CcRosFlushDirtyPages(128, &PagesWritten, FALSE);
329 #endif
330 }
331 }
332
333 NTSTATUS
334 NTAPI
335 INIT_FUNCTION
336 MmInitMpwThread(VOID)
337 {
338 KPRIORITY Priority;
339 NTSTATUS Status;
340 CLIENT_ID MpwThreadId;
341
342 KeInitializeEvent(&MpwThreadEvent, SynchronizationEvent, FALSE);
343
344 Status = PsCreateSystemThread(&MpwThreadHandle,
345 THREAD_ALL_ACCESS,
346 NULL,
347 NULL,
348 &MpwThreadId,
349 (PKSTART_ROUTINE) MmMpwThreadMain,
350 NULL);
351 if (!NT_SUCCESS(Status))
352 {
353 return(Status);
354 }
355
356 Priority = 27;
357 NtSetInformationThread(MpwThreadHandle,
358 ThreadPriority,
359 &Priority,
360 sizeof(Priority));
361
362 return(STATUS_SUCCESS);
363 }
364
365 NTSTATUS
366 NTAPI
367 INIT_FUNCTION
368 MmInitBsmThread(VOID)
369 {
370 NTSTATUS Status;
371 OBJECT_ATTRIBUTES ObjectAttributes;
372 HANDLE ThreadHandle;
373
374 /* Create the thread */
375 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
376 Status = PsCreateSystemThread(&ThreadHandle,
377 THREAD_ALL_ACCESS,
378 &ObjectAttributes,
379 NULL,
380 NULL,
381 KeBalanceSetManager,
382 NULL);
383
384 /* Close the handle and return status */
385 ZwClose(ThreadHandle);
386 return Status;
387 }
388
389 BOOLEAN
390 NTAPI
391 INIT_FUNCTION
392 MmInitSystem(IN ULONG Phase,
393 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
394 {
395 extern MMPTE ValidKernelPte;
396 PMMPTE PointerPte;
397 MMPTE TempPte = ValidKernelPte;
398 PFN_NUMBER PageFrameNumber;
399
400 /* Initialize the kernel address space */
401 ASSERT(Phase == 1);
402
403 InitializeListHead(&MiSegmentList);
404 ExInitializeFastMutex(&MiGlobalPageOperation);
405 KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
406 // Until we're fully demand paged, we can do things the old way through
407 // the balance manager
408 MmInitializeMemoryConsumer(MC_CACHE, MiRosTrimCache);
409
410 MmKernelAddressSpace = &PsIdleProcess->Vm;
411
412 /* Intialize system memory areas */
413 MiInitSystemMemoryAreas();
414
415 /* Dump the address space */
416 MiDbgDumpAddressSpace();
417
418 MmInitGlobalKernelPageDirectory();
419 MiInitializeUserPfnBitmap();
420 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
421 MmInitializeRmapList();
422 MmInitSectionImplementation();
423 MmInitPagingFile();
424
425 //
426 // Create a PTE to double-map the shared data section. We allocate it
427 // from paged pool so that we can't fault when trying to touch the PTE
428 // itself (to map it), since paged pool addresses will already be mapped
429 // by the fault handler.
430 //
431 MmSharedUserDataPte = ExAllocatePoolWithTag(PagedPool,
432 sizeof(MMPTE),
433 ' mM');
434 if (!MmSharedUserDataPte) return FALSE;
435
436 //
437 // Now get the PTE for shared data, and read the PFN that holds it
438 //
439 PointerPte = MiAddressToPte((PVOID)KI_USER_SHARED_DATA);
440 ASSERT(PointerPte->u.Hard.Valid == 1);
441 PageFrameNumber = PFN_FROM_PTE(PointerPte);
442
443 /* Build the PTE and write it */
444 MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte,
445 PointerPte,
446 MM_READONLY,
447 PageFrameNumber);
448 *MmSharedUserDataPte = TempPte;
449
450 /* Setup session IDs */
451 MiInitializeSessionIds();
452
453 /* Setup the memory threshold events */
454 if (!MiInitializeMemoryEvents()) return FALSE;
455
456 /*
457 * Unmap low memory
458 */
459 MiInitBalancerThread();
460
461 /*
462 * Initialise the modified page writer.
463 */
464 MmInitMpwThread();
465
466 /* Initialize the balance set manager */
467 MmInitBsmThread();
468
469 return TRUE;
470 }
471