// REACTOS NT
//
#define RmapListHead AweReferenceCount
-#define SavedSwapEntry u4.EntireFrame
-#define RemoveEntryList(x) RemoveEntryList((PLIST_ENTRY)x)
-#define InsertTailList(x, y) InsertTailList(x, (PLIST_ENTRY)y)
-#define ListEntry u1
#define PHYSICAL_PAGE MMPFN
#define PPHYSICAL_PAGE PMMPFN
/* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
PPHYSICAL_PAGE MmPfnDatabase[2];
-ULONG MmAvailablePages;
-ULONG MmResidentAvailablePages;
+PFN_NUMBER MmAvailablePages;
+PFN_NUMBER MmResidentAvailablePages;
+PFN_NUMBER MmResidentAvailableAtInit;
SIZE_T MmTotalCommitLimit;
SIZE_T MmTotalCommittedPages;
SIZE_T MmPeakCommitment;
SIZE_T MmtotalCommitLimitMaximum;
-MMPFNLIST MmZeroedPageListHead;
-MMPFNLIST MmFreePageListHead;
-MMPFNLIST MmStandbyPageListHead;
-MMPFNLIST MmModifiedPageListHead;
-MMPFNLIST MmModifiedNoWritePageListHead;
-
-/* List of pages zeroed by the ZPW (MmZeroPageThreadMain) */
-static LIST_ENTRY FreeZeroedPageListHead;
-/* List of free pages, filled by MmGetReferenceCountPage and
- * and MmInitializePageList */
-static LIST_ENTRY FreeUnzeroedPageListHead;
-
-static KEVENT ZeroPageThreadEvent;
+KEVENT ZeroPageThreadEvent;
static BOOLEAN ZeroPageThreadShouldTerminate = FALSE;
-
-static ULONG UnzeroedPageCount = 0;
-
-/* FUNCTIONS *************************************************************/
-
static RTL_BITMAP MiUserPfnBitMap;
/* FUNCTIONS *************************************************************/
BOOLEAN
NTAPI
-MiIsPfnInUse(IN PMMPFN Pfn1)
+MiIsPfnFree(IN PMMPFN Pfn1)
{
- return ((Pfn1->u3.e1.PageLocation != FreePageList) &&
- (Pfn1->u3.e1.PageLocation != ZeroedPageList));
+ /* Must be a free or zero page, with no references, linked */
+ return ((Pfn1->u3.e1.PageLocation <= StandbyPageList) &&
+ (Pfn1->u1.Flink) &&
+ (Pfn1->u2.Blink) &&
+ !(Pfn1->u3.e2.ReferenceCount));
}
-PFN_NUMBER
+BOOLEAN
NTAPI
-MiFindContiguousPages(IN PFN_NUMBER LowestPfn,
- IN PFN_NUMBER HighestPfn,
- IN PFN_NUMBER BoundaryPfn,
- IN PFN_NUMBER SizeInPages,
- IN MEMORY_CACHING_TYPE CacheType)
+MiIsPfnInUse(IN PMMPFN Pfn1)
{
- PFN_NUMBER Page, PageCount, LastPage, Length, BoundaryMask;
- ULONG i = 0;
- PMMPFN Pfn1, EndPfn;
- KIRQL OldIrql;
- PAGED_CODE ();
- ASSERT(SizeInPages != 0);
-
- //
- // Convert the boundary PFN into an alignment mask
- //
- BoundaryMask = ~(BoundaryPfn - 1);
-
- //
- // Loop all the physical memory blocks
- //
- do
- {
- //
- // Capture the base page and length of this memory block
- //
- Page = MmPhysicalMemoryBlock->Run[i].BasePage;
- PageCount = MmPhysicalMemoryBlock->Run[i].PageCount;
-
- //
- // Check how far this memory block will go
- //
- LastPage = Page + PageCount;
-
- //
- // Trim it down to only the PFNs we're actually interested in
- //
- if ((LastPage - 1) > HighestPfn) LastPage = HighestPfn + 1;
- if (Page < LowestPfn) Page = LowestPfn;
-
- //
- // Skip this run if it's empty or fails to contain all the pages we need
- //
- if (!(PageCount) || ((Page + SizeInPages) > LastPage)) continue;
-
- //
- // Now scan all the relevant PFNs in this run
- //
- Length = 0;
- for (Pfn1 = MiGetPfnEntry(Page); Page < LastPage; Page++, Pfn1++)
- {
- //
- // If this PFN is in use, ignore it
- //
- if (MiIsPfnInUse(Pfn1)) continue;
-
- //
- // If we haven't chosen a start PFN yet and the caller specified an
- // alignment, make sure the page matches the alignment restriction
- //
- if ((!(Length) && (BoundaryPfn)) &&
- (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask)))
- {
- //
- // It does not, so bail out
- //
- continue;
- }
-
- //
- // Increase the number of valid pages, and check if we have enough
- //
- if (++Length == SizeInPages)
- {
- //
- // It appears we've amassed enough legitimate pages, rollback
- //
- Pfn1 -= (Length - 1);
- Page -= (Length - 1);
-
- //
- // Acquire the PFN lock
- //
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- do
- {
- //
- // Things might've changed for us. Is the page still free?
- //
- if (MiIsPfnInUse(Pfn1)) break;
-
- //
- // So far so good. Is this the last confirmed valid page?
- //
- if (!--Length)
- {
- //
- // Sanity check that we didn't go out of bounds
- //
- ASSERT(i != MmPhysicalMemoryBlock->NumberOfRuns);
-
- //
- // Loop until all PFN entries have been processed
- //
- EndPfn = Pfn1 - SizeInPages + 1;
- do
- {
- //
- // If this was an unzeroed page, there are now less
- //
- if (Pfn1->u3.e1.PageLocation == ZeroedPageList) UnzeroedPageCount--;
-
- //
- // One less free page
- //
- MmAvailablePages--;
-
- //
- // This PFN is now a used page, set it up
- //
- RemoveEntryList(&Pfn1->ListEntry);
- Pfn1->u3.e2.ReferenceCount = 1;
- Pfn1->SavedSwapEntry = 0;
-
- //
- // Check if it was already zeroed
- //
- if (Pfn1->u3.e1.PageLocation != ZeroedPageList)
- {
- //
- // It wasn't, so zero it
- //
- MiZeroPage(MiGetPfnEntryIndex(Pfn1));
- }
-
- //
- // Mark it in use
- //
- Pfn1->u3.e1.PageLocation = ActiveAndValid;
-
- //
- // Check if this is the last PFN, otherwise go on
- //
- if (Pfn1 == EndPfn) break;
- Pfn1--;
- } while (TRUE);
-
- //
- // Mark the first and last PFN so we can find them later
- //
- Pfn1->u3.e1.StartOfAllocation = 1;
- (Pfn1 + SizeInPages - 1)->u3.e1.EndOfAllocation = 1;
-
- //
- // Now it's safe to let go of the PFN lock
- //
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
- //
- // Quick sanity check that the last PFN is consistent
- //
- EndPfn = Pfn1 + SizeInPages;
- ASSERT(EndPfn == MiGetPfnEntry(Page + 1));
-
- //
- // Compute the first page, and make sure it's consistent
- //
- Page -= SizeInPages - 1;
- ASSERT(Pfn1 == MiGetPfnEntry(Page));
- ASSERT(Page != 0);
- return Page;
- }
-
- //
- // Keep going. The purpose of this loop is to reconfirm that
- // after acquiring the PFN lock these pages are still usable
- //
- Pfn1++;
- Page++;
- } while (TRUE);
-
- //
- // If we got here, something changed while we hadn't acquired
- // the PFN lock yet, so we'll have to restart
- //
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
- Length = 0;
- }
- }
- } while (++i != MmPhysicalMemoryBlock->NumberOfRuns);
-
- //
- // And if we get here, it means no suitable physical memory runs were found
- //
- return 0;
+ /* Standby list or higher, unlinked, and with references */
+ return !MiIsPfnFree(Pfn1);
}
PMDL
PFN_NUMBER PageCount, LowPage, HighPage, SkipPages, PagesFound = 0, Page;
PPFN_NUMBER MdlPage, LastMdlPage;
KIRQL OldIrql;
- PLIST_ENTRY ListEntry;
PPHYSICAL_PAGE Pfn1;
INT LookForZeroedPages;
ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
//
// Do we have zeroed pages?
//
- if (!IsListEmpty(&FreeZeroedPageListHead))
+ if (MmZeroedPageListHead.Total)
{
//
// Grab a zero page
//
- ListEntry = RemoveTailList(&FreeZeroedPageListHead);
+ Pfn1 = MiRemoveHeadList(&MmZeroedPageListHead);
}
- else if (!IsListEmpty(&FreeUnzeroedPageListHead))
+ else if (MmFreePageListHead.Total)
{
//
// Nope, grab an unzeroed page
//
- ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
- UnzeroedPageCount--;
+ Pfn1 = MiRemoveHeadList(&MmFreePageListHead);
}
else
{
break;
}
- //
- // Get the PFN entry for this page
- //
- Pfn1 = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
-
//
// Make sure it's really free
//
Pfn1->u3.e1.StartOfAllocation = 1;
Pfn1->u3.e1.EndOfAllocation = 1;
Pfn1->u3.e2.ReferenceCount = 1;
- Pfn1->u3.e1.PageLocation = ActiveAndValid;
- Pfn1->SavedSwapEntry = 0;
//
// Decrease available pages
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u3.e1.StartOfAllocation = 1;
Pfn1->u3.e1.EndOfAllocation = 1;
- Pfn1->SavedSwapEntry = 0;
-
- //
- // If this page was unzeroed, we've consumed such a page
- //
- if (Pfn1->u3.e1.PageLocation != ZeroedPageList) UnzeroedPageCount--;
-
+
//
// Decrease available pages
//
PMEMORY_ALLOCATION_DESCRIPTOR Md;
PLIST_ENTRY NextEntry;
ULONG NrSystemPages = 0;
-
- /* Initialize the page lists */
- InitializeListHead(&FreeUnzeroedPageListHead);
- InitializeListHead(&FreeZeroedPageListHead);
+ KIRQL OldIrql;
/* This is what a used page looks like */
RtlZeroMemory(&UsedPage, sizeof(UsedPage));
UsedPage.u3.e1.PageLocation = ActiveAndValid;
UsedPage.u3.e2.ReferenceCount = 1;
+ /* Lock PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
/* Loop the memory descriptors */
for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
NextEntry = NextEntry->Flink)
{
-#undef ListEntry
/* Get the descriptor */
Md = CONTAINING_RECORD(NextEntry,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
-#define ListEntry u1
/* Skip bad memory */
if ((Md->MemoryType == LoaderFirmwarePermanent) ||
{
/* Mark it as a free page */
MmPfnDatabase[0][Md->BasePage + i].u3.e1.PageLocation = FreePageList;
- InsertTailList(&FreeUnzeroedPageListHead,
- &MmPfnDatabase[0][Md->BasePage + i].ListEntry);
- UnzeroedPageCount++;
+ MiInsertInListTail(&MmFreePageListHead,
+ &MmPfnDatabase[0][Md->BasePage + i]);
MmAvailablePages++;
}
}
MmPfnDatabase[0][i] = UsedPage;
NrSystemPages++;
}
+
+ /* Release the PFN database lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
KeInitializeEvent(&ZeroPageThreadEvent, NotificationEvent, TRUE);
DPRINT("Pages: %x %x\n", MmAvailablePages, NrSystemPages);
KIRQL oldIrql;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- MiGetPfnEntry(Pfn)->SavedSwapEntry = SwapEntry;
+ MiGetPfnEntry(Pfn)->u1.WsIndex = SwapEntry;
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
}
KIRQL oldIrql;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- SwapEntry = MiGetPfnEntry(Pfn)->SavedSwapEntry;
+ SwapEntry = MiGetPfnEntry(Pfn)->u1.WsIndex;
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
return(SwapEntry);
{
MmAvailablePages++;
Page->u3.e1.PageLocation = FreePageList;
- InsertTailList(&FreeUnzeroedPageListHead,
- &Page->ListEntry);
- UnzeroedPageCount++;
- if (UnzeroedPageCount > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
+ MiInsertInListTail(&MmFreePageListHead, Page);
+ if (MmFreePageListHead.Total > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
{
KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
}
PFN_TYPE
NTAPI
-MmAllocPage(ULONG Type, SWAPENTRY SwapEntry)
+MmAllocPage(ULONG Type)
{
PFN_TYPE PfnOffset;
- PLIST_ENTRY ListEntry;
PPHYSICAL_PAGE PageDescriptor;
BOOLEAN NeedClear = FALSE;
DPRINT("MmAllocPage()\n");
- if (IsListEmpty(&FreeZeroedPageListHead))
+ if (MmZeroedPageListHead.Total == 0)
{
- if (IsListEmpty(&FreeUnzeroedPageListHead))
- {
+ if (MmFreePageListHead.Total == 0)
+ {
/* Check if this allocation is for the PFN DB itself */
if (MmNumberOfPhysicalPages == 0)
{
DPRINT1("MmAllocPage(): Out of memory\n");
return 0;
}
- ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
- UnzeroedPageCount--;
-
- PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
+ PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
NeedClear = TRUE;
}
else
{
- ListEntry = RemoveTailList(&FreeZeroedPageListHead);
-
- PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
+ PageDescriptor = MiRemoveHeadList(&MmZeroedPageListHead);
}
PageDescriptor->u3.e2.ReferenceCount = 1;
- PageDescriptor->SavedSwapEntry = SwapEntry;
MmAvailablePages--;
{
MiZeroPage(PfnOffset);
}
-
+
PageDescriptor->u3.e1.PageLocation = ActiveAndValid;
return PfnOffset;
}
{
NTSTATUS Status;
KIRQL oldIrql;
- PLIST_ENTRY ListEntry;
PPHYSICAL_PAGE PageDescriptor;
PFN_TYPE Pfn;
ULONG Count;
}
Count = 0;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- while (!IsListEmpty(&FreeUnzeroedPageListHead))
+ while (MmFreePageListHead.Total)
{
- ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
- UnzeroedPageCount--;
- PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
+ PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
/* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
Pfn = PageDescriptor - MmPfnDatabase[0];
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
if (NT_SUCCESS(Status))
{
- InsertHeadList(&FreeZeroedPageListHead, ListEntry);
- PageDescriptor->u3.e1.PageLocation = ZeroedPageList;
+ MiInsertZeroListAtBack(Pfn);
Count++;
}
else
{
- InsertHeadList(&FreeUnzeroedPageListHead, ListEntry);
+ MiInsertInListTail(&MmFreePageListHead, PageDescriptor);
PageDescriptor->u3.e1.PageLocation = FreePageList;
- UnzeroedPageCount++;
}
}