* Fix multiple bugs in SHFormatDrive dialog
[reactos.git] / reactos / 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 <internal/debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 PCHAR
18 MemType[] =
19 {
20 "ExceptionBlock ",
21 "SystemBlock ",
22 "Free ",
23 "Bad ",
24 "LoadedProgram ",
25 "FirmwareTemporary ",
26 "FirmwarePermanent ",
27 "OsloaderHeap ",
28 "OsloaderStack ",
29 "SystemCode ",
30 "HalCode ",
31 "BootDriver ",
32 "ConsoleInDriver ",
33 "ConsoleOutDriver ",
34 "StartupDpcStack ",
35 "StartupKernelStack",
36 "StartupPanicStack ",
37 "StartupPcrPage ",
38 "StartupPdrPage ",
39 "RegistryData ",
40 "MemoryData ",
41 "NlsData ",
42 "SpecialMemory ",
43 "BBTMemory ",
44 "LoaderReserve ",
45 "LoaderXIPRom "
46 };
47
48 BOOLEAN IsThisAnNtAsSystem = FALSE;
49 MM_SYSTEMSIZE MmSystemSize = MmSmallSystem;
50 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
51 PVOID MiNonPagedPoolStart;
52 ULONG MiNonPagedPoolLength;
53 ULONG MmBootImageSize;
54 ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage;
55 ULONG_PTR MiKSeg0Start, MiKSeg0End;
56 PVOID MmPfnDatabase;
57 ULONG_PTR MmPfnDatabaseEnd;
58 PMEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptor;
59 MEMORY_ALLOCATION_DESCRIPTOR MiFreeDescriptorOrg;
60 extern KMUTANT MmSystemLoadLock;
61 extern HANDLE MpwThreadHandle;
62 extern BOOLEAN MpwThreadShouldTerminate;
63 extern KEVENT MpwThreadEvent;
64 BOOLEAN MiDbgEnableMdDump =
65 #ifdef _ARM_
66 TRUE;
67 #else
68 FALSE;
69 #endif
70
71 /* PRIVATE FUNCTIONS *********************************************************/
72
73 VOID
74 NTAPI
75 MiShutdownMemoryManager(VOID)
76 {
77 #if 0
78 ULONG PagesWritten;
79 PETHREAD Thread;
80
81 /* Ask MPW thread to shutdown */
82 MpwThreadShouldTerminate = TRUE;
83 KeSetEvent(&MpwThreadEvent, IO_NO_INCREMENT, FALSE);
84
85 /* Wait for it */
86 ObReferenceObjectByHandle(MpwThreadHandle,
87 THREAD_ALL_ACCESS,
88 PsThreadType,
89 KernelMode,
90 (PVOID*)&Thread,
91 NULL);
92
93 KeWaitForSingleObject(Thread,
94 Executive,
95 KernelMode,
96 FALSE,
97 NULL);
98
99 ObDereferenceObject(Thread);
100
101 /* Check if there are any dirty pages, and flush them.
102 There will be no other chance to do this later, since filesystems
103 are going to be shut down. */
104 CcRosFlushDirtyPages(128, &PagesWritten);
105 #endif
106 }
107
108 VOID
109 INIT_FUNCTION
110 NTAPI
111 MmInitVirtualMemory()
112 {
113 PVOID BaseAddress;
114 ULONG Length;
115 NTSTATUS Status;
116 PHYSICAL_ADDRESS BoundaryAddressMultiple;
117 PMEMORY_AREA MArea;
118
119 BoundaryAddressMultiple.QuadPart = 0;
120
121 MmInitMemoryAreas();
122
123 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1,
124 MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 1);
125
126 MiInitializeNonPagedPool();
127
128 /*
129 * Setup the system area descriptor list
130 */
131 MiInitPageDirectoryMap();
132
133 BaseAddress = (PVOID)PCR;
134 MmCreateMemoryArea(MmGetKernelAddressSpace(),
135 MEMORY_AREA_SYSTEM,
136 &BaseAddress,
137 PAGE_SIZE * MAXIMUM_PROCESSORS,
138 PAGE_READWRITE,
139 &MArea,
140 TRUE,
141 0,
142 BoundaryAddressMultiple);
143
144 /* Local APIC base */
145 BaseAddress = (PVOID)0xFEE00000;
146 MmCreateMemoryArea(MmGetKernelAddressSpace(),
147 MEMORY_AREA_SYSTEM,
148 &BaseAddress,
149 PAGE_SIZE,
150 PAGE_READWRITE,
151 &MArea,
152 TRUE,
153 0,
154 BoundaryAddressMultiple);
155
156 /* i/o APIC base */
157 BaseAddress = (PVOID)0xFEC00000;
158 MmCreateMemoryArea(MmGetKernelAddressSpace(),
159 MEMORY_AREA_SYSTEM,
160 &BaseAddress,
161 PAGE_SIZE,
162 PAGE_READWRITE,
163 &MArea,
164 TRUE,
165 0,
166 BoundaryAddressMultiple);
167
168 BaseAddress = (PVOID)0xFF3A0000;
169 MmCreateMemoryArea(MmGetKernelAddressSpace(),
170 MEMORY_AREA_SYSTEM,
171 &BaseAddress,
172 0x20000,
173 PAGE_READWRITE,
174 &MArea,
175 TRUE,
176 0,
177 BoundaryAddressMultiple);
178
179 BaseAddress = MiNonPagedPoolStart;
180 MmCreateMemoryArea(MmGetKernelAddressSpace(),
181 MEMORY_AREA_SYSTEM,
182 &BaseAddress,
183 MiNonPagedPoolLength,
184 PAGE_READWRITE,
185 &MArea,
186 TRUE,
187 0,
188 BoundaryAddressMultiple);
189
190 BaseAddress = MmPagedPoolBase;
191 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
192 MEMORY_AREA_PAGED_POOL,
193 &BaseAddress,
194 MmPagedPoolSize,
195 PAGE_READWRITE,
196 &MArea,
197 TRUE,
198 0,
199 BoundaryAddressMultiple);
200
201 MmInitializePagedPool();
202
203 /*
204 * Create the kernel mapping of the user/kernel shared memory.
205 */
206 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
207 Length = PAGE_SIZE;
208 MmCreateMemoryArea(MmGetKernelAddressSpace(),
209 MEMORY_AREA_SYSTEM,
210 &BaseAddress,
211 Length,
212 PAGE_READWRITE,
213 &MArea,
214 TRUE,
215 0,
216 BoundaryAddressMultiple);
217
218 /* Shared data are always located the next page after PCR */
219 MmSharedDataPagePhysicalAddress = MmGetPhysicalAddress((PVOID)PCR);
220 MmSharedDataPagePhysicalAddress.QuadPart += PAGE_SIZE;
221
222 /*
223 *
224 */
225 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
226 }
227
228 VOID
229 NTAPI
230 MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock)
231 {
232 PLIST_ENTRY NextEntry;
233 PMEMORY_ALLOCATION_DESCRIPTOR Md;
234 ULONG FreePages = 0;
235
236 for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
237 NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
238 NextEntry = NextEntry->Flink)
239 {
240 Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
241
242 /* Skip invisible memory */
243 if ((Md->MemoryType != LoaderFirmwarePermanent) &&
244 (Md->MemoryType != LoaderSpecialMemory) &&
245 (Md->MemoryType != LoaderHALCachedMemory) &&
246 (Md->MemoryType != LoaderBBTMemory))
247 {
248 /* Check if BURNMEM was used */
249 if (Md->MemoryType != LoaderBad)
250 {
251 /* Count this in the total of pages */
252 MmNumberOfPhysicalPages += Md->PageCount;
253 }
254
255 /* Check if this is the new lowest page */
256 if (Md->BasePage < MmLowestPhysicalPage)
257 {
258 /* Update the lowest page */
259 MmLowestPhysicalPage = Md->BasePage;
260 }
261
262 /* Check if this is the new highest page */
263 if ((Md->BasePage + Md->PageCount) > MmHighestPhysicalPage)
264 {
265 /* Update the highest page */
266 MmHighestPhysicalPage = Md->BasePage + Md->PageCount - 1;
267 }
268
269 /* Check if this is free memory */
270 if ((Md->MemoryType == LoaderFree) ||
271 (Md->MemoryType == LoaderLoadedProgram) ||
272 (Md->MemoryType == LoaderFirmwareTemporary) ||
273 (Md->MemoryType == LoaderOsloaderStack))
274 {
275 /* Check if this is the largest memory descriptor */
276 if (Md->PageCount > FreePages)
277 {
278 /* For now, it is */
279 FreePages = Md->PageCount;
280 MiFreeDescriptor = Md;
281 }
282 }
283 }
284 }
285
286 /* Save original values of the free descriptor, since it'll be
287 altered by early allocations */
288 MiFreeDescriptorOrg = *MiFreeDescriptor;
289 }
290
291 VOID
292 NTAPI
293 MiDbgKernelLayout(VOID)
294 {
295 DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
296 DPRINT1("0x%p - 0x%p\t%s\n",
297 KSEG0_BASE, MiKSeg0Start,
298 "Undefined region");
299 DPRINT1("0x%p - 0x%p\t%s\n",
300 MiKSeg0Start, MiKSeg0End,
301 "FreeLDR Kernel mapping region");
302 DPRINT1("0x%p - 0x%p\t%s\n",
303 MmPfnDatabase, MmPfnDatabaseEnd,
304 "PFN Database region");
305 if (MmPfnDatabaseEnd != (ULONG_PTR)MiNonPagedPoolStart)
306 DPRINT1("0x%p - 0x%p\t%s\n",
307 MmPfnDatabaseEnd, MiNonPagedPoolStart,
308 "Remaining FreeLDR mapping");
309 DPRINT1("0x%p - 0x%p\t%s\n",
310 MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength,
311 "Non paged pool region");
312 DPRINT1("0x%p - 0x%p\t%s\n",
313 MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize,
314 "Paged pool region");
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 ULONG_PTR
339 NTAPI
340 MiGetLastKernelAddress(VOID)
341 {
342 PLIST_ENTRY NextEntry;
343 PMEMORY_ALLOCATION_DESCRIPTOR Md;
344 ULONG_PTR LastKrnlPhysAddr = 0;
345
346 for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
347 NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
348 NextEntry = NextEntry->Flink)
349 {
350 Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
351
352 if (Md->MemoryType != LoaderFree &&
353 Md->MemoryType != LoaderFirmwareTemporary &&
354 Md->MemoryType != LoaderSpecialMemory)
355 {
356 if (Md->BasePage+Md->PageCount > LastKrnlPhysAddr)
357 LastKrnlPhysAddr = Md->BasePage+Md->PageCount;
358 }
359 }
360
361 /* Convert to a physical address */
362 return LastKrnlPhysAddr << PAGE_SHIFT;
363 }
364
365 VOID
366 INIT_FUNCTION
367 NTAPI
368 MmInit1(VOID)
369 {
370 PLDR_DATA_TABLE_ENTRY LdrEntry;
371 ULONG Dummy[2];
372
373 /* Dump memory descriptors */
374 if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
375
376 /* Set the page directory */
377 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = (ULONG)MmGetPageDirectory();
378
379 /* Get the size of FreeLDR's image allocations */
380 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
381 MmBootImageSize *= PAGE_SIZE;
382
383 /* Set memory limits */
384 MmSystemRangeStart = (PVOID)KSEG0_BASE;
385 MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
386 MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
387 DPRINT("MmSystemRangeStart: %08x\n", MmSystemRangeStart);
388 DPRINT("MmUserProbeAddress: %08x\n", MmUserProbeAddress);
389 DPRINT("MmHighestUserAddress:%08x\n", MmHighestUserAddress);
390
391 /* Initialize memory managment statistics */
392 RtlZeroMemory(&MmStats, sizeof(MmStats));
393
394 /* Count RAM */
395 MiCountFreePagesInLoaderBlock(KeLoaderBlock);
396 DbgPrint("Used memory %dKb\n", (MmNumberOfPhysicalPages * PAGE_SIZE) / 1024);
397
398 /* Initialize the kernel address space */
399 MmInitializeHandBuiltProcess(PsGetCurrentProcess(), Dummy);
400 MmKernelAddressSpace = MmGetCurrentAddressSpace();
401 MmInitGlobalKernelPageDirectory();
402
403 /* Get kernel address boundaries */
404 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
405 LDR_DATA_TABLE_ENTRY,
406 InLoadOrderLinks);
407 MiKSeg0Start = (ULONG_PTR)LdrEntry->DllBase | KSEG0_BASE;
408 MiKSeg0End = PAGE_ROUND_UP(MiGetLastKernelAddress() | KSEG0_BASE);
409
410 /* We'll put the PFN array right after the loaded modules */
411 MmPfnDatabase = (PVOID)MiKSeg0End;
412 MmPfnDatabaseEnd = (ULONG_PTR)MmPfnDatabase + (MmHighestPhysicalPage * sizeof(PHYSICAL_PAGE));
413 MmPfnDatabaseEnd = PAGE_ROUND_UP(MmPfnDatabaseEnd);
414
415 /*
416 * FreeLDR maps 6MB starting at the kernel base address, followed by the
417 * PFN database. If the PFN database doesn't go over the FreeLDR allocation
418 * then choose the end of the FreeLDR block. If it does go past the FreeLDR
419 * allocation, then choose the next PAGE_SIZE boundary.
420 */
421 if ((ULONG_PTR)MmPfnDatabaseEnd < (MiKSeg0Start + 0x600000))
422 {
423 /* Use the first memory following FreeLDR's 6MB mapping */
424 MiNonPagedPoolStart = (PVOID)((ULONG_PTR)MiKSeg0Start + 0x600000);
425 }
426 else
427 {
428 /* Use the next free available page */
429 MiNonPagedPoolStart = (PVOID)MmPfnDatabaseEnd;
430 }
431
432 /* Length of non-paged pool */
433 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
434
435 /* Put the paged pool after the non-paged pool */
436 MmPagedPoolBase = (PVOID)PAGE_ROUND_UP((ULONG_PTR)MiNonPagedPoolStart +
437 MiNonPagedPoolLength);
438 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
439
440 /* Dump kernel memory layout */
441 MiDbgKernelLayout();
442
443 /* Initialize the page list */
444 MmInitializePageList();
445
446 /* Unmap low memory */
447 MmDeletePageTable(NULL, 0);
448
449 /* Intialize memory areas */
450 MmInitVirtualMemory();
451
452 /* Initialize MDLs */
453 MmInitializeMdlImplementation();
454 }
455
456 BOOLEAN
457 NTAPI
458 MmInitSystem(IN ULONG Phase,
459 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
460 {
461 if (Phase == 0)
462 {
463 /* Initialize Mm bootstrap */
464 MmInit1();
465
466 /* Initialize the Loader Lock */
467 KeInitializeMutant(&MmSystemLoadLock, FALSE);
468
469 /* Reload boot drivers */
470 MiReloadBootLoadedDrivers(LoaderBlock);
471
472 /* Initialize the loaded module list */
473 MiInitializeLoadedModuleList(LoaderBlock);
474
475 /* We're done, for now */
476 DPRINT("Mm0: COMPLETE\n");
477 }
478 else if (Phase == 1)
479 {
480 MmInitializeRmapList();
481 MmInitializePageOp();
482 MmInitSectionImplementation();
483 MmInitPagingFile();
484 MmCreatePhysicalMemorySection();
485
486 /* Setup shared user data settings that NT does as well */
487 ASSERT(SharedUserData->NumberOfPhysicalPages == 0);
488 SharedUserData->NumberOfPhysicalPages = MmStats.NrTotalPages;
489 SharedUserData->LargePageMinimum = 0;
490
491 /* For now, we assume that we're always Workstation */
492 SharedUserData->NtProductType = NtProductWinNt;
493 }
494 else if (Phase == 2)
495 {
496 /*
497 * Unmap low memory
498 */
499 MiInitBalancerThread();
500
501 /*
502 * Initialise the modified page writer.
503 */
504 MmInitMpwThread();
505
506 /* Initialize the balance set manager */
507 MmInitBsmThread();
508
509 /* FIXME: Read parameters from memory */
510 }
511
512 return TRUE;
513 }
514
515
516 /* PUBLIC FUNCTIONS **********************************************************/
517
518 /*
519 * @implemented
520 */
521 BOOLEAN
522 NTAPI
523 MmIsThisAnNtAsSystem(VOID)
524 {
525 return IsThisAnNtAsSystem;
526 }
527
528 /*
529 * @implemented
530 */
531 MM_SYSTEMSIZE
532 NTAPI
533 MmQuerySystemSize(VOID)
534 {
535 return MmSystemSize;
536 }