#define MODULE_INVOLVED_IN_ARM3
#include "ARM3/miarm.h"
-/* TYPES *******************************************************************/
-
-#define MM_PHYSICAL_PAGE_FREE (0x1)
-#define MM_PHYSICAL_PAGE_USED (0x2)
-
/* GLOBALS ****************************************************************/
//
//
// REACTOS NT
//
-#define Consumer PageLocation
-#define Type CacheAttribute
-#define Zero PrototypePte
-#define LockCount u3.e1.PageColor
#define RmapListHead AweReferenceCount
-#define SavedSwapEntry u4.EntireFrame
-#define Flags u3.e1
-#define ReferenceCount u3.ReferenceCount
-#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
-PPHYSICAL_PAGE MmPfnDatabase;
+/* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
+PPHYSICAL_PAGE MmPfnDatabase[2];
-/* List of pages allocated to the MC_USER Consumer */
-static LIST_ENTRY UserPageListHead;
-/* 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;
+PFN_NUMBER MmAvailablePages;
+PFN_NUMBER MmResidentAvailablePages;
+PFN_NUMBER MmResidentAvailableAtInit;
-static KEVENT ZeroPageThreadEvent;
-static BOOLEAN ZeroPageThreadShouldTerminate = FALSE;
+SIZE_T MmTotalCommitLimit;
+SIZE_T MmTotalCommittedPages;
+SIZE_T MmSharedCommit;
+SIZE_T MmDriverCommit;
+SIZE_T MmProcessCommit;
+SIZE_T MmPagedPoolCommit;
+SIZE_T MmPeakCommitment;
+SIZE_T MmtotalCommitLimitMaximum;
-static ULONG UnzeroedPageCount = 0;
+KEVENT ZeroPageThreadEvent;
+static BOOLEAN ZeroPageThreadShouldTerminate = FALSE;
+static RTL_BITMAP MiUserPfnBitMap;
/* FUNCTIONS *************************************************************/
+VOID
+NTAPI
+MiInitializeUserPfnBitmap(VOID)
+{
+ PVOID Bitmap;
+
+ /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
+ Bitmap = ExAllocatePoolWithTag(NonPagedPool,
+ (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
+ ' mM');
+ ASSERT(Bitmap);
+
+ /* Initialize it and clear all the bits to begin with */
+ RtlInitializeBitMap(&MiUserPfnBitMap,
+ Bitmap,
+ MmHighestPhysicalPage + 1);
+ RtlClearAllBits(&MiUserPfnBitMap);
+}
+
PFN_TYPE
NTAPI
MmGetLRUFirstUserPage(VOID)
{
- PLIST_ENTRY NextListEntry;
- PHYSICAL_PAGE* PageDescriptor;
- KIRQL oldIrql;
-
- oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- NextListEntry = UserPageListHead.Flink;
- if (NextListEntry == &UserPageListHead)
- {
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
- return 0;
- }
- PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
- ASSERT_PFN(PageDescriptor);
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
- return PageDescriptor - MmPfnDatabase;
+ ULONG Position;
+ KIRQL OldIrql;
+
+ /* Find the first user page */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ if (Position == 0xFFFFFFFF) return 0;
+
+ /* Return it */
+ return Position;
}
VOID
NTAPI
MmInsertLRULastUserPage(PFN_TYPE Pfn)
{
- KIRQL oldIrql;
- PPHYSICAL_PAGE Page;
+ KIRQL OldIrql;
- oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- Page = MiGetPfnEntry(Pfn);
- ASSERT(Page);
- ASSERT(Page->Flags.Type == MM_PHYSICAL_PAGE_USED);
- ASSERT(Page->Flags.Consumer == MC_USER);
- InsertTailList(&UserPageListHead, &Page->ListEntry);
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
+ /* Set the page as a user page */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ RtlSetBit(&MiUserPfnBitMap, Pfn);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
PFN_TYPE
NTAPI
MmGetLRUNextUserPage(PFN_TYPE PreviousPfn)
{
- PLIST_ENTRY NextListEntry;
- PHYSICAL_PAGE* PageDescriptor;
- KIRQL oldIrql;
- PPHYSICAL_PAGE Page;
-
- oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- Page = MiGetPfnEntry(PreviousPfn);
- ASSERT(Page);
- ASSERT(Page->Flags.Type == MM_PHYSICAL_PAGE_USED);
- ASSERT(Page->Flags.Consumer == MC_USER);
- NextListEntry = (PLIST_ENTRY)Page->ListEntry.Flink;
- if (NextListEntry == &UserPageListHead)
- {
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
- return 0;
- }
- PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
- return PageDescriptor - MmPfnDatabase;
+ ULONG Position;
+ KIRQL OldIrql;
+
+ /* Find the next user page */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ Position = RtlFindSetBits(&MiUserPfnBitMap, 1, PreviousPfn + 1);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ if (Position == 0xFFFFFFFF) return 0;
+
+ /* Return it */
+ return Position;
}
VOID
NTAPI
MmRemoveLRUUserPage(PFN_TYPE Page)
{
- RemoveEntryList(&MiGetPfnEntry(Page)->ListEntry);
+ /* Unset the page as a user page */
+ RtlClearBit(&MiUserPfnBitMap, Page);
}
-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)
+MiIsPfnFree(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 (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) 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 (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) 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->Flags.Zero == 0) UnzeroedPageCount--;
-
- //
- // One less free page, one more system page
- //
- MmStats.NrFreePages--;
- MmStats.NrSystemPages++;
-
- //
- // This PFN is now a used page, set it up
- //
- RemoveEntryList(&Pfn1->ListEntry);
- Pfn1->Flags.Type = MM_PHYSICAL_PAGE_USED;
- Pfn1->Flags.Consumer = MC_NPPOOL;
- Pfn1->ReferenceCount = 1;
- Pfn1->LockCount = 0;
- Pfn1->SavedSwapEntry = 0;
-
- //
- // Check if it was already zeroed
- //
- if (Pfn1->Flags.Zero == 0)
- {
- //
- // It wasn't, so zero it
- //
- MiZeroPage(MiGetPfnEntryIndex(Pfn1));
- }
-
- //
- // 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->Flags.StartOfAllocation = 1;
- (Pfn1 + SizeInPages - 1)->Flags.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;
+ /* 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));
+}
+
+BOOLEAN
+NTAPI
+MiIsPfnInUse(IN PMMPFN Pfn1)
+{
+ /* 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
//
- ASSERT(Pfn1->Flags.Type == MM_PHYSICAL_PAGE_FREE);
- ASSERT(Pfn1->ReferenceCount == 0);
+ ASSERT(MiIsPfnInUse(Pfn1) == FALSE);
+ ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
//
// Allocate it and mark it
//
- Pfn1->Flags.Type = MM_PHYSICAL_PAGE_USED;
- Pfn1->Flags.Consumer = MC_NPPOOL;
- Pfn1->Flags.StartOfAllocation = 1;
- Pfn1->Flags.EndOfAllocation = 1;
- Pfn1->ReferenceCount = 1;
- Pfn1->LockCount = 0;
- Pfn1->SavedSwapEntry = 0;
+ Pfn1->u3.e1.StartOfAllocation = 1;
+ Pfn1->u3.e1.EndOfAllocation = 1;
+ Pfn1->u3.e2.ReferenceCount = 1;
//
// Decrease available pages
//
- MmStats.NrSystemPages++;
- MmStats.NrFreePages--;
+ MmAvailablePages--;
//
// Save it into the MDL
//
// Make sure it's free and if this is our first pass, zeroed
//
- if (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) continue;
- if (Pfn1->Flags.Zero != LookForZeroedPages) continue;
+ if (MiIsPfnInUse(Pfn1)) continue;
+ if ((Pfn1->u3.e1.PageLocation == ZeroedPageList) != LookForZeroedPages) continue;
//
// Sanity checks
//
- ASSERT(Pfn1->ReferenceCount == 0);
+ ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
//
// Now setup the page and mark it
//
- Pfn1->Flags.Type = MM_PHYSICAL_PAGE_USED;
- Pfn1->Flags.Consumer = MC_NPPOOL;
- Pfn1->ReferenceCount = 1;
- Pfn1->Flags.StartOfAllocation = 1;
- Pfn1->Flags.EndOfAllocation = 1;
- Pfn1->LockCount = 0;
- Pfn1->SavedSwapEntry = 0;
-
- //
- // If this page was unzeroed, we've consumed such a page
- //
- if (!Pfn1->Flags.Zero) UnzeroedPageCount--;
-
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.StartOfAllocation = 1;
+ Pfn1->u3.e1.EndOfAllocation = 1;
+
//
// Decrease available pages
//
- MmStats.NrSystemPages++;
- MmStats.NrFreePages--;
+ MmAvailablePages--;
//
// Save this page into the MDL
//
// Check if we've reached the end
//
- Page = *MdlPage;
+ Page = *MdlPage++;
if (Page == (PFN_NUMBER)-1) break;
//
//
Pfn1 = MiGetPfnEntry(Page);
ASSERT(Pfn1);
- if (Pfn1->Flags.Zero == 0) MiZeroPage(Page);
+ if (Pfn1->u3.e1.PageLocation != ZeroedPageList) MiZeroPage(Page);
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
}
//
{
ULONG i;
PPHYSICAL_PAGE Pfn1;
- PCHAR State = "????", Consumer = "Unknown";
+ PCHAR State = "????", Type = "Unknown";
KIRQL OldIrql;
ULONG Totals[5] = {0}, FreePages = 0;
if (!Pfn1) continue;
//
- // Get the consumer
+ // Get the type
//
- switch (Pfn1->Flags.Consumer)
+ if (MiIsPfnInUse(Pfn1))
{
- case MC_NPPOOL:
-
- Consumer = "Nonpaged Pool";
- break;
-
- case MC_PPOOL:
-
- Consumer = "Paged Pool";
- break;
-
- case MC_CACHE:
-
- Consumer = "File System Cache";
- break;
-
- case MC_USER:
-
- Consumer = "Process Working Set";
- break;
-
- case MC_SYSTEM:
-
- Consumer = "System";
- break;
+ State = "Used";
}
-
- //
- // Get the type
- //
- switch (Pfn1->Flags.Type)
+ else
{
- case MM_PHYSICAL_PAGE_USED:
-
- State = "Used";
- Totals[Pfn1->Flags.Consumer]++;
- break;
-
- case MM_PHYSICAL_PAGE_FREE:
-
- State = "Free";
- Consumer = "Free";
- FreePages++;
- break;
+ State = "Free";
+ Type = "Free";
+ FreePages++;
+ break;
}
-
+
//
// Pretty-print the page
//
- DbgPrint("0x%08p:\t%04s\t%20s\t(%02d.%02d) [%08p])\n",
+ DbgPrint("0x%08p:\t%04s\t%20s\t(%02d) [%08p])\n",
i << PAGE_SHIFT,
State,
- Consumer,
- Pfn1->ReferenceCount,
- Pfn1->LockCount,
+ Type,
+ Pfn1->u3.e2.ReferenceCount,
Pfn1->RmapListHead);
}
DbgPrint("Nonpaged Pool: %d pages\t[%d KB]\n", Totals[MC_NPPOOL], (Totals[MC_NPPOOL] << PAGE_SHIFT) / 1024);
- DbgPrint("Paged Pool: %d pages\t[%d KB]\n", Totals[MC_PPOOL], (Totals[MC_PPOOL] << PAGE_SHIFT) / 1024);
+ DbgPrint("Paged Pool: %d pages\t[%d KB]\n", Totals[MC_PPOOL], (Totals[MC_PPOOL] << PAGE_SHIFT) / 1024);
DbgPrint("File System Cache: %d pages\t[%d KB]\n", Totals[MC_CACHE], (Totals[MC_CACHE] << PAGE_SHIFT) / 1024);
DbgPrint("Process Working Set: %d pages\t[%d KB]\n", Totals[MC_USER], (Totals[MC_USER] << PAGE_SHIFT) / 1024);
DbgPrint("System: %d pages\t[%d KB]\n", Totals[MC_SYSTEM], (Totals[MC_SYSTEM] << PAGE_SHIFT) / 1024);
PHYSICAL_PAGE UsedPage;
PMEMORY_ALLOCATION_DESCRIPTOR Md;
PLIST_ENTRY NextEntry;
-
- /* Initialize the page lists */
- InitializeListHead(&UserPageListHead);
- InitializeListHead(&FreeUnzeroedPageListHead);
- InitializeListHead(&FreeZeroedPageListHead);
+ ULONG NrSystemPages = 0;
+ KIRQL OldIrql;
/* This is what a used page looks like */
RtlZeroMemory(&UsedPage, sizeof(UsedPage));
- UsedPage.Flags.Type = MM_PHYSICAL_PAGE_USED;
- UsedPage.Flags.Consumer = MC_NPPOOL;
- UsedPage.ReferenceCount = 1;
+ 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) ||
for (i = 0; i < Md->PageCount; i++)
{
/* Mark it as a free page */
- MmPfnDatabase[Md->BasePage + i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
- InsertTailList(&FreeUnzeroedPageListHead,
- &MmPfnDatabase[Md->BasePage + i].ListEntry);
- UnzeroedPageCount++;
- MmStats.NrFreePages++;
+ MmPfnDatabase[0][Md->BasePage + i].u3.e1.PageLocation = FreePageList;
+ MiInsertInListTail(&MmFreePageListHead,
+ &MmPfnDatabase[0][Md->BasePage + i]);
+ MmAvailablePages++;
}
}
else
for (i = 0; i < Md->PageCount; i++)
{
/* Everything else is used memory */
- MmPfnDatabase[Md->BasePage + i] = UsedPage;
- MmStats.NrSystemPages++;
+ MmPfnDatabase[0][Md->BasePage + i] = UsedPage;
+ NrSystemPages++;
}
}
}
/* Finally handle the pages describing the PFN database themselves */
for (i = MxOldFreeDescriptor.BasePage; i < MxFreeDescriptor->BasePage; i++)
{
- /* Ensure this page was not added previously */
- ASSERT(MmPfnDatabase[i].Flags.Type == 0);
-
/* Mark it as used kernel memory */
- MmPfnDatabase[i] = UsedPage;
- MmStats.NrSystemPages++;
+ MmPfnDatabase[0][i] = UsedPage;
+ NrSystemPages++;
}
+
+ /* Release the PFN database lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
KeInitializeEvent(&ZeroPageThreadEvent, NotificationEvent, TRUE);
- DPRINT("Pages: %x %x\n", MmStats.NrFreePages, MmStats.NrSystemPages);
- MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages + MmStats.NrUserPages;
- MmInitializeBalancer(MmStats.NrFreePages, MmStats.NrSystemPages);
+ DPRINT("Pages: %x %x\n", MmAvailablePages, NrSystemPages);
+ MmInitializeBalancer(MmAvailablePages, NrSystemPages);
}
VOID
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);
Page = MiGetPfnEntry(Pfn);
ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Referencing non-used page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- Page->ReferenceCount++;
+ Page->u3.e2.ReferenceCount++;
}
ULONG
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
Page = MiGetPfnEntry(Pfn);
ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Getting reference count for free page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- RCount = Page->ReferenceCount;
+ RCount = Page->u3.e2.ReferenceCount;
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
return(RCount);
NTAPI
MmIsPageInUse(PFN_TYPE Pfn)
{
+ return MiIsPfnInUse(MiGetPfnEntry(Pfn));
+}
- DPRINT("MmIsPageInUse(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
-
- return (MiGetPfnEntry(Pfn)->Flags.Type == MM_PHYSICAL_PAGE_USED);
+VOID
+NTAPI
+MiSetConsumer(IN PFN_TYPE Pfn,
+ IN ULONG Type)
+{
+ MiGetPfnEntry(Pfn)->u3.e1.PageLocation = ActiveAndValid;
}
VOID
Page = MiGetPfnEntry(Pfn);
ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Dereferencing free page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (Page->ReferenceCount == 0)
- {
- DPRINT1("Derefrencing page with reference count 0\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
-
- Page->ReferenceCount--;
- if (Page->ReferenceCount == 0)
+ Page->u3.e2.ReferenceCount--;
+ if (Page->u3.e2.ReferenceCount == 0)
{
- MmStats.NrFreePages++;
- MmStats.NrSystemPages--;
- if (Page->Flags.Consumer == MC_USER) RemoveEntryList(&Page->ListEntry);
- if (Page->RmapListHead != (LONG)NULL)
- {
- DPRINT1("Freeing page with rmap entries.\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (Page->LockCount > 0)
- {
- DPRINT1("Freeing locked page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (Page->SavedSwapEntry != 0)
- {
- DPRINT1("Freeing page with swap entry.\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Freeing page with flags %x\n",
- Page->Flags.Type);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- Page->Flags.Type = MM_PHYSICAL_PAGE_FREE;
- Page->Flags.Consumer = MC_MAXIMUM;
- InsertTailList(&FreeUnzeroedPageListHead,
- &Page->ListEntry);
- UnzeroedPageCount++;
- if (UnzeroedPageCount > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
+ MmAvailablePages++;
+ Page->u3.e1.PageLocation = FreePageList;
+ MiInsertInListTail(&MmFreePageListHead, Page);
+ if (MmFreePageListHead.Total > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
{
KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
}
}
}
-ULONG
-NTAPI
-MmGetLockCountPage(PFN_TYPE Pfn)
-{
- KIRQL oldIrql;
- ULONG CurrentLockCount;
- PPHYSICAL_PAGE Page;
-
- DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
-
- oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
- Page = MiGetPfnEntry(Pfn);
- ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Getting lock count for free page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
-
- CurrentLockCount = Page->LockCount;
- KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
-
- return(CurrentLockCount);
-}
-
-VOID
-NTAPI
-MmLockPage(PFN_TYPE Pfn)
-{
- PPHYSICAL_PAGE Page;
-
- DPRINT("MmLockPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
-
- Page = MiGetPfnEntry(Pfn);
- ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Locking free page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
-
- Page->LockCount++;
-}
-
-VOID
-NTAPI
-MmUnlockPage(PFN_TYPE Pfn)
-{
- PPHYSICAL_PAGE Page;
-
- DPRINT("MmUnlockPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
-
- Page = MiGetPfnEntry(Pfn);
- ASSERT(Page);
- if (Page->Flags.Type != MM_PHYSICAL_PAGE_USED)
- {
- DPRINT1("Unlocking free page\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
-
- Page->LockCount--;
-}
-
PFN_TYPE
NTAPI
-MmAllocPage(ULONG Consumer, 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 (MmStats.NrTotalPages == 0)
+ if (MmNumberOfPhysicalPages == 0)
{
ASSERT(FALSE);
}
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);
}
- if (PageDescriptor->Flags.Type != MM_PHYSICAL_PAGE_FREE)
- {
- DPRINT1("Got non-free page from freelist\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- if (PageDescriptor->ReferenceCount != 0)
- {
- DPRINT1("%d\n", PageDescriptor->ReferenceCount);
- KeBugCheck(MEMORY_MANAGEMENT);
- }
- PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_USED;
- PageDescriptor->Flags.Consumer = Consumer;
- PageDescriptor->ReferenceCount = 1;
- PageDescriptor->LockCount = 0;
- PageDescriptor->SavedSwapEntry = SwapEntry;
+ PageDescriptor->u3.e2.ReferenceCount = 1;
- MmStats.NrSystemPages++;
- MmStats.NrFreePages--;
+ MmAvailablePages--;
- PfnOffset = PageDescriptor - MmPfnDatabase;
- if ((NeedClear) && (Consumer != MC_SYSTEM))
+ PfnOffset = PageDescriptor - MmPfnDatabase[0];
+ if ((NeedClear) && (Type != MC_SYSTEM))
{
MiZeroPage(PfnOffset);
}
+
+ PageDescriptor->u3.e1.PageLocation = ActiveAndValid;
return PfnOffset;
}
+NTSTATUS
+NTAPI
+MiZeroPage(PFN_TYPE Page)
+{
+ KIRQL Irql;
+ PVOID TempAddress;
+
+ Irql = KeRaiseIrqlToDpcLevel();
+ TempAddress = MiMapPageToZeroInHyperSpace(Page);
+ if (TempAddress == NULL)
+ {
+ return(STATUS_NO_MEMORY);
+ }
+ memset(TempAddress, 0, PAGE_SIZE);
+ MiUnmapPagesInZeroSpace(TempAddress, 1);
+ KeLowerIrql(Irql);
+ return(STATUS_SUCCESS);
+}
+
NTSTATUS
NTAPI
MmZeroPageThreadMain(PVOID Ignored)
{
NTSTATUS Status;
KIRQL oldIrql;
- PLIST_ENTRY ListEntry;
PPHYSICAL_PAGE PageDescriptor;
PFN_TYPE Pfn;
ULONG Count;
KernelMode,
FALSE,
NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ZeroPageThread: Wait failed\n");
- KeBugCheck(MEMORY_MANAGEMENT);
- }
if (ZeroPageThreadShouldTerminate)
{
}
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 */
- PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_USED;
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
- Pfn = PageDescriptor - MmPfnDatabase;
+ Pfn = PageDescriptor - MmPfnDatabase[0];
Status = MiZeroPage(Pfn);
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- PageDescriptor->Flags.Zero = 1;
- PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_FREE;
if (NT_SUCCESS(Status))
{
- InsertHeadList(&FreeZeroedPageListHead, ListEntry);
+ MiInsertZeroListAtBack(Pfn);
Count++;
}
else
{
- InsertHeadList(&FreeUnzeroedPageListHead, ListEntry);
- UnzeroedPageCount++;
+ MiInsertInListTail(&MmFreePageListHead, PageDescriptor);
+ PageDescriptor->u3.e1.PageLocation = FreePageList;
}
}