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 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 ULONG MmUserProbeAddress
= 0;
59 PVOID MmHighestUserAddress
= NULL
;
60 PBOOLEAN Mm64BitPhysicalAddress
= FALSE
;
61 PVOID MmSystemRangeStart
= NULL
;
62 ULONG MmReadClusterSize
;
64 PMMSUPPORT MmKernelAddressSpace
;
65 extern KMUTANT MmSystemLoadLock
;
66 extern HANDLE MpwThreadHandle
;
67 extern BOOLEAN MpwThreadShouldTerminate
;
68 extern KEVENT MpwThreadEvent
;
69 BOOLEAN MiDbgEnableMdDump
=
76 /* PRIVATE FUNCTIONS *********************************************************/
80 MiShutdownMemoryManager(VOID
)
86 /* Ask MPW thread to shutdown */
87 MpwThreadShouldTerminate
= TRUE
;
88 KeSetEvent(&MpwThreadEvent
, IO_NO_INCREMENT
, FALSE
);
91 ObReferenceObjectByHandle(MpwThreadHandle
,
98 KeWaitForSingleObject(Thread
,
104 ObDereferenceObject(Thread
);
106 /* Check if there are any dirty pages, and flush them.
107 There will be no other chance to do this later, since filesystems
108 are going to be shut down. */
109 CcRosFlushDirtyPages(128, &PagesWritten
);
116 MiInitSystemMemoryAreas()
119 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
121 BoundaryAddressMultiple
.QuadPart
= 0;
124 // First initialize the page table and hyperspace memory areas
126 MiInitPageDirectoryMap();
131 BaseAddress
= (PVOID
)PCR
;
132 MmCreateMemoryArea(MmGetKernelAddressSpace(),
133 MEMORY_AREA_SYSTEM
| MEMORY_AREA_STATIC
,
135 PAGE_SIZE
* KeNumberProcessors
,
140 BoundaryAddressMultiple
);
143 // Now the KUSER_SHARED_DATA
145 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
146 MmCreateMemoryArea(MmGetKernelAddressSpace(),
147 MEMORY_AREA_SYSTEM
| MEMORY_AREA_STATIC
,
154 BoundaryAddressMultiple
);
159 MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock
)
161 PLIST_ENTRY NextEntry
;
162 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
165 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
166 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
167 NextEntry
= NextEntry
->Flink
)
169 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
171 /* Skip invisible memory */
172 if ((Md
->MemoryType
!= LoaderFirmwarePermanent
) &&
173 (Md
->MemoryType
!= LoaderSpecialMemory
) &&
174 (Md
->MemoryType
!= LoaderHALCachedMemory
) &&
175 (Md
->MemoryType
!= LoaderBBTMemory
))
177 /* Check if BURNMEM was used */
178 if (Md
->MemoryType
!= LoaderBad
)
180 /* Count this in the total of pages */
181 MmNumberOfPhysicalPages
+= Md
->PageCount
;
184 /* Check if this is the new lowest page */
185 if (Md
->BasePage
< MmLowestPhysicalPage
)
187 /* Update the lowest page */
188 MmLowestPhysicalPage
= Md
->BasePage
;
191 /* Check if this is the new highest page */
192 if ((Md
->BasePage
+ Md
->PageCount
) > MmHighestPhysicalPage
)
194 /* Update the highest page */
195 MmHighestPhysicalPage
= Md
->BasePage
+ Md
->PageCount
- 1;
198 /* Check if this is free memory */
199 if ((Md
->MemoryType
== LoaderFree
) ||
200 (Md
->MemoryType
== LoaderLoadedProgram
) ||
201 (Md
->MemoryType
== LoaderFirmwareTemporary
) ||
202 (Md
->MemoryType
== LoaderOsloaderStack
))
204 /* Check if this is the largest memory descriptor */
205 if (Md
->PageCount
> FreePages
)
208 FreePages
= Md
->PageCount
;
209 MiFreeDescriptor
= Md
;
215 /* Save original values of the free descriptor, since it'll be
216 altered by early allocations */
217 MiFreeDescriptorOrg
= *MiFreeDescriptor
;
222 MiDbgKernelLayout(VOID
)
224 DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
225 DPRINT1("0x%p - 0x%p\t%s\n",
226 KSEG0_BASE
, MiKSeg0Start
,
228 DPRINT1("0x%p - 0x%p\t%s\n",
229 MiKSeg0Start
, MiKSeg0End
,
230 "FreeLDR Kernel mapping region");
231 DPRINT1("0x%p - 0x%p\t%s\n",
232 MmPfnDatabase
, MmPfnDatabaseEnd
,
233 "PFN Database region");
234 if (MmPfnDatabaseEnd
!= (ULONG_PTR
)MiNonPagedPoolStart
)
235 DPRINT1("0x%p - 0x%p\t%s\n",
236 MmPfnDatabaseEnd
, MiNonPagedPoolStart
,
237 "Remaining FreeLDR mapping");
238 DPRINT1("0x%p - 0x%p\t%s\n",
239 MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
,
240 "Non paged pool region");
241 DPRINT1("0x%p - 0x%p\t%s\n",
242 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
,
243 "Paged pool region");
248 MiDbgDumpMemoryDescriptors(VOID
)
250 PLIST_ENTRY NextEntry
;
251 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
252 ULONG TotalPages
= 0;
254 DPRINT1("Base\t\tLength\t\tType\n");
255 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
256 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
257 NextEntry
= NextEntry
->Flink
)
259 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
260 DPRINT1("%08lX\t%08lX\t%s\n", Md
->BasePage
, Md
->PageCount
, MemType
[Md
->MemoryType
]);
261 TotalPages
+= Md
->PageCount
;
264 DPRINT1("Total: %08lX (%d MB)\n", TotalPages
, (TotalPages
* PAGE_SIZE
) / 1024 / 1024);
269 MiGetLastKernelAddress(VOID
)
271 PLIST_ENTRY NextEntry
;
272 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
273 ULONG_PTR LastKrnlPhysAddr
= 0;
275 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
276 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
277 NextEntry
= NextEntry
->Flink
)
279 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
281 if (Md
->MemoryType
!= LoaderFree
&&
282 Md
->MemoryType
!= LoaderFirmwareTemporary
&&
283 Md
->MemoryType
!= LoaderSpecialMemory
)
285 if (Md
->BasePage
+Md
->PageCount
> LastKrnlPhysAddr
)
286 LastKrnlPhysAddr
= Md
->BasePage
+Md
->PageCount
;
290 /* Convert to a physical address */
291 return LastKrnlPhysAddr
<< PAGE_SHIFT
;
297 MiInitHyperSpace(VOID
);
301 MmArmInitSystem(IN ULONG Phase
,
302 IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
309 PLDR_DATA_TABLE_ENTRY LdrEntry
;
312 /* Dump memory descriptors */
313 if (MiDbgEnableMdDump
) MiDbgDumpMemoryDescriptors();
315 /* Get the size of FreeLDR's image allocations */
316 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
;
317 MmBootImageSize
*= PAGE_SIZE
;
319 /* Set memory limits */
320 MmSystemRangeStart
= (PVOID
)KSEG0_BASE
;
321 MmUserProbeAddress
= (ULONG_PTR
)MmSystemRangeStart
- 0x10000;
322 MmHighestUserAddress
= (PVOID
)(MmUserProbeAddress
- 1);
323 DPRINT("MmSystemRangeStart: %08x\n", MmSystemRangeStart
);
324 DPRINT("MmUserProbeAddress: %08x\n", MmUserProbeAddress
);
325 DPRINT("MmHighestUserAddress:%08x\n", MmHighestUserAddress
);
327 /* Initialize memory managment statistics */
328 RtlZeroMemory(&MmStats
, sizeof(MmStats
));
331 MiCountFreePagesInLoaderBlock(KeLoaderBlock
);
332 DbgPrint("Used memory %dKb\n", (MmNumberOfPhysicalPages
* PAGE_SIZE
) / 1024);
334 /* Initialize the kernel address space */
335 MmInitializeHandBuiltProcess(PsGetCurrentProcess(), Dummy
);
336 MmKernelAddressSpace
= MmGetCurrentAddressSpace();
337 MmInitGlobalKernelPageDirectory();
339 /* Get kernel address boundaries */
340 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
341 LDR_DATA_TABLE_ENTRY
,
343 MiKSeg0Start
= (ULONG_PTR
)LdrEntry
->DllBase
| KSEG0_BASE
;
344 MiKSeg0End
= PAGE_ROUND_UP(MiGetLastKernelAddress() | KSEG0_BASE
);
346 /* We'll put the PFN array right after the loaded modules */
347 MmPfnDatabase
= (PVOID
)MiKSeg0End
;
348 MmPfnDatabaseEnd
= (ULONG_PTR
)MmPfnDatabase
+ (MmHighestPhysicalPage
* sizeof(MMPFN
));
349 MmPfnDatabaseEnd
= PAGE_ROUND_UP(MmPfnDatabaseEnd
);
352 * FreeLDR maps 6MB starting at the kernel base address, followed by the
353 * PFN database. If the PFN database doesn't go over the FreeLDR allocation
354 * then choose the end of the FreeLDR block. If it does go past the FreeLDR
355 * allocation, then choose the next PAGE_SIZE boundary.
357 if ((ULONG_PTR
)MmPfnDatabaseEnd
< (MiKSeg0Start
+ 0x600000))
359 /* Use the first memory following FreeLDR's 6MB mapping */
360 MiNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MiKSeg0Start
+ 0x600000);
364 /* Use the next free available page */
365 MiNonPagedPoolStart
= (PVOID
)MmPfnDatabaseEnd
;
368 /* Length of non-paged pool */
369 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
371 /* Put the paged pool after the non-paged pool */
372 MmPagedPoolBase
= (PVOID
)PAGE_ROUND_UP((ULONG_PTR
)MiNonPagedPoolStart
+
373 MiNonPagedPoolLength
);
374 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
376 /* Dump kernel memory layout */
379 /* Intialize system memory areas */
380 MiInitSystemMemoryAreas();
382 /* Initialize the page list */
383 MmInitializePageList();
386 // Initialize ARMĀ³ in phase 0
388 MmArmInitSystem(0, KeLoaderBlock
);
390 /* Initialize nonpaged pool */
391 MiInitializeNonPagedPool();
393 /* Initialize paged pool */
394 MmInitializePagedPool();
396 /* Initialize working sets */
397 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
400 // Initialize ARMĀ³ in phase 1
402 MmArmInitSystem(1, KeLoaderBlock
);
407 MmInitSystem(IN ULONG Phase
,
408 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
412 /* Initialize Mm bootstrap */
415 /* Initialize the Loader Lock */
416 KeInitializeMutant(&MmSystemLoadLock
, FALSE
);
418 /* Reload boot drivers */
419 MiReloadBootLoadedDrivers(LoaderBlock
);
421 /* Initialize the loaded module list */
422 MiInitializeLoadedModuleList(LoaderBlock
);
424 /* We're done, for now */
425 DPRINT("Mm0: COMPLETE\n");
429 MmInitializeRmapList();
430 MmInitializePageOp();
431 MmInitSectionImplementation();
433 MmCreatePhysicalMemorySection();
435 /* Setup shared user data settings that NT does as well */
436 ASSERT(SharedUserData
->NumberOfPhysicalPages
== 0);
437 SharedUserData
->NumberOfPhysicalPages
= MmStats
.NrTotalPages
;
438 SharedUserData
->LargePageMinimum
= 0;
440 /* For now, we assume that we're always Workstation */
441 SharedUserData
->NtProductType
= NtProductWinNt
;
448 MiInitBalancerThread();
451 * Initialise the modified page writer.
455 /* Initialize the balance set manager */
458 /* FIXME: Read parameters from memory */
465 /* PUBLIC FUNCTIONS **********************************************************/
472 MmIsThisAnNtAsSystem(VOID
)
474 return IsThisAnNtAsSystem
;
482 MmQuerySystemSize(VOID
)