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