Initialize system PTE pools and implement reservation routines
This commit is contained in:
@@ -57,5 +57,20 @@ LOADER_MEMORY_DESCRIPTOR MM::Pfn::OriginalFreeDescriptor;
|
||||
/* Size of the PFN database in pages */
|
||||
PFN_NUMBER MM::Pfn::PfnDatabaseSize;
|
||||
|
||||
/* Array of lists for available System PTEs, separated by pool type */
|
||||
MMPTE MM::Pte::FirstSystemFreePte[MaximumPtePoolTypes];
|
||||
|
||||
/* Virtual base address of the System PTE space */
|
||||
PMMPTE MM::Pte::SystemPteBase;
|
||||
|
||||
/* End addresses for the System PTE ranges */
|
||||
PMMPTE MM::Pte::SystemPtesEnd[MaximumPtePoolTypes];
|
||||
|
||||
/* Start addresses for the System PTE ranges */
|
||||
PMMPTE MM::Pte::SystemPtesStart[MaximumPtePoolTypes];
|
||||
|
||||
/* Total count of available System PTEs */
|
||||
ULONG MM::Pte::TotalSystemFreePtes[MaximumPtePoolTypes];
|
||||
|
||||
/* Template PTE entry containing standard flags for a valid, present kernel page */
|
||||
MMPTE MM::Pte::ValidPte = {MM_PTE_VALID|MM_PTE_EXECUTE_READWRITE|MM_PTE_DIRTY|MM_PTE_ACCESSED};
|
||||
|
||||
@@ -65,6 +65,9 @@ MM::Manager::InitializeMemoryManager(VOID)
|
||||
|
||||
/* Initialize page table */
|
||||
MM::Pte::InitializePageTable();
|
||||
|
||||
/* Initialize system PTE space */
|
||||
MM::Pte::InitializeSystemPteSpace();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,86 @@
|
||||
#include <xtos.hh>
|
||||
|
||||
|
||||
/**
|
||||
* Finds a free cluster of system PTEs that can satisfy a given size.
|
||||
*
|
||||
* @param NumberOfPtes
|
||||
* The number of contiguous PTEs required.
|
||||
*
|
||||
* @param SystemPtePoolType
|
||||
* Specifies the system PTE pool to search within.
|
||||
*
|
||||
* @param FoundCluster
|
||||
* On success, receives a pointer to the first PTE of the found cluster.
|
||||
*
|
||||
* @param PreviousClusterNode
|
||||
* On success, receives a pointer to the list node that precedes the found cluster.
|
||||
*
|
||||
* @return This routine returns TRUE if a suitable cluster was found, FALSE otherwise.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
BOOLEAN
|
||||
MM::Pte::FindFreeCluster(IN ULONG NumberOfPtes,
|
||||
IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
|
||||
OUT PMMPTE *FoundCluster,
|
||||
OUT PMMPTE *PreviousClusterNode)
|
||||
{
|
||||
PMMPTE CurrentCluster;
|
||||
PMMPTE PreviousNode = &FirstSystemFreePte[SystemPtePoolType];
|
||||
ULONG ClusterSize;
|
||||
|
||||
/* Find a free PTE cluster large enough for the request */
|
||||
while(MM::Paging::GetNextEntry(PreviousNode) != MAXULONG)
|
||||
{
|
||||
/* Retrieve the cluster and its size */
|
||||
CurrentCluster = MM::Paging::AdvancePte(SystemPteBase, MM::Paging::GetNextEntry(PreviousNode));
|
||||
ClusterSize = GetClusterSize(CurrentCluster);
|
||||
|
||||
/* Check if this cluster is large enough */
|
||||
if(NumberOfPtes <= ClusterSize)
|
||||
{
|
||||
/* Found a suitable cluster */
|
||||
*FoundCluster = CurrentCluster;
|
||||
*PreviousClusterNode = PreviousNode;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This cluster is too small, check the next one */
|
||||
PreviousNode = CurrentCluster;
|
||||
}
|
||||
|
||||
/* No suitable cluster was found */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes and returns the size of a free PTE cluster.
|
||||
*
|
||||
* @param Pte
|
||||
* Supplies a pointer to the first PTE of the free cluster to inspect.
|
||||
*
|
||||
* @return This routine returns the total number of contiguous PTEs in the free cluster.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
ULONG
|
||||
MM::Pte::GetClusterSize(IN PMMPTE Pte)
|
||||
{
|
||||
/* A special flag in the first PTE indicates a free cluster of size one */
|
||||
if(MM::Paging::GetOneEntry(Pte))
|
||||
{
|
||||
/* Flag is set, so the cluster size is 1 by definition */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* For larger clusters, the size is encoded in the second PTE of the block */
|
||||
Pte = MM::Paging::GetNextPte(Pte);
|
||||
return MM::Paging::GetNextEntry(Pte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of Page Table Entries (PTEs) that fit within a single page.
|
||||
*
|
||||
@@ -24,6 +104,86 @@ MM::Pte::GetPtesPerPage(VOID)
|
||||
return MM_PAGE_SIZE / MM::Paging::GetPteSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a range of PTEs into a freelist-based pool for system allocations.
|
||||
*
|
||||
* @param StartingPte
|
||||
* Supplies a pointer to the start of the PTE range to be formatted.
|
||||
*
|
||||
* @param NumberOfPtes
|
||||
* Supplies the total number of PTEs in the contiguous range.
|
||||
*
|
||||
* @param PoolType
|
||||
* The system PTE pool type that this range will be used for.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pte::InitializeSystemPtePool(IN PMMPTE StartingPte,
|
||||
IN ULONG NumberOfPtes,
|
||||
IN MMSYSTEM_PTE_POOL_TYPE PoolType)
|
||||
{
|
||||
/* Set the system PTE base address */
|
||||
SystemPteBase = GetSystemPteBaseAddress();
|
||||
|
||||
/* Record the boundaries of this new PTE pool */
|
||||
SystemPtesStart[PoolType] = StartingPte;
|
||||
SystemPtesEnd[PoolType] = MM::Paging::AdvancePte(StartingPte, NumberOfPtes - 1);
|
||||
|
||||
/* Zero the memory for the new PTE pool before use */
|
||||
RTL::Memory::ZeroMemory(StartingPte, NumberOfPtes * MM::Paging::GetPteSize());
|
||||
|
||||
/* Build the free list head to point to the start of the pool */
|
||||
MM::Paging::SetNextEntry(StartingPte, MAXULONG);
|
||||
MM::Paging::ClearPte(&FirstSystemFreePte[PoolType]);
|
||||
MM::Paging::SetNextEntry(&FirstSystemFreePte[PoolType], MM::Paging::GetPteDistance(StartingPte, SystemPteBase));
|
||||
|
||||
/* Use the second PTE slot to store the total size of this pool */
|
||||
StartingPte = MM::Paging::GetNextPte(StartingPte);
|
||||
MM::Paging::ClearPte(StartingPte);
|
||||
MM::Paging::SetNextEntry(StartingPte, NumberOfPtes);
|
||||
|
||||
/* Record the total number of free PTEs in this pool */
|
||||
TotalSystemFreePtes[PoolType] = NumberOfPtes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the entire system PTE address space.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
VOID
|
||||
MM::Pte::InitializeSystemPteSpace(VOID)
|
||||
{
|
||||
PMMPTE PointerPte;
|
||||
PMMPTE FirstZeroingPte;
|
||||
PMMMEMORY_LAYOUT MemoryLayout;
|
||||
|
||||
/* Retrieve the system's memory layout */
|
||||
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||
|
||||
/* Map the page table hierarchy for the entire system PTE space */
|
||||
MM::Pte::MapPPE(MemoryLayout->SystemSpaceStart, MemoryLayout->SystemSpaceEnd, &ValidPte);
|
||||
MM::Pte::MapPDE(MemoryLayout->SystemSpaceStart, MemoryLayout->SystemSpaceEnd, &ValidPte);
|
||||
|
||||
/* Format the main block of system PTEs into a free list pool */
|
||||
PointerPte = MM::Paging::GetPteAddress(MemoryLayout->SystemSpaceStart);
|
||||
InitializeSystemPtePool(PointerPte, MM::Manager::GetNumberOfSystemPtes(), SystemPteSpace);
|
||||
|
||||
/* Reserve and zero a dedicated block of system PTEs */
|
||||
FirstZeroingPte = ReserveSystemPtes(MM_RESERVED_ZERO_PTES + 1, SystemPteSpace, 0);
|
||||
RTL::Memory::ZeroMemory(FirstZeroingPte, (MM_RESERVED_ZERO_PTES + 1) * MM::Paging::GetPteSize());
|
||||
|
||||
/* Use the first PTE of this block as a counter for available zeroing PTEs */
|
||||
MM::Paging::SetPte(FirstZeroingPte, MM_RESERVED_ZERO_PTES, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a range of virtual addresses at the PDE (Page Directory Entry) level.
|
||||
*
|
||||
@@ -117,3 +277,119 @@ MM::Pte::MapPTE(PVOID StartAddress,
|
||||
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves a contiguous block of system PTEs from a specified pool.
|
||||
*
|
||||
* @param NumberOfPtes
|
||||
* The number of contiguous PTEs to reserve.
|
||||
*
|
||||
* @param SystemPtePoolType
|
||||
* Specifies the system PTE pool from which to allocate.
|
||||
*
|
||||
* @param Alignment
|
||||
* This parameter is currently unused.
|
||||
*
|
||||
* @return This routine returns a pointer to the beginning of the reserved block,
|
||||
* or NULLPTR if not enough contiguous PTEs are available.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTAPI
|
||||
PMMPTE
|
||||
MM::Pte::ReserveSystemPtes(IN ULONG NumberOfPtes,
|
||||
IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
|
||||
IN ULONG Alignment)
|
||||
{
|
||||
PMMPTE PreviousPte, NextPte, ReservedPte;
|
||||
ULONG ClusterSize;
|
||||
|
||||
/* Raise runlevel and acquire lock to protect the PTE pool */
|
||||
KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL);
|
||||
KE::QueuedSpinLockGuard SpinLock(SystemSpaceLock);
|
||||
|
||||
/* Find a free PTE cluster large enough for the request */
|
||||
if(!FindFreeCluster(NumberOfPtes, SystemPtePoolType, &NextPte, &PreviousPte))
|
||||
{
|
||||
/* Out of system PTEs for this pool, return NULLPTR */
|
||||
return NULLPTR;
|
||||
}
|
||||
|
||||
/* We have the cluster, now get its size for the allocation logic below */
|
||||
ClusterSize = GetClusterSize(NextPte);
|
||||
|
||||
/* Unlink the found cluster from the free list for processing */
|
||||
MM::Paging::SetNextEntry(PreviousPte, MM::Paging::GetNextEntry(NextPte));
|
||||
|
||||
/* Handle the allocation based on whether the cluster size is an exact match */
|
||||
if(ClusterSize == NumberOfPtes)
|
||||
{
|
||||
/* Exact match, allocate the entire cluster */
|
||||
ReservedPte = NextPte;
|
||||
|
||||
/* Handle metadata cleanup for a single-PTE cluster */
|
||||
if(MM::Paging::GetOneEntry(NextPte))
|
||||
{
|
||||
/* Clear the PTE that held the list metadata */
|
||||
MM::Paging::ClearPte(NextPte);
|
||||
NextPte = MM::Paging::GetNextPte(NextPte);
|
||||
}
|
||||
|
||||
/* Clear the PTE that held the cluster size */
|
||||
MM::Paging::ClearPte(NextPte);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cluster is larger than needed, so it will be split */
|
||||
ClusterSize -= NumberOfPtes;
|
||||
ReservedPte = MM::Paging::AdvancePte(NextPte, ClusterSize);
|
||||
|
||||
/* Update metadata for the new, smaller leftover cluster */
|
||||
if(ClusterSize == 1)
|
||||
{
|
||||
/* The leftover fragment is a single PTE */
|
||||
MM::Paging::SetOneEntry(NextPte, 1);
|
||||
MM::Paging::ClearPte(ReservedPte);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The leftover fragment is larger than one PTE */
|
||||
NextPte = MM::Paging::GetNextPte(NextPte);
|
||||
MM::Paging::SetNextEntry(NextPte, ClusterSize);
|
||||
}
|
||||
|
||||
/* Find the correct sorted position to re-insert the leftover fragment */
|
||||
PreviousPte = &FirstSystemFreePte[SystemPtePoolType];
|
||||
while(MM::Paging::GetNextEntry(PreviousPte) != MAXULONG)
|
||||
{
|
||||
/* Get the next free cluster to check its size */
|
||||
NextPte = MM::Paging::AdvancePte(SystemPteBase, MM::Paging::GetNextEntry(PreviousPte));
|
||||
|
||||
/* Check if the leftover fragment should be inserted here */
|
||||
if(ClusterSize <= GetClusterSize(NextPte))
|
||||
{
|
||||
/* Found the correct sorted position */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance to the next entry */
|
||||
PreviousPte = NextPte;
|
||||
}
|
||||
|
||||
/* Get a pointer to the start of the leftover fragment */
|
||||
NextPte = MM::Paging::AdvancePte(ReservedPte, -ClusterSize);
|
||||
|
||||
/* Insert the leftover fragment back into the free list at its sorted position */
|
||||
MM::Paging::SetNextEntry(NextPte, MM::Paging::GetNextEntry(PreviousPte));
|
||||
MM::Paging::SetNextEntry(PreviousPte, MM::Paging::GetPteDistance(NextPte, SystemPteBase));
|
||||
}
|
||||
|
||||
/* Decrement the total number of available PTEs in this pool */
|
||||
TotalSystemFreePtes[SystemPtePoolType] -= NumberOfPtes;
|
||||
|
||||
/* Flush the TLB to ensure address translation consistency */
|
||||
AR::CpuFunc::FlushTlb();
|
||||
|
||||
/* Return a pointer to the start of the reserved PTE block */
|
||||
return ReservedPte;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user