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