Implement PFN database initialization and memory descriptor processing
This commit is contained in:
@@ -54,6 +54,7 @@ list(APPEND XTOSKRNL_SOURCE
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/mmgr.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/pagemap.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/paging.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/pfn.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/${ARCH}/pte.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/colors.cc
|
||||
${XTOSKRNL_SOURCE_DIR}/mm/data.cc
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MM
|
||||
STATIC XTAPI BOOLEAN AddressValid(IN PVOID VirtualAddress);
|
||||
STATIC XTAPI ULONG GetPtesPerPage(VOID);
|
||||
STATIC XTAPI PMMPTE GetSystemPteBaseAddress(VOID);
|
||||
STATIC XTAPI PMMPTE GetValidPte(VOID);
|
||||
STATIC XTAPI VOID InitializePageTable(VOID);
|
||||
STATIC XTAPI VOID InitializeSystemPteSpace(VOID);
|
||||
STATIC XTAPI VOID MapP5E(PVOID StartAddress,
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MM
|
||||
STATIC XTAPI ULONG GetNextColor();
|
||||
STATIC XTAPI ULONG GetPagingColors();
|
||||
STATIC XTAPI ULONG GetPagingColorsMask();
|
||||
STATIC XTAPI VOID InitializeColorTables(VOID);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MM
|
||||
STATIC XTAPI BOOLEAN AddressValid(IN PVOID VirtualAddress);
|
||||
STATIC XTAPI ULONG GetPtesPerPage(VOID);
|
||||
STATIC XTAPI PMMPTE GetSystemPteBaseAddress(VOID);
|
||||
STATIC XTAPI PMMPTE GetValidPte(VOID);
|
||||
STATIC XTAPI VOID InitializePageTable(VOID);
|
||||
STATIC XTAPI VOID InitializeSystemPteSpace(VOID);
|
||||
STATIC XTAPI VOID MapPDE(PVOID StartAddress,
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace MM
|
||||
private:
|
||||
STATIC PFN_NUMBER AvailablePages;
|
||||
STATIC PLOADER_MEMORY_DESCRIPTOR FreeDescriptor;
|
||||
STATIC MMPFNLIST FreePagesList;
|
||||
STATIC ULONG_PTR HighestPhysicalPage;
|
||||
STATIC ULONG_PTR LowestPhysicalPage;
|
||||
STATIC ULONGLONG NumberOfPhysicalPages;
|
||||
@@ -29,14 +30,25 @@ namespace MM
|
||||
public:
|
||||
STATIC XTAPI PFN_NUMBER AllocateBootstrapPages(IN PFN_NUMBER NumberOfPages);
|
||||
STATIC XTAPI VOID ComputePfnDatabaseSize(VOID);
|
||||
STATIC XTAPI ULONG_PTR GetHighestPhysicalPage(VOID);
|
||||
STATIC XTAPI ULONGLONG GetNumberOfPhysicalPages(VOID);
|
||||
STATIC XTAPI PFN_NUMBER GetPfnDatabaseSize(VOID);
|
||||
STATIC XTAPI PMMPFN GetPfnEntry(IN PFN_NUMBER Pfn);
|
||||
STATIC XTAPI VOID InitializePfnDatabase(VOID);
|
||||
STATIC XTAPI VOID ScanMemoryDescriptors(VOID);
|
||||
|
||||
private:
|
||||
STATIC XTAPI VOID DecrementAvailablePages(VOID);
|
||||
STATIC XTAPI VOID IncrementAvailablePages(VOID);
|
||||
STATIC XTAPI VOID InitializePageTablePfns(VOID);
|
||||
STATIC XTAPI VOID LinkFreePage(IN PFN_NUMBER PageFrameIndex);
|
||||
STATIC XTAPI VOID LinkPfnForPageTable(PFN_NUMBER PageFrameIndex,
|
||||
PMMPTE PointerPte);
|
||||
STATIC XTAPI VOID ProcessMemoryDescriptor(PFN_NUMBER BasePage,
|
||||
PFN_NUMBER PageCount,
|
||||
LOADER_MEMORY_TYPE MemoryType);
|
||||
STATIC XTAPI VOID ScanPageTable(IN PMMPTE PointerPte,
|
||||
ULONG Level);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
249
xtoskrnl/mm/amd64/pfn.cc
Normal file
249
xtoskrnl/mm/amd64/pfn.cc
Normal file
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/mm/amd64/pfn.cc
|
||||
* DESCRIPTION: Physical Frame Number for AMD64 support
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
* Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the PFN database by mapping virtual memory and populating entries.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::InitializePfnDatabase(VOID)
|
||||
{
|
||||
PKERNEL_INITIALIZATION_BLOCK InitializationBlock;
|
||||
PLIST_ENTRY ListEntry;
|
||||
PLOADER_MEMORY_DESCRIPTOR Descriptor;
|
||||
PFN_NUMBER BasePage, PageCount;
|
||||
PUCHAR PfnDatabaseEnd;
|
||||
PMMMEMORY_LAYOUT MemoryLayout;
|
||||
PMMPTE ValidPte;
|
||||
|
||||
/* Raise runlevel and acquire the PFN lock */
|
||||
KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL);
|
||||
KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock);
|
||||
|
||||
/* Get the kernel initialization block */
|
||||
InitializationBlock = KE::BootInformation::GetInitializationBlock();
|
||||
|
||||
/* Get the memory layout */
|
||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||
|
||||
/* Get the PFN database size and calculate the end of the PFN database virtual address space */
|
||||
PfnDatabaseEnd = (PUCHAR)MemoryLayout->PfnDatabaseAddress + (PfnDatabaseSize * MM_PAGE_SIZE) - 1;
|
||||
|
||||
/* Get a template PTE for mapping the PFN database pages */
|
||||
ValidPte = MM::Pte::GetValidPte();
|
||||
|
||||
/* Map the Page Directory and Page Directory Pointer tables for the PFN database */
|
||||
MM::Pte::MapPPE(MemoryLayout->PfnDatabaseAddress, PfnDatabaseEnd, ValidPte);
|
||||
MM::Pte::MapPDE(MemoryLayout->PfnDatabaseAddress, PfnDatabaseEnd, ValidPte);
|
||||
|
||||
/* Initialize the color tables */
|
||||
MM::Colors::InitializeColorTables();
|
||||
|
||||
/* Iterate over memory descriptors to map the PFN database and initialize entries */
|
||||
ListEntry = InitializationBlock->MemoryDescriptorListHead.Flink;
|
||||
while(ListEntry != &InitializationBlock->MemoryDescriptorListHead)
|
||||
{
|
||||
/* Get the descriptor */
|
||||
Descriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
|
||||
|
||||
/* Skip invisible memory regions */
|
||||
if(MM::Manager::VerifyMemoryTypeInvisible(Descriptor->MemoryType))
|
||||
{
|
||||
/* Move to the next descriptor and continue */
|
||||
ListEntry = ListEntry->Flink;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Determine the physical page range to process */
|
||||
if(Descriptor == FreeDescriptor)
|
||||
{
|
||||
BasePage = OriginalFreeDescriptor.BasePage;
|
||||
PageCount = OriginalFreeDescriptor.PageCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
BasePage = Descriptor->BasePage;
|
||||
PageCount = Descriptor->PageCount;
|
||||
}
|
||||
|
||||
/* Map PFN database entries for this physical range */
|
||||
MM::Pte::MapPTE(&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[BasePage],
|
||||
(PUCHAR)&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[BasePage + PageCount] - 1,
|
||||
ValidPte);
|
||||
|
||||
/* Split PFN database allocation out of the free descriptor */
|
||||
if(Descriptor == FreeDescriptor)
|
||||
{
|
||||
/* Initialize PFNs for the remaining free memory */
|
||||
ProcessMemoryDescriptor(BasePage + PfnDatabaseSize, PageCount - PfnDatabaseSize, LoaderFree);
|
||||
|
||||
/* Initialize PFNs for the physical pages backing the PFN database */
|
||||
ProcessMemoryDescriptor(BasePage, PfnDatabaseSize, LoaderMemoryData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialize PFNs for this memory range */
|
||||
ProcessMemoryDescriptor(BasePage, PageCount, Descriptor->MemoryType);
|
||||
}
|
||||
|
||||
/* Move to the next descriptor */
|
||||
ListEntry = ListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Restore original free descriptor */
|
||||
*FreeDescriptor = OriginalFreeDescriptor;
|
||||
|
||||
/* Initialize PFNs backing page tables */
|
||||
InitializePageTablePfns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes PFN database entries for the system page tables.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::InitializePageTablePfns(VOID)
|
||||
{
|
||||
PFN_NUMBER PageFrameIndex;
|
||||
PMMPFN Pfn;
|
||||
ULONG RootLevel;
|
||||
PMMPTE RootPte;
|
||||
|
||||
/* Determine root structure based on paging mode */
|
||||
if(MM::Paging::GetXpaStatus())
|
||||
{
|
||||
/* XPA enabled, 5-level paging (LA57) */
|
||||
RootLevel = 5;
|
||||
|
||||
/* Retrieve the PFN of the PML5 table and its virtual base address */
|
||||
PageFrameIndex = MM::Paging::GetPageFrameNumber(MM::Paging::GetPteAddress((PVOID)MM_P5E_LA57_BASE));
|
||||
RootPte = (PMMPTE)MM::Paging::GetP5eAddress(NULLPTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XPA disabled, 4-level paging */
|
||||
RootLevel = 4;
|
||||
|
||||
/* Retrieve the PFN of the PML4 table and its virtual base address */
|
||||
PageFrameIndex = MM::Paging::GetPageFrameNumber(MM::Paging::GetPteAddress((PVOID)MM_PXE_BASE));
|
||||
RootPte = (PMMPTE)MM::Paging::GetPxeAddress(NULLPTR);
|
||||
}
|
||||
|
||||
/* Initialize the PFN entry for the root page table itself */
|
||||
Pfn = GetPfnEntry(PageFrameIndex);
|
||||
if(Pfn)
|
||||
{
|
||||
/* Initialize the PFN entry */
|
||||
Pfn->PteAddress = NULLPTR;
|
||||
Pfn->u1.WsIndex = 0;
|
||||
Pfn->u2.ShareCount = 1;
|
||||
Pfn->u3.e1.CacheAttribute = PfnNonCached;
|
||||
Pfn->u3.e2.ReferenceCount = 1;
|
||||
Pfn->u4.PteFrame = 0;
|
||||
}
|
||||
|
||||
/* Start recursive scan from the top level */
|
||||
if(RootPte)
|
||||
{
|
||||
/* Scan the root page table */
|
||||
ScanPageTable(RootPte, RootLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans a page table to initialize PFN database entries for active pages.
|
||||
*
|
||||
* @param PointerPte
|
||||
* Pointer to the base of the page table to scan.
|
||||
*
|
||||
* @param Level
|
||||
* The paging level of the table being scanned.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::ScanPageTable(IN PMMPTE PointerPte,
|
||||
IN ULONG Level)
|
||||
{
|
||||
PVOID Address;
|
||||
ULONG Index;
|
||||
PMMPTE NextLevelPte;
|
||||
ULONG PtesPerPage;
|
||||
|
||||
/* Get the number of PTEs per page */
|
||||
PtesPerPage = MM::Pte::GetPtesPerPage();
|
||||
|
||||
/* Iterate through all entries in the current page table */
|
||||
for(Index = 0; Index < PtesPerPage; Index++)
|
||||
{
|
||||
/* Check if the page table entry is present */
|
||||
if(MM::Paging::PteValid(PointerPte))
|
||||
{
|
||||
/* Mark the PFN pointed to by this entry as active */
|
||||
LinkPfnForPageTable(MM::Paging::GetPageFrameNumber(PointerPte), PointerPte);
|
||||
|
||||
/* Recurse to the next level, if this is not a leaf node (PTE) */
|
||||
if(Level > 1)
|
||||
{
|
||||
/* Calculate the virtual address mapped by this entry to find the next table */
|
||||
switch(Level)
|
||||
{
|
||||
case 5:
|
||||
/* Calculate PXE */
|
||||
Address = MM::Paging::GetP5eVirtualAddress((PMMP5E)PointerPte);
|
||||
NextLevelPte = (PMMPTE)MM::Paging::GetPxeAddress(Address);
|
||||
break;
|
||||
case 4:
|
||||
/* Calculate PPE */
|
||||
Address = MM::Paging::GetPxeVirtualAddress((PMMPXE)PointerPte);
|
||||
NextLevelPte = (PMMPTE)MM::Paging::GetPpeAddress(Address);
|
||||
break;
|
||||
case 3:
|
||||
/* Calculate PDE */
|
||||
Address = MM::Paging::GetPpeVirtualAddress((PMMPPE)PointerPte);
|
||||
NextLevelPte = (PMMPTE)MM::Paging::GetPdeAddress(Address);
|
||||
break;
|
||||
case 2:
|
||||
/* Calculate PTE */
|
||||
Address = MM::Paging::GetPdeVirtualAddress((PMMPDE)PointerPte);
|
||||
NextLevelPte = MM::Paging::GetPteAddress(Address);
|
||||
break;
|
||||
default:
|
||||
/* Nothing to calculate, return NULLPTR */
|
||||
NextLevelPte = NULLPTR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Recurse deeper if not at the bottom level (PTE) already */
|
||||
if(NextLevelPte)
|
||||
{
|
||||
/* Recursively scan the next level page table */
|
||||
ScanPageTable(NextLevelPte, Level - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Move to the next entry in the current table */
|
||||
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||
}
|
||||
}
|
||||
@@ -93,3 +93,69 @@ MM::Colors::GetPagingColorsMask()
|
||||
/* Return the mask used for page coloring calculations */
|
||||
return PagingColorsMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the data structures for page coloring.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Colors::InitializeColorTables(VOID)
|
||||
{
|
||||
PMMMEMORY_LAYOUT MemoryLayout;
|
||||
PMMPTE PointerPte, LastPte;
|
||||
ULONG Color;
|
||||
PMMPTE ValidPte;
|
||||
|
||||
/* Get the memory layout */
|
||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||
|
||||
/* Set the base address of the color tables to start right after the PFN database */
|
||||
FreePages[0] = (PMMCOLOR_TABLES)&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[MM::Pfn::GetHighestPhysicalPage() + 1];
|
||||
|
||||
/* Calculate the virtual address range for both color tables */
|
||||
PointerPte = MM::Paging::GetPteAddress(&FreePages[0][0]);
|
||||
LastPte = MM::Paging::GetPteAddress((PVOID)((ULONG_PTR)FreePages[0] +
|
||||
(2 * PagingColors * sizeof(MMCOLOR_TABLES)) - 1));
|
||||
|
||||
/* Get a pointer to a PTE template */
|
||||
ValidPte = MM::Pte::GetValidPte();
|
||||
|
||||
/* Ensure the entire virtual address range for the color tables is mapped */
|
||||
while(PointerPte <= LastPte)
|
||||
{
|
||||
/* Check if a page in the range is not mapped */
|
||||
if(!MM::Paging::PteValid(PointerPte))
|
||||
{
|
||||
/* Use the bootstrap allocator to get a physical page */
|
||||
MM::Paging::SetPte(ValidPte, MM::Pfn::AllocateBootstrapPages(1), 0);
|
||||
*PointerPte = *ValidPte;
|
||||
|
||||
/* Zero out the newly mapped page */
|
||||
RTL::Memory::ZeroMemory(MM::Paging::GetPteVirtualAddress(PointerPte), MM_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* Move to the next PTE in the range */
|
||||
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||
}
|
||||
|
||||
/* Set the pointer for the second list */
|
||||
FreePages[1] = &FreePages[0][PagingColors];
|
||||
|
||||
/* Initialize all entries in both color tables */
|
||||
for(Color = 0; Color < PagingColors; Color++)
|
||||
{
|
||||
/* Initialize the FreePageList entry for the current color */
|
||||
FreePages[FreePageList][Color].Flink = MAXULONG_PTR;
|
||||
FreePages[FreePageList][Color].Blink = (PVOID)MAXULONG_PTR;
|
||||
FreePages[FreePageList][Color].Count = 0;
|
||||
|
||||
/* Initialize the ZeroedPageList entry for the current color */
|
||||
FreePages[ZeroedPageList][Color].Flink = MAXULONG_PTR;
|
||||
FreePages[ZeroedPageList][Color].Blink = (PVOID)MAXULONG_PTR;
|
||||
FreePages[ZeroedPageList][Color].Count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ PFN_NUMBER MM::Pfn::AvailablePages;
|
||||
/* Biggest free memory descriptor */
|
||||
PLOADER_MEMORY_DESCRIPTOR MM::Pfn::FreeDescriptor;
|
||||
|
||||
/* List containing free physical pages */
|
||||
MMPFNLIST MM::Pfn::FreePagesList = {0, FreePageList, MAXULONG_PTR, MAXULONG_PTR};
|
||||
|
||||
/* Highest physical page number */
|
||||
ULONG_PTR MM::Pfn::HighestPhysicalPage;
|
||||
|
||||
|
||||
234
xtoskrnl/mm/i686/pfn.cc
Normal file
234
xtoskrnl/mm/i686/pfn.cc
Normal file
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtoskrnl/mm/i686/pfn.cc
|
||||
* DESCRIPTION: Physical Frame Number for i686 support
|
||||
* DEVELOPERS: Aiken Harris <harraiken91@gmail.com>
|
||||
* Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
*/
|
||||
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the PFN database by mapping virtual memory and populating entries.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::InitializePfnDatabase(VOID)
|
||||
{
|
||||
PLOADER_MEMORY_DESCRIPTOR Descriptor;
|
||||
PKERNEL_INITIALIZATION_BLOCK InitializationBlock;
|
||||
PLIST_ENTRY ListEntry;
|
||||
PMMMEMORY_LAYOUT MemoryLayout;
|
||||
PUCHAR PfnDatabaseEnd;
|
||||
PMMPTE ValidPte;
|
||||
|
||||
/* Raise runlevel and acquire PFN lock */
|
||||
KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL);
|
||||
KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock);
|
||||
|
||||
/* Get the kernel initialization block */
|
||||
InitializationBlock = KE::BootInformation::GetInitializationBlock();
|
||||
|
||||
/* Get memory layout */
|
||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||
|
||||
/* Get the PFN database size and calculate the end of the PFN database virtual address space */
|
||||
PfnDatabaseEnd = (PUCHAR)MemoryLayout->PfnDatabaseAddress + (PfnDatabaseSize * MM_PAGE_SIZE) - 1;
|
||||
|
||||
/* Get a template PTE for mapping the PFN database pages */
|
||||
ValidPte = MM::Pte::GetValidPte();
|
||||
|
||||
/* Map the Page Directory and Page Directory Pointer tables for the PFN database */
|
||||
MM::Pte::MapPDE(MemoryLayout->PfnDatabaseAddress, PfnDatabaseEnd, ValidPte);
|
||||
MM::Pte::MapPTE(MemoryLayout->PfnDatabaseAddress, PfnDatabaseEnd, ValidPte);
|
||||
|
||||
/* Zero PFN database virtual space */
|
||||
RTL::Memory::ZeroMemory(MemoryLayout->PfnDatabaseAddress, PfnDatabaseSize * MM_PAGE_SIZE);
|
||||
|
||||
/* Initialize the color tables */
|
||||
MM::Colors::InitializeColorTables();
|
||||
|
||||
/* Iterate over memory descriptors to map the PFN database and initialize entries */
|
||||
ListEntry = InitializationBlock->MemoryDescriptorListHead.Flink;
|
||||
while(ListEntry != &InitializationBlock->MemoryDescriptorListHead)
|
||||
{
|
||||
/* Get the descriptor */
|
||||
Descriptor = CONTAIN_RECORD(ListEntry, LOADER_MEMORY_DESCRIPTOR, ListEntry);
|
||||
|
||||
/* Skip invisible memory regions */
|
||||
if(MM::Manager::VerifyMemoryTypeInvisible(Descriptor->MemoryType))
|
||||
{
|
||||
/* Move to the next descriptor and continue */
|
||||
ListEntry = ListEntry->Flink;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Split PFN DB allocation out of free descriptor */
|
||||
if(Descriptor == FreeDescriptor)
|
||||
{
|
||||
/* Initialize PFNs for the remaining free memory after the PFN database */
|
||||
ProcessMemoryDescriptor(OriginalFreeDescriptor.BasePage + PfnDatabaseSize,
|
||||
OriginalFreeDescriptor.PageCount - PfnDatabaseSize,
|
||||
LoaderFree);
|
||||
|
||||
/* Initialize PFNs for the physical pages backing the PFN database itself */
|
||||
ProcessMemoryDescriptor(OriginalFreeDescriptor.BasePage, PfnDatabaseSize, LoaderMemoryData);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Initialize PFNs for the physical pages described by this descriptor */
|
||||
ProcessMemoryDescriptor(Descriptor->BasePage, Descriptor->PageCount, Descriptor->MemoryType);
|
||||
}
|
||||
|
||||
/* Move to the next descriptor */
|
||||
ListEntry = ListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Restore original free descriptor */
|
||||
*FreeDescriptor = OriginalFreeDescriptor;
|
||||
|
||||
/* Initialize PFNs backing page tables */
|
||||
InitializePageTablePfns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes PFN database entries for the system page tables.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::InitializePageTablePfns(VOID)
|
||||
{
|
||||
PFN_NUMBER PageFrameIndex;
|
||||
PMMPFN Pfn;
|
||||
ULONG RootLevel;
|
||||
PMMPTE RootPte;
|
||||
|
||||
/* Determine root structure based on paging mode */
|
||||
if(MM::Paging::GetXpaStatus())
|
||||
{
|
||||
/* XPA enabled, 3-level paging (PAE) */
|
||||
RootLevel = 3;
|
||||
|
||||
/* Retrieve the PFN of the PML3 table and its virtual base address */
|
||||
PageFrameIndex = AR::CpuFunc::ReadControlRegister(3) >> MM_PAGE_SHIFT;
|
||||
RootPte = (PMMPTE)MM::Paging::GetPpeAddress(NULLPTR);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XPA disabled, 2-level paging */
|
||||
RootLevel = 2;
|
||||
|
||||
/* Retrieve the PFN of the PML2 table and its virtual base address */
|
||||
PageFrameIndex = AR::CpuFunc::ReadControlRegister(3) >> MM_PAGE_SHIFT;
|
||||
RootPte = (PMMPTE)MM::Paging::GetPdeAddress(NULLPTR);
|
||||
}
|
||||
|
||||
/* Initialize the PFN entry for the root page table itself */
|
||||
Pfn = GetPfnEntry(PageFrameIndex);
|
||||
if(Pfn)
|
||||
{
|
||||
/* Initialize the PFN entry */
|
||||
Pfn->PteAddress = NULLPTR;
|
||||
Pfn->u1.WsIndex = 0;
|
||||
Pfn->u2.ShareCount = 1;
|
||||
Pfn->u3.e1.CacheAttribute = PfnNonCached;
|
||||
Pfn->u3.e1.PageLocation = ActiveAndValid;
|
||||
Pfn->u3.e2.ReferenceCount = 1;
|
||||
Pfn->u4.PteFrame = 0;
|
||||
}
|
||||
|
||||
/* Start recursive scan from the top level */
|
||||
if(RootPte)
|
||||
{
|
||||
/* Scan the root page table */
|
||||
ScanPageTable(RootPte, RootLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scans a page table to initialize PFN database entries for active pages.
|
||||
*
|
||||
* @param PointerPte
|
||||
* Pointer to the base of the page table to scan.
|
||||
*
|
||||
* @param Level
|
||||
* The paging level of the table being scanned.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::ScanPageTable(IN PMMPTE PointerPte,
|
||||
IN ULONG Level)
|
||||
{
|
||||
PVOID Address;
|
||||
ULONG Index;
|
||||
PMMPTE NextLevelPte;
|
||||
ULONG PtesPerPage;
|
||||
|
||||
/* Get the number of PTEs per page */
|
||||
PtesPerPage = MM::Pte::GetPtesPerPage();
|
||||
|
||||
/* Check if PML3 is enabled and current level is PDPT */
|
||||
if(Level == 3)
|
||||
{
|
||||
/* PAE PDPT has only 4 entries */
|
||||
PtesPerPage = 4;
|
||||
}
|
||||
|
||||
/* Iterate through all entries in the current page table */
|
||||
for(Index = 0; Index < PtesPerPage; Index++)
|
||||
{
|
||||
/* Check if the page table entry is present */
|
||||
if(MM::Paging::PteValid(PointerPte))
|
||||
{
|
||||
/* Mark the PFN pointed to by this entry as active */
|
||||
LinkPfnForPageTable(MM::Paging::GetPageFrameNumber(PointerPte), PointerPte);
|
||||
|
||||
/* Recurse to the next level, if this is not a leaf node (PTE) */
|
||||
if(Level > 1)
|
||||
{
|
||||
/* Calculate the virtual address mapped by this entry to find the next table */
|
||||
switch(Level)
|
||||
{
|
||||
case 3:
|
||||
/* Calculate PDE */
|
||||
Address = MM::Paging::GetPpeVirtualAddress(PointerPte);
|
||||
NextLevelPte = (PMMPTE)MM::Paging::GetPdeAddress(Address);
|
||||
break;
|
||||
case 2:
|
||||
/* Calculate PTE */
|
||||
Address = MM::Paging::GetPdeVirtualAddress(PointerPte);
|
||||
NextLevelPte = (PMMPTE)MM::Paging::GetPteAddress(Address);
|
||||
break;
|
||||
default:
|
||||
/* Nothing to calculate, return NULLPTR */
|
||||
NextLevelPte = NULLPTR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Recurse deeper if not at the bottom level (PTE) already */
|
||||
if(NextLevelPte)
|
||||
{
|
||||
/* Recursively scan the next level page table */
|
||||
ScanPageTable(NextLevelPte, Level - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Move to the next entry in the current table */
|
||||
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,9 @@ MM::Manager::InitializeMemoryManager(VOID)
|
||||
|
||||
/* Initialize system PTE space */
|
||||
MM::Pte::InitializeSystemPteSpace();
|
||||
|
||||
/* Initialize PFN database */
|
||||
MM::Pfn::InitializePfnDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,6 +75,21 @@ MM::Pfn::DecrementAvailablePages(VOID)
|
||||
AvailablePages--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the highest physical page number (PFN) detected in the system.
|
||||
*
|
||||
* @return This routine returns the highest physical page number.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
ULONG_PTR
|
||||
MM::Pfn::GetHighestPhysicalPage()
|
||||
{
|
||||
/* Return the highest physical page number */
|
||||
return HighestPhysicalPage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the total number of physical pages managed by the system.
|
||||
*
|
||||
@@ -150,6 +165,246 @@ MM::Pfn::IncrementAvailablePages(VOID)
|
||||
AvailablePages++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Links a physical page to the appropriate free lists.
|
||||
*
|
||||
* @param PageFrameIndex
|
||||
* The Page Frame Number (PFN) of the page to link.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::LinkFreePage(IN PFN_NUMBER PageFrameIndex)
|
||||
{
|
||||
ULONG Color;
|
||||
PMMPFNLIST ListHead;
|
||||
PFN_NUMBER LastPage;
|
||||
PMMPFN ColoredPfn, PfnEntry;
|
||||
PMMCOLOR_TABLES ColorTable;
|
||||
PMMMEMORY_LAYOUT MemoryLayout;
|
||||
|
||||
/* Get the PFN database entry for the page */
|
||||
PfnEntry = GetPfnEntry(PageFrameIndex);
|
||||
|
||||
/* Check if the page is part of a ROM image */
|
||||
if(PfnEntry->u3.e1.Rom == 1)
|
||||
{
|
||||
/* Mark the page as inactive and clear its links */
|
||||
PfnEntry->u1.Flink = 0;
|
||||
PfnEntry->u3.e1.PageLocation = 0;
|
||||
|
||||
/* Do not free ROM pages */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the page is marked for removal */
|
||||
if(PfnEntry->u3.e1.RemovalRequested == 1)
|
||||
{
|
||||
/* Update cache attribute to not mapped */
|
||||
PfnEntry->u3.e1.CacheAttribute = PfnNotMapped;
|
||||
|
||||
/* Do not add it to the free list */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Insert the page into the global free list */
|
||||
ListHead = &FreePagesList;
|
||||
ListHead->Total++;
|
||||
|
||||
/* Get the current last page on the list */
|
||||
LastPage = ListHead->Blink;
|
||||
|
||||
/* Check if the list is not empty */
|
||||
if(LastPage != MAXULONG_PTR)
|
||||
{
|
||||
/* Link with the previous last page */
|
||||
GetPfnEntry(LastPage)->u1.Flink = PageFrameIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Put the page as the first entry */
|
||||
ListHead->Flink = PageFrameIndex;
|
||||
}
|
||||
|
||||
/* Set the page as the new tail of the list */
|
||||
ListHead->Blink = PageFrameIndex;
|
||||
PfnEntry->u1.Flink = MAXULONG_PTR;
|
||||
PfnEntry->u2.Blink = LastPage;
|
||||
PfnEntry->u3.e1.CacheAttribute = PfnNotMapped;
|
||||
PfnEntry->u3.e1.PageLocation = FreePageList;
|
||||
PfnEntry->u4.AweAllocation = 0;
|
||||
PfnEntry->u4.InPageError = 0;
|
||||
PfnEntry->u4.Priority = 3;
|
||||
|
||||
/* Insert the page into the colored free list */
|
||||
Color = PageFrameIndex & MM::Colors::GetPagingColorsMask();
|
||||
ColorTable = MM::Colors::GetFreePages(FreePageList, Color);
|
||||
|
||||
/* Get the memory layout */
|
||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||
|
||||
/* Check if the colored list is empty */
|
||||
if(ColorTable->Flink == MAXULONG_PTR)
|
||||
{
|
||||
/* Put the page as the first entry */
|
||||
ColorTable->Flink = PageFrameIndex;
|
||||
PfnEntry->u4.PteFrame = MM_PFN_PTE_FRAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the current last page on the colored list */
|
||||
ColoredPfn = (PMMPFN)ColorTable->Blink;
|
||||
|
||||
/* Link with the previous last page */
|
||||
MM::Paging::SetPte(&ColoredPfn->OriginalPte, PageFrameIndex);
|
||||
PfnEntry->u4.PteFrame = ColoredPfn - (PMMPFN)MemoryLayout->PfnDatabaseAddress;
|
||||
}
|
||||
|
||||
/* Set the page as the new tail of the colored list */
|
||||
ColorTable->Blink = PfnEntry;
|
||||
ColorTable->Count++;
|
||||
MM::Paging::SetPte(&PfnEntry->OriginalPte, MAXULONG_PTR);
|
||||
|
||||
/* Increment number of available pages */
|
||||
IncrementAvailablePages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the PFN database entry for a physical page that is used as a page table.
|
||||
*
|
||||
* @param PageFrameIndex
|
||||
* The page frame number of the physical page being used as a page table.
|
||||
*
|
||||
* @param PointerPte
|
||||
* A pointer to the higher-level PTE that maps this page table page.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::LinkPfnForPageTable(PFN_NUMBER PageFrameIndex,
|
||||
PMMPTE PointerPte)
|
||||
{
|
||||
PMMPFN Pfn;
|
||||
PMMPDE PointerPde;
|
||||
PVOID EndAddress;
|
||||
|
||||
/* Retrieve the PFN database entry for the physical page of the page table */
|
||||
Pfn = GetPfnEntry(PageFrameIndex);
|
||||
|
||||
/* Calculate the end address of the PFN entry to ensure it's mapped */
|
||||
EndAddress = (PUCHAR)(Pfn + 1) - 1;
|
||||
|
||||
/* Validate that the PFN entry corresponds to a valid, active physical page */
|
||||
if((PageFrameIndex <= HighestPhysicalPage) && (MM::Pte::AddressValid(Pfn)) &&
|
||||
(MM::Pte::AddressValid(EndAddress)) && (Pfn->u3.e1.PageLocation == ActiveAndValid))
|
||||
{
|
||||
/* Initialize the PFN entry for this page table page */
|
||||
Pfn->u1.WsIndex = 0;
|
||||
Pfn->u2.ShareCount++;
|
||||
Pfn->PteAddress = PointerPte;
|
||||
Pfn->OriginalPte = *PointerPte;
|
||||
Pfn->u3.e1.PageLocation = ActiveAndValid;
|
||||
Pfn->u3.e1.CacheAttribute = PfnNonCached;
|
||||
Pfn->u3.e2.ReferenceCount = 1;
|
||||
Pfn->u4.PteFrame = MM::Paging::GetPageFrameNumber(MM::Paging::GetPteAddress(PointerPte));
|
||||
}
|
||||
|
||||
/* Increment the share count of the parent page table that contains the mapping */
|
||||
PointerPde = MM::Paging::GetPdeAddress(MM::Paging::GetPteVirtualAddress(PointerPte));
|
||||
Pfn = GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPde));
|
||||
Pfn->u2.ShareCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a memory descriptor and initializes the corresponding PFN database entries
|
||||
*
|
||||
* @param BasePage
|
||||
* The starting physical page number of the memory run
|
||||
*
|
||||
* @param PageCount
|
||||
* The number of pages in the memory run
|
||||
*
|
||||
* @param MemoryType
|
||||
* The type of memory as reported by the bootloader (e.g., free, ROM, in-use)
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pfn::ProcessMemoryDescriptor(IN PFN_NUMBER BasePage,
|
||||
IN PFN_NUMBER PageCount,
|
||||
IN LOADER_MEMORY_TYPE MemoryType)
|
||||
{
|
||||
PFN_NUMBER CurrentPage, PageNumber;
|
||||
PMMPFN Pfn;
|
||||
|
||||
/* Check if the memory descriptor describes a free memory region */
|
||||
if(MM::Manager::VerifyMemoryTypeFree(MemoryType))
|
||||
{
|
||||
/* Iterate over each page in this free memory run */
|
||||
for(PageNumber = 0; PageNumber < PageCount; PageNumber++)
|
||||
{
|
||||
/* Get the PFN entry for the current page and set its initial cache attribute */
|
||||
CurrentPage = BasePage + PageNumber;
|
||||
Pfn = GetPfnEntry(CurrentPage);
|
||||
Pfn->u3.e1.CacheAttribute = PfnNonCached;
|
||||
|
||||
/* Add the page to the free list to make it available for allocation */
|
||||
LinkFreePage(CurrentPage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle all other (non-free) memory types */
|
||||
switch(MemoryType)
|
||||
{
|
||||
case LoaderBad:
|
||||
/* This memory is marked as bad and should not be used */
|
||||
UNIMPLEMENTED;
|
||||
break;
|
||||
case LoaderXIPRom:
|
||||
/* This memory range contains Read-Only Memory (ROM) */
|
||||
for(PageNumber = 0; PageNumber < PageCount; PageNumber++)
|
||||
{
|
||||
/* Get the PFN entry for the current ROM page */
|
||||
Pfn = GetPfnEntry(BasePage + PageNumber);
|
||||
|
||||
/* Initialize the PFN entry to represent a ROM page */
|
||||
Pfn->PteAddress = 0;
|
||||
Pfn->u1.Flink = 0;
|
||||
Pfn->u2.ShareCount = 0;
|
||||
Pfn->u3.e1.CacheAttribute = PfnNonCached;
|
||||
Pfn->u3.e1.PageLocation = 0;
|
||||
Pfn->u3.e1.PrototypePte = 1;
|
||||
Pfn->u3.e2.ReferenceCount = 0;
|
||||
Pfn->u3.e1.Rom = 1;
|
||||
Pfn->u4.InPageError = 0;
|
||||
Pfn->u4.PteFrame = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* All other types are considered in-use (ie, by the kernel, ACPI, etc) */
|
||||
for(PageNumber = 0; PageNumber < PageCount; PageNumber++)
|
||||
{
|
||||
/* Get the PFN entry for the current in-use page */
|
||||
Pfn = GetPfnEntry(BasePage + PageNumber);
|
||||
|
||||
/* Mark the PFN as active and valid to prevent it from being allocated */
|
||||
Pfn->u3.e1.PageLocation = ActiveAndValid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans memory descriptors provided by the boot loader.
|
||||
*
|
||||
|
||||
@@ -104,6 +104,21 @@ MM::Pte::GetPtesPerPage(VOID)
|
||||
return MM_PAGE_SIZE / MM::Paging::GetPteSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the valid PTE.
|
||||
*
|
||||
* @return This routine returns a pointer to the valid PTE.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PMMPTE
|
||||
MM::Pte::GetValidPte()
|
||||
{
|
||||
/* Return a pointer to the valid PTE */
|
||||
return &ValidPte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a range of PTEs into a freelist-based pool for system allocations.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user