Windows2000/private/ntos/mm/checkpfn.c
2020-09-30 17:12:32 +02:00

396 lines
13 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
checkpfn.c
Abstract:
This module contains routines for sanity checking the PFN database.
Author:
Lou Perazzoli (loup) 25-Apr-1989
--*/
#include "mi.h"
#if DBG
PRTL_BITMAP CheckPfnBitMap;
VOID MiCheckPfn ()
/*++
Routine Description:
This routine checks each physical page in the PFN database to ensure it is in the proper state.
Environment:
Kernel mode, APCs disabled.
--*/
{
PMMPFN Pfn1;
PFN_NUMBER Link, Previous;
ULONG i;
PMMPTE PointerPte;
KIRQL PreviousIrql;
KIRQL OldIrql;
USHORT ValidCheck[4];
USHORT ValidPage[4];
PMMPFN PfnX;
ValidCheck[0] = ValidCheck[1] = ValidCheck[2] = ValidCheck[3] = 0;
ValidPage[0] = ValidPage[1] = ValidPage[2] = ValidPage[3] = 0;
if (CheckPfnBitMap == NULL) {
MiCreateBitMap ( &CheckPfnBitMap, MmNumberOfPhysicalPages, NonPagedPool);
}
RtlClearAllBits (CheckPfnBitMap);
// Walk free list.
KeRaiseIrql (APC_LEVEL, &PreviousIrql);
LOCK_PFN (OldIrql);
Previous = MM_EMPTY_LIST;
Link = MmFreePageListHead.Flink;
for (i=0; i < MmFreePageListHead.Total; i++) {
if (Link == MM_EMPTY_LIST) {
DbgPrint("free list total count wrong\n");
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
return;
}
RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
Pfn1 = MI_PFN_ELEMENT(Link);
if (Pfn1->u3.e2.ReferenceCount != 0) {
DbgPrint("non zero reference count on free list\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u3.e1.PageLocation != FreePageList) {
DbgPrint("page location not freelist\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u2.Blink != Previous) {
DbgPrint("bad blink on free list\n");
MiFormatPfn(Pfn1);
}
Previous = Link;
Link = Pfn1->u1.Flink;
}
if (Link != MM_EMPTY_LIST) {
DbgPrint("free list total count wrong\n");
Pfn1 = MI_PFN_ELEMENT(Link);
MiFormatPfn(Pfn1);
}
// Walk zeroed list.
Previous = MM_EMPTY_LIST;
Link = MmZeroedPageListHead.Flink;
for (i=0; i < MmZeroedPageListHead.Total; i++) {
if (Link == MM_EMPTY_LIST) {
DbgPrint("zero list total count wrong\n");
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
return;
}
RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
Pfn1 = MI_PFN_ELEMENT(Link);
if (Pfn1->u3.e2.ReferenceCount != 0) {
DbgPrint("non zero reference count on zero list\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u3.e1.PageLocation != ZeroedPageList) {
DbgPrint("page location not zerolist\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u2.Blink != Previous) {
DbgPrint("bad blink on zero list\n");
MiFormatPfn(Pfn1);
}
Previous = Link;
Link = Pfn1->u1.Flink;
}
if (Link != MM_EMPTY_LIST) {
DbgPrint("zero list total count wrong\n");
Pfn1 = MI_PFN_ELEMENT(Link);
MiFormatPfn(Pfn1);
}
// Walk Bad list.
Previous = MM_EMPTY_LIST;
Link = MmBadPageListHead.Flink;
for (i=0; i < MmBadPageListHead.Total; i++) {
if (Link == MM_EMPTY_LIST) {
DbgPrint("Bad list total count wrong\n");
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
return;
}
RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
Pfn1 = MI_PFN_ELEMENT(Link);
if (Pfn1->u3.e2.ReferenceCount != 0) {
DbgPrint("non zero reference count on Bad list\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u3.e1.PageLocation != BadPageList) {
DbgPrint("page location not Badlist\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u2.Blink != Previous) {
DbgPrint("bad blink on Bad list\n");
MiFormatPfn(Pfn1);
}
Previous = Link;
Link = Pfn1->u1.Flink;
}
if (Link != MM_EMPTY_LIST) {
DbgPrint("Bad list total count wrong\n");
Pfn1 = MI_PFN_ELEMENT(Link);
MiFormatPfn(Pfn1);
}
// Walk Standby list.
Previous = MM_EMPTY_LIST;
Link = MmStandbyPageListHead.Flink;
for (i=0; i < MmStandbyPageListHead.Total; i++) {
if (Link == MM_EMPTY_LIST) {
DbgPrint("Standby list total count wrong\n");
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
return;
}
RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
Pfn1 = MI_PFN_ELEMENT(Link);
if (Pfn1->u3.e2.ReferenceCount != 0) {
DbgPrint("non zero reference count on Standby list\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u3.e1.PageLocation != StandbyPageList) {
DbgPrint("page location not Standbylist\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u2.Blink != Previous) {
DbgPrint("bad blink on Standby list\n");
MiFormatPfn(Pfn1);
}
// Check to see if referenced PTE is okay.
if (MI_IS_PFN_DELETED (Pfn1)) {
DbgPrint("Invalid pteaddress in standby list\n");
MiFormatPfn(Pfn1);
} else {
OldIrql = 99;
if ((Pfn1->u3.e1.PrototypePte == 1) && (MmIsAddressValid (Pfn1->PteAddress))) {
PointerPte = Pfn1->PteAddress;
} else {
PointerPte = MiMapPageInHyperSpace(Pfn1->PteFrame, &OldIrql);
PointerPte = (PMMPTE)((ULONG_PTR)PointerPte + MiGetByteOffset(Pfn1->PteAddress));
}
if (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) != Link) {
DbgPrint("Invalid PFN - PTE address is wrong in standby list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
if (PointerPte->u.Soft.Transition == 0) {
DbgPrint("Pte not in transition for page on standby list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
if (OldIrql != 99) {
MiUnmapPageInHyperSpace (OldIrql);
OldIrql = 99;
}
}
Previous = Link;
Link = Pfn1->u1.Flink;
}
if (Link != MM_EMPTY_LIST) {
DbgPrint("Standby list total count wrong\n");
Pfn1 = MI_PFN_ELEMENT(Link);
MiFormatPfn(Pfn1);
}
// Walk Modified list.
Previous = MM_EMPTY_LIST;
Link = MmModifiedPageListHead.Flink;
for (i=0; i < MmModifiedPageListHead.Total; i++) {
if (Link == MM_EMPTY_LIST) {
DbgPrint("Modified list total count wrong\n");
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
return;
}
RtlSetBits (CheckPfnBitMap, (ULONG)Link, 1L);
Pfn1 = MI_PFN_ELEMENT(Link);
if (Pfn1->u3.e2.ReferenceCount != 0) {
DbgPrint("non zero reference count on Modified list\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u3.e1.PageLocation != ModifiedPageList) {
DbgPrint("page location not Modifiedlist\n");
MiFormatPfn(Pfn1);
}
if (Pfn1->u2.Blink != Previous) {
DbgPrint("bad blink on Modified list\n");
MiFormatPfn(Pfn1);
}
// Check to see if referenced PTE is okay.
if (MI_IS_PFN_DELETED (Pfn1)) {
DbgPrint("Invalid pteaddress in modified list\n");
MiFormatPfn(Pfn1);
} else {
if ((Pfn1->u3.e1.PrototypePte == 1) && (MmIsAddressValid (Pfn1->PteAddress))) {
PointerPte = Pfn1->PteAddress;
} else {
PointerPte = MiMapPageInHyperSpace(Pfn1->PteFrame, &OldIrql);
PointerPte = (PMMPTE)((ULONG_PTR)PointerPte + MiGetByteOffset(Pfn1->PteAddress));
}
if (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) != Link) {
DbgPrint("Invalid PFN - PTE address is wrong in modified list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
if (PointerPte->u.Soft.Transition == 0) {
DbgPrint("Pte not in transition for page on modified list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
if (OldIrql != 99) {
MiUnmapPageInHyperSpace (OldIrql);
OldIrql = 99;
}
}
Previous = Link;
Link = Pfn1->u1.Flink;
}
if (Link != MM_EMPTY_LIST) {
DbgPrint("Modified list total count wrong\n");
Pfn1 = MI_PFN_ELEMENT(Link);
MiFormatPfn(Pfn1);
}
// All non active pages have been scanned. Locate the active pages and make sure they are consistent.
// set bit zero as page zero is reserved for now
RtlSetBits (CheckPfnBitMap, 0L, 1L);
Link = RtlFindClearBitsAndSet (CheckPfnBitMap, 1L, 0);
while (Link != 0xFFFFFFFF) {
Pfn1 = MI_PFN_ELEMENT (Link);
// Make sure the PTE address is okay
if ((Pfn1->PteAddress >= (PMMPTE)HYPER_SPACE) && (Pfn1->u3.e1.PrototypePte == 0)) {
DbgPrint("pfn with illegal pte address\n");
MiFormatPfn(Pfn1);
break;
}
if (Pfn1->PteAddress < (PMMPTE)PTE_BASE) {
DbgPrint("pfn with illegal pte address\n");
MiFormatPfn(Pfn1);
break;
}
#if defined(_IA64_)
// ignore PTEs mapped to IA64 kernel BAT.
if (MI_IS_PHYSICAL_ADDRESS(MiGetVirtualAddressMappedByPte(Pfn1->PteAddress))) {
goto NoCheck;
}
#endif // _IA64_
#ifdef _ALPHA_
// ignore ptes mapped to ALPHA's 32-bit superpage.
if ((Pfn1->PteAddress > (PMMPTE)(ULONG_PTR)0xc0100000) && (Pfn1->PteAddress < (PMMPTE)(ULONG_PTR)0xc0180000)) {
goto NoCheck;
}
#endif //ALPHA
// Check to make sure the referenced PTE is for this page.
if ((Pfn1->u3.e1.PrototypePte == 1) && (MmIsAddressValid (Pfn1->PteAddress))) {
PointerPte = Pfn1->PteAddress;
} else {
PointerPte = MiMapPageInHyperSpace(Pfn1->PteFrame, &OldIrql);
PointerPte = (PMMPTE)((ULONG_PTR)PointerPte + MiGetByteOffset(Pfn1->PteAddress));
}
if (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) != Link) {
DbgPrint("Invalid PFN - PTE address is wrong in active list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
if (PointerPte->u.Hard.Valid == 0) {
// if the page is a page table page it could be out of the working set yet a transition page is keeping it around in memory (ups the share count).
if ((Pfn1->PteAddress < (PMMPTE)PDE_BASE) || (Pfn1->PteAddress > (PMMPTE)PDE_TOP)) {
DbgPrint("Pte not valid for page on active list\n");
MiFormatPfn(Pfn1);
MiFormatPte(PointerPte);
}
}
if (Pfn1->u3.e2.ReferenceCount != 1) {
DbgPrint("refcount not 1\n");
MiFormatPfn(Pfn1);
}
// Check to make sure the PTE count for the frame is okay.
if (Pfn1->u3.e1.PrototypePte == 1) {
PfnX = MI_PFN_ELEMENT(Pfn1->PteFrame);
for (i = 0; i < 4; i++) {
if (ValidPage[i] == 0) {
ValidPage[i] = (USHORT)Pfn1->PteFrame;
}
if (ValidPage[i] == (USHORT)Pfn1->PteFrame) {
ValidCheck[i] += 1;
break;
}
}
}
if (OldIrql != 99) {
MiUnmapPageInHyperSpace (OldIrql);
OldIrql = 99;
}
#if defined(_ALPHA_) || defined(_IA64_)
NoCheck:
#endif
Link = RtlFindClearBitsAndSet (CheckPfnBitMap, 1L, 0);
}
for (i = 0; i < 4; i++) {
if (ValidPage[i] == 0) {
break;
}
PfnX = MI_PFN_ELEMENT(ValidPage[i]);
}
UNLOCK_PFN (OldIrql);
KeLowerIrql (PreviousIrql);
}
VOID MiDumpPfn ( )
{
ULONG i;
PMMPFN Pfn1;
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage);
for (i=0; i < MmNumberOfPhysicalPages; i++) {
MiFormatPfn (Pfn1);
Pfn1++;
}
}
VOID MiFormatPfn (IN PMMPFN PointerPfn)
{
MMPFN Pfn;
ULONG i;
Pfn = *PointerPfn;
i = (ULONG)(PointerPfn - MmPfnDatabase);
DbgPrint("***PFN %lx flink %lx blink %lx ptecount-refcnt %lx\n", i, Pfn.u1.Flink, Pfn.u2.Blink, Pfn.u3.e2.ReferenceCount);
DbgPrint(" pteaddr %p originalPTE %p flags %lx \n", Pfn.PteAddress, Pfn.OriginalPte, Pfn.u3.e2.ShortFlags);
}
#endif //DBG