#define NDEBUG
#include <debug.h>
-#line 15 "ARMĀ³::PFNLIST"
#define MODULE_INVOLVED_IN_ARM3
#include "../ARM3/miarm.h"
+#if DBG
#define ASSERT_LIST_INVARIANT(x) \
do { \
ASSERT(((x)->Total == 0 && \
(x)->Flink != LIST_HEAD && \
(x)->Blink != LIST_HEAD)); \
} while (0)
+#else
+#define ASSERT_LIST_INVARIANT(x)
+#endif
/* GLOBALS ********************************************************************/
BOOLEAN MmDynamicPfn;
BOOLEAN MmMirroring;
+ULONG MmSystemPageColor;
MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
NULL,
NULL
};
-/* FUNCTIONS ******************************************************************/
-VOID
-NTAPI
-MiInsertInListTail(IN PMMPFNLIST ListHead,
- IN PMMPFN Entry)
-{
- PFN_NUMBER OldBlink, EntryIndex = MiGetPfnEntryIndex(Entry);
-
- ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
- ASSERT_LIST_INVARIANT(ListHead);
+ULONG MI_PFN_CURRENT_USAGE;
+CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet";
- /* Get the back link */
- OldBlink = ListHead->Blink;
- if (OldBlink != LIST_HEAD)
- {
- /* Set the back pointer to point to us now */
- MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
- }
- else
- {
- /* Set the list to point to us */
- ListHead->Flink = EntryIndex;
- }
-
- /* Set the entry to point to the list head forwards, and the old page backwards */
- Entry->u1.Flink = LIST_HEAD;
- Entry->u2.Blink = OldBlink;
-
- /* And now the head points back to us, since we are last */
- ListHead->Blink = EntryIndex;
- ListHead->Total++;
- ASSERT_LIST_INVARIANT(ListHead);
-}
+/* FUNCTIONS ******************************************************************/
VOID
NTAPI
-MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex)
+MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
{
- PFN_NUMBER OldBlink;
- PMMPFNLIST ListHead;
- PMMPFN Pfn1;
-#if 0
- PMMPFN Blink;
- ULONG Color;
- PMMCOLOR_TABLES ColorHead;
-#endif
-
- /* Make sure the PFN lock is held */
- ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-
- /* Get the descriptor */
- Pfn1 = MiGetPfnEntry(EntryIndex);
- ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
- ASSERT(Pfn1->u4.MustBeCached == 0);
- ASSERT(Pfn1->u3.e1.Rom == 0);
- ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
- ASSERT(Pfn1->u4.InPageError == 0);
-
- /* Use the zero list */
- ListHead = &MmZeroedPageListHead;
- ASSERT_LIST_INVARIANT(ListHead);
- ListHead->Total++;
-
- /* Get the back link */
- OldBlink = ListHead->Blink;
- if (OldBlink != LIST_HEAD)
- {
- /* Set the back pointer to point to us now */
- MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
- }
- else
- {
- /* Set the list to point to us */
- ListHead->Flink = EntryIndex;
- }
-
- /* Set the entry to point to the list head forwards, and the old page backwards */
- Pfn1->u1.Flink = LIST_HEAD;
- Pfn1->u2.Blink = OldBlink;
-
- /* And now the head points back to us, since we are last */
- ListHead->Blink = EntryIndex;
-
- /* Update the page location */
- Pfn1->u3.e1.PageLocation = ZeroedPageList;
-
- /* FIXME: NOT YET Due to caller semantics: Update the available page count */
- //MmAvailablePages++;
-
- /* Check if we've reached the configured low memory threshold */
- if (MmAvailablePages == MmLowMemoryThreshold)
- {
- /* Clear the event, because now we're ABOVE the threshold */
- KeClearEvent(MiLowMemoryEvent);
- }
- else if (MmAvailablePages == MmHighMemoryThreshold)
- {
- /* Otherwise check if we reached the high threshold and signal the event */
- KeSetEvent(MiHighMemoryEvent, 0, FALSE);
- }
-
- ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0
- /* Get the page color */
- Color = EntryIndex & MmSecondaryColorMask;
-
- /* Get the first page on the color list */
- ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
- if (ColorHead->Flink == LIST_HEAD)
- {
- /* The list is empty, so we are the first page */
- Pfn1->u4.PteFrame = -1;
- ColorHead->Flink = EntryIndex;
- }
- else
- {
- /* Get the previous page */
- Blink = (PMMPFN)ColorHead->Blink;
-
- /* Make it link to us */
- Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
- Blink->OriginalPte.u.Long = EntryIndex;
- }
-
- /* Now initialize our own list pointers */
- ColorHead->Blink = Pfn1;
- Pfn1->OriginalPte.u.Long = LIST_HEAD;
-
- /* And increase the count in the colored list */
- ColorHead->Count++;
-#endif
+ KIRQL OldIrql;
+ PVOID VirtualAddress;
+ PEPROCESS Process = PsGetCurrentProcess();
+
+ /* Map in hyperspace, then wipe it using XMMI or MEMSET */
+ VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql);
+ ASSERT(VirtualAddress);
+ KeZeroPages(VirtualAddress, PAGE_SIZE);
+ MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql);
}
VOID
PFN_NUMBER OldFlink, OldBlink;
PMMPFNLIST ListHead;
MMLISTS ListName;
-
+ 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;
ASSERT(ListHead != NULL);
ASSERT(ListName <= FreePageList);
- ASSERT_LIST_INVARIANT(ListHead);
-
+ ASSERT_LIST_INVARIANT(ListHead);
+
/* 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)
{
/* It is not, so set the backlink of the actual entry, to our backlink */
- MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
+ MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
}
else
{
/* Set the list head's backlink instead */
ListHead->Blink = OldBlink;
}
-
+
/* Check if the back entry is the list head */
if (OldBlink != LIST_HEAD)
{
/* It is not, so set the backlink of the actual entry, to our backlink */
- MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
+ MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
}
else
{
/* Set the list head's backlink instead */
ListHead->Flink = OldFlink;
}
-
+
+ /* Get the page color */
+ OldBlink = MiGetPfnEntryIndex(Entry);
+ Color = OldBlink & MmSecondaryColorMask;
+
+ /* Get the first page on the color list */
+ ColorTable = &MmFreePagesByColor[ListName][Color];
+
+ /* Check if this was was actually the head */
+ OldFlink = ColorTable->Flink;
+ if (OldFlink == OldBlink)
+ {
+ /* Make the table point to the next page this page was linking to */
+ ColorTable->Flink = Entry->OriginalPte.u.Long;
+ if (ColorTable->Flink != LIST_HEAD)
+ {
+ /* And make the previous link point to the head now */
+ MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
+ }
+ else
+ {
+ /* And if that page was the head, loop the list back around */
+ ColorTable->Blink = (PVOID)LIST_HEAD;
+ }
+ }
+ else
+ {
+ /* This page shouldn't be pointing back to the head */
+ ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD);
+
+ /* Make the back link point to whoever the next page is */
+ Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame);
+ Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long;
+
+ /* Check if this page was pointing to the head */
+ if (Entry->OriginalPte.u.Long != LIST_HEAD)
+ {
+ /* Make the back link point to the head */
+ Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long);
+ Pfn1->u4.PteFrame = Entry->u4.PteFrame;
+ }
+ else
+ {
+ /* Then the table is directly back pointing to this page now */
+ ColorTable->Blink = Pfn1;
+ }
+ }
+
+ /* One less colored page */
+ ASSERT(ColorTable->Count >= 1);
+ ColorTable->Count--;
+
+ /* ReactOS Hack */
+ Entry->OriginalPte.u.Long = 0;
+
/* We are not on a list anymore */
Entry->u1.Flink = Entry->u2.Blink = 0;
- ASSERT_LIST_INVARIANT(ListHead);
-
- /* FIXME: Deal with color list */
-
+ ASSERT_LIST_INVARIANT(ListHead);
+
/* See if we hit any thresholds */
if (MmAvailablePages == MmHighMemoryThreshold)
{
/* 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;
+ memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
+// MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+// memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
+#endif
}
PFN_NUMBER
PMMPFNLIST ListHead;
MMLISTS ListName;
PFN_NUMBER OldFlink, OldBlink;
- ULONG OldColor, OldCache;
-#if 0
+ USHORT OldColor, OldCache;
PMMCOLOR_TABLES ColorTable;
-#endif
+
/* Make sure PFN lock is held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
ASSERT(Color < MmSecondaryColors);
/* Get the PFN entry */
- Pfn1 = MiGetPfnEntry(PageIndex);
+ 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;
/* Could be either on free or zero list */
ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
- ASSERT_LIST_INVARIANT(ListHead);
+ 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)
{
/* It is not, so set the backlink of the actual entry, to our backlink */
- MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
+ MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
}
else
{
/* Set the list head's backlink instead */
- ListHead->Blink = OldFlink;
+ ListHead->Blink = OldBlink;
}
-
+
/* Check if the back entry is the list head */
if (OldBlink != LIST_HEAD)
{
/* It is not, so set the backlink of the actual entry, to our backlink */
- MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
+ MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
}
else
{
/* 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;
Pfn1->u3.e1.CacheAttribute = OldCache;
- ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0 // When switching to ARM3
/* Get the first page on the color list */
+ 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 = LIST_HEAD;
+ ColorTable->Blink = (PVOID)LIST_HEAD;
}
else
{
/* The list is empty, so we are the first page */
- MiGetPfnEntry(ColorTable->Flink)->u4.PteFrame = -1;
+ MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
}
-
- /* One more page */
- ColorTable->Total++;
-#endif
+
+ /* One less page */
+ ColorTable->Count--;
+
+ /* ReactOS Hack */
+ Pfn1->OriginalPte.u.Long = 0;
+
/* See if we hit any thresholds */
if (MmAvailablePages == MmHighMemoryThreshold)
{
/* 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);
+ Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
+ memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
+ //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+ //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
+#endif
+
/* Return the page */
return PageIndex;
}
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
ASSERT(MmAvailablePages != 0);
ASSERT(Color < MmSecondaryColors);
-
+
/* Check the colored free list */
-#if 0 // Enable when using ARM3 database */
PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
if (PageIndex == LIST_HEAD)
{
PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
if (PageIndex == LIST_HEAD)
{
-#endif
/* Check the free list */
- ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
PageIndex = MmFreePageListHead.Flink;
Color = PageIndex & MmSecondaryColorMask;
if (PageIndex == LIST_HEAD)
{
/* Check the zero list */
- ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
PageIndex = MmZeroedPageListHead.Flink;
Color = PageIndex & MmSecondaryColorMask;
ASSERT(PageIndex != LIST_HEAD);
ASSERT(MmZeroedPageListHead.Total == 0);
}
}
-#if 0 // Enable when using ARM3 database */
}
}
-#endif
/* Remove the page from its list */
PageIndex = MiRemovePageByColor(PageIndex, Color);
/* Sanity checks */
- Pfn1 = MiGetPfnEntry(PageIndex);
+ Pfn1 = MI_PFN_ELEMENT(PageIndex);
ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
(Pfn1->u3.e1.PageLocation == ZeroedPageList));
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
ASSERT(Pfn1->u2.ShareCount == 0);
-
- /* Return the page */
- ASSERT_LIST_INVARIANT(&MmFreePageListHead);
- ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+ /* Return the page */
return PageIndex;
}
-PMMPFN
+PFN_NUMBER
NTAPI
-MiRemoveHeadList(IN PMMPFNLIST ListHead)
+MiRemoveZeroPage(IN ULONG Color)
{
- PFN_NUMBER Entry, Flink;
+ PFN_NUMBER PageIndex;
PMMPFN Pfn1;
-
- ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
- ASSERT_LIST_INVARIANT(ListHead);
+ BOOLEAN Zero = FALSE;
- /* Get the entry that's currently first on the list */
- Entry = ListHead->Flink;
- Pfn1 = MiGetPfnEntry(Entry);
-
- /* Make the list point to the entry following the first one */
- Flink = Pfn1->u1.Flink;
- ListHead->Flink = Flink;
+ /* Make sure PFN lock is held and we have pages */
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ ASSERT(MmAvailablePages != 0);
+ ASSERT(Color < MmSecondaryColors);
- /* Check if the next entry is actually the list head */
- if (ListHead->Flink != LIST_HEAD)
- {
- /* It isn't, so therefore whoever is coming next points back to the head */
- MiGetPfnEntry(Flink)->u2.Blink = LIST_HEAD;
- }
- else
+ /* Check the colored zero list */
+ PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
+ if (PageIndex == LIST_HEAD)
{
- /* Then the list is empty, so the backlink should point back to us */
- ListHead->Blink = LIST_HEAD;
+ /* Check the zero list */
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+ PageIndex = MmZeroedPageListHead.Flink;
+ if (PageIndex == LIST_HEAD)
+ {
+ /* This means there's no zero pages, we have to look for free ones */
+ ASSERT(MmZeroedPageListHead.Total == 0);
+ Zero = TRUE;
+
+ /* Check the colored free list */
+ PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
+ if (PageIndex == LIST_HEAD)
+ {
+ /* Check the free list */
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ PageIndex = MmFreePageListHead.Flink;
+ Color = PageIndex & MmSecondaryColorMask;
+ ASSERT(PageIndex != LIST_HEAD);
+ if (PageIndex == LIST_HEAD)
+ {
+ /* FIXME: Should check the standby list */
+ ASSERT(MmZeroedPageListHead.Total == 0);
+ }
+ }
+ }
+ else
+ {
+ Color = PageIndex & MmSecondaryColorMask;
+ }
}
-
- /* We are not on a list anymore */
- Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
- ListHead->Total--;
-
- ASSERT_LIST_INVARIANT(ListHead);
- /* Return the head element */
- return Pfn1;
+ /* Sanity checks */
+ Pfn1 = MI_PFN_ELEMENT(PageIndex);
+ ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
+ (Pfn1->u3.e1.PageLocation == ZeroedPageList));
+
+ /* 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);
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+
+ /* Return the page */
+ return PageIndex;
}
VOID
PMMPFNLIST ListHead;
PFN_NUMBER LastPage;
PMMPFN Pfn1;
-#if 0
ULONG Color;
PMMPFN Blink;
PMMCOLOR_TABLES ColorTable;
-#endif
+
/* Make sure the page index is valid */
- ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+ ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
ASSERT((PageFrameIndex != 0) &&
(PageFrameIndex <= MmHighestPhysicalPage) &&
(PageFrameIndex >= MmLowestPhysicalPage));
/* Get the PFN entry */
- Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
/* Sanity checks that a right kind of page is being inserted here */
ASSERT(Pfn1->u4.MustBeCached == 0);
/* Get the free page list and increment its count */
ListHead = &MmFreePageListHead;
- ASSERT_LIST_INVARIANT(ListHead);
+ ASSERT_LIST_INVARIANT(ListHead);
ListHead->Total++;
/* Get the last page on the list */
if (LastPage != LIST_HEAD)
{
/* Link us with the previous page, so we're at the end now */
- MiGetPfnEntry(LastPage)->u1.Flink = PageFrameIndex;
+ MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
}
else
{
/* Now make the list head point back to us (since we go at the end) */
ListHead->Blink = PageFrameIndex;
-
+ ASSERT_LIST_INVARIANT(ListHead);
+
/* And initialize our own list pointers */
Pfn1->u1.Flink = LIST_HEAD;
Pfn1->u2.Blink = LastPage;
/* Set the list name and default priority */
Pfn1->u3.e1.PageLocation = FreePageList;
Pfn1->u4.Priority = 3;
-
+
/* Clear some status fields */
Pfn1->u4.InPageError = 0;
Pfn1->u4.AweAllocation = 0;
KeSetEvent(MiHighMemoryEvent, 0, FALSE);
}
- ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0 // When using ARM3 PFN
/* Get the page color */
Color = PageFrameIndex & MmSecondaryColorMask;
if (ColorTable->Flink == LIST_HEAD)
{
/* The list is empty, so we are the first page */
- Pfn1->u4.PteFrame = -1;
+ Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
ColorTable->Flink = PageFrameIndex;
}
else
{
/* Get the previous page */
Blink = (PMMPFN)ColorTable->Blink;
-
- /* Make it link to us */
- Pfn1->u4.PteFrame = MI_PFNENTRY_TO_PFN(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++;
-#endif
-
+
/* Notify zero page thread if enough pages are on the free list now */
- extern KEVENT ZeroPageThreadEvent;
- if ((MmFreePageListHead.Total > 8) && !(KeReadStateEvent(&ZeroPageThreadEvent)))
+ if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive))
{
- /* This is ReactOS-specific */
- KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
+ /* Set the event */
+ MmZeroingPageThreadActive = TRUE;
+ KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
}
+
+#if MI_TRACE_PFNS
+ Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
+ RtlZeroMemory(Pfn1->ProcessName, 16);
+#endif
+}
+
+/* Note: This function is hardcoded only for the zeroed page list, for now */
+VOID
+NTAPI
+MiInsertPageInList(IN PMMPFNLIST ListHead,
+ IN PFN_NUMBER PageFrameIndex)
+{
+ PFN_NUMBER Flink;
+ PMMPFN Pfn1, Pfn2;
+ MMLISTS ListName;
+ PMMCOLOR_TABLES ColorHead;
+ ULONG Color;
+
+ /* For free pages, use MiInsertPageInFreeList */
+ ASSERT(ListHead != &MmFreePageListHead);
+
+ /* 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);
+ ASSERT(Pfn1->u3.e1.Rom != 1);
+
+ /* Only used for zero pages in ReactOS */
+ ListName = ListHead->ListName;
+ ASSERT(ListName == ZeroedPageList);
+ ListHead->Total++;
+
+ /* Don't handle bad pages yet yet */
+ ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
+
+ /* Make the head of the list point to this page now */
+ Flink = ListHead->Flink;
+ ListHead->Flink = PageFrameIndex;
+
+ /* Make the page point to the previous head, and back to the list */
+ Pfn1->u1.Flink = Flink;
+ Pfn1->u2.Blink = LIST_HEAD;
+
+ /* Was the list empty? */
+ if (Flink != LIST_HEAD)
+ {
+ /* It wasn't, so update the backlink of the previous head page */
+ Pfn2 = MI_PFN_ELEMENT(Flink);
+ Pfn2->u2.Blink = PageFrameIndex;
+ }
+ else
+ {
+ /* It was empty, so have it loop back around to this new page */
+ ListHead->Blink = PageFrameIndex;
+ }
+
+ /* Move the page onto its new location */
+ Pfn1->u3.e1.PageLocation = ListName;
+
+ /* One more page on the system */
+ MmAvailablePages++;
+
+ /* Check if we've reached the configured low memory threshold */
+ if (MmAvailablePages == MmLowMemoryThreshold)
+ {
+ /* Clear the event, because now we're ABOVE the threshold */
+ KeClearEvent(MiLowMemoryEvent);
+ }
+ else if (MmAvailablePages == MmHighMemoryThreshold)
+ {
+ /* Otherwise check if we reached the high threshold and signal the event */
+ KeSetEvent(MiHighMemoryEvent, 0, FALSE);
+ }
+
+ /* Sanity checks */
+ ASSERT(ListName == ZeroedPageList);
+ ASSERT(Pfn1->u4.InPageError == 0);
+
+ /* Get the page color */
+ Color = PageFrameIndex & MmSecondaryColorMask;
+
+ /* Get the list for this color */
+ ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
+
+ /* Get the old head */
+ Flink = ColorHead->Flink;
+
+ /* Make this page point back to the list, and point forwards to the old head */
+ Pfn1->OriginalPte.u.Long = Flink;
+ Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
+
+ /* Set the new head */
+ ColorHead->Flink = PageFrameIndex;
+
+ /* Was the head empty? */
+ if (Flink != LIST_HEAD)
+ {
+ /* No, so make the old head point to this page */
+ Pfn2 = MI_PFN_ELEMENT(Flink);
+ Pfn2->u4.PteFrame = PageFrameIndex;
+ }
+ else
+ {
+ /* Yes, make it loop back to this page */
+ ColorHead->Blink = (PVOID)Pfn1;
+ }
+
+ /* 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;
+ MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+ RtlZeroMemory(Pfn1->ProcessName, 16);
+#endif
}
VOID
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Setup the PTE */
- Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
Pfn1->PteAddress = PointerPte;
/* Check if this PFN is part of a valid address space */
if (PointerPte->u.Hard.Valid == 1)
{
- /* FIXME: TODO */
- ASSERT(FALSE);
+ /* Only valid from MmCreateProcessAddressSpace path */
+ ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
+
+ /* Make this a demand zero PTE */
+ MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
+ }
+ else
+ {
+ /* Copy the PTE data */
+ Pfn1->OriginalPte = *PointerPte;
+ ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
+ (Pfn1->OriginalPte.u.Soft.Transition == 1)));
}
/* Otherwise this is a fresh page -- set it up */
Pfn1->u4.PteFrame = PageFrameIndex;
/* Increase its share count so we don't get rid of it */
- Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
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,
KIRQL OldIrql;
PFN_NUMBER PageFrameIndex;
MMPTE TempPte;
-
+
+ /* 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);
- PageFrameIndex = MiRemoveAnyPage(0);
-
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+ PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+
/* Write the software PTE */
- ASSERT(PointerPte->u.Hard.Valid == 0);
- *PointerPte = TempPte;
+ 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);
+ ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+ ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
return PageFrameIndex;
}
IN PFN_NUMBER PageFrameIndex)
{
ASSERT(PageFrameIndex > 0);
- ASSERT(MiGetPfnEntry(PageFrameIndex) != NULL);
- ASSERT(Pfn1 == MiGetPfnEntry(PageFrameIndex));
+ ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
+ ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
+ ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
/* Page must be in-use */
if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
/* 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)
/* Clear the last reference */
Pfn1->u3.e2.ReferenceCount = 0;
-
- /*
- * OriginalPte is used by AweReferenceCount in ReactOS, but either
- * ways we shouldn't be seeing RMAP entries at this point
- */
ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
- ASSERT(Pfn1->OriginalPte.u.Long == 0);
/* Mark the page temporarily as valid, we're going to make it free soon */
Pfn1->u3.e1.PageLocation = ActiveAndValid;
}
}
+VOID
+NTAPI
+MiDecrementReferenceCount(IN PMMPFN Pfn1,
+ IN PFN_NUMBER PageFrameIndex)
+{
+ /* PFN lock must be held */
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ /* Sanity checks on the page */
+ ASSERT(PageFrameIndex < MmHighestPhysicalPage);
+ ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
+ ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+
+ /* Dereference the page, bail out if it's still alive */
+ InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
+ if (Pfn1->u3.e2.ReferenceCount) return;
+
+ /* Nobody should still have reference to this page */
+ if (Pfn1->u2.ShareCount != 0)
+ {
+ /* Otherwise something's really wrong */
+ KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
+ }
+
+ /* And it should be lying on some page list */
+ ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
+
+ /* Did someone set the delete flag? */
+ if (MI_IS_PFN_DELETED(Pfn1))
+ {
+ /* Insert it into the free list, there's nothing left to do */
+ MiInsertPageInFreeList(PageFrameIndex);
+ return;
+ }
+
+ /* We don't have a modified list yet */
+ ASSERT(Pfn1->u3.e1.Modified == 0);
+ ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
+
+ /* FIXME: Normally it would go on the standby list, but we're pushing it on the free list */
+ MiInsertPageInFreeList(PageFrameIndex);
+}
+
+VOID
+NTAPI
+MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
+ IN PMMPTE PointerPte,
+ 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->u2.ShareCount = 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 */
+ Pfn1 = MI_PFN_ELEMENT(PteFrame);
+ Pfn1->u2.ShareCount++;
+ }
+}
+
/* EOF */