reactos/ntoskrnl/mm/amd64/init.c
Amine Khaldi c424146e2c Create a branch for cmake bringup.
svn path=/branches/cmake-bringup/; revision=48236
2010-07-24 18:52:44 +00:00

884 lines
28 KiB
C

/*
* COPYRIGHT: GPL, See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/amd64/init.c
* PURPOSE: Memory Manager Initialization for amd64
*
* PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org)
* ReactOS Portable Systems Group
*/
/* INCLUDES ***************************************************************/
#include <ntoskrnl.h>
//#define NDEBUG
#include <debug.h>
#include "../ARM3/miarm.h"
#ifdef _WINKD_
extern PMMPTE MmDebugPte;
#endif
VOID
NTAPI
HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock);
/* GLOBALS *****************************************************************/
/* Template PTE and PDE for a kernel page */
MMPTE ValidKernelPde = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1};
MMPTE ValidKernelPte = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1, .u.Hard.Accessed = 1};
MMPDE DemandZeroPde = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)};
MMPTE PrototypePte = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | PTE_PROTOTYPE | 0xFFFFF000};
/* Sizes */
///SIZE_T MmSessionSize = MI_SESSION_SIZE;
SIZE_T MmSessionViewSize = MI_SESSION_VIEW_SIZE;
SIZE_T MmSessionPoolSize = MI_SESSION_POOL_SIZE;
SIZE_T MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
SIZE_T MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
SIZE_T MiNonPagedSystemSize;
/* Address ranges */
ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
PVOID MmSystemRangeStart = (PVOID)0xFFFF080000000000ULL;
PVOID MmSessionBase; // FFFFF90000000000 = MiSessionPoolStart
PVOID MiSessionPoolStart; // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
PVOID MiSessionPoolEnd; // = MiSessionViewStart
PVOID MiSessionViewStart; // = MiSessionViewEnd - MmSessionViewSize
PVOID MiSessionViewEnd; // FFFFF97FFF000000
PVOID MiSessionImageStart; // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
PVOID MiSessionImageEnd; // FFFFF98000000000 = MiSessionSpaceEnd
PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
PVOID MmSystemCacheStart; // FFFFF98000000000
PVOID MmSystemCacheEnd; // FFFFFA8000000000
/// PVOID MmPagedPoolStart = MI_PAGED_POOL_START; // FFFFFA8000000000
PVOID MmPagedPoolEnd; // FFFFFAA000000000
PVOID MiSystemViewStart;
PVOID MmNonPagedSystemStart; // FFFFFAA000000000
PVOID MmNonPagedPoolStart;
PVOID MmNonPagedPoolExpansionStart;
///PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; // 0xFFFFFAE000000000
PVOID MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END;
MMSUPPORT MmSystemCacheWs;
ULONG64 MxPfnSizeInBytes;
PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
ULONG MiNumberDescriptors = 0;
PFN_NUMBER MiSystemPages = 0;
BOOLEAN MiIncludeType[LoaderMaximum];
PFN_NUMBER MxFreePageBase;
ULONG64 MxFreePageCount = 0;
extern PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
BOOLEAN MiPfnsInitialized = FALSE;
/* FUNCTIONS *****************************************************************/
ULONG
NoDbgPrint(const char *Format, ...)
{
return 0;
}
VOID
NTAPI
MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY ListEntry;
PFN_NUMBER LastPage;
ULONG i;
/* Get the size of the boot loader's image allocations */
MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
MmBootImageSize = ROUND_UP(MmBootImageSize, 4 * 1024 * 1024);
/* Instantiate memory that we don't consider RAM/usable */
for (i = 0; i < LoaderMaximum; i++) MiIncludeType[i] = TRUE;
MiIncludeType[LoaderBad] = FALSE;
MiIncludeType[LoaderFirmwarePermanent] = FALSE;
MiIncludeType[LoaderSpecialMemory] = FALSE;
MiIncludeType[LoaderBBTMemory] = FALSE;
/* Loop the memory descriptors */
for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
ListEntry != &LoaderBlock->MemoryDescriptorListHead;
ListEntry = ListEntry->Flink)
{
/* Get the memory descriptor */
Descriptor = CONTAINING_RECORD(ListEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
/* Count it */
MiNumberDescriptors++;
/* Skip pages that are not part of the PFN database */
if (!MiIncludeType[Descriptor->MemoryType])
{
continue;
}
/* Add this to the total of pages */
MmNumberOfPhysicalPages += Descriptor->PageCount;
/* Check if this is the new lowest page */
if (Descriptor->BasePage < MmLowestPhysicalPage)
{
/* Update the lowest page */
MmLowestPhysicalPage = Descriptor->BasePage;
}
/* Check if this is the new highest page */
LastPage = Descriptor->BasePage + Descriptor->PageCount - 1;
if (LastPage > MmHighestPhysicalPage)
{
/* Update the highest page */
MmHighestPhysicalPage = LastPage;
}
/* Check if this is currently free memory */
if ((Descriptor->MemoryType == LoaderFree) ||
(Descriptor->MemoryType == LoaderLoadedProgram) ||
(Descriptor->MemoryType == LoaderFirmwareTemporary) ||
(Descriptor->MemoryType == LoaderOsloaderStack))
{
/* Check if this is the largest memory descriptor */
if (Descriptor->PageCount > MxFreePageCount)
{
/* For now, it is */
MxFreeDescriptor = Descriptor;
MxFreePageBase = Descriptor->BasePage;
MxFreePageCount = Descriptor->PageCount;
}
}
else
{
/* Add it to the amount of system used pages */
MiSystemPages += Descriptor->PageCount;
}
}
}
PFN_NUMBER
NTAPI
MiEarlyAllocPage()
{
PFN_NUMBER Pfn;
if (MiPfnsInitialized)
{
return MmAllocPage(MC_SYSTEM);
}
/* Make sure we have enough pages */
if (!MxFreePageCount)
{
/* Crash the system */
KeBugCheckEx(INSTALL_MORE_MEMORY,
MmNumberOfPhysicalPages,
MxFreeDescriptor->PageCount,
MxOldFreeDescriptor.PageCount,
1);
}
/* Use our lowest usable free pages */
Pfn = MxFreePageBase;
MxFreePageBase++;
MxFreePageCount--;
return Pfn;
}
PMMPTE
NTAPI
MxGetPte(PVOID Address)
{
PMMPTE Pte;
MMPTE TmplPte;
/* Setup template pte */
TmplPte.u.Long = 0;
TmplPte.u.Flush.Valid = 1;
TmplPte.u.Flush.Write = 1;
/* Get a pointer to the PXE */
Pte = MiAddressToPxe(Address);
if (!Pte->u.Hard.Valid)
{
/* It's not valid, map it! */
TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
*Pte = TmplPte;
/* Zero the page */
RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
}
/* Get a pointer to the PPE */
Pte = MiAddressToPpe(Address);
if (!Pte->u.Hard.Valid)
{
/* It's not valid, map it! */
TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
*Pte = TmplPte;
/* Zero the page */
RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
}
/* Get a pointer to the PDE */
Pte = MiAddressToPde(Address);
if (!Pte->u.Hard.Valid)
{
/* It's not valid, map it! */
TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
*Pte = TmplPte;
/* Zero the page */
RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
}
/* Get a pointer to the PTE */
Pte = MiAddressToPte(Address);
return Pte;
}
VOID
NTAPI
MxMapPage(PVOID Address)
{
MMPTE TmplPte, *Pte;
/* Setup template pte */
TmplPte.u.Long = 0;
TmplPte.u.Flush.Valid = 1;
TmplPte.u.Flush.Write = 1;
TmplPte.u.Hard.PageFrameNumber = MiEarlyAllocPage();
/* Get the PTE for that page */
Pte = MxGetPte(Address);
ASSERT(Pte->u.Hard.Valid == 0);
/* Map a physical page */
*Pte = TmplPte;
}
VOID
MxMapPageRange(PVOID Address, ULONG64 PageCount)
{
while (PageCount--)
{
/* Map the page */
MxMapPage(Address);
/* Goto next page */
Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
}
}
VOID
NTAPI
MiPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY ListEntry;
PUCHAR Page, FirstPage;
SIZE_T Size;
/* Calculate the size of the PFN database and convert to pages */
MxPfnSizeInBytes = ROUND_TO_PAGES((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
MxPfnAllocation = MxPfnSizeInBytes >> PAGE_SHIFT;
/* Simply start at hardcoded address */
MmPfnDatabase = MI_PFN_DATABASE;
/* Loop the memory descriptors */
for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
ListEntry != &LoaderBlock->MemoryDescriptorListHead;
ListEntry = ListEntry->Flink)
{
/* Get the memory descriptor */
Descriptor = CONTAINING_RECORD(ListEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
/* Skip pages that are not part of the PFN database */
if (MiIncludeType[Descriptor->MemoryType])
{
/* Get the base and size of this pfn database entry */
FirstPage = PAGE_ALIGN(&MmPfnDatabase[Descriptor->BasePage]);
Size = ROUND_TO_PAGES(Descriptor->PageCount * sizeof(MMPFN));
/* Loop the pages of this Pfn database entry */
for (Page = FirstPage; Page < FirstPage + Size; Page += PAGE_SIZE)
{
/* Is the page already mapped? */
if (!MmIsAddressValid(Page))
{
/* It's not, map it now */
MxMapPage(Page);
RtlZeroMemory(Page, PAGE_SIZE);
}
}
/* Zero out the pages */
RtlZeroMemory(FirstPage, Size);
}
}
}
VOID
NTAPI
MiInitializeSessionSpace(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
/* Set up session space */
MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
/* This is where we will load Win32k.sys and the video driver */
MiSessionImageEnd = MiSessionSpaceEnd;
MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize;
/* The view starts right below the session working set (itself below
* the image area) */
MiSessionViewEnd = MI_SESSION_VIEW_END;
MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize;
ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart));
/* Session pool follows */
MiSessionPoolEnd = MiSessionViewStart;
MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize;
ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart));
/* And it all begins here */
MmSessionBase = MiSessionPoolStart;
/* System view space ends at session space, so now that we know where
* this is, we can compute the base address of system view space itself. */
MiSystemViewStart = (PCHAR)MmSessionBase - MmSystemViewSize;
ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart));
/* Sanity checks */
ASSERT(MiSessionViewEnd <= MiSessionImageStart);
ASSERT(MmSessionBase <= MiSessionPoolStart);
}
VOID
MiInitializePageTable()
{
ULONG64 PageFrameOffset;
MMPTE TmplPte, *Pte;
/* HACK: don't use freeldr debug print anymore */
//FrLdrDbgPrint = NoDbgPrint;
/* Get current directory base */
MmSystemPageDirectory[0] = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
PageFrameOffset = MmSystemPageDirectory[0] << PAGE_SHIFT;
ASSERT(PageFrameOffset == __readcr3());
/* Set directory base for the system process */
PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
/* Enable global pages */
__writecr4(__readcr4() | CR4_PGE);
ASSERT(__readcr4() & CR4_PGE);
/* Enable no execute */
__writemsr(X86_MSR_EFER, __readmsr(X86_MSR_EFER) | EFER_NXE);
/* Loop the user mode PXEs */
for (Pte = MiAddressToPxe(0);
Pte <= MiAddressToPxe(MmHighestUserAddress);
Pte++)
{
/* Zero the PXE, clear all mappings */
Pte->u.Long = 0;
}
/* Flush the TLB */
KeFlushCurrentTb();
/* Set up a template PTE */
TmplPte.u.Long = 0;
TmplPte.u.Flush.Valid = 1;
TmplPte.u.Flush.Write = 1;
HyperTemplatePte = TmplPte;
/* Create PDPTs (72 KB) for shared system address space,
* skip page tables and hyperspace */
/* Loop the PXEs */
for (Pte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
Pte <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
Pte++)
{
/* Is the PXE already valid? */
if (!Pte->u.Hard.Valid)
{
/* It's not Initialize it */
TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage(0);
*Pte = TmplPte;
/* Zero the page. The PXE is the PTE for the PDPT. */
RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
}
}
/* Setup the mapping PTEs */
MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START);
MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
#ifdef _WINKD_
/* Setup debug mapping PTE */
MmDebugPte = MxGetPte(MI_DEBUG_MAPPING);
#endif
}
VOID
NTAPI
MiBuildNonPagedPool(VOID)
{
PMMPTE Pte;
PFN_COUNT PageCount;
/* Check if this is a machine with less than 256MB of RAM, and no overide */
if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
!(MmSizeOfNonPagedPoolInBytes))
{
/* Force the non paged pool to be 2MB so we can reduce RAM usage */
MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024;
}
/* Check if the user gave a ridicuously large nonpaged pool RAM size */
if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
(MmNumberOfPhysicalPages * 7 / 8))
{
/* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */
MmSizeOfNonPagedPoolInBytes = 0;
}
/* Check if no registry setting was set, or if the setting was too low */
if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize)
{
/* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */
MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
256 * MmMinAdditionNonPagedPoolPerMb;
}
/* Check if the registy setting or our dynamic calculation was too high */
if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
{
/* Set it to the maximum */
MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
}
/* Check if a percentage cap was set through the registry */
if (MmMaximumNonPagedPoolPercent)
{
/* Don't feel like supporting this right now */
UNIMPLEMENTED;
}
/* Page-align the nonpaged pool size */
MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
/* Now, check if there was a registry size for the maximum size */
if (!MmMaximumNonPagedPoolInBytes)
{
/* Start with the default (1MB) and add 400 KB for each MB above 4 */
MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) /
256 * MmMaxAdditionNonPagedPoolPerMb;
}
/* Don't let the maximum go too high */
if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE)
{
/* Set it to the upper limit */
MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
}
/* Put non paged pool to the end of the region */
MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes;
/* Make sure it doesn't collide with the PFN database */
if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes)
{
/* Put non paged pool after the PFN database */
MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes;
MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd -
(ULONG64)MmNonPagedPoolStart;
}
ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart));
/* Calculate the nonpaged pool expansion start region */
MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
MmSizeOfNonPagedPoolInBytes;
ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
/* Map the nonpaged pool */
PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
MxMapPageRange(MmNonPagedPoolStart, PageCount);
/* Loop the non paged pool extension PTEs */
for (Pte = MiAddressToPte(MmNonPagedPoolExpansionStart);
Pte <= MiAddressToPte(MmNonPagedPoolEnd);
Pte++)
{
/* Create PXE, PPE, PDE and zero the PTE */
MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
}
/* Initialize the ARM3 nonpaged pool */
MiInitializeNonPagedPool();
/* Initialize the nonpaged pool */
InitializePool(NonPagedPool, 0);
}
VOID
NTAPI
MiBuildSystemPteSpace()
{
PMMPTE Pte, StartPte, EndPte;
/* Use the default numer of system PTEs */
MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
/* System PTE pool is below the PFN database */
MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
MmNonPagedSystemStart = (PCHAR)MmPfnDatabase - MiNonPagedSystemSize;
MmNonPagedSystemStart = MM_ROUND_DOWN(MmNonPagedSystemStart, 512 * PAGE_SIZE);
/* Don't let it go below the minimum */
if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
{
/* This is a hard-coded limit in the Windows NT address space */
MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
/* Reduce the amount of system PTEs to reach this point */
MmNumberOfSystemPtes = ((ULONG64)MmPfnDatabase -
(ULONG64)MmNonPagedSystemStart) >>
PAGE_SHIFT;
MmNumberOfSystemPtes--;
ASSERT(MmNumberOfSystemPtes > 1000);
}
/* Set the range of system PTEs */
StartPte = MiAddressToPte(MI_SYSTEM_PTE_START);
EndPte = StartPte + MmNumberOfSystemPtes - 1;
/* Loop the system PTEs */
for (Pte = StartPte; Pte <= EndPte; Pte++)
{
/* Create PXE, PPE, PDE and zero the PTE */
MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
}
/* Create the system PTE space */
Pte = MiAddressToPte(MI_SYSTEM_PTE_START);
MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace);
/* Reserve system PTEs for zeroing PTEs and clear them */
MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace);
RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
/* Set the counter to maximum */
MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
}
VOID
NTAPI
MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
PPHYSICAL_MEMORY_DESCRIPTOR Buffer;
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
PLIST_ENTRY ListEntry;
PFN_NUMBER NextPage = -1;
PULONG Bitmap;
ULONG Runs = 0;
ULONG Size;
/* Calculate size for the PFN bitmap */
Size = ROUND_UP(MmHighestPhysicalPage + 1, sizeof(ULONG));
/* Allocate the PFN bitmap */
Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
/* Allocate enough memory for the physical memory block */
Buffer = ExAllocatePoolWithTag(NonPagedPool,
sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
sizeof(PHYSICAL_MEMORY_RUN) *
(MiNumberDescriptors - 1),
'lMmM');
if (!Bitmap || !Buffer)
{
/* This is critical */
KeBugCheckEx(INSTALL_MORE_MEMORY,
MmNumberOfPhysicalPages,
MmLowestPhysicalPage,
MmHighestPhysicalPage,
0x101);
}
/* Initialize the bitmap and clear all bits */
RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1);
RtlClearAllBits(&MiPfnBitMap);
/* Loop the memory descriptors */
for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
ListEntry != &LoaderBlock->MemoryDescriptorListHead;
ListEntry = ListEntry->Flink)
{
/* Get the memory descriptor */
Descriptor = CONTAINING_RECORD(ListEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
/* Skip pages that are not part of the PFN database */
if (!MiIncludeType[Descriptor->MemoryType])
{
continue;
}
/* Does the memory block begin where the last ended? */
if (Descriptor->BasePage == NextPage)
{
/* Add it to the current run */
Buffer->Run[Runs - 1].PageCount += Descriptor->PageCount;
}
else
{
/* Create a new run */
Runs++;
Buffer->Run[Runs - 1].BasePage = Descriptor->BasePage;
Buffer->Run[Runs - 1].PageCount = Descriptor->PageCount;
}
/* Set the bits in the PFN bitmap */
RtlSetBits(&MiPfnBitMap, Descriptor->BasePage, Descriptor->PageCount);
/* Set the next page */
NextPage = Descriptor->BasePage + Descriptor->PageCount;
}
// FIXME: allocate a buffer of better size
Buffer->NumberOfRuns = Runs;
Buffer->NumberOfPages = MmNumberOfPhysicalPages;
MmPhysicalMemoryBlock = Buffer;
}
VOID
NTAPI
MiBuildPagedPool_x(VOID)
{
PMMPTE Pte;
MMPTE TmplPte;
ULONG Size, BitMapSize;
/* Default size for paged pool is 4 times non paged pool */
MmSizeOfPagedPoolInBytes = 4 * MmMaximumNonPagedPoolInBytes;
/* Make sure it doesn't overflow */
if (MmSizeOfPagedPoolInBytes > ((ULONG64)MmNonPagedSystemStart -
(ULONG64)MmPagedPoolStart))
{
MmSizeOfPagedPoolInBytes = (ULONG64)MmNonPagedSystemStart -
(ULONG64)MmPagedPoolStart;
}
/* Make sure paged pool is big enough */
if (MmSizeOfPagedPoolInBytes < MI_MIN_INIT_PAGED_POOLSIZE)
{
MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
}
/* Align down to a PDE boundary */
MmSizeOfPagedPoolInBytes = ROUND_DOWN(MmSizeOfPagedPoolInBytes,
512 * PAGE_SIZE);
MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
/* This is where paged pool ends */
MmPagedPoolEnd = (PCHAR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes - 1;
/* Sanity check */
ASSERT(MmPagedPoolEnd < MmNonPagedSystemStart);
/* setup a template PTE */
TmplPte.u.Long = 0;
TmplPte.u.Flush.Valid = 1;
TmplPte.u.Flush.Write = 1;
/* Make sure the PXE is valid */
Pte = MiAddressToPxe(MmPagedPoolStart);
if (!Pte->u.Flush.Valid)
{
/* Map it! */
TmplPte.u.Flush.PageFrameNumber = MmAllocPage(MC_SYSTEM);
*Pte = TmplPte;
}
/* Map all page directories (max 128) */
for (Pte = MiAddressToPpe(MmPagedPoolStart);
Pte <= MiAddressToPpe(MmPagedPoolEnd);
Pte++)
{
if (!Pte->u.Flush.Valid)
{
/* Map it! */
TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
*Pte = TmplPte;
}
}
/* Create and map the first PTE for paged pool */
Pte = MxGetPte(MmPagedPoolStart);
TmplPte.u.Flush.PageFrameNumber = MiEarlyAllocPage();
*Pte = TmplPte;
/* Save the first and last paged pool PTE */
MmPagedPoolInfo.FirstPteForPagedPool = MiAddressToPte(MmPagedPoolStart);
MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
MmPagedPoolInfo.NextPdeForPagedPoolExpansion =
MiAddressToPde(MmPagedPoolStart) + 1;
// We keep track of each page via a bit, so check how big the bitmap will
// have to be (make sure to align our page count such that it fits nicely
// into a 4-byte aligned bitmap.
/* The size of the bitmap in bits is the size in pages */
BitMapSize = MmSizeOfPagedPoolInPages;
/* Calculate buffer size in bytes, aligned to 32 bits */
Size = sizeof(RTL_BITMAP) + ROUND_UP(BitMapSize, 32) / 8;
// Allocate the allocation bitmap, which tells us which regions have not yet
// been mapped into memory
MmPagedPoolInfo.PagedPoolAllocationMap =
ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
// Initialize it such that at first, only the first page's worth of PTEs is
// marked as allocated (incidentially, the first PDE we allocated earlier).
RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
(PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
BitMapSize);
RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 512);
// We have a second bitmap, which keeps track of where allocations end.
// Given the allocation bitmap and a base address, we can therefore figure
// out which page is the last page of that allocation, and thus how big the
// entire allocation is.
MmPagedPoolInfo.EndOfPagedPoolBitmap =
ExAllocatePoolWithTag(NonPagedPool, Size, ' mM');
ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
/* Initialize the bitmap */
RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
(PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
BitMapSize);
/* No allocations, no allocation ends; clear all bits. */
RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
/* Initialize the paged pool mutex */
KeInitializeGuardedMutex(&MmPagedPoolMutex);
/* Initialize the paged pool */
InitializePool(PagedPool, 0);
}
NTSTATUS
NTAPI
MmArmInitSystem_x(IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
if (Phase == 0)
{
MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
MmBootImageSize = ROUND_UP(MmBootImageSize, PAGE_SIZE);
/* Parse memory descriptors, find free pages */
MiEvaluateMemoryDescriptors(LoaderBlock);
/* Start PFN database at hardcoded address */
MmPfnDatabase = MI_PFN_DATABASE;
/* Prepare PFN database mappings */
MiPreparePfnDatabse(LoaderBlock);
/* Initialize the session space */
MiInitializeSessionSpace(LoaderBlock);
/* Initialize some mappings */
MiInitializePageTable();
/* Update the memory descriptor, to make sure the pages we used
won't get inserted into the PFN database */
MxOldFreeDescriptor = *MxFreeDescriptor;
MxFreeDescriptor->BasePage = MxFreePageBase;
MxFreeDescriptor->PageCount = MxFreePageCount;
}
else if (Phase == 1)
{
/* The PFN database was created, restore the free descriptor */
*MxFreeDescriptor = MxOldFreeDescriptor;
/* The pfn database is ready now */
MiPfnsInitialized = TRUE;
/* Initialize the nonpaged pool */
MiBuildNonPagedPool();
/* Initialize system PTE handling */
MiBuildSystemPteSpace();
/* Build the physical memory block */
MiBuildPhysicalMemoryBlock(LoaderBlock);
/* Size up paged pool and build the shadow system page directory */
//MiBuildPagedPool();
// This is the old stuff:
MmPagedPoolBase = (PVOID)((PCHAR)MmPagedPoolEnd + 1);
MmPagedPoolSize = MM_PAGED_POOL_SIZE;
ASSERT((PCHAR)MmPagedPoolBase + MmPagedPoolSize < (PCHAR)MmNonPagedSystemStart);
HalInitializeBios(0, LoaderBlock);
}
return STATUS_SUCCESS;
}
VOID
FASTCALL
MiSyncARM3WithROS(IN PVOID AddressStart,
IN PVOID AddressEnd)
{
}
NTSTATUS
NTAPI
MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}