text: /*++
  
  Copyright (c) 1989  Microsoft Corporation
  
  Module Name:
  
     checkpte.c
  
  Abstract:
  
      This module contains routines for sanity checking the page directory.
  
  Author:
  
      Lou Perazzoli (loup) 25-Apr-1989
      Landy Wang (landyw) 02-June-1997
  
  Revision History:
  
  --*/
  
  #include "mi.h"
  
  #if DBG
  
  VOID
  CheckValidPte (
      IN PMMPTE PointerPte
      );
  
  
  VOID
  MiCheckPte (
      VOID
      )
  
  /*++
  
  Routine Description:
  
      This routine checks each page table page in an address space to
      ensure it is in the proper state.
  
  Arguments:
  
      None.
  
  Return Value:
  
      None.
  
  Environment:
  
      Kernel mode, APCs disabled.
  
  --*/
  
  {
      ULONG i;
      ULONG j;
      PMMPTE PointerPte;
      PMMPTE PointerPde;
      PMMPFN Pfn1;
      ULONG ValidCount;
      ULONG TransitionCount;
      KIRQL OldIrql;
      PEPROCESS TargetProcess;
      USHORT UsedPages;
  
      TargetProcess = PsGetCurrentProcess ();
  
      PointerPde = MiGetPdeAddress (NULL);
  
      UsedPages = 0;
  
      LOCK_WS (TargetProcess);
      LOCK_PFN (OldIrql);
  
      for (i = 0; i < PDE_PER_PAGE; i += 1) {
  
          if (PointerPde->u.Hard.Valid) {
              ValidCount = 0;
              TransitionCount = 0;
              CheckValidPte (PointerPde);
  
              PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  
              for (j = 0; j < PTE_PER_PAGE; j += 1) {
  
                  if ((PointerPte >= MiGetPteAddress(HYPER_SPACE)) &&
                      (PointerPte < MiGetPteAddress(WORKING_SET_LIST))) {
  
                      goto endloop;
                  }
  
                  if (PointerPte->u.Hard.Valid) {
                      ValidCount += 1;
                      CheckValidPte (PointerPte);
                  }
                  else {
  
                      if ((PointerPte->u.Soft.Transition == 1) &&
                          (PointerPte->u.Soft.Prototype == 0)) {
  
                          //
                          // Transition PTE, up the transition count.
                          //
  
                          TransitionCount += 1;
                      }
                  }
  
                  if (PointerPte->u.Long != 0) {
                      UsedPages += 1;
                  }
  endloop:
                  PointerPte += 1;
              }
              if ((i < 512) || (i == 896)) {
  #if !defined (_WIN64)
                  if (MmWorkingSetList->UsedPageTableEntries[i] != UsedPages) {
                     DbgPrint("used pages and page table used not equal %lx %lx %lx\n",
                      i,MmWorkingSetList->UsedPageTableEntries[i], UsedPages);
                  }
  #endif
              }
  
              //
              // Check the share count for the page table page.
              //
              if ((i < 511) || (i == 896)) {
                  Pfn1 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber);
                  if (Pfn1->u2.ShareCount != ((ULONG)1+ValidCount+TransitionCount)) {
                      DbgPrint("share count for page table page bad - %lx %lx %lx\n",
                          i,ValidCount, TransitionCount);
                      MiFormatPfn(Pfn1);
                  }
              }
          }
          PointerPde += 1;
          UsedPages = 0;
      }
  
      UNLOCK_PFN (OldIrql);
      UNLOCK_WS (TargetProcess);
  
      return;
  }
  
  VOID
  CheckValidPte (
      IN PMMPTE PointerPte
      )
  
  {
      PMMPFN Pfn1;
      PMMPTE PointerPde;
  
      if (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) > MmNumberOfPhysicalPages) {
          return;
      }
  
      Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
  
  #if 0
      if (PointerPte->u.Hard.PageFrameNumber == 0) {
          DbgPrint("physical page zero mapped\n");
          MiFormatPte(PointerPte);
          MiFormatPfn(Pfn1);
      }
  #endif
  
      if (Pfn1->u3.e1.PageLocation != ActiveAndValid) {
          DbgPrint("valid PTE with page frame not active and valid\n");
          MiFormatPfn(Pfn1);
          MiFormatPte(PointerPte);
      }
  
      if (Pfn1->u3.e1.PrototypePte == 0) {
  
          //
          // This is not a prototype PTE.
          //
  
          if (Pfn1->PteAddress != PointerPte) {
              DbgPrint("checkpte - Pfn PTE address and PTE address not equal\n");
              MiFormatPte(PointerPte);
              MiFormatPfn(Pfn1);
              return;
          }
      }
  
      if (!MmIsAddressValid(Pfn1->PteAddress)) {
          return;
      }
  
      PointerPde = MiGetPteAddress (Pfn1->PteAddress);
  
      if (PointerPde->u.Hard.Valid == 1) {
          if (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde) != Pfn1->u4.PteFrame) {
              DbgPrint("checkpte - pteframe not right\n");
              MiFormatPfn(Pfn1);
              MiFormatPte(PointerPte);
              MiFormatPte(PointerPde);
          }
      }
  
      return;
  }
  
  #endif
  