#define NDEBUG
#include <debug.h>
-#line 15 "ARMĀ³::PFNLIST"
#define MODULE_INVOLVED_IN_ARM3
#include "../ARM3/miarm.h"
ULONG Color;
PMMCOLOR_TABLES ColorTable;
PMMPFN Pfn1;
-
+
/* Make sure the PFN lock is held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Make sure the PFN entry isn't in-use */
ASSERT(Entry->u3.e1.WriteInProgress == 0);
ASSERT(Entry->u3.e1.ReadInProgress == 0);
-
+
/* Find the list for this entry, make sure it's the free or zero list */
ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
ListName = ListHead->ListName;
/* Remove one count */
ASSERT(ListHead->Total != 0);
ListHead->Total--;
-
+
/* Get the forward and back pointers */
OldFlink = Entry->u1.Flink;
OldBlink = Entry->u2.Blink;
-
+
/* Check if the next entry is the list head */
if (OldFlink != LIST_HEAD)
{
/* Set the list head's backlink instead */
ListHead->Blink = OldBlink;
}
-
+
/* Check if the back entry is the list head */
if (OldBlink != LIST_HEAD)
{
/* One less colored page */
ASSERT(ColorTable->Count >= 1);
ColorTable->Count--;
-
+
/* ReactOS Hack */
Entry->OriginalPte.u.Long = 0;
/* Signal the low memory event */
KeSetEvent(MiLowMemoryEvent, 0, FALSE);
}
-
+
/* One less page */
if (--MmAvailablePages < MmMinimumFreePages)
{
/* FIXME: Should wake up the MPW and working set manager, if we had one */
}
-
+
#if MI_TRACE_PFNS
ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
Entry->PfnUsage = MI_PFN_CURRENT_USAGE;
PMMPFNLIST ListHead;
MMLISTS ListName;
PFN_NUMBER OldFlink, OldBlink;
- ULONG OldColor, OldCache;
+ USHORT OldColor, OldCache;
PMMCOLOR_TABLES ColorTable;
/* Make sure PFN lock is held */
Pfn1 = MI_PFN_ELEMENT(PageIndex);
ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
ASSERT(Pfn1->u3.e1.Rom == 0);
-
+
/* Capture data for later */
OldColor = Pfn1->u3.e1.PageColor;
OldCache = Pfn1->u3.e1.CacheAttribute;
ASSERT_LIST_INVARIANT(ListHead);
ListName = ListHead->ListName;
ASSERT(ListName <= FreePageList);
-
+
/* Remove a page */
ListHead->Total--;
/* Get the forward and back pointers */
OldFlink = Pfn1->u1.Flink;
OldBlink = Pfn1->u2.Blink;
-
+
/* Check if the next entry is the list head */
if (OldFlink != LIST_HEAD)
{
/* Set the list head's backlink instead */
ListHead->Blink = OldBlink;
}
-
+
/* Check if the back entry is the list head */
if (OldBlink != LIST_HEAD)
{
/* Set the list head's backlink instead */
ListHead->Flink = OldFlink;
}
-
+
/* We are not on a list anymore */
ASSERT_LIST_INVARIANT(ListHead);
Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
-
+
/* Zero flags but restore color and cache */
Pfn1->u3.e2.ShortFlags = 0;
Pfn1->u3.e1.PageColor = OldColor;
ASSERT(Color < MmSecondaryColors);
ColorTable = &MmFreePagesByColor[ListName][Color];
ASSERT(ColorTable->Count >= 1);
-
+
/* Set the forward link to whoever we were pointing to */
ColorTable->Flink = Pfn1->OriginalPte.u.Long;
-
+
/* Get the first page on the color list */
if (ColorTable->Flink == LIST_HEAD)
{
/* This is the beginning of the list, so set the sentinel value */
- ColorTable->Blink = (PVOID)LIST_HEAD;
+ ColorTable->Blink = (PVOID)LIST_HEAD;
}
else
{
/* The list is empty, so we are the first page */
MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
}
-
+
/* One less page */
ColorTable->Count--;
-
+
/* ReactOS Hack */
Pfn1->OriginalPte.u.Long = 0;
/* Signal the low memory event */
KeSetEvent(MiLowMemoryEvent, 0, FALSE);
}
-
+
/* One less page */
if (--MmAvailablePages < MmMinimumFreePages)
{
ASSERT(Pfn1->u2.ShareCount == 0);
ASSERT_LIST_INVARIANT(&MmFreePageListHead);
ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
-
+
/* Return the page */
return PageIndex;
}
{
PFN_NUMBER PageIndex;
PMMPFN Pfn1;
- BOOLEAN Zero;
+ BOOLEAN Zero = FALSE;
/* Make sure PFN lock is held and we have pages */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Check the zero list */
ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
PageIndex = MmZeroedPageListHead.Flink;
- Color = PageIndex & MmSecondaryColorMask;
if (PageIndex == LIST_HEAD)
{
/* This means there's no zero pages, we have to look for free ones */
}
}
}
+ else
+ {
+ Color = PageIndex & MmSecondaryColorMask;
+ }
}
/* Sanity checks */
/* Remove the page from its list */
PageIndex = MiRemovePageByColor(PageIndex, Color);
ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
-
+
/* Zero it, if needed */
if (Zero) MiZeroPhysicalPage(PageIndex);
-
+
/* Sanity checks */
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
ASSERT(Pfn1->u2.ShareCount == 0);
{
/* Get the previous page */
Blink = (PMMPFN)ColorTable->Blink;
-
+
/* Make it link to us, and link back to it */
Blink->OriginalPte.u.Long = PageFrameIndex;
Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
}
-
+
/* Now initialize our own list pointers */
ColorTable->Blink = Pfn1;
/* This page is now the last */
Pfn1->OriginalPte.u.Long = LIST_HEAD;
-
+
/* And increase the count in the colored list */
ColorTable->Count++;
MmZeroingPageThreadActive = TRUE;
KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
}
-
+
#if MI_TRACE_PFNS
Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
RtlZeroMemory(Pfn1->ProcessName, 16);
/* Make sure the lock is held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-
+
/* Make sure the PFN is valid */
ASSERT((PageFrameIndex) &&
(PageFrameIndex <= MmHighestPhysicalPage) &&
(PageFrameIndex >= MmLowestPhysicalPage));
-
+
/* Page should be unused */
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
/* One more page on the system */
MmAvailablePages++;
-
+
/* Check if we've reached the configured low memory threshold */
if (MmAvailablePages == MmLowMemoryThreshold)
{
/* One more paged on the colored list */
ColorHead->Count++;
-
+
#if MI_TRACE_PFNS
//ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
{
/* Only valid from MmCreateProcessAddressSpace path */
ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
-
+
/* Make this a demand zero PTE */
MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
}
Pfn1->u2.ShareCount++;
}
+VOID
+NTAPI
+MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
+ IN PMMPTE PointerPte,
+ IN MMPTE TempPte)
+{
+ PMMPFN Pfn1;
+ NTSTATUS Status;
+ PMMPTE PointerPtePte;
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ /* PTE must be invalid */
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+
+ /* Setup the PTE */
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+ Pfn1->PteAddress = PointerPte;
+ Pfn1->OriginalPte = DemandZeroPte;
+
+ /* Otherwise this is a fresh page -- set it up */
+ ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+ Pfn1->u3.e2.ReferenceCount++;
+ Pfn1->u2.ShareCount++;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ ASSERT(Pfn1->u3.e1.Rom == 0);
+ Pfn1->u3.e1.Modified = 1;
+
+ /* Get the page table for the PTE */
+ PointerPtePte = MiAddressToPte(PointerPte);
+ if (PointerPtePte->u.Hard.Valid == 0)
+ {
+ /* Make sure the PDE gets paged in properly */
+ Status = MiCheckPdeForPagedPool(PointerPte);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Crash */
+ KeBugCheckEx(MEMORY_MANAGEMENT,
+ 0x61940,
+ (ULONG_PTR)PointerPte,
+ (ULONG_PTR)PointerPtePte->u.Long,
+ (ULONG_PTR)MiPteToAddress(PointerPte));
+ }
+ }
+
+ /* Get the PFN for the page table */
+ PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
+ ASSERT(PageFrameIndex != 0);
+ Pfn1->u4.PteFrame = PageFrameIndex;
+
+ /* Increase its share count so we don't get rid of it */
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+ Pfn1->u2.ShareCount++;
+
+ /* Write valid PTE */
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+}
+
+
PFN_NUMBER
NTAPI
MiAllocatePfn(IN PMMPTE PointerPte,
/* Sanity check that we aren't passed a valid PTE */
ASSERT(PointerPte->u.Hard.Valid == 0);
-
+
/* Make an empty software PTE */
MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
- /* Lock the PFN database */
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
/* Check if we're running low on pages */
if (MmAvailablePages < 128)
{
DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages);
+
//MiEnsureAvailablePageOrWait(NULL, OldIrql);
+
+ /* Call RosMm and see if it can release any pages for us */
+ MmRebalanceMemoryConsumers();
+
+ DPRINT1("Rebalance complete: %d pages left\n", MmAvailablePages);
}
-
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
/* Grab a page */
ASSERT_LIST_INVARIANT(&MmFreePageListHead);
ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
/* Write the software PTE */
MI_WRITE_INVALID_PTE(PointerPte, TempPte);
PointerPte->u.Soft.Protection |= Protection;
-
+
/* Initialize its PFN entry */
MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
-
+
/* Release the PFN lock and return the page */
ASSERT_LIST_INVARIANT(&MmFreePageListHead);
ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
/* Put the page in transition */
Pfn1->u3.e1.PageLocation = TransitionPage;
-
+
/* PFN lock must be held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-
+
/* Page should at least have one reference */
ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
if (Pfn1->u3.e2.ReferenceCount == 1)
IN PFN_NUMBER PteFrame)
{
PMMPFN Pfn1;
-
+
/* Setup the PTE */
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
Pfn1->PteAddress = PointerPte;
/* Make this a software PTE */
MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
-
+
/* Setup the page */
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->u3.e1.Modified = TRUE;
Pfn1->u4.InPageError = FALSE;
-
+
/* Did we get a PFN for the page table */
if (PteFrame)
{
/* Store it */
Pfn1->u4.PteFrame = PteFrame;
-
- /* Increase its share count so we don't get rid of it */
+
+ /* Increase its share count so we don't get rid of it */
Pfn1 = MI_PFN_ELEMENT(PteFrame);
Pfn1->u2.ShareCount++;
}