test: mmsup.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# mmsup.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007    mmsup.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the various routines for miscellaneous support
    00012     operations for memory management.
    00013
    00014 Author:
    00015
    00016     Lou Perazzoli (loup) 31-Aug-1989
    00017
    00018 Revision History:
    00019
    00020     Landy Wang (landyw) 08-April-1998 : Modifications for 3-level 64-bit NT.
    00021
    00022 --*/
    00023
    00024 #include "mi.h"
    00025
    00026 #ifdef ALLOC_PRAGMA
    00027 #pragma alloc_text(PAGE, MmHibernateInformation)
    00028 #endif
    00029
    00030 #if _WIN64
    00031 #if DBGXX
    00032 VOID
    00033 MiCheckPageTableTrim(
    00034     IN PMMPTE PointerPte
    00035 );
    00036 #endif
    00037 #endif
    00038
    00039
    00040 ULONG
    00041 FASTCALL
    00042 MiIsPteDecommittedPage (
    00043     IN PMMPTE PointerPte
    00044     )
    00045
    00046 /*++
    00047
    00048 Routine Description:
    00049
    00050     This function checks the contents of a PTE to determine if the
    00051     PTE is explicitly decommitted.
    00052
    00053     If the PTE is a prototype PTE and the protection is not in the
    00054     prototype PTE, the value FALSE is returned.
    00055
    00056 Arguments:
    00057
    00058     PointerPte - Supplies a pointer to the PTE to examine.
    00059
    00060 Return Value:
    00061
    00062     TRUE if the PTE is in the explicit decommitted state.
    00063     FALSE if the PTE is not in the explicit decommitted state.
    00064
    00065 Environment:
    00066
    00067     Kernel mode, APCs disabled, WorkingSetLock held.
    00068
    00069 --*/
    00070
    00071 {
    00072     MMPTE PteContents;
    00073
    00074     PteContents = *PointerPte;
    00075
    00076     //
    00077     // If the protection in the PTE is not decommitted, return false.
    00078     //
    00079
    00080     if (PteContents.u.Soft.Protection != MM_DECOMMIT) {
    00081         return FALSE;
    00082     }
    00083
    00084     //
    00085     // Check to make sure the protection field is really being interpreted
    00086     // correctly.
    00087     //
    00088
    00089     if (PteContents.u.Hard.Valid == 1) {
    00090
    00091         //
    00092         // The PTE is valid and therefore cannot be decommitted.
    00093         //
    00094
    00095         return FALSE;
    00096     }
    00097
    00098     if ((PteContents.u.Soft.Prototype == 1) &&
    00099          (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)) {
    00100
    00101         //
    00102         // The PTE's protection is not known as it is in
    00103         // prototype PTE format.  Return FALSE.
    00104         //
    00105
    00106         return FALSE;
    00107     }
    00108
    00109     //
    00110     // It is a decommitted PTE.
    00111     //
    00112
    00113     return TRUE;
    00114 }
    00115
    00116 //
    00117 // Data for is protection compatible.
    00118 //
    00119
    00120 ULONG MmCompatibleProtectionMask[8] = {
    00121             PAGE_NOACCESS,
    00122             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY,
    00123             PAGE_NOACCESS | PAGE_EXECUTE,
    00124             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE |
    00125                 PAGE_EXECUTE_READ,
    00126             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE,
    00127             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY,
    00128             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_READWRITE |
    00129                 PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE |
    00130                 PAGE_EXECUTE_WRITECOPY,
    00131             PAGE_NOACCESS | PAGE_READONLY | PAGE_WRITECOPY | PAGE_EXECUTE |
    00132                 PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
    00133             };
    00134
    00135
    00136
    00137 ULONG
    00138 FASTCALL
    00139 MiIsProtectionCompatible (
    00140     IN ULONG OldProtect,
    00141     IN ULONG NewProtect
    00142     )
    00143
    00144 /*++
    00145
    00146 Routine Description:
    00147
    00148     This function takes two user supplied page protections and checks
    00149     to see if the new protection is compatible with the old protection.
    00150
    00151    protection        compatible protections
    00152     NoAccess          NoAccess
    00153     ReadOnly          NoAccess, ReadOnly, ReadWriteCopy
    00154     ReadWriteCopy     NoAccess, ReadOnly, ReadWriteCopy
    00155     ReadWrite         NoAccess, ReadOnly, ReadWriteCopy, ReadWrite
    00156     Execute           NoAccess, Execute
    00157     ExecuteRead       NoAccess, ReadOnly, ReadWriteCopy, Execute, ExecuteRead,
    00158                         ExecuteWriteCopy
    00159     ExecuteWrite      NoAccess, ReadOnly, ReadWriteCopy, Execute, ExecuteRead,
    00160                         ExecuteWriteCopy, ReadWrite, ExecuteWrite
    00161     ExecuteWriteCopy  NoAccess, ReadOnly, ReadWriteCopy, Execute, ExecuteRead,
    00162                         ExecuteWriteCopy
    00163
    00164 Arguments:
    00165
    00166     OldProtect - Supplies the protection to be compatible with.
    00167
    00168     NewProtect - Supplies the protection to check out.
    00169
    00170
    00171 Return Value:
    00172
    00173     Returns TRUE if the protection is compatible, FALSE if not.
    00174
    00175 Environment:
    00176
    00177     Kernel Mode.
    00178
    00179 --*/
    00180
    00181 {
    00182     ULONG Mask;
    00183     ULONG ProtectMask;
    00184
    00185     try {
    00186         Mask = MiMakeProtectionMask (OldProtect) & 0x7;
    00187     } except (EXCEPTION_EXECUTE_HANDLER) {
    00188         return FALSE;
    00189     }
    00190
    00191     ProtectMask = MmCompatibleProtectionMask[Mask] | PAGE_GUARD | PAGE_NOCACHE;
    00192
    00193     if ((ProtectMask | NewProtect) != ProtectMask) {
    00194         return FALSE;
    00195     }
    00196     return TRUE;
    00197 }
    00198
    00199
    00200 //
    00201 // Protection data for MiMakeProtectionMask
    00202 //
    00203
    00204 CCHAR MmUserProtectionToMask1[16] = {
    00205                                  0,
    00206                                  MM_NOACCESS,
    00207                                  MM_READONLY,
    00208                                  -1,
    00209                                  MM_READWRITE,
    00210                                  -1,
    00211                                  -1,
    00212                                  -1,
    00213                                  MM_WRITECOPY,
    00214                                  -1,
    00215                                  -1,
    00216                                  -1,
    00217                                  -1,
    00218                                  -1,
    00219                                  -1,
    00220                                  -1 };
    00221
    00222 CCHAR MmUserProtectionToMask2[16] = {
    00223                                  0,
    00224                                  MM_EXECUTE,
    00225                                  MM_EXECUTE_READ,
    00226                                  -1,
    00227                                  MM_EXECUTE_READWRITE,
    00228                                  -1,
    00229                                  -1,
    00230                                  -1,
    00231                                  MM_EXECUTE_WRITECOPY,
    00232                                  -1,
    00233                                  -1,
    00234                                  -1,
    00235                                  -1,
    00236                                  -1,
    00237                                  -1,
    00238                                  -1 };
    00239
    00240
    00241 ULONG
    00242 FASTCALL
    00243 MiMakeProtectionMask (
    00244     IN ULONG Protect
    00245     )
    00246
    00247 /*++
    00248
    00249 Routine Description:
    00250
    00251     This function takes a user supplied protection and converts it
    00252     into a 5-bit protection code for the PTE.
    00253
    00254 Arguments:
    00255
    00256     Protect - Supplies the protection.
    00257
    00258
    00259 Return Value:
    00260
    00261     Returns the protection code for use in the PTE.
    00262     An exception is raised if the user supplied protection is invalid.
    00263
    00264 Environment:
    00265
    00266     Kernel Mode.
    00267
    00268 --*/
    00269
    00270 {
    00271     ULONG Field1;
    00272     ULONG Field2;
    00273     ULONG ProtectCode;
    00274
    00275     if (Protect >= (PAGE_NOCACHE * 2)) {
    00276         ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00277     }
    00278
    00279     Field1 = Protect & 0xF;
    00280     Field2 = (Protect >> 4) & 0xF;
    00281
    00282     //
    00283     // Make sure at least one field is set.
    00284     //
    00285
    00286     if (Field1 == 0) {
    00287         if (Field2 == 0) {
    00288
    00289             //
    00290             // Both fields are zero, raise exception.
    00291             //
    00292
    00293             ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00294             return 0;
    00295         }
    00296         ProtectCode = MmUserProtectionToMask2[Field2];
    00297     } else {
    00298         if (Field2 != 0) {
    00299             //
    00300             //  Both fields are non-zero, raise exception.
    00301             //
    00302
    00303             ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00304             return 0;
    00305         }
    00306         ProtectCode = MmUserProtectionToMask1[Field1];
    00307     }
    00308
    00309     if (ProtectCode == -1) {
    00310         ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00311     }
    00312
    00313     if (Protect & PAGE_GUARD) {
    00314         if (ProtectCode == MM_NOACCESS) {
    00315
    00316             //
    00317             // Invalid protection, no access and no_cache.
    00318             //
    00319
    00320             ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00321         }
    00322
    00323         ProtectCode |= MM_GUARD_PAGE;
    00324     }
    00325
    00326     if (Protect & PAGE_NOCACHE) {
    00327
    00328         if (ProtectCode == MM_NOACCESS) {
    00329
    00330             //
    00331             // Invalid protection, no access and no cache.
    00332             //
    00333
    00334             ExRaiseStatus (STATUS_INVALID_PAGE_PROTECTION);
    00335         }
    00336
    00337         ProtectCode |= MM_NOCACHE;
    00338     }
    00339
    00340     return ProtectCode;
    00341 }
    00342
    00343 #if defined (_WIN64)
    00344
    00345 LOGICAL
    00346 MiDoesPpeExistAndMakeValid (
    00347     IN PMMPTE PointerPpe,
    00348     IN PEPROCESS TargetProcess,
    00349     IN ULONG PfnMutexHeld,
    00350     OUT PULONG Waited
    00351     )
    00352
    00353 /*++
    00354
    00355 Routine Description:
    00356
    00357     This routine examines the specified Page Directory Parent Entry to determine
    00358     if the page directory page mapped by the PPE exists.
    00359
    00360     If the page directory page exists and is not currently in memory, the
    00361     working set mutex and, if held, the PFN mutex are released and the
    00362     page directory page is faulted into the working set.  The mutexes are
    00363     reacquired.
    00364
    00365     If the PPE exists, the function returns true.
    00366
    00367 Arguments:
    00368
    00369     PointerPpe - Supplies a pointer to the PPE to examine and potentially
    00370                  bring into the working set.
    00371
    00372     TargetProcess - Supplies a pointer to the current process.
    00373
    00374     PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    00375                    otherwise.
    00376
    00377     Waited - Supplies a pointer to a ULONG to increment if the mutex is released
    00378              and reacquired.  Note this value may be incremented more than once.
    00379
    00380 Return Value:
    00381
    00382     TRUE if the PPE exists, FALSE if the PPE is zero.
    00383
    00384 Environment:
    00385
    00386     Kernel mode, APCs disabled, WorkingSetLock held.
    00387
    00388 --*/
    00389
    00390 {
    00391     PMMPTE PointerPde;
    00392     KIRQL OldIrql;
    00393
    00394     OldIrql = APC_LEVEL;
    00395
    00396     if (PointerPpe->u.Long == 0) {
    00397
    00398         //
    00399         // This page directory parent entry doesn't exist, return FALSE.
    00400         //
    00401
    00402         return FALSE;
    00403     }
    00404
    00405     if (PointerPpe->u.Hard.Valid == 1) {
    00406
    00407         //
    00408         // Already valid.
    00409         //
    00410
    00411         return TRUE;
    00412     }
    00413
    00414     //
    00415     // Page directory parent entry exists, it is either valid, in transition
    00416     // or in the paging file.  Fault it in.
    00417     //
    00418
    00419     if (PfnMutexHeld) {
    00420         UNLOCK_PFN (OldIrql);
    00421         *Waited += 1;
    00422     }
    00423
    00424     PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    00425
    00426     *Waited += MiMakeSystemAddressValid (PointerPde, TargetProcess);
    00427
    00428     if (PfnMutexHeld) {
    00429         LOCK_PFN (OldIrql);
    00430     }
    00431     return TRUE;
    00432 }
    00433 #endif
    00434
    00435
    00436 ULONG
    00437 MiDoesPdeExistAndMakeValid (
    00438     IN PMMPTE PointerPde,
    00439     IN PEPROCESS TargetProcess,
    00440     IN ULONG PfnMutexHeld,
    00441     OUT PULONG Waited
    00442     )
    00443
    00444 /*++
    00445
    00446 Routine Description:
    00447
    00448     This routine examines the specified Page Directory Entry to determine
    00449     if the page table page mapped by the PDE exists.
    00450
    00451     If the page table page exists and is not currently in memory, the
    00452     working set mutex and, if held, the PFN mutex are released and the
    00453     page table page is faulted into the working set.  The mutexes are
    00454     reacquired.
    00455
    00456     If the PDE exists, the function returns true.
    00457
    00458 Arguments:
    00459
    00460     PointerPde - Supplies a pointer to the PDE to examine and potentially
    00461                  bring into the working set.
    00462
    00463     TargetProcess - Supplies a pointer to the current process.
    00464
    00465     PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    00466                    otherwise.
    00467
    00468     Waited - Supplies a pointer to a ULONG to increment if the mutex is released
    00469              and reacquired.  Note this value may be incremented more than once.
    00470
    00471 Return Value:
    00472
    00473     TRUE if the PDE exists, FALSE if the PDE is zero.
    00474
    00475 Environment:
    00476
    00477     Kernel mode, APCs disabled, WorkingSetLock held.
    00478
    00479 --*/
    00480
    00481 {
    00482     PMMPTE PointerPte;
    00483     KIRQL OldIrql;
    00484
    00485     OldIrql = APC_LEVEL;
    00486
    00487     if (PointerPde->u.Long == 0) {
    00488
    00489         //
    00490         // This page directory entry doesn't exist, return FALSE.
    00491         //
    00492
    00493         return FALSE;
    00494     }
    00495
    00496     if (PointerPde->u.Hard.Valid == 1) {
    00497
    00498         //
    00499         // Already valid.
    00500         //
    00501
    00502         return TRUE;
    00503     }
    00504
    00505     //
    00506     // Page directory entry exists, it is either valid, in transition
    00507     // or in the paging file.  Fault it in.
    00508     //
    00509
    00510     if (PfnMutexHeld) {
    00511         UNLOCK_PFN (OldIrql);
    00512         *Waited += 1;
    00513     }
    00514
    00515     PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00516
    00517     *Waited += MiMakeSystemAddressValid (PointerPte, TargetProcess);
    00518
    00519     if (PfnMutexHeld) {
    00520         LOCK_PFN (OldIrql);
    00521     }
    00522     return TRUE;
    00523 }
    00524
    00525 #if defined (_WIN64)
    00526
    00527 ULONG
    00528 MiMakePpeExistAndMakeValid (
    00529     IN PMMPTE PointerPpe,
    00530     IN PEPROCESS TargetProcess,
    00531     IN ULONG PfnMutexHeld
    00532     )
    00533
    00534 /*++
    00535
    00536 Routine Description:
    00537
    00538     This routine examines the specified Page Directory Parent Entry to
    00539     determine if the page directory page mapped by the PPE exists.
    00540
    00541     If the page directory page exists and is not currently in memory, the
    00542     working set mutex and, if held, the PFN mutex are released and the
    00543     page directory page is faulted into the working set.  The mutexes are
    00544     reacquired.
    00545
    00546     If the PPE exists, the function returns true.
    00547
    00548     If the PPE does not exist, a zero filled page directory is created
    00549     and it is brought into the working set.  In this case the return
    00550     value is FALSE.
    00551
    00552 Arguments:
    00553
    00554     PointerPpe - Supplies a pointer to the PPE to examine and bring
    00555                  into the working set.
    00556
    00557     TargetProcess - Supplies a pointer to the current process.
    00558
    00559     PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    00560                    otherwise.
    00561
    00562 Return Value:
    00563
    00564     TRUE if the PDE exists, FALSE if the PPE was created.
    00565
    00566 Environment:
    00567
    00568     Kernel mode, APCs disabled, WorkingSetLock held.
    00569
    00570 --*/
    00571
    00572 {
    00573     PMMPTE PointerPde;
    00574     KIRQL OldIrql;
    00575     ULONG ReturnValue;
    00576
    00577     if (PointerPpe->u.Hard.Valid == 1) {
    00578
    00579         //
    00580         // Already valid.
    00581         //
    00582
    00583         return TRUE;
    00584     }
    00585
    00586     //
    00587     // Deal with the page directory page first.
    00588     //
    00589
    00590     if (PointerPpe->u.Long == 0) {
    00591         ReturnValue = FALSE;
    00592     } else {
    00593         ReturnValue = TRUE;
    00594     }
    00595
    00596     //
    00597     // Page directory parent entry not valid, make it valid.
    00598     //
    00599
    00600     OldIrql = APC_LEVEL;
    00601
    00602     if (PfnMutexHeld) {
    00603         UNLOCK_PFN (OldIrql);
    00604     }
    00605
    00606     //
    00607     // Fault it in.
    00608     //
    00609
    00610     PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
    00611     MiMakeSystemAddressValid (PointerPde, TargetProcess);
    00612
    00613     ASSERT (PointerPpe->u.Hard.Valid == 1);
    00614
    00615     if (PfnMutexHeld) {
    00616         LOCK_PFN (OldIrql);
    00617     }
    00618
    00619     return ReturnValue;
    00620 }
    00621 #endif
    00622
    00623 ULONG
    00624 MiMakePdeExistAndMakeValid (
    00625     IN PMMPTE PointerPde,
    00626     IN PEPROCESS TargetProcess,
    00627     IN ULONG PfnMutexHeld
    00628     )
    00629
    00630 /*++
    00631
    00632 Routine Description:
    00633
    00634     This routine examines the specified Page Directory Parent Entry to
    00635     determine if the page directory page mapped by the PPE exists.  If it does,
    00636     then it examines the specified Page Directory Entry to determine if
    00637     the page table page mapped by the PDE exists.
    00638
    00639     If the page table page exists and is not currently in memory, the
    00640     working set mutex and, if held, the PFN mutex are released and the
    00641     page table page is faulted into the working set.  The mutexes are
    00642     reacquired.
    00643
    00644     If the PDE exists, the function returns true.
    00645
    00646     If the PDE does not exist, a zero filled PTE is created and it
    00647     too is brought into the working set.  In this case the return
    00648     value is FALSE.
    00649
    00650 Arguments:
    00651
    00652     PointerPde - Supplies a pointer to the PDE to examine and bring
    00653                  into the working set.
    00654
    00655     TargetProcess - Supplies a pointer to the current process.
    00656
    00657     PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE
    00658                    otherwise.
    00659
    00660 Return Value:
    00661
    00662     TRUE if the PDE exists, FALSE if the PDE was created.
    00663
    00664 Environment:
    00665
    00666     Kernel mode, APCs disabled, WorkingSetLock held.
    00667
    00668 --*/
    00669
    00670 {
    00671     PMMPTE PointerPte;
    00672     PMMPTE PointerPpe;
    00673     KIRQL OldIrql;
    00674     ULONG ReturnValue;
    00675
    00676     PointerPpe = MiGetPteAddress (PointerPde);
    00677
    00678     if (PointerPpe->u.Hard.Valid == 1 && PointerPde->u.Hard.Valid == 1) {
    00679
    00680         //
    00681         // Already valid.
    00682         //
    00683
    00684         return TRUE;
    00685     }
    00686
    00687     //
    00688     // Deal with the page directory page first.
    00689     //
    00690
    00691     if (PointerPpe->u.Long == 0) {
    00692         ReturnValue = FALSE;
    00693     } else {
    00694         ReturnValue = TRUE;
    00695     }
    00696
    00697     //
    00698     // Page directory parent entry not valid, make it valid.
    00699     //
    00700
    00701     OldIrql = APC_LEVEL;
    00702
    00703     do {
    00704
    00705         if (PfnMutexHeld) {
    00706             UNLOCK_PFN (OldIrql);
    00707         }
    00708
    00709         //
    00710         // Fault it in.
    00711         //
    00712
    00713         MiMakeSystemAddressValid (PointerPde, TargetProcess);
    00714
    00715         ASSERT (PointerPpe->u.Hard.Valid == 1);
    00716
    00717         if (PfnMutexHeld) {
    00718             LOCK_PFN (OldIrql);
    00719         }
    00720
    00721         //
    00722         // Now deal with the page table page.
    00723         //
    00724
    00725         if (ReturnValue == TRUE) {
    00726             if (PointerPde->u.Long == 0) {
    00727                 ReturnValue = FALSE;
    00728             } else {
    00729                 ReturnValue = TRUE;
    00730             }
    00731         }
    00732
    00733         //
    00734         // Page directory entry not valid, make it valid.
    00735         //
    00736
    00737         OldIrql = APC_LEVEL;
    00738
    00739         if (PfnMutexHeld) {
    00740             UNLOCK_PFN (OldIrql);
    00741         }
    00742
    00743         PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
    00744
    00745         //
    00746         // Fault it in.
    00747         //
    00748
    00749         MiMakeSystemAddressValid (PointerPte, TargetProcess);
    00750
    00751         ASSERT (PointerPde->u.Hard.Valid == 1);
    00752
    00753         if (PfnMutexHeld) {
    00754             LOCK_PFN (OldIrql);
    00755         }
    00756
    00757     } while (PointerPpe->u.Hard.Valid == 0 || PointerPde->u.Hard.Valid == 0);
    00758
    00759     return ReturnValue;
    00760 }
    00761
    00762 ULONG
    00763 FASTCALL
    00764 MiMakeSystemAddressValid (
    00765     IN PVOID VirtualAddress,
    00766     IN PEPROCESS CurrentProcess
    00767     )
    00768
    00769 /*++
    00770
    00771 Routine Description:
    00772
    00773     This routine checks to see if the virtual address is valid, and if
    00774     not makes it valid.
    00775
    00776 Arguments:
    00777
    00778     VirtualAddress - Supplies the virtual address to make valid.
    00779
    00780     CurrentProcess - Supplies a pointer to the current process.
    00781
    00782 Return Value:
    00783
    00784     Returns TRUE if lock released and wait performed, FALSE otherwise.
    00785
    00786 Environment:
    00787
    00788     Kernel mode, APCs disabled, WorkingSetLock held.
    00789
    00790 --*/
    00791
    00792 {
    00793     NTSTATUS status;
    00794     LOGICAL WsHeldSafe;
    00795     ULONG Waited;
    00796
    00797     Waited = FALSE;
    00798
    00799     ASSERT (VirtualAddress > MM_HIGHEST_USER_ADDRESS);
    00800
    00801     ASSERT ((VirtualAddress < MM_PAGED_POOL_START) ||
    00802         (VirtualAddress > MmPagedPoolEnd));
    00803
    00804     while (!MmIsAddressValid(VirtualAddress)) {
    00805
    00806         //
    00807         // The virtual address is not present.  Release
    00808         // the working set mutex and fault it in.
    00809         //
    00810         // The working set lock may have been acquired safely or unsafely
    00811         // by our caller.  Handle both cases here and below.
    00812         //
    00813
    00814         UNLOCK_WS_REGARDLESS(CurrentProcess, WsHeldSafe);
    00815
    00816         status = MmAccessFault (FALSE, VirtualAddress, KernelMode, (PVOID)0);
    00817         if (!NT_SUCCESS(status)) {
    00818             KdPrint (("MM:page fault status %lx\n",status));
    00819             KeBugCheckEx (KERNEL_DATA_INPAGE_ERROR,
    00820                           1,
    00821                           (ULONG)status,
    00822                           (ULONG_PTR)CurrentProcess,
    00823                           (ULONG_PTR)VirtualAddress);
    00824         }
    00825
    00826         LOCK_WS_REGARDLESS(CurrentProcess, WsHeldSafe);
    00827
    00828         Waited = TRUE;
    00829     }
    00830
    00831     return Waited;
    00832 }
    00833
    00834
    00835 ULONG
    00836 FASTCALL
    00837 MiMakeSystemAddressValidPfnWs (
    00838     IN PVOID VirtualAddress,
    00839     IN PEPROCESS CurrentProcess OPTIONAL
    00840     )
    00841
    00842 /*++
    00843
    00844 Routine Description:
    00845
    00846     This routine checks to see if the virtual address is valid, and if
    00847     not makes it valid.
    00848
    00849 Arguments:
    00850
    00851     VirtualAddress - Supplies the virtual address to make valid.
    00852
    00853     CurrentProcess - Supplies a pointer to the current process, if the
    00854                      working set lock is not held, this value is NULL.
    00855
    00856 Return Value:
    00857
    00858     Returns TRUE if lock released and wait performed, FALSE otherwise.
    00859
    00860 Environment:
    00861
    00862     Kernel mode, APCs disabled, PFN lock held, working set lock held
    00863        if CurrentProcess != NULL.
    00864
    00865 --*/
    00866
    00867 {
    00868     NTSTATUS status;
    00869     ULONG Waited;
    00870     KIRQL OldIrql;
    00871     LOGICAL WsHeldSafe;
    00872
    00873     Waited = FALSE;
    00874     OldIrql = APC_LEVEL;
    00875
    00876     ASSERT (VirtualAddress > MM_HIGHEST_USER_ADDRESS);
    00877
    00878     while (!MmIsAddressValid(VirtualAddress)) {
    00879
    00880         //
    00881         // The virtual address is not present.  Release
    00882         // the working set mutex and fault it in.
    00883         //
    00884
    00885         UNLOCK_PFN (OldIrql);
    00886         if (CurrentProcess != NULL) {
    00887
    00888             //
    00889             // The working set lock may have been acquired safely or unsafely
    00890             // by our caller.  Handle both cases here and below.
    00891             //
    00892
    00893             UNLOCK_WS_REGARDLESS(CurrentProcess, WsHeldSafe);
    00894         }
    00895         status = MmAccessFault (FALSE, VirtualAddress, KernelMode, (PVOID)0);
    00896         if (!NT_SUCCESS(status)) {
    00897             KdPrint (("MM:page fault status %lx\n",status));
    00898             KeBugCheckEx (KERNEL_DATA_INPAGE_ERROR,
    00899                           2,
    00900                           (ULONG)status,
    00901                           (ULONG_PTR)CurrentProcess,
    00902                           (ULONG_PTR)VirtualAddress);
    00903         }
    00904         if (CurrentProcess != NULL) {
    00905             LOCK_WS_REGARDLESS(CurrentProcess, WsHeldSafe);
    00906         }
    00907         LOCK_PFN (OldIrql);
    00908
    00909         Waited = TRUE;
    00910     }
    00911     return Waited;
    00912 }
    00913
    00914 ULONG
    00915 FASTCALL
    00916 MiMakeSystemAddressValidPfnSystemWs (
    00917     IN PVOID VirtualAddress
    00918     )
    00919
    00920 /*++
    00921
    00922 Routine Description:
    00923
    00924     This routine checks to see if the virtual address is valid, and if
    00925     not makes it valid.
    00926
    00927 Arguments:
    00928
    00929     VirtualAddress - Supplies the virtual address to make valid.
    00930
    00931 Return Value:
    00932
    00933     Returns TRUE if lock released and wait performed, FALSE otherwise.
    00934
    00935 Environment:
    00936
    00937     Kernel mode, APCs disabled, PFN lock held, system working set lock held.
    00938
    00939 --*/
    00940
    00941 {
    00942     NTSTATUS status;
    00943     ULONG Waited;
    00944     KIRQL OldIrql;
    00945     KIRQL OldIrqlWs;
    00946     LOGICAL SessionSpace;
    00947
    00948     Waited = FALSE;
    00949     OldIrql = APC_LEVEL;
    00950     OldIrqlWs = APC_LEVEL;
    00951
    00952     ASSERT (VirtualAddress > MM_HIGHEST_USER_ADDRESS);
    00953
    00954     SessionSpace = MI_IS_SESSION_IMAGE_ADDRESS (VirtualAddress);
    00955
    00956     while (!MmIsAddressValid(VirtualAddress)) {
    00957
    00958         //
    00959         // The virtual address is not present.  Release
    00960         // the working set mutex and fault it in.
    00961         //
    00962
    00963         UNLOCK_PFN (OldIrql);
    00964
    00965         if (SessionSpace == TRUE) {
    00966             UNLOCK_SESSION_SPACE_WS (OldIrqlWs);
    00967         }
    00968         else {
    00969             UNLOCK_SYSTEM_WS (OldIrqlWs);
    00970         }
    00971
    00972         status = MmAccessFault (FALSE, VirtualAddress, KernelMode, (PVOID)0);
    00973         if (!NT_SUCCESS(status)) {
    00974             KdPrint (("MM:page fault status %lx\n",status));
    00975             KeBugCheckEx (KERNEL_DATA_INPAGE_ERROR,
    00976                           2,
    00977                           (ULONG)status,
    00978                           (ULONG_PTR)0,
    00979                           (ULONG_PTR)VirtualAddress);
    00980         }
    00981         if (SessionSpace == TRUE) {
    00982             LOCK_SESSION_SPACE_WS (OldIrqlWs);
    00983         }
    00984         else {
    00985             LOCK_SYSTEM_WS (OldIrqlWs);
    00986         }
    00987         LOCK_PFN (OldIrql);
    00988
    00989         Waited = TRUE;
    00990     }
    00991     return Waited;
    00992 }
    00993
    00994 ULONG
    00995 FASTCALL
    00996 MiMakeSystemAddressValidPfn (
    00997     IN PVOID VirtualAddress
    00998     )
    00999
    01000 /*++
    01001
    01002 Routine Description:
    01003
    01004     This routine checks to see if the virtual address is valid, and if
    01005     not makes it valid.
    01006
    01007 Arguments:
    01008
    01009     VirtualAddress - Supplies the virtual address to make valid.
    01010
    01011 Return Value:
    01012
    01013     Returns TRUE if lock released and wait performed, FALSE otherwise.
    01014
    01015 Environment:
    01016
    01017     Kernel mode, APCs disabled, only the PFN Lock held.
    01018
    01019 --*/
    01020
    01021 {
    01022     NTSTATUS status;
    01023     KIRQL OldIrql = APC_LEVEL;
    01024
    01025     ULONG Waited = FALSE;
    01026
    01027     ASSERT (VirtualAddress > MM_HIGHEST_USER_ADDRESS);
    01028
    01029     while (!MmIsAddressValid(VirtualAddress)) {
    01030
    01031         //
    01032         // The virtual address is not present.  Release
    01033         // the working set mutex and fault it in.
    01034         //
    01035
    01036         UNLOCK_PFN (OldIrql);
    01037
    01038         status = MmAccessFault (FALSE, VirtualAddress, KernelMode, (PVOID)0);
    01039         if (!NT_SUCCESS(status)) {
    01040             KdPrint (("MM:page fault status %lx\n",status));
    01041             KeBugCheckEx (KERNEL_DATA_INPAGE_ERROR,
    01042                           3,
    01043                           (ULONG)status,
    01044                           (ULONG_PTR)VirtualAddress,
    01045                           0);
    01046         }
    01047
    01048         LOCK_PFN (OldIrql);
    01049
    01050         Waited = TRUE;
    01051     }
    01052
    01053     return Waited;
    01054 }
    01055
    01056 ULONG
    01057 FASTCALL
    01058 MiLockPagedAddress (
    01059     IN PVOID VirtualAddress,
    01060     IN ULONG PfnLockHeld
    01061     )
    01062
    01063 /*++
    01064
    01065 Routine Description:
    01066
    01067     This routine checks to see if the virtual address is valid, and if
    01068     not makes it valid.
    01069
    01070 Arguments:
    01071
    01072     VirtualAddress - Supplies the virtual address to make valid.
    01073
    01074     CurrentProcess - Supplies a pointer to the current process.
    01075
    01076 Return Value:
    01077
    01078     Returns TRUE if lock released and wait performed, FALSE otherwise.
    01079
    01080 Environment:
    01081
    01082     Kernel mode.
    01083
    01084 --*/
    01085
    01086 {
    01087
    01088     PMMPTE PointerPte;
    01089     PMMPFN Pfn1;
    01090     KIRQL OldIrql;
    01091     ULONG Waited = FALSE;
    01092
    01093     PointerPte = MiGetPteAddress(VirtualAddress);
    01094
    01095     //
    01096     // The address must be within paged pool.
    01097     //
    01098
    01099     if (PfnLockHeld == FALSE) {
    01100         LOCK_PFN2 (OldIrql);
    01101     }
    01102
    01103     if (PointerPte->u.Hard.Valid == 0) {
    01104
    01105         Waited = MiMakeSystemAddressValidPfn (
    01106                                 MiGetVirtualAddressMappedByPte(PointerPte));
    01107
    01108     }
    01109
    01110     Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01111     MI_ADD_LOCKED_PAGE_CHARGE(Pfn1, 6);
    01112     Pfn1->u3.e2.ReferenceCount += 1;
    01113
    01114     if (PfnLockHeld == FALSE) {
    01115         UNLOCK_PFN2 (OldIrql);
    01116     }
    01117     return Waited;
    01118 }
    01119
    01120
    01121 VOID
    01122 FASTCALL
    01123 MiUnlockPagedAddress (
    01124     IN PVOID VirtualAddress,
    01125     IN ULONG PfnLockHeld
    01126     )
    01127
    01128 /*++
    01129
    01130 Routine Description:
    01131
    01132     This routine checks to see if the virtual address is valid, and if
    01133     not makes it valid.
    01134
    01135 Arguments:
    01136
    01137     VirtualAddress - Supplies the virtual address to make valid.
    01138
    01139
    01140 Return Value:
    01141
    01142     None.
    01143
    01144 Environment:
    01145
    01146     Kernel mode.  PFN LOCK MUST NOT BE HELD.
    01147
    01148 --*/
    01149
    01150 {
    01151     PMMPFN Pfn1;
    01152     PMMPTE PointerPte;
    01153     KIRQL OldIrql;
    01154     PFN_NUMBER PageFrameIndex;
    01155
    01156     PointerPte = MiGetPteAddress(VirtualAddress);
    01157
    01158     //
    01159     // Address must be within paged pool.
    01160     //
    01161
    01162     if (PfnLockHeld == FALSE) {
    01163         LOCK_PFN2 (OldIrql);
    01164     }
    01165
    01166     ASSERT (PointerPte->u.Hard.Valid == 1);
    01167     PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
    01168     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    01169
    01170     ASSERT (Pfn1->u3.e2.ReferenceCount > 1);
    01171
    01172     MI_REMOVE_LOCKED_PAGE_CHARGE(Pfn1, 7);
    01173
    01174     MiDecrementReferenceCount (PageFrameIndex);
    01175
    01176     if (PfnLockHeld == FALSE) {
    01177         UNLOCK_PFN2 (OldIrql);
    01178     }
    01179     return;
    01180 }
    01181
    01182 VOID
    01183 FASTCALL
    01184 MiZeroPhysicalPage (
    01185     IN PFN_NUMBER PageFrameIndex,
    01186     IN ULONG PageColor
    01187     )
    01188
    01189 /*++
    01190
    01191 Routine Description:
    01192
    01193     This procedure maps the specified physical page into hyper space
    01194     and fills the page with zeros.
    01195
    01196 Arguments:
    01197
    01198     PageFrameIndex - Supplies the physical page number to fill with
    01199                     zeroes.
    01200
    01201 Return Value:
    01202
    01203     none.
    01204
    01205 Environment:
    01206
    01207     Kernel mode.
    01208
    01209 --*/
    01210
    01211 {
    01212     PULONG va;
    01213     KIRQL OldIrql;
    01214
    01215 #if defined(_ALPHA_)
    01216
    01217     HalZeroPage((PVOID)ULongToPtr((PageColor & MM_COLOR_MASK) << PAGE_SHIFT),
    01218                 (PVOID)ULongToPtr((PageColor & MM_COLOR_MASK) << PAGE_SHIFT),
    01219                 PageFrameIndex);
    01220 #else
    01221
    01222     UNREFERENCED_PARAMETER (PageColor);
    01223
    01224     va = (PULONG)MiMapPageInHyperSpace (PageFrameIndex, &OldIrql);
    01225
    01226 #if defined(_X86_)
    01227
    01228     KeZeroPage(va);
    01229
    01230 #else
    01231
    01232     RtlZeroMemory (va, PAGE_SIZE);
    01233
    01234 #endif // X86
    01235
    01236     MiUnmapPageInHyperSpace (OldIrql);
    01237
    01238 #endif // ALPHA
    01239
    01240     return;
    01241 }
    01242
    01243 VOID
    01244 FASTCALL
    01245 MiRestoreTransitionPte (
    01246     IN PFN_NUMBER PageFrameIndex
    01247     )
    01248
    01249 /*++
    01250
    01251 Routine Description:
    01252
    01253     This procedure restores the original contents into the PTE (which could
    01254     be a prototype PTE) referred to by the PFN database for the specified
    01255     physical page.  It also updates all necessary data structures to
    01256     reflect the fact that the referenced PTE is no longer in transition.
    01257
    01258     The physical address of the referenced PTE is mapped into hyper space
    01259     of the current process and the PTE is then updated.
    01260
    01261 Arguments:
    01262
    01263     PageFrameIndex - Supplies the physical page number which refers to a
    01264                     transition PTE.
    01265
    01266 Return Value:
    01267
    01268     none.
    01269
    01270 Environment:
    01271
    01272     Must be holding the PFN database mutex with APCs disabled.
    01273
    01274 --*/
    01275
    01276 {
    01277     PMMPFN Pfn1;
    01278     PMMPTE PointerPte;
    01279     PSUBSECTION Subsection;
    01280     PCONTROL_AREA ControlArea;
    01281     KIRQL OldIrql = 99;
    01282
    01283     Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
    01284
    01285     ASSERT (Pfn1->u3.e1.PageLocation == StandbyPageList);
    01286
    01287     if (Pfn1->u3.e1.PrototypePte) {
    01288
    01289         if (MmIsAddressValid (Pfn1->PteAddress)) {
    01290             PointerPte = Pfn1->PteAddress;
    01291         } else {
    01292
    01293             //
    01294             // The page containing the prototype PTE is not valid,
    01295             // map the page into hyperspace and reference it that way.
    01296             //
    01297
    01298             PointerPte = MiMapPageInHyperSpace (Pfn1->PteFrame, &OldIrql);
    01299             PointerPte = (PMMPTE)((PCHAR)PointerPte +
    01300                                     MiGetByteOffset(Pfn1->PteAddress));
    01301         }
    01302
    01303         ASSERT ((MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) == PageFrameIndex) &&
    01304                  (PointerPte->u.Hard.Valid == 0));
    01305
    01306         //
    01307         // This page is referenced by a prototype PTE.  The
    01308         // segment structures need to be updated when the page
    01309         // is removed from the transition state.
    01310         //
    01311
    01312         if (Pfn1->OriginalPte.u.Soft.Prototype) {
    01313
    01314             //
    01315             // The prototype PTE is in subsection format, calculate the
    01316             // address of the control area for the subsection and decrement
    01317             // the number of PFN references to the control area.
    01318             //
    01319             // Calculate address of subsection for this prototype PTE.
    01320             //
    01321
    01322             Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
    01323             ControlArea = Subsection->ControlArea;
    01324             ControlArea->NumberOfPfnReferences -= 1;
    01325             ASSERT ((LONG)ControlArea->NumberOfPfnReferences >= 0);
    01326
    01327             MiCheckForControlAreaDeletion (ControlArea);
    01328         }
    01329
    01330     } else {
    01331
    01332         //
    01333         // The page points to a page or page table page which may not be
    01334         // for the current process.  Map the page into hyperspace and
    01335         // reference it through hyperspace.  If the page resides in
    01336         // system space (but not session space), it does not need to be
    01337         // mapped as all PTEs for system space must be resident.  Session
    01338         // space PTEs are only mapped per session so access to them must
    01339         // also go through hyperspace.
    01340         //
    01341
    01342         PointerPte = Pfn1->PteAddress;
    01343
    01344         if (PointerPte < MiGetPteAddress (MM_SYSTEM_SPACE_START) ||
    01345                MI_IS_SESSION_PTE (PointerPte)) {
    01346
    01347             PointerPte = MiMapPageInHyperSpace (Pfn1->PteFrame, &OldIrql);
    01348             PointerPte = (PMMPTE)((PCHAR)PointerPte +
    01349                                        MiGetByteOffset(Pfn1->PteAddress));
    01350         }
    01351         ASSERT ((MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte) == PageFrameIndex) &&
    01352                  (PointerPte->u.Hard.Valid == 0));
    01353
    01354         MI_CAPTURE_USED_PAGETABLE_ENTRIES (Pfn1);
    01355
    01356 #if _WIN64
    01357 #if DBGXX
    01358         MiCheckPageTableTrim(PointerPte);
    01359 #endif
    01360 #endif
    01361     }
    01362
    01363     ASSERT (Pfn1->OriginalPte.u.Hard.Valid == 0);
    01364     ASSERT (!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
    01365              (Pfn1->OriginalPte.u.Soft.Transition == 1)));
    01366
    01367     MI_WRITE_INVALID_PTE (PointerPte, Pfn1->OriginalPte);
    01368
    01369     if (OldIrql != 99) {
    01370         MiUnmapPageInHyperSpace (OldIrql);
    01371     }
    01372
    01373     //
    01374     // The PTE has been restored to its original contents and is
    01375     // no longer in transition.  Decrement the share count on
    01376     // the page table page which contains the PTE.
    01377     //
    01378
    01379     MiDecrementShareCount (Pfn1->PteFrame);
    01380
    01381     return;
    01382 }
    01383
    01384 PSUBSECTION
    01385 MiGetSubsectionAndProtoFromPte (
    01386     IN PMMPTE PointerPte,
    01387     OUT PMMPTE *ProtoPte,
    01388     IN PEPROCESS Process
    01389     )
    01390
    01391 /*++
    01392
    01393 Routine Description:
    01394
    01395     This routine examines the contents of the supplied PTE (which must
    01396     map a page within a section) and determines the address of the
    01397     subsection in which the PTE is contained.
    01398
    01399 Arguments:
    01400
    01401     PointerPte - Supplies a pointer to the PTE.
    01402
    01403     ProtoPte - Supplies a pointer to a PMMPTE which receives the
    01404                address of the prototype PTE which is mapped by the supplied
    01405                PointerPte.
    01406
    01407     Process - Supplies a pointer to the current process.
    01408
    01409 Return Value:
    01410
    01411     Returns the pointer to the subsection for this PTE.
    01412
    01413 Environment:
    01414
    01415     Kernel mode - Must be holding the PFN database lock and
    01416                   working set mutex (acquired safely) with APCs disabled.
    01417
    01418 --*/
    01419
    01420 {
    01421     PMMPTE PointerProto;
    01422     PMMPFN Pfn1;
    01423
    01424     if (PointerPte->u.Hard.Valid == 1) {
    01425         Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
    01426         *ProtoPte = Pfn1->PteAddress;
    01427         return MiGetSubsectionAddress (&Pfn1->OriginalPte);
    01428     }
    01429
    01430     PointerProto = MiPteToProto (PointerPte);
    01431     *ProtoPte = PointerProto;
    01432
    01433     MiMakeSystemAddressValidPfnWs (PointerProto, Process);
    01434
    01435     if (PointerProto->u.Hard.Valid == 1) {
    01436         //
    01437         // Prototype Pte is valid.
    01438         //
    01439
    01440         Pfn1 = MI_PFN_ELEMENT (PointerProto->u.Hard.PageFrameNumber);
    01441         return MiGetSubsectionAddress (&Pfn1->OriginalPte);
    01442     }
    01443
    01444     if ((PointerProto->u.Soft.Transition == 1) &&
    01445          (PointerProto->u.Soft.Prototype == 0)) {
    01446
    01447         //
    01448         // Prototype Pte is in transition.
    01449         //
    01450
    01451         Pfn1 = MI_PFN_ELEMENT (PointerProto->u.Trans.PageFrameNumber);
    01452         return MiGetSubsectionAddress (&Pfn1->OriginalPte);
    01453     }
    01454
    01455     ASSERT (PointerProto->u.Soft.Prototype == 1);
    01456     return MiGetSubsectionAddress (PointerProto);
    01457 }
    01458
    01459 BOOLEAN
    01460 MmIsNonPagedSystemAddressValid (
    01461     IN PVOID VirtualAddress
    01462     )
    01463
    01464 /*++
    01465
    01466 Routine Description:
    01467
    01468     For a given virtual address this function returns TRUE if the address
    01469     is within the nonpagable portion of the system's address space,
    01470     FALSE otherwise.
    01471
    01472 Arguments:
    01473
    01474     VirtualAddress - Supplies the virtual address to check.
    01475
    01476 Return Value:
    01477
    01478     TRUE if the address is within the nonpagable portion of the system
    01479     address space, FALSE otherwise.
    01480
    01481 Environment:
    01482
    01483     Kernel mode.
    01484
    01485 --*/
    01486
    01487 {
    01488     //
    01489     // Return TRUE if address is within the nonpagable portion
    01490     // of the system.  Check limits for paged pool and if not within
    01491     // those limits, return TRUE.
    01492     //
    01493
    01494     if ((VirtualAddress >= MmPagedPoolStart) &&
    01495         (VirtualAddress <= MmPagedPoolEnd)) {
    01496         return FALSE;
    01497     }
    01498
    01499     return TRUE;
    01500 }
    01501
    01502 VOID
    01503 MmHibernateInformation (
    01504     IN PVOID    MemoryMap,
    01505     OUT PULONG_PTR  HiberVa,
    01506     OUT PPHYSICAL_ADDRESS HiberPte
    01507     )
    01508 {
    01509     //
    01510     // Mark PTE page where the 16 dump PTEs reside as needing cloned
    01511     //
    01512
    01513     PoSetHiberRange (
    01514         MemoryMap,
    01515         PO_MEM_CLONE,
    01516         MmCrashDumpPte,
    01517         1,
    01518         ' etP'
    01519         );
    01520
    01521     //
    01522     // Return the dump PTEs to the loader (as it needs to use them
    01523     // to map it's relocation code into the kernel space on the
    01524     // final bit of restoring memory)
    01525     //
    01526
    01527     *HiberVa = (ULONG_PTR) MiGetVirtualAddressMappedByPte(MmCrashDumpPte);
    01528     *HiberPte = MmGetPhysicalAddress(MmCrashDumpPte);
    01529 }
    01530
    01531 #if _WIN64
    01532 #if DBGXX
    01533
    01534 ULONG zok[16];
    01535
    01536 VOID
    01537 MiCheckPageTableTrim(
    01538     IN PMMPTE PointerPte
    01539 )
    01540 {
    01541     ULONG i;
    01542     PFN_NUMBER Frame;
    01543     PMMPFN Pfn;
    01544     PMMPTE FrameData;
    01545     PMMPTE p;
    01546     ULONG count;
    01547
    01548     Frame = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte);
    01549     Pfn = MI_PFN_ELEMENT (Frame);
    01550
    01551     if (Pfn->UsedPageTableEntries) {
    01552
    01553         count = 0;
    01554
    01555         p = FrameData = (PMMPTE)KSEG_ADDRESS (Frame);
    01556
    01557         for (i = 0; i < PTE_PER_PAGE; i += 1, p += 1) {
    01558             if (p->u.Long != 0) {
    01559                 count += 1;
    01560             }
    01561         }
    01562
    01563         DbgPrint ("MiCheckPageTableTrim: %I64X %I64X %I64X\n",
    01564             PointerPte, Pfn, Pfn->UsedPageTableEntries);
    01565
    01566         if (count != Pfn->UsedPageTableEntries) {
    01567             DbgPrint ("MiCheckPageTableTrim1: %I64X %I64X %I64X %I64X\n",
    01568                 PointerPte, Pfn, Pfn->UsedPageTableEntries, count);
    01569             DbgBreakPoint();
    01570         }
    01571         zok[0] += 1;
    01572     }
    01573     else {
    01574         zok[1] += 1;
    01575     }
    01576 }
    01577
    01578 VOID
    01579 MiCheckPageTableInPage(
    01580     IN PMMPFN Pfn,
    01581     IN PMMINPAGE_SUPPORT Support
    01582 )
    01583 {
    01584     ULONG i;
    01585     PFN_NUMBER Frame;
    01586     PMMPTE FrameData;
    01587     PMMPTE p;
    01588     ULONG count;
    01589
    01590     if (Support->UsedPageTableEntries) {
    01591
    01592         Frame = (PFN_NUMBER)((PMMPFN)Pfn - (PMMPFN)MmPfnDatabase);
    01593
    01594         count = 0;
    01595
    01596         p = FrameData = (PMMPTE)KSEG_ADDRESS (Frame);
    01597
    01598         for (i = 0; i < PTE_PER_PAGE; i += 1, p += 1) {
    01599             if (p->u.Long != 0) {
    01600                 count += 1;
    01601             }
    01602         }
    01603
    01604         DbgPrint ("MiCheckPageTableIn: %I64X %I64X %I64X\n",
    01605             FrameData, Pfn, Support->UsedPageTableEntries);
    01606
    01607         if (count != Support->UsedPageTableEntries) {
    01608             DbgPrint ("MiCheckPageTableIn1: %I64X %I64X %I64X %I64X\n",
    01609                 FrameData, Pfn, Support->UsedPageTableEntries, count);
    01610             DbgBreakPoint();
    01611         }
    01612         zok[2] += 1;
    01613     }
    01614     else {
    01615         zok[3] += 1;
    01616     }
    01617 }
    01618 #endif
    01619 #endif