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