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;
121 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
- 1,
122 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
- 1);
124 MiInitializeNonPagedPool();
127 * Setup the system area descriptor list
129 MiInitPageDirectoryMap();
131 BaseAddress
= (PVOID
)PCR
;
132 MmCreateMemoryArea(MmGetKernelAddressSpace(),
135 PAGE_SIZE
* KeNumberProcessors
,
140 BoundaryAddressMultiple
);
143 /* Local APIC base */
144 BaseAddress
= (PVOID
)0xFEE00000;
145 MmCreateMemoryArea(MmGetKernelAddressSpace(),
153 BoundaryAddressMultiple
);
156 BaseAddress
= (PVOID
)0xFEC00000;
157 MmCreateMemoryArea(MmGetKernelAddressSpace(),
165 BoundaryAddressMultiple
);
168 BaseAddress
= MiNonPagedPoolStart
;
169 MmCreateMemoryArea(MmGetKernelAddressSpace(),
172 MiNonPagedPoolLength
,
177 BoundaryAddressMultiple
);
179 BaseAddress
= MmPagedPoolBase
;
180 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
181 MEMORY_AREA_PAGED_POOL
,
188 BoundaryAddressMultiple
);
190 MmInitializePagedPool();
193 * Create the kernel mapping of the user/kernel shared memory.
195 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
197 MmCreateMemoryArea(MmGetKernelAddressSpace(),
205 BoundaryAddressMultiple
);
207 /* Shared data are always located the next page after PCR */
208 MmSharedDataPagePhysicalAddress
= MmGetPhysicalAddress((PVOID
)PCR
);
209 MmSharedDataPagePhysicalAddress
.QuadPart
+= PAGE_SIZE
;
214 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
219 MiCountFreePagesInLoaderBlock(PLOADER_PARAMETER_BLOCK LoaderBlock
)
221 PLIST_ENTRY NextEntry
;
222 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
225 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
226 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
227 NextEntry
= NextEntry
->Flink
)
229 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
231 /* Skip invisible memory */
232 if ((Md
->MemoryType
!= LoaderFirmwarePermanent
) &&
233 (Md
->MemoryType
!= LoaderSpecialMemory
) &&
234 (Md
->MemoryType
!= LoaderHALCachedMemory
) &&
235 (Md
->MemoryType
!= LoaderBBTMemory
))
237 /* Check if BURNMEM was used */
238 if (Md
->MemoryType
!= LoaderBad
)
240 /* Count this in the total of pages */
241 MmNumberOfPhysicalPages
+= Md
->PageCount
;
244 /* Check if this is the new lowest page */
245 if (Md
->BasePage
< MmLowestPhysicalPage
)
247 /* Update the lowest page */
248 MmLowestPhysicalPage
= Md
->BasePage
;
251 /* Check if this is the new highest page */
252 if ((Md
->BasePage
+ Md
->PageCount
) > MmHighestPhysicalPage
)
254 /* Update the highest page */
255 MmHighestPhysicalPage
= Md
->BasePage
+ Md
->PageCount
- 1;
258 /* Check if this is free memory */
259 if ((Md
->MemoryType
== LoaderFree
) ||
260 (Md
->MemoryType
== LoaderLoadedProgram
) ||
261 (Md
->MemoryType
== LoaderFirmwareTemporary
) ||
262 (Md
->MemoryType
== LoaderOsloaderStack
))
264 /* Check if this is the largest memory descriptor */
265 if (Md
->PageCount
> FreePages
)
268 FreePages
= Md
->PageCount
;
269 MiFreeDescriptor
= Md
;
275 /* Save original values of the free descriptor, since it'll be
276 altered by early allocations */
277 MiFreeDescriptorOrg
= *MiFreeDescriptor
;
282 MiDbgKernelLayout(VOID
)
284 DPRINT1("%8s%12s\t\t%s\n", "Start", "End", "Type");
285 DPRINT1("0x%p - 0x%p\t%s\n",
286 KSEG0_BASE
, MiKSeg0Start
,
288 DPRINT1("0x%p - 0x%p\t%s\n",
289 MiKSeg0Start
, MiKSeg0End
,
290 "FreeLDR Kernel mapping region");
291 DPRINT1("0x%p - 0x%p\t%s\n",
292 MmPfnDatabase
, MmPfnDatabaseEnd
,
293 "PFN Database region");
294 if (MmPfnDatabaseEnd
!= (ULONG_PTR
)MiNonPagedPoolStart
)
295 DPRINT1("0x%p - 0x%p\t%s\n",
296 MmPfnDatabaseEnd
, MiNonPagedPoolStart
,
297 "Remaining FreeLDR mapping");
298 DPRINT1("0x%p - 0x%p\t%s\n",
299 MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
,
300 "Non paged pool region");
301 DPRINT1("0x%p - 0x%p\t%s\n",
302 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
,
303 "Paged pool region");
308 MiDbgDumpMemoryDescriptors(VOID
)
310 PLIST_ENTRY NextEntry
;
311 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
312 ULONG TotalPages
= 0;
314 DPRINT1("Base\t\tLength\t\tType\n");
315 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
316 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
317 NextEntry
= NextEntry
->Flink
)
319 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
320 DPRINT1("%08lX\t%08lX\t%s\n", Md
->BasePage
, Md
->PageCount
, MemType
[Md
->MemoryType
]);
321 TotalPages
+= Md
->PageCount
;
324 DPRINT1("Total: %08lX (%d MB)\n", TotalPages
, (TotalPages
* PAGE_SIZE
) / 1024 / 1024);
329 MiGetLastKernelAddress(VOID
)
331 PLIST_ENTRY NextEntry
;
332 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
333 ULONG_PTR LastKrnlPhysAddr
= 0;
335 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
336 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
337 NextEntry
= NextEntry
->Flink
)
339 Md
= CONTAINING_RECORD(NextEntry
, MEMORY_ALLOCATION_DESCRIPTOR
, ListEntry
);
341 if (Md
->MemoryType
!= LoaderFree
&&
342 Md
->MemoryType
!= LoaderFirmwareTemporary
&&
343 Md
->MemoryType
!= LoaderSpecialMemory
)
345 if (Md
->BasePage
+Md
->PageCount
> LastKrnlPhysAddr
)
346 LastKrnlPhysAddr
= Md
->BasePage
+Md
->PageCount
;
350 /* Convert to a physical address */
351 return LastKrnlPhysAddr
<< PAGE_SHIFT
;
357 MiInitHyperSpace(VOID
);
364 PLDR_DATA_TABLE_ENTRY LdrEntry
;
367 /* Dump memory descriptors */
368 if (MiDbgEnableMdDump
) MiDbgDumpMemoryDescriptors();
370 /* Set the page directory */
371 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = (ULONG_PTR
)MmGetPageDirectory();
373 /* Get the size of FreeLDR's image allocations */
374 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
;
375 MmBootImageSize
*= PAGE_SIZE
;
377 /* Set memory limits */
378 MmSystemRangeStart
= (PVOID
)KSEG0_BASE
;
379 MmUserProbeAddress
= (ULONG_PTR
)MmSystemRangeStart
- 0x10000;
380 MmHighestUserAddress
= (PVOID
)(MmUserProbeAddress
- 1);
381 DPRINT("MmSystemRangeStart: %08x\n", MmSystemRangeStart
);
382 DPRINT("MmUserProbeAddress: %08x\n", MmUserProbeAddress
);
383 DPRINT("MmHighestUserAddress:%08x\n", MmHighestUserAddress
);
385 /* Initialize memory managment statistics */
386 RtlZeroMemory(&MmStats
, sizeof(MmStats
));
389 MiCountFreePagesInLoaderBlock(KeLoaderBlock
);
390 DbgPrint("Used memory %dKb\n", (MmNumberOfPhysicalPages
* PAGE_SIZE
) / 1024);
392 /* Initialize the kernel address space */
393 MmInitializeHandBuiltProcess(PsGetCurrentProcess(), Dummy
);
394 MmKernelAddressSpace
= MmGetCurrentAddressSpace();
395 MmInitGlobalKernelPageDirectory();
397 /* Get kernel address boundaries */
398 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
399 LDR_DATA_TABLE_ENTRY
,
401 MiKSeg0Start
= (ULONG_PTR
)LdrEntry
->DllBase
| KSEG0_BASE
;
402 MiKSeg0End
= PAGE_ROUND_UP(MiGetLastKernelAddress() | KSEG0_BASE
);
404 /* We'll put the PFN array right after the loaded modules */
405 MmPfnDatabase
= (PVOID
)MiKSeg0End
;
406 MmPfnDatabaseEnd
= (ULONG_PTR
)MmPfnDatabase
+ (MmHighestPhysicalPage
* sizeof(PHYSICAL_PAGE
));
407 MmPfnDatabaseEnd
= PAGE_ROUND_UP(MmPfnDatabaseEnd
);
410 * FreeLDR maps 6MB starting at the kernel base address, followed by the
411 * PFN database. If the PFN database doesn't go over the FreeLDR allocation
412 * then choose the end of the FreeLDR block. If it does go past the FreeLDR
413 * allocation, then choose the next PAGE_SIZE boundary.
415 if ((ULONG_PTR
)MmPfnDatabaseEnd
< (MiKSeg0Start
+ 0x600000))
417 /* Use the first memory following FreeLDR's 6MB mapping */
418 MiNonPagedPoolStart
= (PVOID
)((ULONG_PTR
)MiKSeg0Start
+ 0x600000);
422 /* Use the next free available page */
423 MiNonPagedPoolStart
= (PVOID
)MmPfnDatabaseEnd
;
426 /* Length of non-paged pool */
427 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
429 /* Put the paged pool after the non-paged pool */
430 MmPagedPoolBase
= (PVOID
)PAGE_ROUND_UP((ULONG_PTR
)MiNonPagedPoolStart
+
431 MiNonPagedPoolLength
);
432 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
434 /* Dump kernel memory layout */
437 /* Initialize hyperspace */
440 /* Initialize the page list */
441 MmInitializePageList();
443 /* Unmap low memory */
444 MmDeletePageTable(NULL
, 0);
446 /* Intialize memory areas */
447 MmInitVirtualMemory();
449 /* Initialize MDLs */
450 MmInitializeMdlImplementation();
455 MmInitSystem(IN ULONG Phase
,
456 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
460 /* Initialize Mm bootstrap */
463 /* Initialize the Loader Lock */
464 KeInitializeMutant(&MmSystemLoadLock
, FALSE
);
466 /* Reload boot drivers */
467 MiReloadBootLoadedDrivers(LoaderBlock
);
469 /* Initialize the loaded module list */
470 MiInitializeLoadedModuleList(LoaderBlock
);
472 /* We're done, for now */
473 DPRINT("Mm0: COMPLETE\n");
477 MmInitializeRmapList();
478 MmInitializePageOp();
479 MmInitSectionImplementation();
481 MmCreatePhysicalMemorySection();
483 /* Setup shared user data settings that NT does as well */
484 ASSERT(SharedUserData
->NumberOfPhysicalPages
== 0);
485 SharedUserData
->NumberOfPhysicalPages
= MmStats
.NrTotalPages
;
486 SharedUserData
->LargePageMinimum
= 0;
488 /* For now, we assume that we're always Workstation */
489 SharedUserData
->NtProductType
= NtProductWinNt
;
496 MiInitBalancerThread();
499 * Initialise the modified page writer.
503 /* Initialize the balance set manager */
506 /* FIXME: Read parameters from memory */
513 /* PUBLIC FUNCTIONS **********************************************************/
520 MmIsThisAnNtAsSystem(VOID
)
522 return IsThisAnNtAsSystem
;
530 MmQuerySystemSize(VOID
)