Track valid physical memory pages using a PFN bitmap
This commit is contained in:
@@ -177,4 +177,19 @@ typedef struct _MMPFNLIST
|
|||||||
PFN_NUMBER Blink;
|
PFN_NUMBER Blink;
|
||||||
} MMPFNLIST, *PMMPFNLIST;
|
} MMPFNLIST, *PMMPFNLIST;
|
||||||
|
|
||||||
|
/* Physical memory run structure definition */
|
||||||
|
typedef struct _PHYSICAL_MEMORY_RUN
|
||||||
|
{
|
||||||
|
PFN_NUMBER BasePage;
|
||||||
|
PFN_NUMBER PageCount;
|
||||||
|
} PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;
|
||||||
|
|
||||||
|
/* Physical memory descriptor structure definition */
|
||||||
|
typedef struct _PHYSICAL_MEMORY_DESCRIPTOR
|
||||||
|
{
|
||||||
|
ULONG NumberOfRuns;
|
||||||
|
PFN_NUMBER NumberOfPages;
|
||||||
|
PHYSICAL_MEMORY_RUN Run[1];
|
||||||
|
} PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;
|
||||||
|
|
||||||
#endif /* __XTDK_MMTYPES_H */
|
#endif /* __XTDK_MMTYPES_H */
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ typedef struct _PECOFF_IMAGE_ROM_HEADER PECOFF_IMAGE_ROM_HEADER, *PPECOFF_IMAGE_
|
|||||||
typedef struct _PECOFF_IMAGE_ROM_OPTIONAL_HEADER PECOFF_IMAGE_ROM_OPTIONAL_HEADER, *PPECOFF_IMAGE_ROM_OPTIONAL_HEADER;
|
typedef struct _PECOFF_IMAGE_ROM_OPTIONAL_HEADER PECOFF_IMAGE_ROM_OPTIONAL_HEADER, *PPECOFF_IMAGE_ROM_OPTIONAL_HEADER;
|
||||||
typedef struct _PECOFF_IMAGE_SECTION_HEADER PECOFF_IMAGE_SECTION_HEADER, *PPECOFF_IMAGE_SECTION_HEADER;
|
typedef struct _PECOFF_IMAGE_SECTION_HEADER PECOFF_IMAGE_SECTION_HEADER, *PPECOFF_IMAGE_SECTION_HEADER;
|
||||||
typedef struct _PECOFF_IMAGE_VXD_HEADER PECOFF_IMAGE_VXD_HEADER, *PPECOFF_IMAGE_VXD_HEADER;
|
typedef struct _PECOFF_IMAGE_VXD_HEADER PECOFF_IMAGE_VXD_HEADER, *PPECOFF_IMAGE_VXD_HEADER;
|
||||||
|
typedef struct _PHYSICAL_MEMORY_DESCRIPTOR PHYSICAL_MEMORY_DESCRIPTOR, *PPHYSICAL_MEMORY_DESCRIPTOR;
|
||||||
|
typedef struct _PHYSICAL_MEMORY_RUN PHYSICAL_MEMORY_RUN, *PPHYSICAL_MEMORY_RUN;
|
||||||
typedef struct _PROCESSOR_IDENTITY PROCESSOR_IDENTITY, *PPROCESSOR_IDENTITY;
|
typedef struct _PROCESSOR_IDENTITY PROCESSOR_IDENTITY, *PPROCESSOR_IDENTITY;
|
||||||
typedef struct _PROCESSOR_POWER_STATE PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE;
|
typedef struct _PROCESSOR_POWER_STATE PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE;
|
||||||
typedef struct _RTL_BITMAP RTL_BITMAP, *PRTL_BITMAP;
|
typedef struct _RTL_BITMAP RTL_BITMAP, *PRTL_BITMAP;
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ namespace MM
|
|||||||
private:
|
private:
|
||||||
STATIC MMMEMORY_LAYOUT MemoryLayout;
|
STATIC MMMEMORY_LAYOUT MemoryLayout;
|
||||||
STATIC PFN_NUMBER NumberOfSystemPtes;
|
STATIC PFN_NUMBER NumberOfSystemPtes;
|
||||||
|
STATIC PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC XTAPI ULONG_PTR GetInstalledMemorySize(VOID);
|
STATIC XTAPI ULONG_PTR GetInstalledMemorySize(VOID);
|
||||||
STATIC XTAPI PMMMEMORY_LAYOUT GetMemoryLayout(VOID);
|
STATIC XTAPI PMMMEMORY_LAYOUT GetMemoryLayout(VOID);
|
||||||
STATIC XTAPI PFN_NUMBER GetNumberOfSystemPtes();
|
STATIC XTAPI PFN_NUMBER GetNumberOfSystemPtes(VOID);
|
||||||
|
STATIC XTAPI PPHYSICAL_MEMORY_DESCRIPTOR GetPhysicalMemoryBlock(VOID);
|
||||||
STATIC XTAPI VOID InitializeMemoryLayout(VOID);
|
STATIC XTAPI VOID InitializeMemoryLayout(VOID);
|
||||||
STATIC XTAPI VOID InitializeMemoryManager(VOID);
|
STATIC XTAPI VOID InitializeMemoryManager(VOID);
|
||||||
STATIC XTAPI BOOLEAN VerifyMemoryTypeFree(IN LOADER_MEMORY_TYPE MemoryType);
|
STATIC XTAPI BOOLEAN VerifyMemoryTypeFree(IN LOADER_MEMORY_TYPE MemoryType);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace MM
|
|||||||
STATIC ULONGLONG NumberOfPhysicalPages;
|
STATIC ULONGLONG NumberOfPhysicalPages;
|
||||||
STATIC LOADER_MEMORY_DESCRIPTOR OriginalFreeDescriptor;
|
STATIC LOADER_MEMORY_DESCRIPTOR OriginalFreeDescriptor;
|
||||||
STATIC PMMPFNLIST PageLocationList[];
|
STATIC PMMPFNLIST PageLocationList[];
|
||||||
|
STATIC RTL_BITMAP PfnBitMap;
|
||||||
STATIC MMPFNLIST RomPagesList;
|
STATIC MMPFNLIST RomPagesList;
|
||||||
STATIC MMPFNLIST StandbyPagesList;
|
STATIC MMPFNLIST StandbyPagesList;
|
||||||
STATIC MMPFNLIST ZeroedPagesList;
|
STATIC MMPFNLIST ZeroedPagesList;
|
||||||
@@ -49,6 +50,7 @@ namespace MM
|
|||||||
STATIC XTAPI ULONG_PTR GetHighestPhysicalPage(VOID);
|
STATIC XTAPI ULONG_PTR GetHighestPhysicalPage(VOID);
|
||||||
STATIC XTAPI ULONGLONG GetNumberOfPhysicalPages(VOID);
|
STATIC XTAPI ULONGLONG GetNumberOfPhysicalPages(VOID);
|
||||||
STATIC XTAPI PMMPFN GetPfnEntry(IN PFN_NUMBER Pfn);
|
STATIC XTAPI PMMPFN GetPfnEntry(IN PFN_NUMBER Pfn);
|
||||||
|
STATIC XTAPI VOID InitializePfnBitmap(VOID);
|
||||||
STATIC XTAPI VOID InitializePfnDatabase(VOID);
|
STATIC XTAPI VOID InitializePfnDatabase(VOID);
|
||||||
STATIC XTAPI VOID LinkPfn(IN PFN_NUMBER PageFrameIndex,
|
STATIC XTAPI VOID LinkPfn(IN PFN_NUMBER PageFrameIndex,
|
||||||
IN PMMPTE PointerPte,
|
IN PMMPTE PointerPte,
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ MMMEMORY_LAYOUT MM::Manager::MemoryLayout;
|
|||||||
/* Total number of PTEs reserved for system space mapping */
|
/* Total number of PTEs reserved for system space mapping */
|
||||||
PFN_NUMBER MM::Manager::NumberOfSystemPtes;
|
PFN_NUMBER MM::Manager::NumberOfSystemPtes;
|
||||||
|
|
||||||
|
/* Physical memory block descriptor */
|
||||||
|
PPHYSICAL_MEMORY_DESCRIPTOR MM::Manager::PhysicalMemoryBlock;
|
||||||
|
|
||||||
/* Instance of the page map routines for the current PML level */
|
/* Instance of the page map routines for the current PML level */
|
||||||
MM::PPAGEMAP MM::Paging::PmlRoutines;
|
MM::PPAGEMAP MM::Paging::PmlRoutines;
|
||||||
|
|
||||||
@@ -91,6 +94,9 @@ PMMPFNLIST MM::Pfn::PageLocationList[] = {&ZeroedPagesList,
|
|||||||
NULLPTR,
|
NULLPTR,
|
||||||
NULLPTR};
|
NULLPTR};
|
||||||
|
|
||||||
|
/* Bitmap used to track physical pages */
|
||||||
|
RTL_BITMAP MM::Pfn::PfnBitMap;
|
||||||
|
|
||||||
/* List containing pages mapped as Read-Only (ROM) */
|
/* List containing pages mapped as Read-Only (ROM) */
|
||||||
MMPFNLIST MM::Pfn::RomPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR};
|
MMPFNLIST MM::Pfn::RomPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR};
|
||||||
|
|
||||||
|
|||||||
@@ -81,11 +81,146 @@ MM::Manager::GetMemoryLayout(VOID)
|
|||||||
*/
|
*/
|
||||||
XTAPI
|
XTAPI
|
||||||
PFN_NUMBER
|
PFN_NUMBER
|
||||||
MM::Manager::GetNumberOfSystemPtes()
|
MM::Manager::GetNumberOfSystemPtes(VOID)
|
||||||
{
|
{
|
||||||
return NumberOfSystemPtes;
|
return NumberOfSystemPtes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes and returns the system physical memory descriptor block.
|
||||||
|
*
|
||||||
|
* @return This routine returns a pointer to the structure representing the system usable physical memory block.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
PPHYSICAL_MEMORY_DESCRIPTOR
|
||||||
|
MM::Manager::GetPhysicalMemoryBlock(VOID)
|
||||||
|
{
|
||||||
|
PPHYSICAL_MEMORY_DESCRIPTOR PrimaryBuffer, SecondaryBuffer;
|
||||||
|
PKERNEL_INITIALIZATION_BLOCK InitializationBlock;
|
||||||
|
PLOADER_MEMORY_DESCRIPTOR MemoryDescriptor;
|
||||||
|
PFN_NUMBER PageFrameNumer, NumberOfPages;
|
||||||
|
ULONG DescriptorCount, RunCount;
|
||||||
|
PLIST_ENTRY ListEntry;
|
||||||
|
XTSTATUS Status;
|
||||||
|
|
||||||
|
/* Check if the physical memory block has already been initialized */
|
||||||
|
if(!PhysicalMemoryBlock)
|
||||||
|
{
|
||||||
|
/* Reset local tracking variables */
|
||||||
|
DescriptorCount = 0;
|
||||||
|
NumberOfPages = 0;
|
||||||
|
PageFrameNumer = -1;
|
||||||
|
RunCount = 0;
|
||||||
|
|
||||||
|
/* Retrieve the kernel initialization block */
|
||||||
|
InitializationBlock = KE::BootInformation::GetInitializationBlock();
|
||||||
|
|
||||||
|
/* Iterate through the loader memory descriptor list to determine its size */
|
||||||
|
ListEntry = InitializationBlock->MemoryDescriptorListHead.Flink;
|
||||||
|
while(ListEntry != &InitializationBlock->MemoryDescriptorListHead)
|
||||||
|
{
|
||||||
|
/* Count this descriptor */
|
||||||
|
DescriptorCount++;
|
||||||
|
|
||||||
|
/* Go to the next descriptor */
|
||||||
|
ListEntry = ListEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the memory descriptor list is not empty */
|
||||||
|
if(DescriptorCount == 0)
|
||||||
|
{
|
||||||
|
/* Fail gracefully if no memory descriptors were found, by returning NULLPTR */
|
||||||
|
return NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a primary buffer sized for the maximum possible number of runs */
|
||||||
|
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||||
|
sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
|
||||||
|
sizeof(PHYSICAL_MEMORY_RUN) *
|
||||||
|
(DescriptorCount - 1),
|
||||||
|
(PVOID*)&PrimaryBuffer,
|
||||||
|
SIGNATURE32('M', 'M', 'g', 'r'));
|
||||||
|
if(Status != STATUS_SUCCESS || !PrimaryBuffer)
|
||||||
|
{
|
||||||
|
/* Primary pool allocation failed, return NULLPTR */
|
||||||
|
return NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Traverse the memory descriptor list a second time to build the map */
|
||||||
|
ListEntry = InitializationBlock->MemoryDescriptorListHead.Flink;
|
||||||
|
while(ListEntry != &InitializationBlock->MemoryDescriptorListHead)
|
||||||
|
{
|
||||||
|
/* Resolve the memory descriptor record from the current list entry */
|
||||||
|
MemoryDescriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
|
||||||
|
|
||||||
|
/* Filter out bad, reserved, or invisible memory types */
|
||||||
|
if((MemoryDescriptor->MemoryType < LoaderMaximum) &&
|
||||||
|
(MemoryDescriptor->MemoryType != LoaderBad) &&
|
||||||
|
!VerifyMemoryTypeInvisible(MemoryDescriptor->MemoryType))
|
||||||
|
{
|
||||||
|
/* Accumulate the total number of usable physical pages */
|
||||||
|
NumberOfPages += MemoryDescriptor->PageCount;
|
||||||
|
|
||||||
|
/* Check if the current descriptor is contiguous with the previous run */
|
||||||
|
if(RunCount > 0 && MemoryDescriptor->BasePage == PageFrameNumer)
|
||||||
|
{
|
||||||
|
/* Coalesce the contiguous descriptor into the existing physical run */
|
||||||
|
PrimaryBuffer->Run[RunCount - 1].PageCount += MemoryDescriptor->PageCount;
|
||||||
|
PageFrameNumer += MemoryDescriptor->PageCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Start a new physical run with the new descriptor's boundaries */
|
||||||
|
PrimaryBuffer->Run[RunCount].BasePage = MemoryDescriptor->BasePage;
|
||||||
|
PrimaryBuffer->Run[RunCount].PageCount = MemoryDescriptor->PageCount;
|
||||||
|
|
||||||
|
/* Update the expected next page frame number for future contiguity checks */
|
||||||
|
PageFrameNumer = PrimaryBuffer->Run[RunCount].BasePage + PrimaryBuffer->Run[RunCount].PageCount;
|
||||||
|
|
||||||
|
/* Increment the total number of distinct physical memory runs */
|
||||||
|
RunCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the next descriptor */
|
||||||
|
ListEntry = ListEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the buffer can be shrunk due to coalesced memory runs */
|
||||||
|
if(DescriptorCount > RunCount)
|
||||||
|
{
|
||||||
|
/* Allocate a secondary, more tightly sized buffer to reduce memory footprint */
|
||||||
|
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||||
|
sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
|
||||||
|
sizeof(PHYSICAL_MEMORY_RUN) *
|
||||||
|
(RunCount - 1),
|
||||||
|
(PVOID*)&SecondaryBuffer,
|
||||||
|
SIGNATURE32('M', 'M', 'g', 'r'));
|
||||||
|
if(Status == STATUS_SUCCESS && SecondaryBuffer)
|
||||||
|
{
|
||||||
|
/* Copy the coalesced runs from the oversized primary buffer */
|
||||||
|
RtlCopyMemory(SecondaryBuffer->Run, PrimaryBuffer->Run, sizeof(PHYSICAL_MEMORY_RUN) * RunCount);
|
||||||
|
|
||||||
|
/* Free the primary buffer */
|
||||||
|
MM::Allocator::FreePool(PrimaryBuffer, SIGNATURE32('M', 'M', 'g', 'r'));
|
||||||
|
|
||||||
|
/* Update the primary buffer pointer */
|
||||||
|
PrimaryBuffer = SecondaryBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Populate the final metadata and save the physical memory block globally */
|
||||||
|
PrimaryBuffer->NumberOfRuns = RunCount;
|
||||||
|
PrimaryBuffer->NumberOfPages = NumberOfPages;
|
||||||
|
PhysicalMemoryBlock = PrimaryBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a pointer to the physical memory block */
|
||||||
|
return PhysicalMemoryBlock;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs an early initialization of the XTOS Memory Manager.
|
* Performs an early initialization of the XTOS Memory Manager.
|
||||||
*
|
*
|
||||||
@@ -130,6 +265,9 @@ MM::Manager::InitializeMemoryManager(VOID)
|
|||||||
/* Initialize PFN database */
|
/* Initialize PFN database */
|
||||||
MM::Pfn::InitializePfnDatabase();
|
MM::Pfn::InitializePfnDatabase();
|
||||||
|
|
||||||
|
/* Initialize PFN bitmap */
|
||||||
|
MM::Pfn::InitializePfnBitmap();
|
||||||
|
|
||||||
/* Initialize paged pool */
|
/* Initialize paged pool */
|
||||||
MM::Allocator::InitializePagedPool();
|
MM::Allocator::InitializePagedPool();
|
||||||
|
|
||||||
|
|||||||
@@ -423,6 +423,13 @@ MM::Pfn::GetPfnEntry(IN PFN_NUMBER Pfn)
|
|||||||
return NULLPTR;
|
return NULLPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure this page has a PFN entry set */
|
||||||
|
if(PfnBitMap.Buffer && !RTL::BitMap::TestBit(&PfnBitMap, Pfn))
|
||||||
|
{
|
||||||
|
/* The requested page number is not set in the bitmap, return NULLPTR */
|
||||||
|
return NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the memory layout */
|
/* Get the memory layout */
|
||||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||||
|
|
||||||
@@ -445,6 +452,60 @@ MM::Pfn::IncrementAvailablePages(VOID)
|
|||||||
AvailablePages++;
|
AvailablePages++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the PFN bitmap to track available physical memory.
|
||||||
|
*
|
||||||
|
* @return This routine does not return any value.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
VOID
|
||||||
|
MM::Pfn::InitializePfnBitmap(VOID)
|
||||||
|
{
|
||||||
|
PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock;
|
||||||
|
XTSTATUS Status;
|
||||||
|
PVOID BitMap;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
/* Retrieve the global physical memory descriptor block */
|
||||||
|
PhysicalMemoryBlock = MM::Manager::GetPhysicalMemoryBlock();
|
||||||
|
if(!PhysicalMemoryBlock)
|
||||||
|
{
|
||||||
|
/* Physical memory layout unavailable, kernel panic */
|
||||||
|
KE::Crash::Panic(0x7D, NumberOfPhysicalPages, LowestPhysicalPage, HighestPhysicalPage, 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the required bitmap size and allocate memory */
|
||||||
|
Status = MM::Allocator::AllocatePool(NonPagedPool,
|
||||||
|
(((HighestPhysicalPage + 1) + 31) / 32) * 4,
|
||||||
|
(PVOID *)&BitMap,
|
||||||
|
SIGNATURE32('M', 'M', 'g', 'r'));
|
||||||
|
if(Status != STATUS_SUCCESS || !BitMap)
|
||||||
|
{
|
||||||
|
/* Memory allocation failed, kernel panic */
|
||||||
|
DebugPrint(L"Insufficient physical pages! Install additional memory\n");
|
||||||
|
KE::Crash::Panic(0x7D, NumberOfPhysicalPages, LowestPhysicalPage, HighestPhysicalPage, 0x101);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the PFN bitmap structure and clear all bits by default */
|
||||||
|
RTL::BitMap::InitializeBitMap(&PfnBitMap, (PULONG_PTR)BitMap, (ULONG)HighestPhysicalPage + 1);
|
||||||
|
RTL::BitMap::ClearAllBits(&PfnBitMap);
|
||||||
|
|
||||||
|
/* Iterate through all contiguous physical memory runs to populate the availability map */
|
||||||
|
for(Index = 0; Index < PhysicalMemoryBlock->NumberOfRuns; Index++)
|
||||||
|
{
|
||||||
|
/* Ensure the current memory run contains at least one valid page frame */
|
||||||
|
if((&PhysicalMemoryBlock->Run[Index])->PageCount)
|
||||||
|
{
|
||||||
|
/* Set the corresponding bits to mark these physical pages as available for allocation */
|
||||||
|
RtlSetBits(&PfnBitMap,
|
||||||
|
(ULONG)(&PhysicalMemoryBlock->Run[Index])->BasePage,
|
||||||
|
(ULONG)(&PhysicalMemoryBlock->Run[Index])->PageCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Links a physical page to the appropriate free lists.
|
* Links a physical page to the appropriate free lists.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user