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 PxePhysicalAddress
;
380 /* HACK: don't use freeldr debug print anymore */
381 //FrLdrDbgPrint = NoDbgPrint;
383 /* Get current directory base */
384 PxePfn
= ((PMMPTE
)PXE_SELFMAP
)->u
.Hard
.PageFrameNumber
;
385 PxePhysicalAddress
= PxePfn
<< PAGE_SHIFT
;
386 ASSERT(PxePhysicalAddress
== __readcr3());
388 /* Set directory base for the system process */
389 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
[0] = PxePhysicalAddress
;
391 /* Enable global pages */
392 __writecr4(__readcr4() | CR4_PGE
);
393 ASSERT(__readcr4() & CR4_PGE
);
395 /* Enable no execute */
396 __writemsr(X86_MSR_EFER
, __readmsr(X86_MSR_EFER
) | EFER_NXE
);
398 /* Loop the user mode PXEs */
399 for (Pte
= MiAddressToPxe(0);
400 Pte
<= MiAddressToPxe(MmHighestUserAddress
);
403 /* Zero the PXE, clear all mappings */
410 /* Set up a template PTE */
412 TmplPte
.u
.Flush
.Valid
= 1;
413 TmplPte
.u
.Flush
.Write
= 1;
414 HyperTemplatePte
= TmplPte
;
416 /* Create PDPTs (72 KB) for shared system address space,
417 * skip page tables and hyperspace */
420 for (Pte
= MiAddressToPxe((PVOID
)(HYPER_SPACE_END
+ 1));
421 Pte
<= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS
);
424 /* Is the PXE already valid? */
425 if (!Pte
->u
.Hard
.Valid
)
427 /* It's not Initialize it */
428 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage(0);
431 /* Zero the page. The PXE is the PTE for the PDPT. */
432 RtlZeroMemory(MiPteToAddress(Pte
), PAGE_SIZE
);
436 /* Setup the mapping PTEs */
437 MmFirstReservedMappingPte
= MxGetPte((PVOID
)MI_MAPPING_RANGE_START
);
438 MmFirstReservedMappingPte
->u
.Hard
.PageFrameNumber
= MI_HYPERSPACE_PTES
;
439 MmLastReservedMappingPte
= MiAddressToPte((PVOID
)MI_MAPPING_RANGE_END
);
442 /* Setup debug mapping PTE */
443 MmDebugPte
= MxGetPte(MI_DEBUG_MAPPING
);
449 MiBuildNonPagedPool(VOID
)
454 /* Check if this is a machine with less than 256MB of RAM, and no overide */
455 if ((MmNumberOfPhysicalPages
<= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING
) &&
456 !(MmSizeOfNonPagedPoolInBytes
))
458 /* Force the non paged pool to be 2MB so we can reduce RAM usage */
459 MmSizeOfNonPagedPoolInBytes
= 2 * 1024 * 1024;
462 /* Check if the user gave a ridicuously large nonpaged pool RAM size */
463 if ((MmSizeOfNonPagedPoolInBytes
>> PAGE_SHIFT
) >
464 (MmNumberOfPhysicalPages
* 7 / 8))
466 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
467 MmSizeOfNonPagedPoolInBytes
= 0;
470 /* Check if no registry setting was set, or if the setting was too low */
471 if (MmSizeOfNonPagedPoolInBytes
< MmMinimumNonPagedPoolSize
)
473 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
474 MmSizeOfNonPagedPoolInBytes
= MmMinimumNonPagedPoolSize
;
475 MmSizeOfNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
476 256 * MmMinAdditionNonPagedPoolPerMb
;
479 /* Check if the registy setting or our dynamic calculation was too high */
480 if (MmSizeOfNonPagedPoolInBytes
> MI_MAX_INIT_NONPAGED_POOL_SIZE
)
482 /* Set it to the maximum */
483 MmSizeOfNonPagedPoolInBytes
= MI_MAX_INIT_NONPAGED_POOL_SIZE
;
486 /* Check if a percentage cap was set through the registry */
487 if (MmMaximumNonPagedPoolPercent
)
489 /* Don't feel like supporting this right now */
493 /* Page-align the nonpaged pool size */
494 MmSizeOfNonPagedPoolInBytes
&= ~(PAGE_SIZE
- 1);
496 /* Now, check if there was a registry size for the maximum size */
497 if (!MmMaximumNonPagedPoolInBytes
)
499 /* Start with the default (1MB) and add 400 KB for each MB above 4 */
500 MmMaximumNonPagedPoolInBytes
= MmDefaultMaximumNonPagedPool
;
501 MmMaximumNonPagedPoolInBytes
+= (MmNumberOfPhysicalPages
- 1024) /
502 256 * MmMaxAdditionNonPagedPoolPerMb
;
505 /* Don't let the maximum go too high */
506 if (MmMaximumNonPagedPoolInBytes
> MI_MAX_NONPAGED_POOL_SIZE
)
508 /* Set it to the upper limit */
509 MmMaximumNonPagedPoolInBytes
= MI_MAX_NONPAGED_POOL_SIZE
;
512 /* Put non paged pool to the end of the region */
513 MmNonPagedPoolStart
= (PCHAR
)MmNonPagedPoolEnd
- MmMaximumNonPagedPoolInBytes
;
515 /* Make sure it doesn't collide with the PFN database */
516 if ((PCHAR
)MmNonPagedPoolStart
< (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
)
518 /* Put non paged pool after the PFN database */
519 MmNonPagedPoolStart
= (PCHAR
)MmPfnDatabase
+ MxPfnSizeInBytes
;
520 MmMaximumNonPagedPoolInBytes
= (ULONG64
)MmNonPagedPoolEnd
-
521 (ULONG64
)MmNonPagedPoolStart
;
524 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart
));
526 /* Calculate the nonpaged pool expansion start region */
527 MmNonPagedPoolExpansionStart
= (PCHAR
)MmNonPagedPoolStart
+
528 MmSizeOfNonPagedPoolInBytes
;
529 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart
));
531 /* Map the nonpaged pool */
532 PageCount
= (MmSizeOfNonPagedPoolInBytes
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
533 MxMapPageRange(MmNonPagedPoolStart
, PageCount
);
535 /* Loop the non paged pool extension PTEs */
536 for (Pte
= MiAddressToPte(MmNonPagedPoolExpansionStart
);
537 Pte
<= MiAddressToPte(MmNonPagedPoolEnd
);
540 /* Create PXE, PPE, PDE and zero the PTE */
541 MxGetPte(MiPteToAddress(Pte
))->u
.Long
= 0;
544 /* Initialize the ARM3 nonpaged pool */
545 MiInitializeNonPagedPool();
547 /* Initialize the nonpaged pool */
548 InitializePool(NonPagedPool
, 0);
553 MiBuildSystemPteSpace()
555 PMMPTE Pte
, StartPte
, EndPte
;
557 /* Use the default numer of system PTEs */
558 MmNumberOfSystemPtes
= MI_NUMBER_SYSTEM_PTES
;
560 /* System PTE pool is below the PFN database */
561 MiNonPagedSystemSize
= (MmNumberOfSystemPtes
+ 1) * PAGE_SIZE
;
562 MmNonPagedSystemStart
= (PCHAR
)MmPfnDatabase
- MiNonPagedSystemSize
;
563 MmNonPagedSystemStart
= MM_ROUND_DOWN(MmNonPagedSystemStart
, 512 * PAGE_SIZE
);
565 /* Don't let it go below the minimum */
566 if (MmNonPagedSystemStart
< (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
)
568 /* This is a hard-coded limit in the Windows NT address space */
569 MmNonPagedSystemStart
= (PVOID
)MI_NON_PAGED_SYSTEM_START_MIN
;
571 /* Reduce the amount of system PTEs to reach this point */
572 MmNumberOfSystemPtes
= ((ULONG64
)MmPfnDatabase
-
573 (ULONG64
)MmNonPagedSystemStart
) >>
575 MmNumberOfSystemPtes
--;
576 ASSERT(MmNumberOfSystemPtes
> 1000);
579 /* Set the range of system PTEs */
580 StartPte
= MiAddressToPte(MI_SYSTEM_PTE_START
);
581 EndPte
= StartPte
+ MmNumberOfSystemPtes
- 1;
583 /* Loop the system PTEs */
584 for (Pte
= StartPte
; Pte
<= EndPte
; Pte
++)
586 /* Create PXE, PPE, PDE and zero the PTE */
587 MxGetPte(MiPteToAddress(Pte
))->u
.Long
= 0;
590 /* Create the system PTE space */
591 Pte
= MiAddressToPte(MI_SYSTEM_PTE_START
);
592 MiInitializeSystemPtes(Pte
, MmNumberOfSystemPtes
, SystemPteSpace
);
594 /* Reserve system PTEs for zeroing PTEs and clear them */
595 MiFirstReservedZeroingPte
= MiReserveSystemPtes(MI_ZERO_PTES
, SystemPteSpace
);
596 RtlZeroMemory(MiFirstReservedZeroingPte
, MI_ZERO_PTES
* sizeof(MMPTE
));
598 /* Set the counter to maximum */
599 MiFirstReservedZeroingPte
->u
.Hard
.PageFrameNumber
= MI_ZERO_PTES
- 1;
604 MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
606 PPHYSICAL_MEMORY_DESCRIPTOR Buffer
;
607 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
608 PLIST_ENTRY ListEntry
;
609 PFN_NUMBER NextPage
= -1;
614 /* Calculate size for the PFN bitmap */
615 Size
= ROUND_UP(MmHighestPhysicalPage
+ 1, sizeof(ULONG
));
617 /* Allocate the PFN bitmap */
618 Bitmap
= ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
620 /* Allocate enough memory for the physical memory block */
621 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
622 sizeof(PHYSICAL_MEMORY_DESCRIPTOR
) +
623 sizeof(PHYSICAL_MEMORY_RUN
) *
624 (MiNumberDescriptors
- 1),
626 if (!Bitmap
|| !Buffer
)
628 /* This is critical */
629 KeBugCheckEx(INSTALL_MORE_MEMORY
,
630 MmNumberOfPhysicalPages
,
631 MmLowestPhysicalPage
,
632 MmHighestPhysicalPage
,
636 /* Initialize the bitmap and clear all bits */
637 RtlInitializeBitMap(&MiPfnBitMap
, Bitmap
, MmHighestPhysicalPage
+ 1);
638 RtlClearAllBits(&MiPfnBitMap
);
640 /* Loop the memory descriptors */
641 for (ListEntry
= LoaderBlock
->MemoryDescriptorListHead
.Flink
;
642 ListEntry
!= &LoaderBlock
->MemoryDescriptorListHead
;
643 ListEntry
= ListEntry
->Flink
)
645 /* Get the memory descriptor */
646 Descriptor
= CONTAINING_RECORD(ListEntry
,
647 MEMORY_ALLOCATION_DESCRIPTOR
,
650 /* Skip pages that are not part of the PFN database */
651 if (!MiIncludeType
[Descriptor
->MemoryType
])
656 /* Does the memory block begin where the last ended? */
657 if (Descriptor
->BasePage
== NextPage
)
659 /* Add it to the current run */
660 Buffer
->Run
[Runs
- 1].PageCount
+= Descriptor
->PageCount
;
664 /* Create a new run */
666 Buffer
->Run
[Runs
- 1].BasePage
= Descriptor
->BasePage
;
667 Buffer
->Run
[Runs
- 1].PageCount
= Descriptor
->PageCount
;
670 /* Set the bits in the PFN bitmap */
671 RtlSetBits(&MiPfnBitMap
, Descriptor
->BasePage
, Descriptor
->PageCount
);
673 /* Set the next page */
674 NextPage
= Descriptor
->BasePage
+ Descriptor
->PageCount
;
677 // FIXME: allocate a buffer of better size
679 Buffer
->NumberOfRuns
= Runs
;
680 Buffer
->NumberOfPages
= MmNumberOfPhysicalPages
;
681 MmPhysicalMemoryBlock
= Buffer
;
686 MiBuildPagedPool_x(VOID
)
690 ULONG Size
, BitMapSize
;
692 /* Default size for paged pool is 4 times non paged pool */
693 MmSizeOfPagedPoolInBytes
= 4 * MmMaximumNonPagedPoolInBytes
;
695 /* Make sure it doesn't overflow */
696 if (MmSizeOfPagedPoolInBytes
> ((ULONG64
)MmNonPagedSystemStart
-
697 (ULONG64
)MmPagedPoolStart
))
699 MmSizeOfPagedPoolInBytes
= (ULONG64
)MmNonPagedSystemStart
-
700 (ULONG64
)MmPagedPoolStart
;
703 /* Make sure paged pool is big enough */
704 if (MmSizeOfPagedPoolInBytes
< MI_MIN_INIT_PAGED_POOLSIZE
)
706 MmSizeOfPagedPoolInBytes
= MI_MIN_INIT_PAGED_POOLSIZE
;
709 /* Align down to a PDE boundary */
710 MmSizeOfPagedPoolInBytes
= ROUND_DOWN(MmSizeOfPagedPoolInBytes
,
712 MmSizeOfPagedPoolInPages
= MmSizeOfPagedPoolInBytes
>> PAGE_SHIFT
;
714 /* This is where paged pool ends */
715 MmPagedPoolEnd
= (PCHAR
)MmPagedPoolStart
+ MmSizeOfPagedPoolInBytes
- 1;
718 ASSERT(MmPagedPoolEnd
< MmNonPagedSystemStart
);
720 /* setup a template PTE */
722 TmplPte
.u
.Flush
.Valid
= 1;
723 TmplPte
.u
.Flush
.Write
= 1;
725 /* Make sure the PXE is valid */
726 Pte
= MiAddressToPxe(MmPagedPoolStart
);
727 if (!Pte
->u
.Flush
.Valid
)
730 TmplPte
.u
.Flush
.PageFrameNumber
= MmAllocPage(MC_SYSTEM
);
734 /* Map all page directories (max 128) */
735 for (Pte
= MiAddressToPpe(MmPagedPoolStart
);
736 Pte
<= MiAddressToPpe(MmPagedPoolEnd
);
739 if (!Pte
->u
.Flush
.Valid
)
742 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage();
747 /* Create and map the first PTE for paged pool */
748 Pte
= MxGetPte(MmPagedPoolStart
);
749 TmplPte
.u
.Flush
.PageFrameNumber
= MiEarlyAllocPage();
752 /* Save the first and last paged pool PTE */
753 MmPagedPoolInfo
.FirstPteForPagedPool
= MiAddressToPte(MmPagedPoolStart
);
754 MmPagedPoolInfo
.LastPteForPagedPool
= MiAddressToPte(MmPagedPoolEnd
);
756 MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
=
757 MiAddressToPde(MmPagedPoolStart
) + 1;
759 // We keep track of each page via a bit, so check how big the bitmap will
760 // have to be (make sure to align our page count such that it fits nicely
761 // into a 4-byte aligned bitmap.
763 /* The size of the bitmap in bits is the size in pages */
764 BitMapSize
= MmSizeOfPagedPoolInPages
;
766 /* Calculate buffer size in bytes, aligned to 32 bits */
767 Size
= sizeof(RTL_BITMAP
) + ROUND_UP(BitMapSize
, 32) / 8;
769 // Allocate the allocation bitmap, which tells us which regions have not yet
770 // been mapped into memory
772 MmPagedPoolInfo
.PagedPoolAllocationMap
=
773 ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
774 ASSERT(MmPagedPoolInfo
.PagedPoolAllocationMap
);
776 // Initialize it such that at first, only the first page's worth of PTEs is
777 // marked as allocated (incidentially, the first PDE we allocated earlier).
778 RtlInitializeBitMap(MmPagedPoolInfo
.PagedPoolAllocationMap
,
779 (PULONG
)(MmPagedPoolInfo
.PagedPoolAllocationMap
+ 1),
781 RtlSetAllBits(MmPagedPoolInfo
.PagedPoolAllocationMap
);
782 RtlClearBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 0, 512);
784 // We have a second bitmap, which keeps track of where allocations end.
785 // Given the allocation bitmap and a base address, we can therefore figure
786 // out which page is the last page of that allocation, and thus how big the
787 // entire allocation is.
788 MmPagedPoolInfo
.EndOfPagedPoolBitmap
=
789 ExAllocatePoolWithTag(NonPagedPool
, Size
, ' mM');
790 ASSERT(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
792 /* Initialize the bitmap */
793 RtlInitializeBitMap(MmPagedPoolInfo
.EndOfPagedPoolBitmap
,
794 (PULONG
)(MmPagedPoolInfo
.EndOfPagedPoolBitmap
+ 1),
797 /* No allocations, no allocation ends; clear all bits. */
798 RtlClearAllBits(MmPagedPoolInfo
.EndOfPagedPoolBitmap
);
800 /* Initialize the paged pool mutex */
801 KeInitializeGuardedMutex(&MmPagedPoolMutex
);
803 /* Initialize the paged pool */
804 InitializePool(PagedPool
, 0);
810 MmArmInitSystem_x(IN ULONG Phase
,
811 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
815 MmBootImageSize
= KeLoaderBlock
->Extension
->LoaderPagesSpanned
* PAGE_SIZE
;
816 MmBootImageSize
= ROUND_UP(MmBootImageSize
, PAGE_SIZE
);
818 /* Parse memory descriptors, find free pages */
819 MiEvaluateMemoryDescriptors(LoaderBlock
);
821 /* Start PFN database at hardcoded address */
822 MmPfnDatabase
= MI_PFN_DATABASE
;
824 /* Prepare PFN database mappings */
825 MiPreparePfnDatabse(LoaderBlock
);
827 /* Initialize the session space */
828 MiInitializeSessionSpace(LoaderBlock
);
830 /* Initialize some mappings */
831 MiInitializePageTable();
833 /* Update the memory descriptor, to make sure the pages we used
834 won't get inserted into the PFN database */
835 MxOldFreeDescriptor
= *MxFreeDescriptor
;
836 MxFreeDescriptor
->BasePage
= MxFreePageBase
;
837 MxFreeDescriptor
->PageCount
= MxFreePageCount
;
841 /* The PFN database was created, restore the free descriptor */
842 *MxFreeDescriptor
= MxOldFreeDescriptor
;
844 /* The pfn database is ready now */
845 MiPfnsInitialized
= TRUE
;
847 /* Initialize the nonpaged pool */
848 MiBuildNonPagedPool();
850 /* Initialize system PTE handling */
851 MiBuildSystemPteSpace();
853 /* Build the physical memory block */
854 MiBuildPhysicalMemoryBlock(LoaderBlock
);
856 /* Size up paged pool and build the shadow system page directory */
857 //MiBuildPagedPool();
859 // This is the old stuff:
860 //MmPagedPoolBase = (PVOID)((PCHAR)MmPagedPoolEnd + 1);
861 //MmPagedPoolSize = MM_PAGED_POOL_SIZE;
862 //ASSERT((PCHAR)MmPagedPoolBase + MmPagedPoolSize < (PCHAR)MmNonPagedSystemStart);
865 HalInitializeBios(0, LoaderBlock
);
868 return STATUS_SUCCESS
;
873 MiSyncARM3WithROS(IN PVOID AddressStart
,
881 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
884 return STATUS_NOT_IMPLEMENTED
;