mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
613 lines
15 KiB
613 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pfndec.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the routines to decrement the share count and
|
|
the reference counts within the Page Frame Database.
|
|
|
|
Author:
|
|
|
|
Lou Perazzoli (loup) 5-Apr-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mi.h"
|
|
|
|
ULONG MmFrontOfList;
|
|
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiDecrementShareCount2 (
|
|
IN ULONG PageFrameIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the share count within the PFN element
|
|
for the specified physical page. If the share count becomes
|
|
zero the corresponding PTE is coverted to the transition state
|
|
and the reference count is decremented and the ValidPte count
|
|
of the PTEframe is decremented.
|
|
|
|
Arguments:
|
|
|
|
PageFrameIndex - Supplies the physical page number of which to decrement
|
|
the share count.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Must be holding the PFN database mutex with APC's disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE TempPte;
|
|
PMMPTE PointerPte;
|
|
PMMPFN Pfn1;
|
|
PMMPFN PfnX;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT ((PageFrameIndex <= MmHighestPhysicalPage) &&
|
|
(PageFrameIndex > 0));
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
|
|
Pfn1->u2.ShareCount -= 1;
|
|
|
|
ASSERT (Pfn1->u2.ShareCount < 0xF000000);
|
|
|
|
if (Pfn1->u2.ShareCount == 0) {
|
|
|
|
//
|
|
// The share count is now zero, decrement the reference count
|
|
// for the PFN element and turn the referenced PTE into
|
|
// the transition state if it refers to a prototype PTE.
|
|
// PTEs which are not prototype PTE do not need to be placed
|
|
// into transition as they are placed in transition when
|
|
// they are removed from the working set (working set free routine).
|
|
//
|
|
|
|
//
|
|
// If the PTE referenced by this PFN element is actually
|
|
// a prototype PTE, it must be mapped into hyperspace and
|
|
// then operated on.
|
|
//
|
|
|
|
if (Pfn1->u3.e1.PrototypePte == 1) {
|
|
|
|
OldIrql = 99;
|
|
if (MmIsAddressValid (Pfn1->PteAddress)) {
|
|
PointerPte = Pfn1->PteAddress;
|
|
} else {
|
|
|
|
//
|
|
// The address is not valid in this process, map it into
|
|
// hyperspace so it can be operated upon.
|
|
//
|
|
|
|
PointerPte = (PMMPTE)MiMapPageInHyperSpace(Pfn1->PteFrame,
|
|
&OldIrql);
|
|
PointerPte = (PMMPTE)((ULONG)PointerPte +
|
|
MiGetByteOffset(Pfn1->PteAddress));
|
|
}
|
|
|
|
TempPte = *PointerPte;
|
|
MI_MAKE_VALID_PTE_TRANSITION (TempPte,
|
|
Pfn1->OriginalPte.u.Soft.Protection);
|
|
*PointerPte = TempPte;
|
|
|
|
if (OldIrql != 99) {
|
|
MiUnmapPageInHyperSpace (OldIrql);
|
|
}
|
|
|
|
//
|
|
// There is no need to flush the translation buffer at this
|
|
// time as we only invalidated a prototytpe PTE.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Change the page location to inactive (from active and valid).
|
|
//
|
|
|
|
Pfn1->u3.e1.PageLocation = TransitionPage;
|
|
|
|
//
|
|
// Decrement the reference count as the share count is now zero.
|
|
//
|
|
|
|
MiDecrementReferenceCount (PageFrameIndex);
|
|
}
|
|
|
|
return;
|
|
}
|
|
#if 0
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiDecrementShareCount (
|
|
IN ULONG PageFrameIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the share count within the PFN element
|
|
for the specified physical page. If the share count becomes
|
|
zero the corresponding PTE is coverted to the transition state
|
|
and the reference count is decremented and the ValidPte count
|
|
of the PTEframe is decremented.
|
|
|
|
Arguments:
|
|
|
|
PageFrameIndex - Supplies the physical page number of which to decrement
|
|
the share count.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Must be holding the PFN database mutex with APC's disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE TempPte;
|
|
PMMPTE PointerPte;
|
|
PMMPFN Pfn1;
|
|
PMMPFN PfnX;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT ((PageFrameIndex <= MmHighestPhysicalPage) &&
|
|
(PageFrameIndex > 0));
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
|
|
Pfn1->u2.ShareCount -= 1;
|
|
|
|
ASSERT (Pfn1->u2.ShareCount < 0xF000000);
|
|
|
|
if (Pfn1->u2.ShareCount == 0) {
|
|
|
|
//
|
|
// The share count is now zero, decrement the reference count
|
|
// for the PFN element and turn the referenced PTE into
|
|
// the transition state if it refers to a prototype PTE.
|
|
// PTEs which are not prototype PTE do not need to be placed
|
|
// into transition as they are placed in transition when
|
|
// they are removed from the working set (working set free routine).
|
|
//
|
|
|
|
//
|
|
// If the PTE referenced by this PFN element is actually
|
|
// a prototype PTE, it must be mapped into hyperspace and
|
|
// then operated on.
|
|
//
|
|
|
|
if (Pfn1->u3.e1.PrototypePte == 1) {
|
|
|
|
OldIrql = 99;
|
|
if (MmIsAddressValid (Pfn1->PteAddress)) {
|
|
PointerPte = Pfn1->PteAddress;
|
|
} else {
|
|
|
|
//
|
|
// The address is not valid in this process, map it into
|
|
// hyperspace so it can be operated upon.
|
|
//
|
|
|
|
PointerPte = (PMMPTE)MiMapPageInHyperSpace(Pfn1->PteFrame,
|
|
&OldIrql);
|
|
PointerPte = (PMMPTE)((ULONG)PointerPte +
|
|
MiGetByteOffset(Pfn1->PteAddress));
|
|
}
|
|
|
|
TempPte = *PointerPte;
|
|
MI_MAKE_VALID_PTE_TRANSITION (TempPte,
|
|
Pfn1->OriginalPte.u.Soft.Protection);
|
|
*PointerPte = TempPte;
|
|
|
|
if (OldIrql != 99) {
|
|
MiUnmapPageInHyperSpace (OldIrql);
|
|
}
|
|
|
|
//
|
|
// There is no need to flush the translation buffer at this
|
|
// time as we only invalidated a prototytpe PTE.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Change the page location to inactive (from active and valid).
|
|
//
|
|
|
|
Pfn1->u3.e1.PageLocation = TransitionPage;
|
|
|
|
//
|
|
// Decrement the valid pte count for the PteFrame page.
|
|
//
|
|
|
|
#if DBG
|
|
PfnX = MI_PFN_ELEMENT (Pfn1->PteFrame);
|
|
|
|
ASSERT (PfnX->u2.ShareCount != 0);
|
|
#endif //DBG
|
|
|
|
//
|
|
// Decrement the reference count as the share count is now zero.
|
|
//
|
|
|
|
MiDecrementReferenceCount (PageFrameIndex);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiDecrementShareCountOnly (
|
|
IN ULONG PageFrameIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the share count within the PFN element
|
|
for the specified physical page. If the share count becomes
|
|
zero the corresponding PTE is coverted to the transition state
|
|
and the reference count is decremented; the ValidPte count
|
|
of the corresponding PTE FRAME field is not updated.
|
|
|
|
Arguments:
|
|
|
|
PageFrameIndex - Supplies the physical page number of which to decrement
|
|
the share count.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Must be holding the PFN database mutex with APC's disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE TempPte;
|
|
PMMPTE PointerPte;
|
|
PMMPFN Pfn1;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT ((PageFrameIndex <= MmHighestPhysicalPage) &&
|
|
(PageFrameIndex > 0));
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
|
|
Pfn1->u2.ShareCount -= 1;
|
|
|
|
ASSERT (Pfn1->u2.ShareCount < 0xF000000);
|
|
|
|
if (Pfn1->u2.ShareCount == 0) {
|
|
|
|
//
|
|
// The share count is now zero, decrement the reference count
|
|
// for the PFN element and turn the referenced PTE into
|
|
// the transition state if it refers to a prototype PTE.
|
|
// PTEs which are not prototype PTE do not need to be placed
|
|
// into transition as they are placed in transition when
|
|
// they are removed from the working set (working set free routine).
|
|
//
|
|
|
|
//
|
|
// If the PTE referenced by this PFN element is actually
|
|
// a prototype PTE, it must be mapped into hyperspace and
|
|
// then operated on.
|
|
//
|
|
|
|
if (Pfn1->u3.e1.PrototypePte == 1) {
|
|
|
|
OldIrql = 99;
|
|
if (MmIsAddressValid (Pfn1->PteAddress)) {
|
|
PointerPte = Pfn1->PteAddress;
|
|
} else {
|
|
|
|
//
|
|
// The address is not valid in this process, map it into
|
|
// hyperspace so it can be operated upon.
|
|
//
|
|
|
|
PointerPte = (PMMPTE)MiMapPageInHyperSpace(Pfn1->PteFrame,
|
|
&OldIrql);
|
|
PointerPte = (PMMPTE)((ULONG)PointerPte +
|
|
MiGetByteOffset(Pfn1->PteAddress));
|
|
}
|
|
|
|
TempPte = *PointerPte;
|
|
MI_MAKE_VALID_PTE_TRANSITION (TempPte,
|
|
Pfn1->OriginalPte.u.Soft.Protection);
|
|
*PointerPte = TempPte;
|
|
|
|
if (OldIrql != 99) {
|
|
MiUnmapPageInHyperSpace (OldIrql);
|
|
}
|
|
|
|
//
|
|
// There is no need to flush the translation buffer at this
|
|
// time as we only invalidated a prototytpe PTE.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Change the page location to inactive (from active and valid).
|
|
//
|
|
|
|
Pfn1->u3.e1.PageLocation = TransitionPage;
|
|
|
|
//
|
|
// Decrement the reference count as the share count is now zero.
|
|
//
|
|
|
|
MiDecrementReferenceCount (PageFrameIndex);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiDecrementShareAndValidCount (
|
|
IN ULONG PageFrameIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the share count and the valid count
|
|
within the PFN element
|
|
for the specified physical page. If the share count becomes
|
|
zero the corresponding PTE is coverted to the transition state
|
|
and the reference count is decremented.
|
|
|
|
Arguments:
|
|
|
|
PageFrameIndex - Supplies the physical page number of which to decrement
|
|
the share count.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Environment:
|
|
|
|
Must be holding the PFN database mutex with APC's disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE TempPte;
|
|
PMMPTE PointerPte;
|
|
PMMPFN Pfn1;
|
|
KIRQL OldIrql;
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
|
|
|
|
ASSERT ((PageFrameIndex <= MmHighestPhysicalPage) &&
|
|
(PageFrameIndex > 0));
|
|
|
|
ASSERT (Pfn1->u2.ShareCount != 0);
|
|
|
|
Pfn1->u2.ShareCount -= 1;
|
|
|
|
ASSERT (Pfn1->u2.ShareCount < (ULONG)0xF000000);
|
|
|
|
if (Pfn1->u2.ShareCount == 0) {
|
|
|
|
//
|
|
// The share count is now zero, decrement the reference count
|
|
// for the PFN element and turn the referenced PTE into
|
|
// the transition state if it refers to a prototype PTE.
|
|
// PTEs which are not prototype PTE do not need to be placed
|
|
// into transition as they are placed in transition when
|
|
// they are removed from the working set (working set free routine).
|
|
//
|
|
|
|
//
|
|
// If the PTE referenced by this PFN element is actually
|
|
// a prototype PTE, it must be mapped into hyperspace and
|
|
// then operated on.
|
|
//
|
|
|
|
if (Pfn1->u3.e1.PrototypePte) {
|
|
|
|
OldIrql = 99;
|
|
if (MmIsAddressValid (Pfn1->PteAddress)) {
|
|
PointerPte = Pfn1->PteAddress;
|
|
} else {
|
|
|
|
//
|
|
// The address is not valid in this process, map it into
|
|
// hyperspace so it can be operated upon.
|
|
//
|
|
|
|
PointerPte = (PMMPTE)MiMapPageInHyperSpace(Pfn1->PteFrame,
|
|
&OldIrql);
|
|
PointerPte = (PMMPTE)((ULONG)PointerPte +
|
|
MiGetByteOffset(Pfn1->PteAddress));
|
|
}
|
|
|
|
TempPte = *PointerPte;
|
|
MI_MAKE_VALID_PTE_TRANSITION (TempPte,
|
|
Pfn1->OriginalPte.u.Soft.Protection);
|
|
*PointerPte = TempPte;
|
|
|
|
if (OldIrql != 99) {
|
|
MiUnmapPageInHyperSpace (OldIrql);
|
|
}
|
|
|
|
//
|
|
// There is no need to flush the translation buffer at this
|
|
// time as we only invalidated a prototytpe PTE.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Change the page location to inactive (from active and valid).
|
|
//
|
|
|
|
Pfn1->u3.e1.PageLocation = TransitionPage;
|
|
|
|
//
|
|
// Decrement the reference count as the share count is now zero.
|
|
//
|
|
|
|
KdPrint(("MM:shareandvalid decremented share to 0 pteframe = %lx\n",
|
|
Pfn1->PteFrame));
|
|
|
|
MiDecrementReferenceCount (PageFrameIndex);
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif // 0
|
|
|
|
VOID
|
|
FASTCALL
|
|
MiDecrementReferenceCount (
|
|
IN ULONG PageFrameIndex
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine decrements the reference count for the specified page.
|
|
If the reference count becomes zero, the page is placed on the
|
|
appropriate list (free, modified, standby or bad). If the page
|
|
is placed on the free or standby list, the number of available
|
|
pages is incremented and if it transitions from zero to one, the
|
|
available page event is set.
|
|
|
|
|
|
Arguments:
|
|
|
|
PageFrameIndex - Supplies the physical page number of which to
|
|
decrement the reference count.
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
|
|
Environment:
|
|
|
|
Must be holding the PFN database mutex with APC's disabled.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMMPFN Pfn1;
|
|
|
|
MM_PFN_LOCK_ASSERT();
|
|
|
|
ASSERT ((PageFrameIndex <= MmHighestPhysicalPage) &&
|
|
(PageFrameIndex > 0));
|
|
|
|
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
|
|
ASSERT (Pfn1->u3.e2.ReferenceCount != 0);
|
|
Pfn1->u3.e2.ReferenceCount -= 1;
|
|
|
|
|
|
if (Pfn1->u3.e2.ReferenceCount != 0) {
|
|
|
|
//
|
|
// The reference count is not zero, return.
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The reference count is now zero, put the page on some
|
|
// list.
|
|
//
|
|
|
|
|
|
if (Pfn1->u2.ShareCount != 0) {
|
|
|
|
KeBugCheckEx (PFN_LIST_CORRUPT,
|
|
7,
|
|
PageFrameIndex,
|
|
Pfn1->u2.ShareCount,
|
|
0);
|
|
return;
|
|
}
|
|
|
|
ASSERT (Pfn1->u3.e1.PageLocation != ActiveAndValid);
|
|
|
|
#ifdef PARITY
|
|
if (Pfn1->u3.e1.ParityError == 1) {
|
|
|
|
//
|
|
// This page has parity (ECC) errors, put it on the
|
|
// bad page list.
|
|
//
|
|
|
|
MiInsertPageInList (MmPageLocationList[BadPageList], PageFrameIndex);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (MI_IS_PFN_DELETED (Pfn1)) {
|
|
|
|
//
|
|
// There is no referenced PTE for this page, delete
|
|
// the page file space, if any, and place
|
|
// the page on the free list.
|
|
//
|
|
|
|
MiReleasePageFileSpace (Pfn1->OriginalPte);
|
|
|
|
MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Place the page on the modified or standby list depending
|
|
// on the state of the modify bit in the PFN element.
|
|
//
|
|
|
|
if (Pfn1->u3.e1.Modified == 1) {
|
|
MiInsertPageInList (MmPageLocationList[ModifiedPageList], PageFrameIndex);
|
|
} else {
|
|
if (!MmFrontOfList) {
|
|
MiInsertPageInList (MmPageLocationList[StandbyPageList],
|
|
PageFrameIndex);
|
|
} else {
|
|
MiInsertStandbyListAtFront (PageFrameIndex);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|