summaryrefslogtreecommitdiffstats
path: root/private/ntos/mm/checkpfn.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/mm/checkpfn.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/mm/checkpfn.c')
-rw-r--r--private/ntos/mm/checkpfn.c538
1 files changed, 538 insertions, 0 deletions
diff --git a/private/ntos/mm/checkpfn.c b/private/ntos/mm/checkpfn.c
new file mode 100644
index 000000000..332b373ec
--- /dev/null
+++ b/private/ntos/mm/checkpfn.c
@@ -0,0 +1,538 @@
+/*++
+
+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
+
+Revision History:
+
+--*/
+
+#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.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Environment:
+
+ Kernel mode, APC's disabled.
+
+--*/
+
+{
+ PMMPFN Pfn1;
+ ULONG 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, 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, 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, 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, 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)PointerPte +
+ MiGetByteOffset(Pfn1->PteAddress));
+ }
+ if (PointerPte->u.Trans.PageFrameNumber != 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, 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)PointerPte +
+ MiGetByteOffset(Pfn1->PteAddress));
+ }
+
+ if (PointerPte->u.Trans.PageFrameNumber != 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;
+ }
+
+#ifdef _MIPS_
+
+ //
+ // ignore ptes mapped to kseg0 or kseg1.
+ //
+
+ if ((Pfn1->PteAddress > (PMMPTE)0xc0200000) &&
+ (Pfn1->PteAddress < (PMMPTE)0xc0300000)) {
+
+ goto NoCheck;
+ }
+#endif //MIPS
+
+#ifdef _PPC_
+
+ //
+ // ignore ptes mapped to PowerPC kernel BAT.
+ //
+
+ if (MI_IS_PHYSICAL_ADDRESS(MiGetVirtualAddressMappedByPte(Pfn1->PteAddress))) {
+
+ goto NoCheck;
+ }
+#endif // _PPC_
+
+#ifdef _ALPHA_
+
+ //
+ // ignore ptes mapped to ALPHA's 32-bit superpage.
+ //
+
+ if ((Pfn1->PteAddress > (PMMPTE)0xc0100000) &&
+ (Pfn1->PteAddress < (PMMPTE)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)PointerPte +
+ MiGetByteOffset(Pfn1->PteAddress));
+ }
+
+ if (PointerPte->u.Hard.PageFrameNumber != 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(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
+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);
+ return;
+
+}
+
+VOID
+MiDumpPfn ( )
+
+{
+ ULONG i;
+ PMMPFN Pfn1;
+
+ Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage);
+
+ for (i=0; i < MmNumberOfPhysicalPages; i++) {
+ MiFormatPfn (Pfn1);
+ Pfn1++;
+ }
+ return;
+}
+
+VOID
+MiFormatPfn (
+ IN PMMPFN PointerPfn
+ )
+
+{
+ struct longs {
+ ULONG Flink;
+ ULONG Pteadd;
+ ULONG Blink;
+ ULONG Refcount;
+ ULONG Origpte;
+ ULONG Flags;
+ };
+
+ struct longs *Pfake;
+ ULONG i;
+
+ i = PointerPfn - MmPfnDatabase;
+
+ Pfake = (struct longs *)PointerPfn;
+
+ DbgPrint("***PFN %lx flink %lx blink %lx ptecout-refcnt %lx\n",
+ i,
+ Pfake->Flink,
+ Pfake->Blink,
+ Pfake->Refcount);
+
+ DbgPrint(" pteaddr %lx originalPTE %lx flags %lx \n",
+ Pfake->Pteadd,
+ Pfake->Origpte,
+ Pfake->Flags);
+
+ return;
+
+}
+#endif //DBG