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 ******************************************************************/
13 #include <internal/debug.h>
15 /* GLOBALS *******************************************************************/
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
;
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
=
70 /* PRIVATE FUNCTIONS *********************************************************/
74 MiShutdownMemoryManager(VOID
)
80 /* Ask MPW thread to shutdown */
81 MpwThreadShouldTerminate
= TRUE
;
82 KeSetEvent(&MpwThreadEvent
, IO_NO_INCREMENT
, FALSE
);
85 ObReferenceObjectByHandle(MpwThreadHandle
,
92 KeWaitForSingleObject(Thread
,
98 ObDereferenceObject(Thread
);
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
);
110 MmInitVirtualMemory()
115 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
118 BoundaryAddressMultiple
.QuadPart
= 0;
122 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
- 1,
123 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
- 1);
125 MiInitializeNonPagedPool();
128 * Setup the system area descriptor list
130 MiInitPageDirectoryMap();
132 BaseAddress
= (PVOID
)PCR
;
133 MmCreateMemoryArea(MmGetKernelAddressSpace(),
136 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
141 BoundaryAddressMultiple
);
143 /* Local APIC base */
144 BaseAddress
= (PVOID
)0xFEE00000;
145 MmCreateMemoryArea(MmGetKernelAddressSpace(),
153 BoundaryAddressMultiple
);
156 BaseAddress
= (PVOID
)0xFEC00000;
157 MmCreateMemoryArea(MmGetKernelAddressSpace(),
165 BoundaryAddressMultiple
);
167 BaseAddress
= (PVOID
)0xFF3A0000;
168 MmCreateMemoryArea(MmGetKernelAddressSpace(),
176 BoundaryAddressMultiple
);
178 BaseAddress
= MiNonPagedPoolStart
;
179 MmCreateMemoryArea(MmGetKernelAddressSpace(),
182 MiNonPagedPoolLength
,
187 BoundaryAddressMultiple
);
189 BaseAddress
= MmPagedPoolBase
;
190 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
191 MEMORY_AREA_PAGED_POOL
,
198 BoundaryAddressMultiple
);
200 MmInitializePagedPool();
203 * Create the kernel mapping of the user/kernel shared memory.
205 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
207 MmCreateMemoryArea(MmGetKernelAddressSpace(),
215 BoundaryAddressMultiple
);
217 /* Shared data are always located the next page after PCR */
218 MmSharedDataPagePhysicalAddress
= MmGetPhysicalAddress((PVOID
)PCR
);
219 MmSharedDataPagePhysicalAddress
.QuadPart
+= PAGE_SIZE
;
224 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
229 MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock
)
231 PLIST_ENTRY NextEntry
;
232 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
235 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
236 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
237 NextEntry
= NextEntry
->Flink
)
239 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
241 /* Skip invisible memory */
242 if ((Md
->MemoryType
!= LoaderFirmwarePermanent
) &&
243 (Md
->MemoryType
!= LoaderSpecialMemory
) &&
244 (Md
->MemoryType
!= LoaderHALCachedMemory
) &&
245 (Md
->MemoryType
!= LoaderBBTMemory
))
247 /* Check if BURNMEM was used */
248 if (Md
->MemoryType
!= LoaderBad
)
250 /* Count this in the total of pages */
251 MmNumberOfPhysicalPages
+= Md
->PageCount
;
254 /* Check if this is the new lowest page */
255 if (Md
->BasePage
< MmLowestPhysicalPage
)
257 /* Update the lowest page */
258 MmLowestPhysicalPage
= Md
->BasePage
;
261 /* Check if this is the new highest page */
262 if ((Md
->BasePage
+ Md
->PageCount
) > MmHighestPhysicalPage
)
264 /* Update the highest page */
265 MmHighestPhysicalPage
= Md
->BasePage
+ Md
->PageCount
- 1;
268 /* Check if this is free memory */
269 if ((Md
->MemoryType
== LoaderFree
) ||
270 (Md
->MemoryType
== LoaderLoadedProgram
) ||
271 (Md
->MemoryType
== LoaderFirmwareTemporary
) ||
272 (Md
->MemoryType
== LoaderOsloaderStack
))
274 /* Check if this is the largest memory descriptor */
275 if (Md
->PageCount
> FreePages
)
278 FreePages
= Md
->PageCount
;
279 MiFreeDescriptor
= Md
;
285 /* Save original values of the free descriptor, since it'll be
286 altered by early allocations */
287 MiFreeDescriptorOrg
= *MiFreeDescriptor
;
292 MiDbgKernelLayout(VOID
)
294 DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
295 DPRINT1("0x%p - 0x%p\t%s\n",
296 KSEG0_BASE
, MiKSeg0Start
,
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");
318 MiDbgDumpMemoryDescriptors(VOID
)
320 PLIST_ENTRY NextEntry
;
321 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
322 ULONG TotalPages
= 0;
324 DPRINT1("Base\t\tLength\t\tType\n");
325 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
326 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
327 NextEntry
= NextEntry
->Flink
)
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
;
334 DPRINT1("Total: %08lX (%d MB)\n", TotalPages
, (TotalPages
* PAGE_SIZE
) / 1024 / 1024);
339 MiGetLastKernelAddress(VOID
)
341 PLIST_ENTRY NextEntry
;
342 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
343 ULONG_PTR LastKrnlPhysAddr
= 0;
345 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
346 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
347 NextEntry
= NextEntry
->Flink
)
349 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
350 if (Md
->MemoryType
== LoaderBootDriver
||
351 Md
->MemoryType
== LoaderSystemCode
||
352 Md
->MemoryType
== LoaderHalCode
)
354 if (Md
->BasePage
+Md
->PageCount
> LastKrnlPhysAddr
)
355 LastKrnlPhysAddr
= Md
->BasePage
+Md
->PageCount
;
359 /* Convert to a physical address */
360 return LastKrnlPhysAddr
<< PAGE_SHIFT
;
368 PLDR_DATA_TABLE_ENTRY LdrEntry
;
370 /* Dump memory descriptors */
371 if (MiDbgEnableMdDump
) MiDbgDumpMemoryDescriptors();
373 /* Set the page directory */
374 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
.LowPart
= (ULONG
)MmGetPageDirectory();
376 /* Get the size of FreeLDR's image allocations */
377 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
;
378 MmBootImageSize
*= PAGE_SIZE
;
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
);
388 /* Initialize memory managment statistics */
389 RtlZeroMemory(&MmStats
, sizeof(MmStats
));
392 MiCountFreePagesInLoaderBlock(KeLoaderBlock
);
393 DbgPrint("Used memory %dKb\n", (MmNumberOfPhysicalPages
* PAGE_SIZE
) / 1024);
395 /* Initialize the kernel address space */
396 MmInitializeKernelAddressSpace();
397 MmInitGlobalKernelPageDirectory();
399 /* Get kernel address boundaries */
400 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
401 LDR_DATA_TABLE_ENTRY
,
403 MiKSeg0Start
= (ULONG_PTR
)LdrEntry
->DllBase
| KSEG0_BASE
;
404 MiKSeg0End
= PAGE_ROUND_UP(MiGetLastKernelAddress() | KSEG0_BASE
);
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
);
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.
417 if ((ULONG_PTR
)MmPfnDatabaseEnd
< (MiKSeg0Start
+ 0x600000))
419 /* Use the first memory following FreeLDR's 6MB mapping */
420 MiNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MiKSeg0Start
+ 0x600000);
424 /* Use the next free available page */
425 MiNonPagedPoolStart
= (PVOID
)MmPfnDatabaseEnd
;
428 /* Length of non-paged pool */
429 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
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 */
437 /* Initialize the page list */
438 MmInitializePageList();
439 /* Unmap low memory */
440 MmDeletePageTable(NULL
, 0);
442 /* Intialize memory areas */
443 MmInitVirtualMemory();
445 /* Initialize MDLs */
446 MmInitializeMdlImplementation();
451 MmInitSystem(IN ULONG Phase
,
452 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
457 /* Initialize Mm bootstrap */
460 /* Initialize the Loader Lock */
461 KeInitializeMutant(&MmSystemLoadLock
, FALSE
);
463 /* Initialize the address space for the system process */
464 MmInitializeProcessAddressSpace(PsGetCurrentProcess(),
470 /* Reload boot drivers */
471 MiReloadBootLoadedDrivers(LoaderBlock
);
473 /* Initialize the loaded module list */
474 MiInitializeLoadedModuleList(LoaderBlock
);
476 /* We're done, for now */
477 DPRINT("Mm0: COMPLETE\n");
481 MmInitializeRmapList();
482 MmInitializePageOp();
483 MmInitSectionImplementation();
485 MmCreatePhysicalMemorySection();
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;
492 /* For now, we assume that we're always Workstation */
493 SharedUserData
->NtProductType
= NtProductWinNt
;
500 MiInitBalancerThread();
503 * Initialise the modified page writer.
507 /* Initialize the balance set manager */
510 /* FIXME: Read parameters from memory */
517 /* PUBLIC FUNCTIONS **********************************************************/
524 MmIsThisAnNtAsSystem(VOID
)
526 return IsThisAnNtAsSystem
;
534 MmQuerySystemSize(VOID
)