mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
[NTOS]: Add initial support for standby page list and modified page list in the current page list routines. Add support for prototype PTEs in a few more cases, including handling of transition pages. Should not affect any of the current code as those lists/transition pages aren't yet used.
svn path=/trunk/; revision=56291
This commit is contained in:
parent
696287a5ed
commit
4993239ac6
1 changed files with 258 additions and 57 deletions
|
@ -723,41 +723,37 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: This function is hardcoded only for the zeroed page list, for now */
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
FASTCALL
|
||||||
MiInsertPageInList(IN PMMPFNLIST ListHead,
|
MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
|
||||||
IN PFN_NUMBER PageFrameIndex)
|
|
||||||
{
|
{
|
||||||
|
PMMPFNLIST ListHead;
|
||||||
PFN_NUMBER Flink;
|
PFN_NUMBER Flink;
|
||||||
PMMPFN Pfn1, Pfn2;
|
PMMPFN Pfn1, Pfn2;
|
||||||
MMLISTS ListName;
|
|
||||||
PMMCOLOR_TABLES ColorHead;
|
|
||||||
ULONG Color;
|
|
||||||
|
|
||||||
/* For free pages, use MiInsertPageInFreeList */
|
|
||||||
ASSERT(ListHead != &MmFreePageListHead);
|
|
||||||
|
|
||||||
/* Make sure the lock is held */
|
/* Make sure the lock is held */
|
||||||
|
DPRINT1("Inserting page: %lx into standby list !\n", PageFrameIndex);
|
||||||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
|
|
||||||
/* Make sure the PFN is valid */
|
/* Make sure the PFN is valid */
|
||||||
ASSERT((PageFrameIndex) &&
|
ASSERT((PageFrameIndex != 0) &&
|
||||||
(PageFrameIndex <= MmHighestPhysicalPage) &&
|
(PageFrameIndex <= MmHighestPhysicalPage) &&
|
||||||
(PageFrameIndex >= MmLowestPhysicalPage));
|
(PageFrameIndex >= MmLowestPhysicalPage));
|
||||||
|
|
||||||
/* Page should be unused */
|
/* Grab the PFN and validate it is the right kind of PFN being inserted */
|
||||||
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
|
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
|
||||||
|
ASSERT(Pfn1->u4.MustBeCached == 0);
|
||||||
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
|
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
|
||||||
|
ASSERT(Pfn1->u3.e1.PrototypePte == 1);
|
||||||
ASSERT(Pfn1->u3.e1.Rom != 1);
|
ASSERT(Pfn1->u3.e1.Rom != 1);
|
||||||
|
|
||||||
/* Only used for zero pages in ReactOS */
|
/* One more transition page on a list */
|
||||||
ListName = ListHead->ListName;
|
MmTransitionSharedPages++;
|
||||||
ASSERT(ListName == ZeroedPageList);
|
|
||||||
ListHead->Total++;
|
|
||||||
|
|
||||||
/* Don't handle bad pages yet yet */
|
/* Get the standby page list and increment its count */
|
||||||
ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
|
ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
|
||||||
|
ASSERT_LIST_INVARIANT(ListHead);
|
||||||
|
ListHead->Total++;
|
||||||
|
|
||||||
/* Make the head of the list point to this page now */
|
/* Make the head of the list point to this page now */
|
||||||
Flink = ListHead->Flink;
|
Flink = ListHead->Flink;
|
||||||
|
@ -781,7 +777,7 @@ MiInsertPageInList(IN PMMPFNLIST ListHead,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move the page onto its new location */
|
/* Move the page onto its new location */
|
||||||
Pfn1->u3.e1.PageLocation = ListName;
|
Pfn1->u3.e1.PageLocation = StandbyPageList;
|
||||||
|
|
||||||
/* One more page on the system */
|
/* One more page on the system */
|
||||||
MmAvailablePages++;
|
MmAvailablePages++;
|
||||||
|
@ -797,49 +793,210 @@ MiInsertPageInList(IN PMMPFNLIST ListHead,
|
||||||
/* Otherwise check if we reached the high threshold and signal the event */
|
/* Otherwise check if we reached the high threshold and signal the event */
|
||||||
KeSetEvent(MiHighMemoryEvent, 0, FALSE);
|
KeSetEvent(MiHighMemoryEvent, 0, FALSE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Sanity checks */
|
VOID
|
||||||
ASSERT(ListName == ZeroedPageList);
|
NTAPI
|
||||||
ASSERT(Pfn1->u4.InPageError == 0);
|
MiInsertPageInList(IN PMMPFNLIST ListHead,
|
||||||
|
IN PFN_NUMBER PageFrameIndex)
|
||||||
|
{
|
||||||
|
PFN_NUMBER Flink, LastPage;
|
||||||
|
PMMPFN Pfn1, Pfn2;
|
||||||
|
MMLISTS ListName;
|
||||||
|
PMMCOLOR_TABLES ColorHead;
|
||||||
|
ULONG Color;
|
||||||
|
|
||||||
/* Get the page color */
|
/* For free pages, use MiInsertPageInFreeList */
|
||||||
Color = PageFrameIndex & MmSecondaryColorMask;
|
ASSERT(ListHead != &MmFreePageListHead);
|
||||||
|
|
||||||
/* Get the list for this color */
|
/* Make sure the lock is held */
|
||||||
ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
|
|
||||||
/* Get the old head */
|
/* Make sure the PFN is valid */
|
||||||
Flink = ColorHead->Flink;
|
ASSERT((PageFrameIndex) &&
|
||||||
|
(PageFrameIndex <= MmHighestPhysicalPage) &&
|
||||||
|
(PageFrameIndex >= MmLowestPhysicalPage));
|
||||||
|
|
||||||
/* Make this page point back to the list, and point forwards to the old head */
|
/* Page should be unused */
|
||||||
Pfn1->OriginalPte.u.Long = Flink;
|
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
|
||||||
Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
|
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
|
||||||
|
ASSERT(Pfn1->u3.e1.Rom != 1);
|
||||||
|
|
||||||
/* Set the new head */
|
/* Is a standby or modified page being inserted? */
|
||||||
ColorHead->Flink = PageFrameIndex;
|
ListName = ListHead->ListName;
|
||||||
|
if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
|
||||||
/* Was the head empty? */
|
|
||||||
if (Flink != LIST_HEAD)
|
|
||||||
{
|
{
|
||||||
/* No, so make the old head point to this page */
|
/* If the page is in transition, it must also be a prototype page */
|
||||||
Pfn2 = MI_PFN_ELEMENT(Flink);
|
if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
|
||||||
Pfn2->u4.PteFrame = PageFrameIndex;
|
(Pfn1->OriginalPte.u.Soft.Transition == 1))
|
||||||
|
{
|
||||||
|
/* Crash the system on inconsistency */
|
||||||
|
KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standby pages are prioritized, so we need to get the real head */
|
||||||
|
if (ListHead == &MmStandbyPageListHead)
|
||||||
|
{
|
||||||
|
/* Obviously the prioritized list should still have the same name */
|
||||||
|
ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
|
||||||
|
ASSERT(ListHead->ListName == ListName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the list count */
|
||||||
|
ListHead->Total++;
|
||||||
|
|
||||||
|
/* Is a modified page being inserted? */
|
||||||
|
if (ListHead == &MmModifiedPageListHead)
|
||||||
|
{
|
||||||
|
/* For now, only single-prototype pages should end up in this path */
|
||||||
|
DPRINT1("Modified page being added: %lx\n", PageFrameIndex);
|
||||||
|
ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
|
||||||
|
|
||||||
|
/* Modified pages are colored when they are selected for page file */
|
||||||
|
ListHead = &MmModifiedPageListByColor[0];
|
||||||
|
ASSERT (ListHead->ListName == ListName);
|
||||||
|
ListHead->Total++;
|
||||||
|
|
||||||
|
/* Increment the number of paging file modified pages */
|
||||||
|
MmTotalPagesForPagingFile++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't handle bad pages yet yet */
|
||||||
|
ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
|
||||||
|
|
||||||
|
/* Zero pages go to the head, all other pages go to the end */
|
||||||
|
if (ListName == ZeroedPageList)
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Yes, make it loop back to this page */
|
/* Get the last page on the list */
|
||||||
ColorHead->Blink = (PVOID)Pfn1;
|
LastPage = ListHead->Blink;
|
||||||
|
if (LastPage != LIST_HEAD)
|
||||||
|
{
|
||||||
|
/* Link us with the previous page, so we're at the end now */
|
||||||
|
MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The list is empty, so we are the first page */
|
||||||
|
ListHead->Flink = PageFrameIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One more paged on the colored list */
|
/* Move the page onto its new location */
|
||||||
ColorHead->Count++;
|
Pfn1->u3.e1.PageLocation = ListName;
|
||||||
|
|
||||||
|
/* For zero/free pages, we also have to handle the colored lists */
|
||||||
|
if (ListName <= StandbyPageList)
|
||||||
|
{
|
||||||
|
/* 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
|
#if MI_TRACE_PFNS
|
||||||
//ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
|
//ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
|
||||||
Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
|
Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
|
||||||
MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
|
MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
|
||||||
RtlZeroMemory(Pfn1->ProcessName, 16);
|
RtlZeroMemory(Pfn1->ProcessName, 16);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else if (ListName == ModifiedPageList)
|
||||||
|
{
|
||||||
|
/* In ARM3, page must be destined for page file, and not yet written out */
|
||||||
|
ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
|
||||||
|
ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
|
||||||
|
|
||||||
|
/* One more transition page */
|
||||||
|
ASSERT(Pfn1->u3.e1.PrototypePte == 1);
|
||||||
|
MmTransitionSharedPages++;
|
||||||
|
|
||||||
|
/* Increment the number of per-process modified pages */
|
||||||
|
PsGetCurrentProcess()->ModifiedPageCount++;
|
||||||
|
|
||||||
|
/* FIXME: Wake up modified page writer if there are not enough free pages */
|
||||||
|
}
|
||||||
|
else if (ListName == ModifiedNoWritePageList)
|
||||||
|
{
|
||||||
|
/* This list is not yet implemented */
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
@ -1020,6 +1177,9 @@ NTAPI
|
||||||
MiDecrementShareCount(IN PMMPFN Pfn1,
|
MiDecrementShareCount(IN PMMPFN Pfn1,
|
||||||
IN PFN_NUMBER PageFrameIndex)
|
IN PFN_NUMBER PageFrameIndex)
|
||||||
{
|
{
|
||||||
|
PMMPTE PointerPte;
|
||||||
|
MMPTE TempPte;
|
||||||
|
|
||||||
ASSERT(PageFrameIndex > 0);
|
ASSERT(PageFrameIndex > 0);
|
||||||
ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
|
ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
|
||||||
ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
|
ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
|
||||||
|
@ -1041,8 +1201,27 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
|
||||||
ASSERT(Pfn1->u2.ShareCount < 0xF000000);
|
ASSERT(Pfn1->u2.ShareCount < 0xF000000);
|
||||||
if (!--Pfn1->u2.ShareCount)
|
if (!--Pfn1->u2.ShareCount)
|
||||||
{
|
{
|
||||||
/* ReactOS does not handle these */
|
/* Was this a prototype PTE? */
|
||||||
ASSERT(Pfn1->u3.e1.PrototypePte == 0);
|
if (Pfn1->u3.e1.PrototypePte)
|
||||||
|
{
|
||||||
|
/* Grab the PTE address and make sure it's in prototype pool */
|
||||||
|
PointerPte = Pfn1->PteAddress;
|
||||||
|
ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
|
||||||
|
|
||||||
|
/* The PTE that backs it should also be valdi */
|
||||||
|
PointerPte = MiAddressToPte(PointerPte);
|
||||||
|
ASSERT(PointerPte->u.Hard.Valid == 1);
|
||||||
|
|
||||||
|
/* Get the original prototype PTE and turn it into a transition PTE */
|
||||||
|
PointerPte = Pfn1->PteAddress;
|
||||||
|
TempPte = *PointerPte;
|
||||||
|
TempPte.u.Soft.Transition = 1;
|
||||||
|
TempPte.u.Soft.Valid = 0;
|
||||||
|
TempPte.u.Soft.Prototype = 0;
|
||||||
|
TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
|
||||||
|
MI_WRITE_INVALID_PTE(PointerPte, TempPte);
|
||||||
|
DPRINT1("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
|
||||||
|
}
|
||||||
|
|
||||||
/* Put the page in transition */
|
/* Put the page in transition */
|
||||||
Pfn1->u3.e1.PageLocation = TransitionPage;
|
Pfn1->u3.e1.PageLocation = TransitionPage;
|
||||||
|
@ -1054,8 +1233,24 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
|
||||||
ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
|
ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
|
||||||
if (Pfn1->u3.e2.ReferenceCount == 1)
|
if (Pfn1->u3.e2.ReferenceCount == 1)
|
||||||
{
|
{
|
||||||
/* In ReactOS, this path should always be hit with a deleted PFN */
|
/* Is there still a PFN for this page? */
|
||||||
ASSERT((MI_IS_PFN_DELETED(Pfn1) == TRUE) || (Pfn1->u3.e1.PrototypePte == 1));
|
if (MI_IS_PFN_DELETED(Pfn1) == TRUE)
|
||||||
|
{
|
||||||
|
/* Clear the last reference */
|
||||||
|
Pfn1->u3.e2.ReferenceCount = 0;
|
||||||
|
ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
|
||||||
|
|
||||||
|
/* Mark the page temporarily as valid, we're going to make it free soon */
|
||||||
|
Pfn1->u3.e1.PageLocation = ActiveAndValid;
|
||||||
|
|
||||||
|
/* Bring it back into the free list */
|
||||||
|
MiInsertPageInFreeList(PageFrameIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* PFN not yet deleted, drop a ref count */
|
||||||
|
MiDecrementReferenceCount(Pfn1, PageFrameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear the last reference */
|
/* Clear the last reference */
|
||||||
Pfn1->u3.e2.ReferenceCount = 0;
|
Pfn1->u3.e2.ReferenceCount = 0;
|
||||||
|
@ -1110,12 +1305,18 @@ MiDecrementReferenceCount(IN PMMPFN Pfn1,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't have a modified list yet */
|
/* Check to see which list this page should go into */
|
||||||
ASSERT(Pfn1->u3.e1.Modified == 0);
|
if (Pfn1->u3.e1.Modified == 1)
|
||||||
ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
|
{
|
||||||
|
/* Push it into the modified page list */
|
||||||
/* FIXME: Normally it would go on the standby list, but we're pushing it on the free list */
|
MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
|
||||||
MiInsertPageInFreeList(PageFrameIndex);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, insert this page into the standby list */
|
||||||
|
ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
|
||||||
|
MiInsertStandbyListAtFront(PageFrameIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
|
Loading…
Reference in a new issue