diff --git a/sdk/xtdk/mmtypes.h b/sdk/xtdk/mmtypes.h index 7e81b0f..7858784 100644 --- a/sdk/xtdk/mmtypes.h +++ b/sdk/xtdk/mmtypes.h @@ -177,4 +177,19 @@ typedef struct _MMPFNLIST PFN_NUMBER Blink; } 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 */ diff --git a/sdk/xtdk/xtstruct.h b/sdk/xtdk/xtstruct.h index 7f95d8e..31c2337 100644 --- a/sdk/xtdk/xtstruct.h +++ b/sdk/xtdk/xtstruct.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_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 _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_POWER_STATE PROCESSOR_POWER_STATE, *PPROCESSOR_POWER_STATE; typedef struct _RTL_BITMAP RTL_BITMAP, *PRTL_BITMAP; diff --git a/xtoskrnl/includes/mm/mmgr.hh b/xtoskrnl/includes/mm/mmgr.hh index 770491b..97209a9 100644 --- a/xtoskrnl/includes/mm/mmgr.hh +++ b/xtoskrnl/includes/mm/mmgr.hh @@ -20,11 +20,13 @@ namespace MM private: STATIC MMMEMORY_LAYOUT MemoryLayout; STATIC PFN_NUMBER NumberOfSystemPtes; + STATIC PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock; public: STATIC XTAPI ULONG_PTR GetInstalledMemorySize(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 InitializeMemoryManager(VOID); STATIC XTAPI BOOLEAN VerifyMemoryTypeFree(IN LOADER_MEMORY_TYPE MemoryType); diff --git a/xtoskrnl/includes/mm/pfn.hh b/xtoskrnl/includes/mm/pfn.hh index 5b7a810..506228c 100644 --- a/xtoskrnl/includes/mm/pfn.hh +++ b/xtoskrnl/includes/mm/pfn.hh @@ -30,6 +30,7 @@ namespace MM STATIC ULONGLONG NumberOfPhysicalPages; STATIC LOADER_MEMORY_DESCRIPTOR OriginalFreeDescriptor; STATIC PMMPFNLIST PageLocationList[]; + STATIC RTL_BITMAP PfnBitMap; STATIC MMPFNLIST RomPagesList; STATIC MMPFNLIST StandbyPagesList; STATIC MMPFNLIST ZeroedPagesList; @@ -49,6 +50,7 @@ namespace MM STATIC XTAPI ULONG_PTR GetHighestPhysicalPage(VOID); STATIC XTAPI ULONGLONG GetNumberOfPhysicalPages(VOID); STATIC XTAPI PMMPFN GetPfnEntry(IN PFN_NUMBER Pfn); + STATIC XTAPI VOID InitializePfnBitmap(VOID); STATIC XTAPI VOID InitializePfnDatabase(VOID); STATIC XTAPI VOID LinkPfn(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte, diff --git a/xtoskrnl/mm/data.cc b/xtoskrnl/mm/data.cc index 5a067dc..0f57f01 100644 --- a/xtoskrnl/mm/data.cc +++ b/xtoskrnl/mm/data.cc @@ -48,6 +48,9 @@ MMMEMORY_LAYOUT MM::Manager::MemoryLayout; /* Total number of PTEs reserved for system space mapping */ 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 */ MM::PPAGEMAP MM::Paging::PmlRoutines; @@ -91,6 +94,9 @@ PMMPFNLIST MM::Pfn::PageLocationList[] = {&ZeroedPagesList, NULLPTR, NULLPTR}; +/* Bitmap used to track physical pages */ +RTL_BITMAP MM::Pfn::PfnBitMap; + /* List containing pages mapped as Read-Only (ROM) */ MMPFNLIST MM::Pfn::RomPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR}; diff --git a/xtoskrnl/mm/mmgr.cc b/xtoskrnl/mm/mmgr.cc index 859b8a4..bff8a7b 100644 --- a/xtoskrnl/mm/mmgr.cc +++ b/xtoskrnl/mm/mmgr.cc @@ -81,11 +81,146 @@ MM::Manager::GetMemoryLayout(VOID) */ XTAPI PFN_NUMBER -MM::Manager::GetNumberOfSystemPtes() +MM::Manager::GetNumberOfSystemPtes(VOID) { 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. * @@ -130,6 +265,9 @@ MM::Manager::InitializeMemoryManager(VOID) /* Initialize PFN database */ MM::Pfn::InitializePfnDatabase(); + /* Initialize PFN bitmap */ + MM::Pfn::InitializePfnBitmap(); + /* Initialize paged pool */ MM::Allocator::InitializePagedPool(); diff --git a/xtoskrnl/mm/pfn.cc b/xtoskrnl/mm/pfn.cc index 16b1221..4b095f7 100644 --- a/xtoskrnl/mm/pfn.cc +++ b/xtoskrnl/mm/pfn.cc @@ -423,6 +423,13 @@ MM::Pfn::GetPfnEntry(IN PFN_NUMBER Pfn) 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 */ MemoryLayout = MM::Manager::GetMemoryLayout(); @@ -445,6 +452,60 @@ MM::Pfn::IncrementAvailablePages(VOID) 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. *