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
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
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
;
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
=
71 /* PRIVATE FUNCTIONS *********************************************************/
75 MiShutdownMemoryManager(VOID
)
81 /* Ask MPW thread to shutdown */
82 MpwThreadShouldTerminate
= TRUE
;
83 KeSetEvent(&MpwThreadEvent
, IO_NO_INCREMENT
, FALSE
);
86 ObReferenceObjectByHandle(MpwThreadHandle
,
93 KeWaitForSingleObject(Thread
,
99 ObDereferenceObject(Thread
);
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
);
111 MmInitVirtualMemory()
116 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
119 BoundaryAddressMultiple
.QuadPart
= 0;
123 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
- 1,
124 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
- 1);
126 MiInitializeNonPagedPool();
129 * Setup the system area descriptor list
131 MiInitPageDirectoryMap();
133 BaseAddress
= (PVOID
)PCR
;
134 MmCreateMemoryArea(MmGetKernelAddressSpace(),
137 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
142 BoundaryAddressMultiple
);
144 /* Local APIC base */
145 BaseAddress
= (PVOID
)0xFEE00000;
146 MmCreateMemoryArea(MmGetKernelAddressSpace(),
154 BoundaryAddressMultiple
);
157 BaseAddress
= (PVOID
)0xFEC00000;
158 MmCreateMemoryArea(MmGetKernelAddressSpace(),
166 BoundaryAddressMultiple
);
168 BaseAddress
= (PVOID
)0xFF3A0000;
169 MmCreateMemoryArea(MmGetKernelAddressSpace(),
177 BoundaryAddressMultiple
);
179 BaseAddress
= MiNonPagedPoolStart
;
180 MmCreateMemoryArea(MmGetKernelAddressSpace(),
183 MiNonPagedPoolLength
,
188 BoundaryAddressMultiple
);
190 BaseAddress
= MmPagedPoolBase
;
191 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
192 MEMORY_AREA_PAGED_POOL
,
199 BoundaryAddressMultiple
);
201 MmInitializePagedPool();
204 * Create the kernel mapping of the user/kernel shared memory.
206 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
208 MmCreateMemoryArea(MmGetKernelAddressSpace(),
216 BoundaryAddressMultiple
);
218 /* Shared data are always located the next page after PCR */
219 MmSharedDataPagePhysicalAddress
= MmGetPhysicalAddress((PVOID
)PCR
);
220 MmSharedDataPagePhysicalAddress
.QuadPart
+= PAGE_SIZE
;
225 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
230 MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock
)
232 PLIST_ENTRY NextEntry
;
233 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
236 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
237 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
238 NextEntry
= NextEntry
->Flink
)
240 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
242 /* Skip invisible memory */
243 if ((Md
->MemoryType
!= LoaderFirmwarePermanent
) &&
244 (Md
->MemoryType
!= LoaderSpecialMemory
) &&
245 (Md
->MemoryType
!= LoaderHALCachedMemory
) &&
246 (Md
->MemoryType
!= LoaderBBTMemory
))
248 /* Check if BURNMEM was used */
249 if (Md
->MemoryType
!= LoaderBad
)
251 /* Count this in the total of pages */
252 MmNumberOfPhysicalPages
+= Md
->PageCount
;
255 /* Check if this is the new lowest page */
256 if (Md
->BasePage
< MmLowestPhysicalPage
)
258 /* Update the lowest page */
259 MmLowestPhysicalPage
= Md
->BasePage
;
262 /* Check if this is the new highest page */
263 if ((Md
->BasePage
+ Md
->PageCount
) > MmHighestPhysicalPage
)
265 /* Update the highest page */
266 MmHighestPhysicalPage
= Md
->BasePage
+ Md
->PageCount
- 1;
269 /* Check if this is free memory */
270 if ((Md
->MemoryType
== LoaderFree
) ||
271 (Md
->MemoryType
== LoaderLoadedProgram
) ||
272 (Md
->MemoryType
== LoaderFirmwareTemporary
) ||
273 (Md
->MemoryType
== LoaderOsloaderStack
))
275 /* Check if this is the largest memory descriptor */
276 if (Md
->PageCount
> FreePages
)
279 FreePages
= Md
->PageCount
;
280 MiFreeDescriptor
= Md
;
286 /* Save original values of the free descriptor, since it'll be
287 altered by early allocations */
288 MiFreeDescriptorOrg
= *MiFreeDescriptor
;
293 MiDbgKernelLayout(VOID
)
295 DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
296 DPRINT1("0x%p - 0x%p\t%s\n",
297 KSEG0_BASE
, MiKSeg0Start
,
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");
319 MiDbgDumpMemoryDescriptors(VOID
)
321 PLIST_ENTRY NextEntry
;
322 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
323 ULONG TotalPages
= 0;
325 DPRINT1("Base\t\tLength\t\tType\n");
326 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
327 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
328 NextEntry
= NextEntry
->Flink
)
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
;
335 DPRINT1("Total: %08lX (%d MB)\n", TotalPages
, (TotalPages
* PAGE_SIZE
) / 1024 / 1024);
340 MiGetLastKernelAddress(VOID
)
342 PLIST_ENTRY NextEntry
;
343 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
344 ULONG_PTR LastKrnlPhysAddr
= 0;
346 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
347 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
348 NextEntry
= NextEntry
->Flink
)
350 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
352 if (Md
->MemoryType
!= LoaderFree
&&
353 Md
->MemoryType
!= LoaderFirmwareTemporary
&&
354 Md
->MemoryType
!= LoaderSpecialMemory
)
356 if (Md
->BasePage
+Md
->PageCount
> LastKrnlPhysAddr
)
357 LastKrnlPhysAddr
= Md
->BasePage
+Md
->PageCount
;
361 /* Convert to a physical address */
362 return LastKrnlPhysAddr
<< PAGE_SHIFT
;
370 PLDR_DATA_TABLE_ENTRY LdrEntry
;
373 /* Dump memory descriptors */
374 if (MiDbgEnableMdDump
) MiDbgDumpMemoryDescriptors();
376 /* Set the page directory */
377 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = (ULONG
)MmGetPageDirectory();
379 /* Get the size of FreeLDR's image allocations */
380 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
;
381 MmBootImageSize
*= PAGE_SIZE
;
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
);
391 /* Initialize memory managment statistics */
392 RtlZeroMemory(&MmStats
, sizeof(MmStats
));
395 MiCountFreePagesInLoaderBlock(KeLoaderBlock
);
396 DbgPrint("Used memory %dKb\n", (MmNumberOfPhysicalPages
* PAGE_SIZE
) / 1024);
398 /* Initialize the kernel address space */
399 MmInitializeHandBuiltProcess(PsGetCurrentProcess(), Dummy
);
400 MmKernelAddressSpace
= MmGetCurrentAddressSpace();
401 MmInitGlobalKernelPageDirectory();
403 /* Get kernel address boundaries */
404 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
405 LDR_DATA_TABLE_ENTRY
,
407 MiKSeg0Start
= (ULONG_PTR
)LdrEntry
->DllBase
| KSEG0_BASE
;
408 MiKSeg0End
= PAGE_ROUND_UP(MiGetLastKernelAddress() | KSEG0_BASE
);
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
);
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.
421 if ((ULONG_PTR
)MmPfnDatabaseEnd
< (MiKSeg0Start
+ 0x600000))
423 /* Use the first memory following FreeLDR's 6MB mapping */
424 MiNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MiKSeg0Start
+ 0x600000);
428 /* Use the next free available page */
429 MiNonPagedPoolStart
= (PVOID
)MmPfnDatabaseEnd
;
432 /* Length of non-paged pool */
433 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
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
;
440 /* Dump kernel memory layout */
443 /* Initialize the page list */
444 MmInitializePageList();
446 /* Unmap low memory */
447 MmDeletePageTable(NULL
, 0);
449 /* Intialize memory areas */
450 MmInitVirtualMemory();
452 /* Initialize MDLs */
453 MmInitializeMdlImplementation();
458 MmInitSystem(IN ULONG Phase
,
459 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
463 /* Initialize Mm bootstrap */
466 /* Initialize the Loader Lock */
467 KeInitializeMutant(&MmSystemLoadLock
, FALSE
);
469 /* Reload boot drivers */
470 MiReloadBootLoadedDrivers(LoaderBlock
);
472 /* Initialize the loaded module list */
473 MiInitializeLoadedModuleList(LoaderBlock
);
475 /* We're done, for now */
476 DPRINT("Mm0: COMPLETE\n");
480 MmInitializeRmapList();
481 MmInitializePageOp();
482 MmInitSectionImplementation();
484 MmCreatePhysicalMemorySection();
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;
491 /* For now, we assume that we're always Workstation */
492 SharedUserData
->NtProductType
= NtProductWinNt
;
499 MiInitBalancerThread();
502 * Initialise the modified page writer.
506 /* Initialize the balance set manager */
509 /* FIXME: Read parameters from memory */
516 /* PUBLIC FUNCTIONS **********************************************************/
523 MmIsThisAnNtAsSystem(VOID
)
525 return IsThisAnNtAsSystem
;
533 MmQuerySystemSize(VOID
)