diff --git a/xtoskrnl/includes/mm/pfn.hh b/xtoskrnl/includes/mm/pfn.hh index cd4386e..a0b9c34 100644 --- a/xtoskrnl/includes/mm/pfn.hh +++ b/xtoskrnl/includes/mm/pfn.hh @@ -31,6 +31,7 @@ namespace MM STATIC LOADER_MEMORY_DESCRIPTOR OriginalFreeDescriptor; STATIC PMMPFNLIST PageLocationList[]; STATIC PFN_NUMBER PfnDatabaseSize; + STATIC MMPFNLIST RomPagesList; STATIC MMPFNLIST StandbyPagesList; STATIC MMPFNLIST ZeroedPagesList; @@ -53,6 +54,8 @@ namespace MM STATIC XTAPI VOID IncrementAvailablePages(VOID); STATIC XTAPI VOID InitializePageTablePfns(VOID); STATIC XTAPI VOID LinkFreePage(IN PFN_NUMBER PageFrameIndex); + STATIC XTAPI VOID LinkPage(IN PMMPFNLIST ListHead, + IN PFN_NUMBER PageFrameIndex); STATIC XTAPI VOID LinkPfnForPageTable(IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPte); STATIC XTAPI VOID ProcessMemoryDescriptor(IN PFN_NUMBER BasePage, diff --git a/xtoskrnl/mm/data.cc b/xtoskrnl/mm/data.cc index 06bdf9b..b1ca086 100644 --- a/xtoskrnl/mm/data.cc +++ b/xtoskrnl/mm/data.cc @@ -72,9 +72,6 @@ ULONGLONG MM::Pfn::NumberOfPhysicalPages; /* Old biggest free memory descriptor */ LOADER_MEMORY_DESCRIPTOR MM::Pfn::OriginalFreeDescriptor; -/* List containing standby pages (clean, can be reclaimed or repurposed) */ -MMPFNLIST MM::Pfn::StandbyPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR}; - /* Array of pointers to PFN lists */ PMMPFNLIST MM::Pfn::PageLocationList[] = {&ZeroedPagesList, &FreePagesList, @@ -88,6 +85,12 @@ PMMPFNLIST MM::Pfn::PageLocationList[] = {&ZeroedPagesList, /* Size of the PFN database in pages */ PFN_NUMBER MM::Pfn::PfnDatabaseSize; +/* List containing pages mapped as Read-Only (ROM) */ +MMPFNLIST MM::Pfn::RomPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR}; + +/* List containing standby pages (clean, can be reclaimed or repurposed) */ +MMPFNLIST MM::Pfn::StandbyPagesList = {0, StandbyPageList, MAXULONG_PTR, MAXULONG_PTR}; + /* List containing free physical pages that have been zeroed out */ MMPFNLIST MM::Pfn::ZeroedPagesList = {0, ZeroedPageList, MAXULONG_PTR, MAXULONG_PTR}; diff --git a/xtoskrnl/mm/pfn.cc b/xtoskrnl/mm/pfn.cc index 93379f7..8fc1e7c 100644 --- a/xtoskrnl/mm/pfn.cc +++ b/xtoskrnl/mm/pfn.cc @@ -326,6 +326,200 @@ MM::Pfn::LinkFreePage(IN PFN_NUMBER PageFrameIndex) IncrementAvailablePages(); } + +/** + * Links a physical page to the appropriate list. + * + * @param ListHead + * Pointer to the list head. + * + * @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::LinkPage(IN PMMPFNLIST ListHead, + IN PFN_NUMBER PageFrameIndex) +{ + PMMCOLOR_TABLES ColorHead; + MMPAGELISTS ListName; + PMMPFN PageFrame; + + /* Get the memory layout */ + PMMMEMORY_LAYOUT MemoryLayout = MM::Manager::GetMemoryLayout(); + + /* Get the PFN database entry for the target page */ + PageFrame = &((PMMPFN)MemoryLayout->PfnDatabaseAddress)[PageFrameIndex]; + + /* Get the list name */ + ListName = ListHead->ListName; + + /* Handle pages being linked to the modified or standby lists */ + if(ListName == ModifiedPageList || ListName == StandbyPageList) + { + /* Detect an invalid prototype/transition PTE state */ + if(!MM::Paging::GetPteSoftwarePrototype(&PageFrame->OriginalPte) && + MM::Paging::GetPteSoftwareTransition(&PageFrame->OriginalPte)) + { + /* Crash system due to corrupted PFN/PTE state */ + KE::Crash::PanicEx(0x71, 0x8888, 0, 0, 0); + } + } + + /* Check if the page is ROM */ + if(PageFrame->u3.e1.Rom == 1) + { + /* Link the page to the ROM list */ + ListHead = &RomPagesList; + ListHead->Total++; + + /* Append the page to the end of the ROM list */ + if(ListHead->Blink != MAXULONG_PTR) + { + /* Update the previous tail to point to this page */ + (&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[ListHead->Blink])->u1.Flink = PageFrameIndex; + } + else + { + /* Initialize the list if it was empty */ + ListHead->Flink = PageFrameIndex; + } + + /* Update list tail and PFN linkage */ + ListHead->Blink = PageFrameIndex; + PageFrame->u1.Flink = MAXULONG_PTR; + PageFrame->u2.Blink = ListHead->Blink; + PageFrame->u3.e1.PageLocation = ListName; + + /* ROM pages require no further processing */ + return; + } + + /* Account for the page being inserted into the target list */ + ListHead->Total++; + + /* Redirect modified pages to the per-color modified list */ + if(ListHead == &ModifiedPagesList) + { + /* Select the modified list matching the page color */ + ListHead = MM::Colors::GetModifiedPages(PageFrame->u3.e1.PageColor); + ListHead->Total++; + } + else if((PageFrame->u3.e1.RemovalRequested == 1) && (ListName <= StandbyPageList)) + { + /* Undo the insertion into the current list */ + ListHead->Total--; + + /* Preserve the standby location for removed pages */ + if(ListName == StandbyPageList) + { + /* Keep the page marked as standby */ + PageFrame->u3.e1.PageLocation = StandbyPageList; + } + + /* Mark the page as no longer cache-mapped */ + PageFrame->u3.e1.CacheAttribute = PfnNotMapped; + + /* Move the page to the bad page list */ + ListHead = &BadPagesList; + ListHead->Total++; + ListName = BadPageList; + } + + /* Insert zeroed pages at the head of the list */ + if(ListName == ZeroedPageList) + { + /* Link the page as the new list head */ + ListHead->Flink = PageFrameIndex; + + /* Initialize PFN forward and backward links */ + PageFrame->u1.Flink = ListHead->Flink; + PageFrame->u2.Blink = MAXULONG_PTR; + + /* Update the previous head if it exists */ + if(ListHead->Flink != MAXULONG_PTR) + { + /* Fix up the backward link of the old head */ + (&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[ListHead->Flink])->u2.Blink = PageFrameIndex; + } + else + { + /* Set the tail if the list was empty */ + ListHead->Blink = PageFrameIndex; + } + } + else + { + /* Append the page to the tail of the list */ + if(ListHead->Blink != MAXULONG_PTR) + { + /* Link the current tail to the new page */ + (&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[ListHead->Blink])->u1.Flink = PageFrameIndex; + } + else + { + /* Initialize the list if it was empty */ + ListHead->Flink = PageFrameIndex; + } + + /* Update list tail */ + ListHead->Blink = PageFrameIndex; + + /* Terminate PFN forward link and set backward link */ + PageFrame->u1.Flink = MAXULONG_PTR; + PageFrame->u2.Blink = ListHead->Blink; + } + + /* Record the page’s current location */ + PageFrame->u3.e1.PageLocation = ListName; + + /* Handle pages that contribute to the available page count */ + if(ListName <= StandbyPageList) + { + /* Increment the system-wide available page counter */ + MM::Pfn::IncrementAvailablePages(); + + /* Select the free list matching the page color */ + ColorHead = MM::Colors::GetFreePages(ZeroedPageList, PageFrameIndex & MM::Colors::GetPagingColorsMask()); + + /* Store the color list linkage in the original PTE */ + MM::Paging::SetPte(&PageFrame->OriginalPte, ColorHead->Flink); + PageFrame->u4.PteFrame = MM_PFN_PTE_FRAME; + + /* Insert the page into the color free list */ + ColorHead->Flink = PageFrameIndex; + + /* Update the previous head or initialize the tail */ + if(ColorHead->Flink != MAXULONG_PTR) + { + /* Fix up the PTE frame of the previous entry */ + (&((PMMPFN)MemoryLayout->PfnDatabaseAddress)[ColorHead->Flink])->u4.PteFrame = PageFrameIndex; + } + else + { + /* Set the tail for an empty color list */ + ColorHead->Blink = (PVOID)PageFrame; + } + + /* Increment the color list page count */ + ColorHead->Count++; + } + else if(ListName == ModifiedPageList) + { + /* Modified page insertion logic not implemented yet */ + UNIMPLEMENTED; + } + else if(ListName == ModifiedReadOnlyPageList) + { + /* Modified read-only page handling not implemented yet */ + UNIMPLEMENTED; + } +} + /** * Initializes the PFN database entry for a physical page that is used as a page table. *