Implement PFN database initialization and memory descriptor processing
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in 32s
Builds / ExectOS (i686, debug) (push) Successful in 31s
Builds / ExectOS (amd64, release) (push) Successful in 33s
Builds / ExectOS (i686, release) (push) Successful in 34s

This commit is contained in:
2025-12-28 23:25:07 +01:00
parent 4593a89a9b
commit 0880a0f344
12 changed files with 841 additions and 0 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -29,6 +29,7 @@ namespace MM
STATIC XTAPI ULONG GetNextColor();
STATIC XTAPI ULONG GetPagingColors();
STATIC XTAPI ULONG GetPagingColorsMask();
STATIC XTAPI VOID InitializeColorTables(VOID);
};
}

View File

@@ -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,

View File

@@ -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
View 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);
}
}

View File

@@ -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;
}
}

View File

@@ -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
View 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);
}
}

View File

@@ -68,6 +68,9 @@ MM::Manager::InitializeMemoryManager(VOID)
/* Initialize system PTE space */
MM::Pte::InitializeSystemPteSpace();
/* Initialize PFN database */
MM::Pfn::InitializePfnDatabase();
}
/**

View File

@@ -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.
*

View File

@@ -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.
*