Implement memory deallocation and coalescing for non-paged pool
This commit is contained in:
@@ -18,12 +18,15 @@ namespace MM
|
|||||||
class Allocator
|
class Allocator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
STATIC PFN_NUMBER NonPagedPoolFrameEnd;
|
||||||
|
STATIC PFN_NUMBER NonPagedPoolFrameStart;
|
||||||
STATIC LIST_ENTRY NonPagedPoolFreeList[MM_MAX_FREE_PAGE_LIST_HEADS];
|
STATIC LIST_ENTRY NonPagedPoolFreeList[MM_MAX_FREE_PAGE_LIST_HEADS];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
STATIC XTAPI XTSTATUS AllocatePages(IN MMPOOL_TYPE PoolType,
|
STATIC XTAPI XTSTATUS AllocatePages(IN MMPOOL_TYPE PoolType,
|
||||||
IN SIZE_T Bytes,
|
IN SIZE_T Bytes,
|
||||||
OUT PVOID *Memory);
|
OUT PVOID *Memory);
|
||||||
|
STATIC XTAPI XTSTATUS FreePages(IN PVOID VirtualAddress);
|
||||||
STATIC XTAPI VOID InitializeNonPagedPool(VOID);
|
STATIC XTAPI VOID InitializeNonPagedPool(VOID);
|
||||||
STATIC XTAPI VOID InitializePagedPool(VOID);
|
STATIC XTAPI VOID InitializePagedPool(VOID);
|
||||||
|
|
||||||
@@ -32,6 +35,8 @@ namespace MM
|
|||||||
OUT PVOID *Memory);
|
OUT PVOID *Memory);
|
||||||
STATIC XTAPI XTSTATUS AllocatePagedPoolPages(IN PFN_COUNT Pages,
|
STATIC XTAPI XTSTATUS AllocatePagedPoolPages(IN PFN_COUNT Pages,
|
||||||
OUT PVOID *Memory);
|
OUT PVOID *Memory);
|
||||||
|
STATIC XTAPI XTSTATUS FreeNonPagedPoolPages(IN PVOID VirtualAddress);
|
||||||
|
STATIC XTAPI XTSTATUS FreePagedPoolPages(IN PVOID VirtualAddress);
|
||||||
STATIC XTAPI VOID MapNonPagedPool(VOID);
|
STATIC XTAPI VOID MapNonPagedPool(VOID);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,6 +254,241 @@ MM::Allocator::AllocatePages(IN MMPOOL_TYPE PoolType,
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a previously allocated block of pages from the non-paged pool.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress
|
||||||
|
* Supplies the base virtual address of the non-paged pool allocation to free.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::Allocator::FreeNonPagedPoolPages(IN PVOID VirtualAddress)
|
||||||
|
{
|
||||||
|
PMMFREE_POOL_ENTRY FreePage, NextPage, LastPage;
|
||||||
|
PFN_COUNT FreePages, Pages;
|
||||||
|
PMMMEMORY_LAYOUT MemoryLayout;
|
||||||
|
PMMPFN Pfn, FirstPfn;
|
||||||
|
PMMPTE PointerPte;
|
||||||
|
ULONG Index;
|
||||||
|
|
||||||
|
/* Retrieve memory layout */
|
||||||
|
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||||
|
|
||||||
|
/* Get the first PTE of the allocation */
|
||||||
|
PointerPte = MM::Paging::GetPteAddress(VirtualAddress);
|
||||||
|
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
|
||||||
|
|
||||||
|
/* Basic sanity check to prevent double-frees or freeing unallocated memory */
|
||||||
|
if(Pfn->u3.e1.ReadInProgress == 0)
|
||||||
|
{
|
||||||
|
/* Memory is not marked as the start of an allocation, return error */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the first PFN entry and initialize the allocation page counter */
|
||||||
|
FirstPfn = Pfn;
|
||||||
|
Pages = 1;
|
||||||
|
|
||||||
|
/* Seek to the end of the allocation */
|
||||||
|
while(Pfn->u3.e1.WriteInProgress == 0)
|
||||||
|
{
|
||||||
|
/* Get the next PTE and its PFN */
|
||||||
|
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||||
|
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
|
||||||
|
|
||||||
|
/* Increment the page count */
|
||||||
|
Pages++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the total free page count */
|
||||||
|
FreePages = Pages;
|
||||||
|
|
||||||
|
/* Acquire the Non-Paged pool lock and raise runlevel to DISPATCH_LEVEL */
|
||||||
|
KE::RaiseRunLevel RunLevel(DISPATCH_LEVEL);
|
||||||
|
KE::QueuedSpinLockGuard NonPagedPoolSpinLock(NonPagedPoolLock);
|
||||||
|
|
||||||
|
/* Denote allocation boundaries */
|
||||||
|
FirstPfn->u3.e1.ReadInProgress = 0;
|
||||||
|
Pfn->u3.e1.WriteInProgress = 0;
|
||||||
|
|
||||||
|
/* Get the next PTE */
|
||||||
|
PointerPte = MM::Paging::GetNextPte(PointerPte);
|
||||||
|
|
||||||
|
/* Check if the end of the initial nonpaged pool has been reached */
|
||||||
|
if(Pfn - MemoryLayout->PfnDatabase == NonPagedPoolFrameEnd)
|
||||||
|
{
|
||||||
|
/* Ignore the last page of the initial nonpaged pool */
|
||||||
|
Pfn = NULLPTR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check if the PTE is valid */
|
||||||
|
if(MM::Paging::PteValid(PointerPte))
|
||||||
|
{
|
||||||
|
/* Get the PFN entry for the page laying in either the expansion or initial nonpaged pool */
|
||||||
|
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Ignore the last page of the expansion nonpaged pool */
|
||||||
|
Pfn = NULLPTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the adjacent physical page following the allocation is free */
|
||||||
|
if((Pfn) && (Pfn->u3.e1.ReadInProgress == 0))
|
||||||
|
{
|
||||||
|
/* Calculate the virtual address of the adjacent forward free pool entry */
|
||||||
|
FreePage = (PMMFREE_POOL_ENTRY)((ULONG_PTR)VirtualAddress + (Pages << MM_PAGE_SHIFT));
|
||||||
|
|
||||||
|
/* Absorb the adjacent free block's pages into the current free page count */
|
||||||
|
FreePages += FreePage->Size;
|
||||||
|
|
||||||
|
/* Unlink the adjacent free block from its current segregated free list */
|
||||||
|
RTL::LinkedList::RemoveEntryList(&FreePage->List);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the free pool entry structure from the list entry */
|
||||||
|
FreePage = (PMMFREE_POOL_ENTRY)VirtualAddress;
|
||||||
|
|
||||||
|
/* Check if the beginning of the initial nonpaged pool has been reached */
|
||||||
|
if(FirstPfn - MemoryLayout->PfnDatabase == NonPagedPoolFrameStart)
|
||||||
|
{
|
||||||
|
/* Ignore the first page of the initial nonpaged pool */
|
||||||
|
Pfn = NULLPTR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Calculate the PTE address for the page immediately preceding the allocation */
|
||||||
|
PointerPte = MM::Paging::AdvancePte(PointerPte, -Pages - 1);
|
||||||
|
|
||||||
|
/* Check if the PTE is valid */
|
||||||
|
if(MM::Paging::PteValid(PointerPte))
|
||||||
|
{
|
||||||
|
/* Get the PFN entry for the page laying in either the expansion or initial nonpaged pool */
|
||||||
|
Pfn = MM::Pfn::GetPfnEntry(MM::Paging::GetPageFrameNumber(PointerPte));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Ignore the first page of the expansion nonpaged pool */
|
||||||
|
Pfn = NULLPTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the adjacent physical page preceding the allocation is free */
|
||||||
|
if((Pfn) && (Pfn->u3.e1.WriteInProgress == 0))
|
||||||
|
{
|
||||||
|
/* Retrieve the owner header of the preceding free block for backward coalescing */
|
||||||
|
FreePage = (PMMFREE_POOL_ENTRY)((ULONG_PTR)VirtualAddress - MM_PAGE_SIZE);
|
||||||
|
FreePage = FreePage->Owner;
|
||||||
|
|
||||||
|
/* Check if the allocation is small enough */
|
||||||
|
if(FreePage->Size < MM_MAX_FREE_PAGE_LIST_HEADS)
|
||||||
|
{
|
||||||
|
/* Remove the entry from the list */
|
||||||
|
RTL::LinkedList::RemoveEntryList(&FreePage->List);
|
||||||
|
|
||||||
|
/* Adjust the size of the free block to account for the allocated pages */
|
||||||
|
FreePage->Size += FreePages;
|
||||||
|
|
||||||
|
/* Calculate the new list index */
|
||||||
|
Index = MIN(FreePage->Size, MM_MAX_FREE_PAGE_LIST_HEADS) - 1;
|
||||||
|
|
||||||
|
/* Insert the entry into the head of the list */
|
||||||
|
RTL::LinkedList::InsertHeadList(&NonPagedPoolFreeList[Index], &FreePage->List);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Adjust the size of the free block to account for the allocated pages */
|
||||||
|
FreePage->Size += FreePages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if backward coalescing failed, requiring the freed block to become a new list head */
|
||||||
|
if(FreePage == VirtualAddress)
|
||||||
|
{
|
||||||
|
/* Adjust the size of the free block to account for the allocated pages */
|
||||||
|
FreePage->Size = FreePages;
|
||||||
|
|
||||||
|
/* Calculate the new list index */
|
||||||
|
Index = MIN(FreePage->Size, MM_MAX_FREE_PAGE_LIST_HEADS) - 1;
|
||||||
|
|
||||||
|
/* Insert the entry into the head of the list */
|
||||||
|
RTL::LinkedList::InsertHeadList(&NonPagedPoolFreeList[Index], &FreePage->List);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the start and end boundaries for updating the owner pointers */
|
||||||
|
NextPage = (PMMFREE_POOL_ENTRY)VirtualAddress;
|
||||||
|
LastPage = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextPage + (FreePages << MM_PAGE_SHIFT));
|
||||||
|
|
||||||
|
/* Iterate through all freed and coalesced pages to update their owner reference */
|
||||||
|
while(NextPage != LastPage)
|
||||||
|
{
|
||||||
|
/* Link the page to the owner */
|
||||||
|
NextPage->Owner = FreePage;
|
||||||
|
NextPage = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextPage + MM_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a previously allocated block of pages from the paged pool.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress
|
||||||
|
* Supplies the base virtual address of the paged pool allocation to free.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::Allocator::FreePagedPoolPages(IN PVOID VirtualAddress)
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
|
||||||
|
/* Return not implemented status code */
|
||||||
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees a previously allocated block of pages.
|
||||||
|
*
|
||||||
|
* @param VirtualAddress
|
||||||
|
* Supplies the base virtual address of the paged pool allocation to free.
|
||||||
|
*
|
||||||
|
* @return This routine returns a status code.
|
||||||
|
*
|
||||||
|
* @since XT 1.0
|
||||||
|
*/
|
||||||
|
XTAPI
|
||||||
|
XTSTATUS
|
||||||
|
MM::Allocator::FreePages(IN PVOID VirtualAddress)
|
||||||
|
{
|
||||||
|
PMMMEMORY_LAYOUT MemoryLayout;
|
||||||
|
|
||||||
|
/* Retrieve memory layout */
|
||||||
|
MemoryLayout = MM::Manager::GetMemoryLayout();
|
||||||
|
|
||||||
|
/* Check if the address is in the paged pool */
|
||||||
|
if(VirtualAddress >= MemoryLayout->PagedPoolStart && VirtualAddress < MemoryLayout->PagedPoolEnd)
|
||||||
|
{
|
||||||
|
/* Free pages from the paged pool */
|
||||||
|
return FreePagedPoolPages(VirtualAddress);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Free pages from the non-paged pool */
|
||||||
|
return FreeNonPagedPoolPages(VirtualAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the non-paged pool for memory allocator.
|
* Initializes the non-paged pool for memory allocator.
|
||||||
*
|
*
|
||||||
@@ -265,7 +500,7 @@ XTAPI
|
|||||||
VOID
|
VOID
|
||||||
MM::Allocator::InitializeNonPagedPool(VOID)
|
MM::Allocator::InitializeNonPagedPool(VOID)
|
||||||
{
|
{
|
||||||
PMMFREE_POOL_ENTRY FreeEntry, SetupEntry;
|
PMMFREE_POOL_ENTRY FreePage, SetupPage;
|
||||||
PMMMEMORY_LAYOUT MemoryLayout;
|
PMMMEMORY_LAYOUT MemoryLayout;
|
||||||
ULONG Index;
|
ULONG Index;
|
||||||
|
|
||||||
@@ -282,9 +517,9 @@ MM::Allocator::InitializeNonPagedPool(VOID)
|
|||||||
RTL::LinkedList::InitializeListHead(&NonPagedPoolFreeList[Index]);
|
RTL::LinkedList::InitializeListHead(&NonPagedPoolFreeList[Index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Take the first free entry from the pool and set its size */
|
/* Take the first free page from the pool and set its size */
|
||||||
FreeEntry = (PMMFREE_POOL_ENTRY)MemoryLayout->NonPagedPoolStart;
|
FreePage = (PMMFREE_POOL_ENTRY)MemoryLayout->NonPagedPoolStart;
|
||||||
FreeEntry->Size = MemoryLayout->NonPagedPoolSize;
|
FreePage->Size = MemoryLayout->NonPagedPoolSize;
|
||||||
|
|
||||||
/* Take number of pages in the pool */
|
/* Take number of pages in the pool */
|
||||||
Index = (ULONG)(MemoryLayout->NonPagedPoolSize - 1);
|
Index = (ULONG)(MemoryLayout->NonPagedPoolSize - 1);
|
||||||
@@ -294,17 +529,21 @@ MM::Allocator::InitializeNonPagedPool(VOID)
|
|||||||
Index = MM_MAX_FREE_PAGE_LIST_HEADS - 1;
|
Index = MM_MAX_FREE_PAGE_LIST_HEADS - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the first free entry into the free page list */
|
/* Insert the first free page into the free page list */
|
||||||
RTL::LinkedList::InsertHeadList(&NonPagedPoolFreeList[Index], &FreeEntry->List);
|
RTL::LinkedList::InsertHeadList(&NonPagedPoolFreeList[Index], &FreePage->List);
|
||||||
|
|
||||||
/* Create a free entry for each page in the pool */
|
/* Create a free page for each page in the pool */
|
||||||
SetupEntry = FreeEntry;
|
SetupPage = FreePage;
|
||||||
for(Index = 0; Index < MemoryLayout->NonPagedPoolSize; Index++)
|
for(Index = 0; Index < MemoryLayout->NonPagedPoolSize; Index++)
|
||||||
{
|
{
|
||||||
/* Initialize the owner for each entry */
|
/* Initialize the owner for each page */
|
||||||
SetupEntry->Owner = FreeEntry;
|
SetupPage->Owner = FreePage;
|
||||||
SetupEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)SetupEntry + MM_PAGE_SIZE);
|
SetupPage = (PMMFREE_POOL_ENTRY)((ULONG_PTR)SetupPage + MM_PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store first and last allocated non-paged pool page */
|
||||||
|
NonPagedPoolFrameStart = MM::Paging::GetPageFrameNumber(MM::Paging::GetPteAddress(MemoryLayout->NonPagedPoolStart));
|
||||||
|
NonPagedPoolFrameEnd = MM::Paging::GetPageFrameNumber(MM::Paging::GetPteAddress(MemoryLayout->NonPagedPoolEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,12 @@
|
|||||||
#include <xtos.hh>
|
#include <xtos.hh>
|
||||||
|
|
||||||
|
|
||||||
|
/* PFN marking the initial non-paged pool end boundary */
|
||||||
|
PFN_NUMBER MM::Allocator::NonPagedPoolFrameEnd;
|
||||||
|
|
||||||
|
/* PFN marking the initial non-paged pool start boundary */
|
||||||
|
PFN_NUMBER MM::Allocator::NonPagedPoolFrameStart;
|
||||||
|
|
||||||
/* Array of non-paged pool free list heads */
|
/* Array of non-paged pool free list heads */
|
||||||
LIST_ENTRY MM::Allocator::NonPagedPoolFreeList[MM_MAX_FREE_PAGE_LIST_HEADS];
|
LIST_ENTRY MM::Allocator::NonPagedPoolFreeList[MM_MAX_FREE_PAGE_LIST_HEADS];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user