2 * COPYRIGHT: GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/amd64/init.c
5 * PURPOSE: Memory Manager Initialization for amd64
7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
8 * ReactOS Portable Systems Group
11 /* INCLUDES ***************************************************************/
17 #include "../ARM3/miarm.h"
20 extern PMMPTE MmDebugPte
;
25 HalInitializeBios(ULONG Unknown
, PLOADER_PARAMETER_BLOCK LoaderBlock
);
27 /* GLOBALS *****************************************************************/
29 /* Template PTE and PDE for a kernel page */
30 MMPTE ValidKernelPde
= {.u
.Hard
.Valid
= 1, .u
.Hard
.Write
= 1, .u
.Hard
.Dirty
= 1, .u
.Hard
.Accessed
= 1};
31 MMPTE ValidKernelPte
= {.u
.Hard
.Valid
= 1, .u
.Hard
.Write
= 1, .u
.Hard
.Dirty
= 1, .u
.Hard
.Accessed
= 1};
32 MMPDE DemandZeroPde
= {.u
.Long
= (MM_READWRITE
<< MM_PTE_SOFTWARE_PROTECTION_BITS
)};
33 MMPTE PrototypePte
= {.u
.Long
= (MM_READWRITE
<< MM_PTE_SOFTWARE_PROTECTION_BITS
) | PTE_PROTOTYPE
| 0xFFFFF000};
36 ///SIZE_T MmSessionSize = MI_SESSION_SIZE;
37 SIZE_T MmSessionViewSize
= MI_SESSION_VIEW_SIZE
;
38 SIZE_T MmSessionPoolSize
= MI_SESSION_POOL_SIZE
;
39 SIZE_T MmSessionImageSize
= MI_SESSION_IMAGE_SIZE
;
40 SIZE_T MmSystemViewSize
= MI_SYSTEM_VIEW_SIZE
;
41 SIZE_T MiNonPagedSystemSize
;
44 ULONG64 MmUserProbeAddress
= 0x7FFFFFF0000ULL
;
45 PVOID MmHighestUserAddress
= (PVOID
)0x7FFFFFEFFFFULL
;
46 PVOID MmSystemRangeStart
= (PVOID
)0xFFFF080000000000ULL
;
47 PVOID MmSessionBase
; // FFFFF90000000000 = MiSessionPoolStart
48 PVOID MiSessionPoolStart
; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
49 PVOID MiSessionPoolEnd
; // = MiSessionViewStart
50 PVOID MiSessionViewStart
; // = MiSessionViewEnd - MmSessionViewSize
51 PVOID MiSessionViewEnd
; // FFFFF97FFF000000
52 PVOID MiSessionImageStart
; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
53 PVOID MiSessionImageEnd
; // FFFFF98000000000 = MiSessionSpaceEnd
54 PVOID MiSessionSpaceEnd
= MI_SESSION_SPACE_END
; // FFFFF98000000000
55 PVOID MmSystemCacheStart
; // FFFFF98000000000
56 PVOID MmSystemCacheEnd
; // FFFFFA8000000000
57 /// PVOID MmPagedPoolStart = MI_PAGED_POOL_START; // FFFFFA8000000000
58 PVOID MmPagedPoolEnd
; // FFFFFAA000000000
59 PVOID MiSystemViewStart
;
60 PVOID MmNonPagedSystemStart
; // FFFFFAA000000000
61 PVOID MmNonPagedPoolStart
;
62 PVOID MmNonPagedPoolExpansionStart
;
63 ///PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; // 0xFFFFFAE000000000
64 PVOID MmHyperSpaceEnd
= (PVOID
)HYPER_SPACE_END
;
66 MMSUPPORT MmSystemCacheWs
;
68 ULONG64 MxPfnSizeInBytes
;
70 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor
;
71 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor
;
72 ULONG MiNumberDescriptors
= 0;
73 PFN_NUMBER MiSystemPages
= 0;
74 BOOLEAN MiIncludeType
[LoaderMaximum
];
76 PFN_NUMBER MxFreePageBase
;
77 ULONG64 MxFreePageCount
= 0;
79 extern PFN_NUMBER MmSystemPageDirectory
[PD_COUNT
];
81 BOOLEAN MiPfnsInitialized
= FALSE
;
83 /* FUNCTIONS *****************************************************************/
86 NoDbgPrint(const char *Format
, ...)
93 MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
95 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
96 PLIST_ENTRY ListEntry
;
100 /* Get the size of the boot loader's image allocations */
101 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
* PAGE_SIZE
;
102 MmBootImageSize
= ROUND_UP(MmBootImageSize
, 4 * 1024 * 1024);
104 /* Instantiate memory that we don't consider RAM/usable */
105 for (i
= 0; i
< LoaderMaximum
; i
++) MiIncludeType
[i
] = TRUE
;
106 MiIncludeType
[LoaderBad
] = FALSE
;
107 MiIncludeType
[LoaderFirmwarePermanent
] = FALSE
;
108 MiIncludeType
[LoaderSpecialMemory
] = FALSE
;
109 MiIncludeType
[LoaderBBTMemory
] = FALSE
;
111 /* Loop the memory descriptors */
112 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
113 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
114 ListEntry
= ListEntry
->Flink
)
116 /* Get the memory descriptor */
117 Descriptor
= CONTAINING_RECORD(ListEntry
,
118 MEMORY_ALLOCATION_DESCRIPTOR
,
122 MiNumberDescriptors
++;
124 /* Skip pages that are not part of the PFN database */
125 if (!MiIncludeType
[Descriptor
->MemoryType
])
130 /* Add this to the total of pages */
131 MmNumberOfPhysicalPages
+= Descriptor
->PageCount
;
133 /* Check if this is the new lowest page */
134 if (Descriptor
->BasePage
< MmLowestPhysicalPage
)
136 /* Update the lowest page */
137 MmLowestPhysicalPage
= Descriptor
->BasePage
;
140 /* Check if this is the new highest page */
141 LastPage
= Descriptor
->BasePage
+ Descriptor
->PageCount
- 1;
142 if (LastPage
> MmHighestPhysicalPage
)
144 /* Update the highest page */
145 MmHighestPhysicalPage
= LastPage
;
148 /* Check if this is currently free memory */
149 if ((Descriptor
->MemoryType
== LoaderFree
) ||
150 (Descriptor
->MemoryType
== LoaderLoadedProgram
) ||
151 (Descriptor
->MemoryType
== LoaderFirmwareTemporary
) ||
152 (Descriptor
->MemoryType
== LoaderOsloaderStack
))
154 /* Check if this is the largest memory descriptor */
155 if (Descriptor
->PageCount
> MxFreePageCount
)
158 MxFreeDescriptor
= Descriptor
;
159 MxFreePageBase
= Descriptor
->BasePage
;
160 MxFreePageCount
= Descriptor
->PageCount
;
165 /* Add it to the amount of system used pages */
166 MiSystemPages
+= Descriptor
->PageCount
;
177 if (MiPfnsInitialized
)
179 return MmAllocPage(MC_SYSTEM
);
182 /* Make sure we have enough pages */
183 if (!MxFreePageCount
)
185 /* Crash the system */
186 KeBugCheckEx(INSTALL_MORE_MEMORY
,
187 MmNumberOfPhysicalPages
,
188 MxFreeDescriptor
->PageCount
,
189 MxOldFreeDescriptor
.PageCount
,
193 /* Use our lowest usable free pages */
194 Pfn
= MxFreePageBase
;
202 MxGetPte(PVOID Address
)
207 /* Setup template pte */
209 TmplPte
.u
.Flush
.Valid
= 1;
210 TmplPte
.u
.Flush
.Write
= 1;
212 /* Get a pointer to the PXE */
213 Pte
= MiAddressToPxe(Address
);
214 if (!Pte
->u
.Hard
.Valid
)
216 /* It's not valid, map it! */
217 TmplPte
.u
.Hard
.PageFrameNumber
= MiEarlyAllocPage();
221 RtlZeroMemory(MiPteToAddress(Pte
), PAGE_SIZE
);
224 /* Get a pointer to the PPE */
225 Pte
= MiAddressToPpe(Address
);
226 if (!Pte
->u
.Hard
.Valid
)
228 /* It's not valid, map it! */
229 TmplPte
.u
.Hard
.PageFrameNumber
= MiEarlyAllocPage();
233 RtlZeroMemory(MiPteToAddress(Pte
), PAGE_SIZE
);
236 /* Get a pointer to the PDE */
237 Pte
= MiAddressToPde(Address
);
238 if (!Pte
->u
.Hard
.Valid
)
240 /* It's not valid, map it! */
241 TmplPte
.u
.Hard
.PageFrameNumber
= MiEarlyAllocPage();
245 RtlZeroMemory(MiPteToAddress(Pte
), PAGE_SIZE
);
248 /* Get a pointer to the PTE */
249 Pte
= MiAddressToPte(Address
);
255 MxMapPage(PVOID Address
)
259 /* Setup template pte */
261 TmplPte
.u
.Flush
.Valid
= 1;
262 TmplPte
.u
.Flush
.Write
= 1;
263 TmplPte
.u
.Hard
.PageFrameNumber
= MiEarlyAllocPage();
265 /* Get the PTE for that page */
266 Pte
= MxGetPte(Address
);
267 ASSERT(Pte
->u
.Hard
.Valid
== 0);
269 /* Map a physical page */
274 MxMapPageRange(PVOID Address
, ULONG64 PageCount
)
282 Address
= (PVOID
)((ULONG64
)Address
+ PAGE_SIZE
);
288 MiPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
290 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
291 PLIST_ENTRY ListEntry
;
292 PUCHAR Page
, FirstPage
;
295 /* Calculate the size of the PFN database and convert to pages */
296 MxPfnSizeInBytes
= ROUND_TO_PAGES((MmHighestPhysicalPage
+ 1) * sizeof(MMPFN
));
297 MxPfnAllocation
= MxPfnSizeInBytes
>> PAGE_SHIFT
;
299 /* Simply start at hardcoded address */
300 MmPfnDatabase
= MI_PFN_DATABASE
;
302 /* Loop the memory descriptors */
303 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
304 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
305 ListEntry
= ListEntry
->Flink
)
307 /* Get the memory descriptor */
308 Descriptor
= CONTAINING_RECORD(ListEntry
,
309 MEMORY_ALLOCATION_DESCRIPTOR
,
312 /* Skip pages that are not part of the PFN database */
313 if (MiIncludeType
[Descriptor
->MemoryType
])
315 /* Get the base and size of this pfn database entry */
316 FirstPage
= PAGE_ALIGN(&MmPfnDatabase
[Descriptor
->BasePage
]);
317 Size
= ROUND_TO_PAGES(Descriptor
->PageCount
* sizeof(MMPFN
));
319 /* Loop the pages of this Pfn database entry */
320 for (Page
= FirstPage
; Page
< FirstPage
+ Size
; Page
+= PAGE_SIZE
)
322 /* Is the page already mapped? */
323 if (!MmIsAddressValid(Page
))
325 /* It's not, map it now */
327 RtlZeroMemory(Page
, PAGE_SIZE
);
331 /* Zero out the pages */
332 RtlZeroMemory(FirstPage
, Size
);
340 MiInitializeSessionSpace(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
342 /* Set up session space */
343 MiSessionSpaceEnd
= (PVOID
)MI_SESSION_SPACE_END
;
345 /* This is where we will load Win32k.sys and the video driver */
346 MiSessionImageEnd
= MiSessionSpaceEnd
;
347 MiSessionImageStart
= (PCHAR
)MiSessionImageEnd
- MmSessionImageSize
;
349 /* The view starts right below the session working set (itself below
351 MiSessionViewEnd
= MI_SESSION_VIEW_END
;
352 MiSessionViewStart
= (PCHAR
)MiSessionViewEnd
- MmSessionViewSize
;
353 ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart
));
355 /* Session pool follows */
356 MiSessionPoolEnd
= MiSessionViewStart
;
357 MiSessionPoolStart
= (PCHAR
)MiSessionPoolEnd
- MmSessionPoolSize
;
358 ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart
));
360 /* And it all begins here */
361 MmSessionBase
= MiSessionPoolStart
;
363 /* System view space ends at session space, so now that we know where
364 * this is, we can compute the base address of system view space itself. */
365 MiSystemViewStart
= (PCHAR
)MmSessionBase
- MmSystemViewSize
;
366 ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart
));
369 ASSERT(MiSessionViewEnd
<= MiSessionImageStart
);
370 ASSERT(MmSessionBase
<= MiSessionPoolStart
);
374 MiInitializePageTable()
376 ULONG64 PageFrameOffset
;
379 /* HACK: don't use freeldr debug print anymore */
380 //FrLdrDbgPrint = NoDbgPrint;
382 /* Get current directory base */
383 MmSystemPageDirectory
[0] = ((PMMPTE
)PXE_SELFMAP
)->u
.Hard
.PageFrameNumber
;
384 PageFrameOffset
= MmSystemPageDirectory
[0] << PAGE_SHIFT
;
385 ASSERT(PageFrameOffset
== __readcr3());
387 /* Set directory base for the system process */
388 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PageFrameOffset
;
390 /* Enable global pages */
391 __writecr4(__readcr4() | CR4_PGE
);
392 ASSERT(__readcr4() & CR4_PGE
);
394 /* Enable no execute */
395 __writemsr(X86_MSR_EFER
, __readmsr(X86_MSR_EFER
) | EFER_NXE
);
397 /* Loop the user mode PXEs */
398 for (Pte
= MiAddressToPxe(0);
399 Pte
<= MiAddressToPxe(MmHighestUserAddress
);
402 /* Zero the PXE, clear all mappings */
409 /* Set up a template PTE */
411 TmplPte
.u
.Flush
.Valid
= 1;
412 TmplPte
.u
.Flush
.Write
= 1;
413 HyperTemplatePte
= TmplPte
;
415 /* Create PDPTs (72 KB) for shared system address space,
416 * skip page tables and hyperspace */
419 for (Pte
= MiAddressToPxe((PVOID
)(HYPER_SPACE_END
+ 1));
420 Pte
<= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS
);
423 /* Is the PXE already valid? */
424 if (!Pte
->u
.Hard
.Valid
)
426 /* It's not Initialize it */
427 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage(0);
430 /* Zero the page. The PXE is the PTE for the PDPT. */
431 RtlZeroMemory(MiPteToAddress(Pte
), PAGE_SIZE
);
435 /* Setup the mapping PTEs */
436 MmFirstReservedMappingPte
= MxGetPte((PVOID
)MI_MAPPING_RANGE_START
);
437 MmFirstReservedMappingPte
->u
.Hard
.PageFrameNumber
= MI_HYPERSPACE_PTES
;
438 MmLastReservedMappingPte
= MiAddressToPte((PVOID
)MI_MAPPING_RANGE_END
);
441 /* Setup debug mapping PTE */
442 MmDebugPte
= MxGetPte(MI_DEBUG_MAPPING
);
448 MiBuildNonPagedPool(VOID
)
453 /* Check if this is a machine with less than 256MB of RAM, and no overide */
454 if ((MmNumberOfPhysicalPages
<= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING
) &&
455 !(MmSizeOfNonPagedPoolInBytes
))
457 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
458 MmSizeOfNonPagedPoolInBytes
= 2 * 1024 * 1024;
461 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
462 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) >
463 (MmNumberOfPhysicalPages
* 7 / 8))
465 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
466 MmSizeOfNonPagedPoolInBytes
= 0;
469 /* Check if no registry setting was set, or if the setting was too low */
470 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
472 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
473 MmSizeOfNonPagedPoolInBytes
= MmMinimumNonPagedPoolSize
;
474 MmSizeOfNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
475 256 * MmMinAdditionNonPagedPoolPerMb
;
478 /* Check if the registy setting or our dynamic calculation was too high */
479 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
481 /* Set it to the maximum */
482 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
485 /* Check if a percentage cap was set through the registry */
486 if (MmMaximumNonPagedPoolPercent
)
488 /* Don't feel like supporting this right now */
492 /* Page-align the nonpaged pool size */
493 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
495 /* Now, check if there was a registry size for the maximum size */
496 if (!MmMaximumNonPagedPoolInBytes
)
498 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
499 MmMaximumNonPagedPoolInBytes
= MmDefaultMaximumNonPagedPool
;
500 MmMaximumNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
501 256 * MmMaxAdditionNonPagedPoolPerMb
;
504 /* Don't let the maximum go too high */
505 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
507 /* Set it to the upper limit */
508 MmMaximumNonPagedPoolInBytes
= MI_MAX_NONPAGED_POOL_SIZE
;
511 /* Put non paged pool to the end of the region */
512 MmNonPagedPoolStart
= (PCHAR
)MmNonPagedPoolEnd
- MmMaximumNonPagedPoolInBytes
;
514 /* Make sure it doesn't collide with the PFN database */
515 if ((PCHAR
)MmNonPagedPoolStart
< (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
)
517 /* Put non paged pool after the PFN database */
518 MmNonPagedPoolStart
= (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
;
519 MmMaximumNonPagedPoolInBytes
= (ULONG64
)MmNonPagedPoolEnd
-
520 (ULONG64
)MmNonPagedPoolStart
;
523 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart
));
525 /* Calculate the nonpaged pool expansion start region */
526 MmNonPagedPoolExpansionStart
= (PCHAR
)MmNonPagedPoolStart
+
527 MmSizeOfNonPagedPoolInBytes
;
528 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart
));
530 /* Map the nonpaged pool */
531 PageCount
= (MmSizeOfNonPagedPoolInBytes
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
532 MxMapPageRange(MmNonPagedPoolStart
, PageCount
);
534 /* Loop the non paged pool extension PTEs */
535 for (Pte
= MiAddressToPte(MmNonPagedPoolExpansionStart
);
536 Pte
<= MiAddressToPte(MmNonPagedPoolEnd
);
539 /* Create PXE, PPE, PDE and zero the PTE */
540 MxGetPte(MiPteToAddress(Pte
))->u
.Long
= 0;
543 /* Initialize the ARM3 nonpaged pool */
544 MiInitializeNonPagedPool();
546 /* Initialize the nonpaged pool */
547 InitializePool(NonPagedPool
, 0);
552 MiBuildSystemPteSpace()
554 PMMPTE Pte
, StartPte
, EndPte
;
556 /* Use the default numer of system PTEs */
557 MmNumberOfSystemPtes
= MI_NUMBER_SYSTEM_PTES
;
559 /* System PTE pool is below the PFN database */
560 MiNonPagedSystemSize
= (MmNumberOfSystemPtes
+ 1) * PAGE_SIZE
;
561 MmNonPagedSystemStart
= (PCHAR
)MmPfnDatabase
- MiNonPagedSystemSize
;
562 MmNonPagedSystemStart
= MM_ROUND_DOWN(MmNonPagedSystemStart
, 512 * PAGE_SIZE
);
564 /* Don't let it go below the minimum */
565 if (MmNonPagedSystemStart
< (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
)
567 /* This is a hard-coded limit in the Windows NT address space */
568 MmNonPagedSystemStart
= (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
;
570 /* Reduce the amount of system PTEs to reach this point */
571 MmNumberOfSystemPtes
= ((ULONG64
)MmPfnDatabase
-
572 (ULONG64
)MmNonPagedSystemStart
) >>
574 MmNumberOfSystemPtes
--;
575 ASSERT(MmNumberOfSystemPtes
> 1000);
578 /* Set the range of system PTEs */
579 StartPte
= MiAddressToPte(MI_SYSTEM_PTE_START
);
580 EndPte
= StartPte
+ MmNumberOfSystemPtes
- 1;
582 /* Loop the system PTEs */
583 for (Pte
= StartPte
; Pte
<= EndPte
; Pte
++)
585 /* Create PXE, PPE, PDE and zero the PTE */
586 MxGetPte(MiPteToAddress(Pte
))->u
.Long
= 0;
589 /* Create the system PTE space */
590 Pte
= MiAddressToPte(MI_SYSTEM_PTE_START
);
591 MiInitializeSystemPtes(Pte
, MmNumberOfSystemPtes
, SystemPteSpace
);
593 /* Reserve system PTEs for zeroing PTEs and clear them */
594 MiFirstReservedZeroingPte
= MiReserveSystemPtes(MI_ZERO_PTES
, SystemPteSpace
);
595 RtlZeroMemory(MiFirstReservedZeroingPte
, MI_ZERO_PTES
* sizeof(MMPTE
));
597 /* Set the counter to maximum */
598 MiFirstReservedZeroingPte
->u
.Hard
.PageFrameNumber
= MI_ZERO_PTES
- 1;
603 MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
605 PPHYSICAL_MEMORY_DESCRIPTOR Buffer
;
606 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
607 PLIST_ENTRY ListEntry
;
608 PFN_NUMBER NextPage
= -1;
613 /* Calculate size for the PFN bitmap */
614 Size
= ROUND_UP(MmHighestPhysicalPage
+ 1, sizeof(ULONG
));
616 /* Allocate the PFN bitmap */
617 Bitmap
= ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
619 /* Allocate enough memory for the physical memory block */
620 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
621 sizeof(PHYSICAL_MEMORY_DESCRIPTOR
) +
622 sizeof(PHYSICAL_MEMORY_RUN
) *
623 (MiNumberDescriptors
- 1),
625 if (!Bitmap
|| !Buffer
)
627 /* This is critical */
628 KeBugCheckEx(INSTALL_MORE_MEMORY
,
629 MmNumberOfPhysicalPages
,
630 MmLowestPhysicalPage
,
631 MmHighestPhysicalPage
,
635 /* Initialize the bitmap and clear all bits */
636 RtlInitializeBitMap(&MiPfnBitMap
, Bitmap
, MmHighestPhysicalPage
+ 1);
637 RtlClearAllBits(&MiPfnBitMap
);
639 /* Loop the memory descriptors */
640 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
641 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
642 ListEntry
= ListEntry
->Flink
)
644 /* Get the memory descriptor */
645 Descriptor
= CONTAINING_RECORD(ListEntry
,
646 MEMORY_ALLOCATION_DESCRIPTOR
,
649 /* Skip pages that are not part of the PFN database */
650 if (!MiIncludeType
[Descriptor
->MemoryType
])
655 /* Does the memory block begin where the last ended? */
656 if (Descriptor
->BasePage
== NextPage
)
658 /* Add it to the current run */
659 Buffer
->Run
[Runs
- 1].PageCount
+= Descriptor
->PageCount
;
663 /* Create a new run */
665 Buffer
->Run
[Runs
- 1].BasePage
= Descriptor
->BasePage
;
666 Buffer
->Run
[Runs
- 1].PageCount
= Descriptor
->PageCount
;
669 /* Set the bits in the PFN bitmap */
670 RtlSetBits(&MiPfnBitMap
, Descriptor
->BasePage
, Descriptor
->PageCount
);
672 /* Set the next page */
673 NextPage
= Descriptor
->BasePage
+ Descriptor
->PageCount
;
676 // FIXME: allocate a buffer of better size
678 Buffer
->NumberOfRuns
= Runs
;
679 Buffer
->NumberOfPages
= MmNumberOfPhysicalPages
;
680 MmPhysicalMemoryBlock
= Buffer
;
685 MiBuildPagedPool_x(VOID
)
689 ULONG Size
, BitMapSize
;
691 /* Default size for paged pool is 4 times non paged pool */
692 MmSizeOfPagedPoolInBytes
= 4 * MmMaximumNonPagedPoolInBytes
;
694 /* Make sure it doesn't overflow */
695 if (MmSizeOfPagedPoolInBytes
> ((ULONG64
)MmNonPagedSystemStart
-
696 (ULONG64
)MmPagedPoolStart
))
698 MmSizeOfPagedPoolInBytes
= (ULONG64
)MmNonPagedSystemStart
-
699 (ULONG64
)MmPagedPoolStart
;
702 /* Make sure paged pool is big enough */
703 if (MmSizeOfPagedPoolInBytes
< MI_MIN_INIT_PAGED_POOLSIZE
)
705 MmSizeOfPagedPoolInBytes
= MI_MIN_INIT_PAGED_POOLSIZE
;
708 /* Align down to a PDE boundary */
709 MmSizeOfPagedPoolInBytes
= ROUND_DOWN(MmSizeOfPagedPoolInBytes
,
711 MmSizeOfPagedPoolInPages
= MmSizeOfPagedPoolInBytes
>> PAGE_SHIFT
;
713 /* This is where paged pool ends */
714 MmPagedPoolEnd
= (PCHAR
)MmPagedPoolStart
+ MmSizeOfPagedPoolInBytes
- 1;
717 ASSERT(MmPagedPoolEnd
< MmNonPagedSystemStart
);
719 /* setup a template PTE */
721 TmplPte
.u
.Flush
.Valid
= 1;
722 TmplPte
.u
.Flush
.Write
= 1;
724 /* Make sure the PXE is valid */
725 Pte
= MiAddressToPxe(MmPagedPoolStart
);
726 if (!Pte
->u
.Flush
.Valid
)
729 TmplPte
.u
.Flush
.PageFrameNumber
= MmAllocPage(MC_SYSTEM
);
733 /* Map all page directories (max 128) */
734 for (Pte
= MiAddressToPpe(MmPagedPoolStart
);
735 Pte
<= MiAddressToPpe(MmPagedPoolEnd
);
738 if (!Pte
->u
.Flush
.Valid
)
741 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage();
746 /* Create and map the first PTE for paged pool */
747 Pte
= MxGetPte(MmPagedPoolStart
);
748 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage();
751 /* Save the first and last paged pool PTE */
752 MmPagedPoolInfo
.FirstPteForPagedPool
= MiAddressToPte(MmPagedPoolStart
);
753 MmPagedPoolInfo
.LastPteForPagedPool
= MiAddressToPte(MmPagedPoolEnd
);
755 MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
=
756 MiAddressToPde(MmPagedPoolStart
) + 1;
758 // We keep track of each page via a bit, so check how big the bitmap will
759 // have to be (make sure to align our page count such that it fits nicely
760 // into a 4-byte aligned bitmap.
762 /* The size of the bitmap in bits is the size in pages */
763 BitMapSize
= MmSizeOfPagedPoolInPages
;
765 /* Calculate buffer size in bytes, aligned to 32 bits */
766 Size
= sizeof(RTL_BITMAP
) + ROUND_UP(BitMapSize
, 32) / 8;
768 // Allocate the allocation bitmap, which tells us which regions have not yet
769 // been mapped into memory
771 MmPagedPoolInfo
.PagedPoolAllocationMap
=
772 ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
773 ASSERT(MmPagedPoolInfo
.PagedPoolAllocationMap
);
775 // Initialize it such that at first, only the first page's worth of PTEs is
776 // marked as allocated (incidentially, the first PDE we allocated earlier).
777 RtlInitializeBitMap(MmPagedPoolInfo
.PagedPoolAllocationMap
,
778 (PULONG
)(MmPagedPoolInfo
.PagedPoolAllocationMap
+ 1),
780 RtlSetAllBits(MmPagedPoolInfo
.PagedPoolAllocationMap
);
781 RtlClearBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 0, 512);
783 // We have a second bitmap, which keeps track of where allocations end.
784 // Given the allocation bitmap and a base address, we can therefore figure
785 // out which page is the last page of that allocation, and thus how big the
786 // entire allocation is.
787 MmPagedPoolInfo
.EndOfPagedPoolBitmap
=
788 ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
789 ASSERT(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
791 /* Initialize the bitmap */
792 RtlInitializeBitMap(MmPagedPoolInfo
.EndOfPagedPoolBitmap
,
793 (PULONG
)(MmPagedPoolInfo
.EndOfPagedPoolBitmap
+ 1),
796 /* No allocations, no allocation ends; clear all bits. */
797 RtlClearAllBits(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
799 /* Initialize the paged pool mutex */
800 KeInitializeGuardedMutex(&MmPagedPoolMutex
);
802 /* Initialize the paged pool */
803 InitializePool(PagedPool
, 0);
809 MmArmInitSystem_x(IN ULONG Phase
,
810 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
814 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
* PAGE_SIZE
;
815 MmBootImageSize
= ROUND_UP(MmBootImageSize
, PAGE_SIZE
);
817 /* Parse memory descriptors, find free pages */
818 MiEvaluateMemoryDescriptors(LoaderBlock
);
820 /* Start PFN database at hardcoded address */
821 MmPfnDatabase
= MI_PFN_DATABASE
;
823 /* Prepare PFN database mappings */
824 MiPreparePfnDatabse(LoaderBlock
);
826 /* Initialize the session space */
827 MiInitializeSessionSpace(LoaderBlock
);
829 /* Initialize some mappings */
830 MiInitializePageTable();
832 /* Update the memory descriptor, to make sure the pages we used
833 won't get inserted into the PFN database */
834 MxOldFreeDescriptor
= *MxFreeDescriptor
;
835 MxFreeDescriptor
->BasePage
= MxFreePageBase
;
836 MxFreeDescriptor
->PageCount
= MxFreePageCount
;
840 /* The PFN database was created, restore the free descriptor */
841 *MxFreeDescriptor
= MxOldFreeDescriptor
;
843 /* The pfn database is ready now */
844 MiPfnsInitialized
= TRUE
;
846 /* Initialize the nonpaged pool */
847 MiBuildNonPagedPool();
849 /* Initialize system PTE handling */
850 MiBuildSystemPteSpace();
852 /* Build the physical memory block */
853 MiBuildPhysicalMemoryBlock(LoaderBlock
);
855 /* Size up paged pool and build the shadow system page directory */
856 //MiBuildPagedPool();
858 // This is the old stuff:
859 MmPagedPoolBase
= (PVOID
)((PCHAR
)MmPagedPoolEnd
+ 1);
860 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
861 ASSERT((PCHAR
)MmPagedPoolBase
+ MmPagedPoolSize
< (PCHAR
)MmNonPagedSystemStart
);
864 HalInitializeBios(0, LoaderBlock
);
867 return STATUS_SUCCESS
;
872 MiSyncARM3WithROS(IN PVOID AddressStart
,
880 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
883 return STATUS_NOT_IMPLEMENTED
;