test: sysptes.c Source File

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

# sysptes.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007    sysptes.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the routines which reserve and release
    00012     system wide PTEs reserved within the non paged portion of the
    00013     system space.  These PTEs are used for mapping I/O devices
    00014     and mapping kernel stacks for threads.
    00015
    00016 Author:
    00017
    00018     Lou Perazzoli (loup) 6-Apr-1989
    00019
    00020 Revision History:
    00021
    00022 --*/
    00023
    00024 #include "mi.h"
    00025
    00026 VOID
    00027 MiFeedSysPtePool (
    00028     IN ULONG Index
    00029     );
    00030
    00031 PMMPTE
    00032 MiReserveSystemPtes2 (
    00033     IN ULONG NumberOfPtes,
    00034     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
    00035     IN ULONG Alignment,
    00036     IN ULONG Offset,
    00037     IN ULONG BugCheckOnFailure
    00038     );
    00039
    00040 ULONG
    00041 MiGetSystemPteListCount (
    00042     IN ULONG ListSize
    00043     );
    00044
    00045 #ifdef ALLOC_PRAGMA
    00046 #pragma alloc_text(INIT,MiInitializeSystemPtes)
    00047 #pragma alloc_text(INIT,MiAddSystemPtes)
    00048 #pragma alloc_text(MISYSPTE,MiReserveSystemPtes)
    00049 #pragma alloc_text(MISYSPTE,MiReserveSystemPtes2)
    00050 #pragma alloc_text(MISYSPTE,MiFeedSysPtePool)
    00051 #pragma alloc_text(MISYSPTE,MiReleaseSystemPtes)
    00052 #pragma alloc_text(MISYSPTE,MiGetSystemPteListCount)
    00053 #endif
    00054
    00055 #ifdef _MI_GUARD_PTE_
    00056 #define _MI_SYSPTE_DEBUG_ 1
    00057 #endif
    00058
    00059 #ifdef _MI_SYSPTE_DEBUG_
    00060 typedef struct _MMPTE_TRACKER {
    00061     USHORT   NumberOfPtes;
    00062     BOOLEAN  InUse;
    00063     BOOLEAN  Reserved;
    00064 } MMPTE_TRACKER, *PMMPTE_TRACKER;
    00065
    00066 PMMPTE_TRACKER MiPteTracker;
    00067 #endif
    00068
    00069 ULONG MmTotalFreeSystemPtes[MaximumPtePoolTypes];
    00070 PMMPTE MmSystemPtesStart[MaximumPtePoolTypes];
    00071 PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes];
    00072
    00073 #define MM_MIN_SYSPTE_FREE 500
    00074 #define MM_MAX_SYSPTE_FREE 3000
    00075
    00076 PMMPTE MmFlushPte1;
    00077
    00078 ULONG MmFlushCounter;
    00079
    00080 //
    00081 // PTEs are binned at sizes 1, 2, 4, 8, and 16.
    00082 //
    00083
    00084 #ifdef _ALPHA_
    00085
    00086 //
    00087 // Alpha has an 8k page size and stacks consume 9 pages (including guard page).
    00088 //
    00089
    00090 ULONG MmSysPteIndex[MM_SYS_PTE_TABLES_MAX] = {1,2,4,9,16};
    00091
    00092 UCHAR MmSysPteTables[17] = {0,0,1,2,2,3,3,3,3,3,4,4,4,4,4,4,4};
    00093
    00094 #else
    00095
    00096 ULONG MmSysPteIndex[MM_SYS_PTE_TABLES_MAX] = {1,2,4,8,16};
    00097
    00098 UCHAR MmSysPteTables[17] = {0,0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4};
    00099 #endif
    00100
    00101 MMPTE MmFreeSysPteListBySize [MM_SYS_PTE_TABLES_MAX];
    00102 PMMPTE MmLastSysPteListBySize [MM_SYS_PTE_TABLES_MAX];
    00103 ULONG MmSysPteListBySizeCount [MM_SYS_PTE_TABLES_MAX];
    00104 ULONG MmSysPteMinimumFree [MM_SYS_PTE_TABLES_MAX] = {100,50,30,20,20};
    00105
    00106 //
    00107 // Initial sizes for PTE lists.
    00108 //
    00109
    00110 #define MM_PTE_LIST_1  400
    00111 #define MM_PTE_LIST_2  100
    00112 #define MM_PTE_LIST_4   60
    00113 #define MM_PTE_LIST_8   50
    00114 #define MM_PTE_LIST_16  40
    00115
    00116 #define MM_PTE_TABLE_LIMIT 16
    00117
    00118 PMMPTE
    00119 MiReserveSystemPtes2 (
    00120     IN ULONG NumberOfPtes,
    00121     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
    00122     IN ULONG Alignment,
    00123     IN ULONG Offset,
    00124     IN ULONG BugCheckOnFailure
    00125     );
    00126
    00127 VOID
    00128 MiFeedSysPtePool (
    00129     IN ULONG Index
    00130     );
    00131
    00132 VOID
    00133 MiDumpSystemPtes (
    00134     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    00135     );
    00136
    00137 ULONG
    00138 MiCountFreeSystemPtes (
    00139     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    00140     );
    00141
    00142 PVOID
    00143 MiGetHighestPteConsumer (
    00144     OUT PULONG_PTR NumberOfPtes
    00145     );
    00146
    00147 #ifdef _MI_SYSPTE_DEBUG_
    00148 ULONG MiPtesChecked[0x10];
    00149
    00150
    00151 VOID
    00152 MiValidateSystemPtes (
    00153     IN PMMPTE StartingPte,
    00154     IN ULONG NumberOfPtes
    00155     )
    00156
    00157 /*++
    00158
    00159 Routine Description:
    00160
    00161     This function validates the PTE range passed in, guaranteeing that it
    00162     doesn't overlap with any free system PTEs.  This enables us to catch
    00163     callers that are freeing one too many PTEs.
    00164
    00165 Arguments:
    00166
    00167     StartingPte - Supplies the first PTE being freed.
    00168
    00169     NumberOfPtes - Supplies the number of PTEs being freed.
    00170
    00171 Return Value:
    00172
    00173     None.
    00174
    00175 Environment:
    00176
    00177     Kernel mode, DISPATCH_LEVEL or below.
    00178
    00179 --*/
    00180
    00181 {
    00182     KIRQL OldIrql;
    00183     ULONG Index;
    00184     PMMPTE EndingPte;
    00185     PMMPTE PointerPte1;
    00186     PMMPTE PointerFreedPte;
    00187     ULONG PtesInThisBucket;
    00188     ULONG j;
    00189
    00190     ASSERT (NumberOfPtes != 0);
    00191
    00192     EndingPte = StartingPte + NumberOfPtes - 1;
    00193
    00194     MiLockSystemSpace(OldIrql);
    00195
    00196     for (Index = 0; Index < MM_SYS_PTE_TABLES_MAX; Index += 1) {
    00197
    00198         PointerPte1 = &MmFreeSysPteListBySize[Index];
    00199
    00200         while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    00201
    00202             MiPtesChecked[0] += 1;
    00203
    00204             PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry;
    00205
    00206             PtesInThisBucket = MmSysPteIndex[Index];
    00207
    00208             if (StartingPte >= PointerPte1 && StartingPte < PointerPte1 + PtesInThisBucket) {
    00209                 DbgPrint("MiValidateSystemPtes1: %x %x %x %x %x %x\n",
    00210                     StartingPte,
    00211                     EndingPte,
    00212                     NumberOfPtes,
    00213                     PointerPte1,
    00214                     PtesInThisBucket,
    00215                     Index);
    00216                 DbgBreakPoint ();
    00217             }
    00218
    00219             if (EndingPte >= PointerPte1 && EndingPte < PointerPte1 + PtesInThisBucket) {
    00220                 DbgPrint("MiValidateSystemPtes2: %x %x %x %x %x %x\n",
    00221                     StartingPte,
    00222                     EndingPte,
    00223                     NumberOfPtes,
    00224                     PointerPte1,
    00225                     PtesInThisBucket,
    00226                     Index);
    00227                 DbgBreakPoint ();
    00228             }
    00229
    00230             if (StartingPte < PointerPte1 && EndingPte >= PointerPte1 + PtesInThisBucket) {
    00231                 DbgPrint("MiValidateSystemPtes3: %x %x %x %x %x %x\n",
    00232                     StartingPte,
    00233                     EndingPte,
    00234                     NumberOfPtes,
    00235                     PointerPte1,
    00236                     PtesInThisBucket,
    00237                     Index);
    00238                 DbgBreakPoint ();
    00239             }
    00240
    00241             PointerFreedPte = PointerPte1;
    00242             for (j = 0; j < MmSysPteIndex[Index]; j++) {
    00243                 ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    00244                 PointerFreedPte += 1;
    00245                 MiPtesChecked[1] += 1;
    00246             }
    00247         }
    00248     }
    00249
    00250     MiUnlockSystemSpace(OldIrql);
    00251 }
    00252
    00253
    00254 VOID
    00255 MiCheckPteAllocation (
    00256     IN PMMPTE StartingPte,
    00257     IN ULONG NumberOfPtes,
    00258     IN ULONG CallerId,
    00259     IN ULONG Context1
    00260     )
    00261
    00262 /*++
    00263
    00264 Routine Description:
    00265
    00266     This function validates the PTE range passed in, guaranteeing that it
    00267     is not already allocated.
    00268
    00269 Arguments:
    00270
    00271     StartingPte - Supplies the first PTE being allocated.
    00272
    00273     NumberOfPtes - Supplies the number of PTEs being allocated.
    00274
    00275     CallerId - Supplies the caller's ID.
    00276
    00277     Context1 - Opaque.
    00278
    00279 Return Value:
    00280
    00281     None.
    00282
    00283 Environment:
    00284
    00285     Kernel mode, MmSystemSpaceLock held.
    00286
    00287 --*/
    00288
    00289 {
    00290     ULONG i;
    00291     ULONG_PTR Index;
    00292     PMMPTE BasePte;
    00293     PMMPTE_TRACKER Tracker;
    00294
    00295     //
    00296     // Don't track nonpaged pool expansion.
    00297     //
    00298
    00299     if (StartingPte < MmSystemPtesStart[SystemPteSpace] ||
    00300         StartingPte + NumberOfPtes > MmSystemPtesEnd[SystemPteSpace] + 1) {
    00301             return;
    00302     }
    00303
    00304     if (MiPteTracker == NULL) {
    00305             return;
    00306     }
    00307
    00308     Index = StartingPte - MmSystemPtesStart[SystemPteSpace];
    00309
    00310     Tracker = &MiPteTracker[Index];
    00311
    00312     for (i = 0; i < NumberOfPtes; i += 1) {
    00313
    00314         if (Tracker->InUse == TRUE) {
    00315             KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00316                           7,
    00317                           (ULONG_PTR)StartingPte,
    00318                           NumberOfPtes,
    00319                           CallerId);
    00320         }
    00321
    00322         Tracker += 1;
    00323     }
    00324
    00325     Tracker = &MiPteTracker[Index];
    00326
    00327     ASSERT (NumberOfPtes < 0x10000);
    00328
    00329     Tracker->NumberOfPtes = (USHORT)NumberOfPtes;
    00330
    00331     for (i = 0; i < NumberOfPtes; i += 1) {
    00332         Tracker->InUse = TRUE;
    00333         Tracker += 1;
    00334     }
    00335
    00336     MiPtesChecked[0xE] += 1;
    00337 }
    00338
    00339
    00340 VOID
    00341 MiCheckPteRelease (
    00342     IN PMMPTE StartingPte,
    00343     IN ULONG NumberOfPtes
    00344     )
    00345
    00346 /*++
    00347
    00348 Routine Description:
    00349
    00350     This function validates the PTE range passed in, guaranteeing that it
    00351     is not already free.
    00352
    00353 Arguments:
    00354
    00355     StartingPte - Supplies the first PTE being allocated.
    00356
    00357     NumberOfPtes - Supplies the number of PTEs being allocated.
    00358
    00359 Return Value:
    00360
    00361     None.
    00362
    00363 Environment:
    00364
    00365     Kernel mode, MmSystemSpaceLock held.
    00366
    00367 --*/
    00368
    00369 {
    00370     ULONG i;
    00371     ULONG_PTR Index;
    00372     PMMPTE BasePte;
    00373     PMMPTE_TRACKER Tracker;
    00374
    00375     //
    00376     // Don't track nonpaged pool expansion.
    00377     //
    00378
    00379     if (StartingPte < MmSystemPtesStart[SystemPteSpace] ||
    00380         StartingPte + NumberOfPtes > MmSystemPtesEnd[SystemPteSpace] + 1) {
    00381             return;
    00382     }
    00383
    00384     if (MiPteTracker == NULL) {
    00385             return;
    00386     }
    00387
    00388     ASSERT (NumberOfPtes < 0x10000);
    00389
    00390     Index = StartingPte - MmSystemPtesStart[SystemPteSpace];
    00391
    00392     Tracker = &MiPteTracker[Index];
    00393
    00394     if ((NumberOfPtes == 0) ||
    00395         (Tracker->NumberOfPtes != NumberOfPtes)) {
    00396         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00397                       8,
    00398                       (ULONG_PTR)StartingPte,
    00399                       NumberOfPtes,
    00400                       Tracker->NumberOfPtes);
    00401     }
    00402
    00403     Tracker->NumberOfPtes = 0;
    00404
    00405     for (i = 0; i < NumberOfPtes; i += 1) {
    00406
    00407         if (Tracker->InUse == FALSE) {
    00408             KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00409                           9,
    00410                           (ULONG_PTR)StartingPte,
    00411                           NumberOfPtes,
    00412                           i);
    00413         }
    00414
    00415         Tracker += 1;
    00416     }
    00417
    00418     Tracker = &MiPteTracker[Index];
    00419
    00420     for (i = 0; i < NumberOfPtes; i += 1) {
    00421         Tracker->InUse = FALSE;
    00422         Tracker += 1;
    00423     }
    00424
    00425     MiPtesChecked[0xF] += 1;
    00426 }
    00427
    00428
    00429 VOID
    00430 MiRebuildPteTracker (
    00431     IN PMMPTE StartingPte,
    00432     IN ULONG NumberOfPtes
    00433     )
    00434
    00435 /*++
    00436
    00437 Routine Description:
    00438
    00439     This function resizes the PTE tracking data structures to account for
    00440     system PTE table growth.
    00441
    00442     Note that the original PTE tracker structure cannot be freed unless
    00443     MiFreePoolPages is modified to deal with the boundary allocations being
    00444     freed - since this never happens in a normal system, there are no bounds
    00445     checks in place and it will coalesce past the ends of pool.
    00446
    00447 Arguments:
    00448
    00449     StartingPte - Supplies the first PTE for the system PTE pool.
    00450
    00451     NumberOfPtes - Supplies the number of PTEs in the system PTE pool.
    00452
    00453 Return Value:
    00454
    00455     None.
    00456
    00457 Environment:
    00458
    00459     Kernel mode, MmSystemSpaceLock held.
    00460
    00461 --*/
    00462
    00463 {
    00464     KIRQL OldIrql;
    00465     ULONG_PTR OldPtes;
    00466     ULONG_PTR NewPtes;
    00467     PMMPTE_TRACKER OldTracker;
    00468     PMMPTE_TRACKER NewTracker;
    00469
    00470     //
    00471     // If we've already discovered a discontiguity don't coalesce now.
    00472     //
    00473
    00474     if (MiPteTracker == (PMMPTE_TRACKER) 0) {
    00475         return;
    00476     }
    00477
    00478     if (StartingPte + NumberOfPtes != MmSystemPtesStart[SystemPteSpace]) {
    00479 #if 0
    00480         MiFreePoolPages ((PVOID)MiPteTracker);
    00481 #endif
    00482         MiPteTracker = (PMMPTE_TRACKER) 0;
    00483         return;
    00484     }
    00485
    00486     if (MiPteTracker) {
    00487         OldPtes = MmSystemPtesEnd[SystemPteSpace] - MmSystemPtesStart[SystemPteSpace] + 1;
    00488
    00489         NewPtes = OldPtes + NumberOfPtes;
    00490
    00491         NewTracker = (PMMPTE_TRACKER) ExAllocatePoolWithTag (
    00492                                           NonPagedPool,
    00493                                           (ULONG_PTR)(NewPtes * sizeof (MMPTE_TRACKER)),
    00494                                           '  mM');
    00495
    00496         if (NewTracker == (PMMPTE_TRACKER) 0) {
    00497             MiPteTracker = (PMMPTE_TRACKER) 0;
    00498             return;
    00499         }
    00500
    00501         RtlZeroMemory (NewTracker, NewPtes * sizeof (MMPTE_TRACKER));
    00502
    00503         OldTracker = MiPteTracker;
    00504
    00505         MiLockSystemSpace(OldIrql);
    00506
    00507         RtlCopyMemory (NewTracker + NumberOfPtes, OldTracker, OldPtes * sizeof (MMPTE_TRACKER));
    00508
    00509         MiPteTracker = NewTracker;
    00510
    00511         MiUnlockSystemSpace(OldIrql);
    00512
    00513 #if 0
    00514         MiFreePoolPages ((PVOID)OldTracker);
    00515 #endif
    00516
    00517         MiPtesChecked[0xD] += 1;
    00518     }
    00519 }
    00520 #endif
    00521
    00522
    00523 PMMPTE
    00524 MiReserveSystemPtes (
    00525     IN ULONG NumberOfPtes,
    00526     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
    00527     IN ULONG Alignment,
    00528     IN ULONG Offset,
    00529     IN ULONG BugCheckOnFailure
    00530     )
    00531
    00532 /*++
    00533
    00534 Routine Description:
    00535
    00536     This function locates the specified number of unused PTEs to locate
    00537     within the non paged portion of system space.
    00538
    00539 Arguments:
    00540
    00541     NumberOfPtes - Supplies the number of PTEs to locate.
    00542
    00543     SystemPtePoolType - Supplies the PTE type of the pool to expand, one of
    00544                         SystemPteSpace or NonPagedPoolExpansion.
    00545
    00546     Alignment - Supplies the virtual address alignment for the address
    00547                 the returned PTE maps. For example, if the value is 64K,
    00548                 the returned PTE will map an address on a 64K boundary.
    00549                 An alignment of zero means to align on a page boundary.
    00550
    00551     Offset - Supplies the offset into the alignment for the virtual address.
    00552              For example, if the Alignment is 64k and the Offset is 4k,
    00553              the returned address will be 4k above a 64k boundary.
    00554
    00555     BugCheckOnFailure - Supplies FALSE if NULL should be returned if
    00556                         the request cannot be satisfied, TRUE if
    00557                         a bugcheck should be issued.
    00558
    00559 Return Value:
    00560
    00561     Returns the address of the first PTE located.
    00562     NULL if no system PTEs can be located and BugCheckOnFailure is FALSE.
    00563
    00564 Environment:
    00565
    00566     Kernel mode, DISPATCH_LEVEL or below.
    00567
    00568 --*/
    00569
    00570 {
    00571     PMMPTE PointerPte;
    00572     PMMPTE Previous;
    00573     KIRQL OldIrql;
    00574     ULONG PteMask;
    00575     ULONG MaskSize;
    00576     ULONG Index;
    00577
    00578 #ifdef _MI_GUARD_PTE_
    00579     ULONG ExactPtes;
    00580
    00581     if (NumberOfPtes == 0) {
    00582         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00583                       0xA,
    00584                       BugCheckOnFailure,
    00585                       NumberOfPtes,
    00586                       SystemPtePoolType);
    00587     }
    00588
    00589     if (SystemPtePoolType == SystemPteSpace) {
    00590         NumberOfPtes += 1;
    00591     }
    00592
    00593     ExactPtes = NumberOfPtes;
    00594 #endif
    00595
    00596     if (SystemPtePoolType == SystemPteSpace) {
    00597
    00598         MaskSize = (Alignment - 1) >> (PAGE_SHIFT - PTE_SHIFT);
    00599         PteMask = MaskSize & (Offset >> (PAGE_SHIFT - PTE_SHIFT));
    00600
    00601         //
    00602         // Acquire the system space lock to synchronize access to this
    00603         // routine.
    00604         //
    00605
    00606         MiLockSystemSpace(OldIrql);
    00607
    00608         if (NumberOfPtes <= MM_PTE_TABLE_LIMIT) {
    00609             Index = MmSysPteTables [NumberOfPtes];
    00610             ASSERT (NumberOfPtes <= MmSysPteIndex[Index]);
    00611             PointerPte = &MmFreeSysPteListBySize[Index];
    00612 #if DBG
    00613             if (MmDebug & MM_DBG_SYS_PTES) {
    00614                 PMMPTE PointerPte1;
    00615                 PointerPte1 = &MmFreeSysPteListBySize[Index];
    00616                 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    00617                     PMMPTE PointerFreedPte;
    00618                     ULONG j;
    00619
    00620                     PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry;
    00621                     PointerFreedPte = PointerPte1;
    00622                     for (j = 0; j < MmSysPteIndex[Index]; j++) {
    00623                         ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    00624                         PointerFreedPte++;
    00625                     }
    00626                 }
    00627             }
    00628 #endif //DBG
    00629
    00630             Previous = PointerPte;
    00631
    00632             while (PointerPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    00633
    00634                 //
    00635                 //  Try to find suitable PTEs with the proper alignment.
    00636                 //
    00637
    00638                 Previous = PointerPte;
    00639                 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    00640 #if !defined(_IA64_)
    00641                 if (PointerPte == MmFlushPte1) {
    00642                     KeFlushEntireTb (TRUE, TRUE);
    00643                     MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK;
    00644                     MmFlushPte1 = NULL;
    00645                 }
    00646 #endif
    00647                 if ((Alignment == 0) ||
    00648                     (((ULONG_PTR)PointerPte & MaskSize) == PteMask)) {
    00649
    00650 #ifdef _MI_SYSPTE_DEBUG_
    00651                     MiCheckPteAllocation (PointerPte,
    00652                                           NumberOfPtes,
    00653                                           0,
    00654                                           MmSysPteIndex[Index]);
    00655 #endif
    00656                     //
    00657                     // Proper alignment and offset, update list index.
    00658                     //
    00659
    00660                     ASSERT ((PointerPte->u.List.NextEntry + MmSystemPteBase) >=
    00661                              MmSystemPtesStart[SystemPtePoolType] ||
    00662                              PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST);
    00663                     ASSERT ((PointerPte->u.List.NextEntry + MmSystemPteBase) <=
    00664                              MmSystemPtesEnd[SystemPtePoolType] ||
    00665                              PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST);
    00666
    00667                     Previous->u.List.NextEntry = PointerPte->u.List.NextEntry;
    00668                     MmSysPteListBySizeCount [Index] -= 1;
    00669
    00670 #if !defined(_IA64_)
    00671                     if (NumberOfPtes != 1) {
    00672
    00673                         //
    00674                         // Check to see if the TB should be flushed.
    00675                         //
    00676
    00677                         if ((PointerPte + 1)->u.List.NextEntry == MmFlushCounter) {
    00678                             KeFlushEntireTb (TRUE, TRUE);
    00679                             MmFlushCounter = (MmFlushCounter + 1) &
    00680                                                     MM_FLUSH_COUNTER_MASK;
    00681                             MmFlushPte1 = NULL;
    00682                         }
    00683                     }
    00684 #endif
    00685                     if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    00686                         MmLastSysPteListBySize[Index] = Previous;
    00687                     }
    00688 #if DBG
    00689
    00690                     if (MmDebug & MM_DBG_SYS_PTES) {
    00691                         PMMPTE PointerPte1;
    00692                         PointerPte1 = &MmFreeSysPteListBySize[Index];
    00693                         while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    00694                             PMMPTE PointerFreedPte;
    00695                             ULONG j;
    00696
    00697                             PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry;
    00698                             PointerFreedPte = PointerPte1;
    00699                             for (j = 0; j < MmSysPteIndex[Index]; j++) {
    00700                                 ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    00701                                 PointerFreedPte++;
    00702                             }
    00703                         }
    00704                     }
    00705 #endif //DBG
    00706                     MiUnlockSystemSpace(OldIrql);
    00707
    00708 #if DBG
    00709                     PointerPte->u.List.NextEntry = 0xABCDE;
    00710                     if (MmDebug & MM_DBG_SYS_PTES) {
    00711
    00712                         PMMPTE PointerFreedPte;
    00713                         ULONG j;
    00714
    00715                         PointerFreedPte = PointerPte;
    00716                         for (j = 0; j < MmSysPteIndex[Index]; j++) {
    00717                             ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    00718                             PointerFreedPte++;
    00719                         }
    00720                     }
    00721                     if (PointerPte < MmSystemPtesStart[SystemPtePoolType]) {
    00722                         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00723                                       0xB,
    00724                                       (ULONG_PTR)PointerPte,
    00725                                       NumberOfPtes,
    00726                                       SystemPtePoolType);
    00727                     }
    00728                     if (PointerPte > MmSystemPtesEnd[SystemPtePoolType]) {
    00729                         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    00730                                       0xC,
    00731                                       (ULONG_PTR)PointerPte,
    00732                                       NumberOfPtes,
    00733                                       SystemPtePoolType);
    00734                     }
    00735 #endif //DBG
    00736
    00737                     if (MmSysPteListBySizeCount[Index] <
    00738                                             MmSysPteMinimumFree[Index]) {
    00739                         MiFeedSysPtePool (Index);
    00740                     }
    00741 #ifdef _MI_GUARD_PTE_
    00742                     (PointerPte + ExactPtes - 1)->u.Long = MM_KERNEL_NOACCESS_PTE;
    00743 #endif
    00744                     return PointerPte;
    00745                 }
    00746             }
    00747             NumberOfPtes = MmSysPteIndex [Index];
    00748         }
    00749         MiUnlockSystemSpace(OldIrql);
    00750     }
    00751
    00752 #ifdef _MI_GUARD_PTE_
    00753     NumberOfPtes = ExactPtes;
    00754 #endif
    00755
    00756     PointerPte = MiReserveSystemPtes2 (NumberOfPtes,
    00757                                        SystemPtePoolType,
    00758                                        Alignment,
    00759                                        Offset,
    00760                                        BugCheckOnFailure);
    00761
    00762 #if DBG
    00763     if (MmDebug & MM_DBG_SYS_PTES) {
    00764
    00765         PMMPTE PointerFreedPte;
    00766         ULONG j;
    00767
    00768         if (PointerPte) {
    00769             PointerFreedPte = PointerPte;
    00770             for (j = 0; j < NumberOfPtes; j++) {
    00771                 ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    00772                 PointerFreedPte++;
    00773             }
    00774         }
    00775     }
    00776 #endif //DBG
    00777
    00778 #ifdef _MI_GUARD_PTE_
    00779     if (PointerPte) {
    00780         (PointerPte + ExactPtes - 1)->u.Long = MM_KERNEL_NOACCESS_PTE;
    00781     }
    00782 #endif
    00783
    00784     return PointerPte;
    00785 }
    00786
    00787 VOID
    00788 MiFeedSysPtePool (
    00789     IN ULONG Index
    00790     )
    00791
    00792 /*++
    00793
    00794 Routine Description:
    00795
    00796     This routine adds PTEs to the look aside lists.
    00797
    00798 Arguments:
    00799
    00800     Index - Supplies the index for the look aside list to fill.
    00801
    00802 Return Value:
    00803
    00804     None.
    00805
    00806
    00807 Environment:
    00808
    00809     Kernel mode, internal to SysPtes.
    00810
    00811 --*/
    00812
    00813 {
    00814 #ifdef _MI_GUARD_PTE_
    00815     UNREFERENCED_PARAMETER (Index);
    00816 #else
    00817     ULONG i;
    00818     PMMPTE PointerPte;
    00819
    00820     if (MmTotalFreeSystemPtes[SystemPteSpace] < MM_MIN_SYSPTE_FREE) {
    00821         return;
    00822     }
    00823
    00824     for (i = 0; i < 10 ; i++ ) {
    00825         PointerPte = MiReserveSystemPtes2 (MmSysPteIndex [Index],
    00826                                            SystemPteSpace,
    00827                                            0,
    00828                                            0,
    00829                                            FALSE);
    00830         if (PointerPte == NULL) {
    00831             return;
    00832         }
    00833         MiReleaseSystemPtes (PointerPte,
    00834                              MmSysPteIndex [Index],
    00835                              SystemPteSpace);
    00836     }
    00837 #endif
    00838     return;
    00839 }
    00840
    00841
    00842 PMMPTE
    00843 MiReserveSystemPtes2 (
    00844     IN ULONG NumberOfPtes,
    00845     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType,
    00846     IN ULONG Alignment,
    00847     IN ULONG Offset,
    00848     IN ULONG BugCheckOnFailure
    00849     )
    00850
    00851 /*++
    00852
    00853 Routine Description:
    00854
    00855     This function locates the specified number of unused PTEs to locate
    00856     within the non paged portion of system space.
    00857
    00858 Arguments:
    00859
    00860     NumberOfPtes - Supplies the number of PTEs to locate.
    00861
    00862     SystemPtePoolType - Supplies the PTE type of the pool to expand, one of
    00863                         SystemPteSpace or NonPagedPoolExpansion.
    00864
    00865     Alignment - Supplies the virtual address alignment for the address
    00866                 the returned PTE maps. For example, if the value is 64K,
    00867                 the returned PTE will map an address on a 64K boundary.
    00868                 An alignment of zero means to align on a page boundary.
    00869
    00870     Offset - Supplies the offset into the alignment for the virtual address.
    00871              For example, if the Alignment is 64k and the Offset is 4k,
    00872              the returned address will be 4k above a 64k boundary.
    00873
    00874     BugCheckOnFailure - Supplies FALSE if NULL should be returned if
    00875                         the request cannot be satisfied, TRUE if
    00876                         a bugcheck should be issued.
    00877
    00878 Return Value:
    00879
    00880     Returns the address of the first PTE located.
    00881     NULL if no system PTEs can be located and BugCheckOnFailure is FALSE.
    00882
    00883 Environment:
    00884
    00885     Kernel mode, DISPATCH_LEVEL or below.
    00886
    00887 --*/
    00888
    00889 {
    00890     PMMPTE PointerPte;
    00891     PMMPTE PointerFollowingPte;
    00892     PMMPTE Previous;
    00893     ULONG_PTR SizeInSet;
    00894     KIRQL OldIrql;
    00895     ULONG MaskSize;
    00896     ULONG NumberOfRequiredPtes;
    00897     ULONG OffsetSum;
    00898     ULONG PtesToObtainAlignment;
    00899     PMMPTE NextSetPointer;
    00900     ULONG_PTR LeftInSet;
    00901     ULONG_PTR PteOffset;
    00902     MMPTE_FLUSH_LIST PteFlushList;
    00903     PVOID HighConsumer;
    00904     ULONG_PTR HighPteUse;
    00905
    00906     MaskSize = (Alignment - 1) >> (PAGE_SHIFT - PTE_SHIFT);
    00907
    00908     OffsetSum = (Offset >> (PAGE_SHIFT - PTE_SHIFT)) |
    00909                             (Alignment >> (PAGE_SHIFT - PTE_SHIFT));
    00910
    00911     MiLockSystemSpace(OldIrql);
    00912
    00913     //
    00914     // The nonpaged PTE pool uses the invalid PTEs to define the pool
    00915     // structure.   A global pointer points to the first free set
    00916     // in the list, each free set contains the number free and a pointer
    00917     // to the next free set.  The free sets are kept in an ordered list
    00918     // such that the pointer to the next free set is always greater
    00919     // than the address of the current free set.
    00920     //
    00921     // As to not limit the size of this pool, two PTEs are used
    00922     // to define a free region.  If the region is a single PTE, the
    00923     // prototype field within the PTE is set indicating the set
    00924     // consists of a single PTE.
    00925     //
    00926     // The page frame number field is used to define the next set
    00927     // and the number free.  The two flavors are:
    00928     //
    00929     //                           o          V
    00930     //                           n          l
    00931     //                           e          d
    00932     //  +-----------------------+-+----------+
    00933     //  |  next set             |0|0        0|
    00934     //  +-----------------------+-+----------+
    00935     //  |  number in this set   |0|0        0|
    00936     //  +-----------------------+-+----------+
    00937     //
    00938     //
    00939     //  +-----------------------+-+----------+
    00940     //  |  next set             |1|0        0|
    00941     //  +-----------------------+-+----------+
    00942     //  ...
    00943     //
    00944
    00945     //
    00946     // Acquire the system space lock to synchronize access to this routine.
    00947     //
    00948
    00949     PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType];
    00950     Previous = PointerPte;
    00951
    00952     if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    00953
    00954         //
    00955         // End of list and none found, return NULL or bugcheck.
    00956         //
    00957
    00958         if (BugCheckOnFailure) {
    00959             goto IssueBugcheck;
    00960         }
    00961
    00962         MiUnlockSystemSpace(OldIrql);
    00963         return NULL;
    00964     }
    00965
    00966     PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    00967
    00968     if (Alignment <= PAGE_SIZE) {
    00969
    00970         //
    00971         // Don't deal with alignment issues.
    00972         //
    00973
    00974         while (TRUE) {
    00975
    00976             if (PointerPte->u.List.OneEntry) {
    00977                 SizeInSet = 1;
    00978
    00979             } else {
    00980
    00981                 PointerFollowingPte = PointerPte + 1;
    00982                 SizeInSet = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry;
    00983             }
    00984
    00985             if (NumberOfPtes < SizeInSet) {
    00986
    00987                 //
    00988                 // Get the PTEs from this set and reduce the size of the
    00989                 // set.  Note that the size of the current set cannot be 1.
    00990                 //
    00991
    00992                 if ((SizeInSet - NumberOfPtes) == 1) {
    00993
    00994                     //
    00995                     // Collapse to the single PTE format.
    00996                     //
    00997
    00998                     PointerPte->u.List.OneEntry = 1;
    00999
    01000                 } else {
    01001
    01002                     PointerFollowingPte->u.List.NextEntry = SizeInSet - NumberOfPtes;
    01003
    01004                     //
    01005                     // Get the required PTEs from the end of the set.
    01006                     //
    01007
    01008 #if 0
    01009                     if (MmDebug & MM_DBG_SYS_PTES) {
    01010                         MiDumpSystemPtes(SystemPtePoolType);
    01011                         PointerFollowingPte = PointerPte + (SizeInSet - NumberOfPtes);
    01012                         DbgPrint("allocated 0x%lx Ptes at %lx\n",NumberOfPtes,PointerFollowingPte);
    01013                     }
    01014 #endif //0
    01015                 }
    01016
    01017                 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes;
    01018 #if DBG
    01019                 if (MmDebug & MM_DBG_SYS_PTES) {
    01020                     ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01021                              MiCountFreeSystemPtes (SystemPtePoolType));
    01022                 }
    01023 #endif //DBG
    01024
    01025 #ifdef _MI_SYSPTE_DEBUG_
    01026                 MiCheckPteAllocation (PointerPte + (SizeInSet - NumberOfPtes),
    01027                                       NumberOfPtes,
    01028                                       1,
    01029                                       0);
    01030 #endif
    01031
    01032                 MiUnlockSystemSpace(OldIrql);
    01033
    01034                 PointerPte =  PointerPte + (SizeInSet - NumberOfPtes);
    01035                 goto Flush;
    01036             }
    01037
    01038             if (NumberOfPtes == SizeInSet) {
    01039
    01040                 //
    01041                 // Satisfy the request with this complete set and change
    01042                 // the list to reflect the fact that this set is gone.
    01043                 //
    01044
    01045                 Previous->u.List.NextEntry = PointerPte->u.List.NextEntry;
    01046
    01047                 //
    01048                 // Release the system PTE lock.
    01049                 //
    01050
    01051 #if 0
    01052                 if (MmDebug & MM_DBG_SYS_PTES) {
    01053                         MiDumpSystemPtes(SystemPtePoolType);
    01054                         PointerFollowingPte = PointerPte + (SizeInSet - NumberOfPtes);
    01055                         DbgPrint("allocated 0x%lx Ptes at %lx\n",NumberOfPtes,PointerFollowingPte);
    01056                 }
    01057 #endif //0
    01058
    01059                 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes;
    01060 #if DBG
    01061                 if (MmDebug & MM_DBG_SYS_PTES) {
    01062                     ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01063                              MiCountFreeSystemPtes (SystemPtePoolType));
    01064                 }
    01065 #endif //DBG
    01066
    01067 #ifdef _MI_SYSPTE_DEBUG_
    01068                 MiCheckPteAllocation (PointerPte,
    01069                                       NumberOfPtes,
    01070                                       2,
    01071                                       0);
    01072 #endif
    01073
    01074                 MiUnlockSystemSpace(OldIrql);
    01075                 goto Flush;
    01076             }
    01077
    01078             //
    01079             // Point to the next set and try again
    01080             //
    01081
    01082             if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    01083
    01084                 //
    01085                 // End of list and none found, return NULL or bugcheck.
    01086                 //
    01087
    01088                 if (BugCheckOnFailure) {
    01089                     goto IssueBugcheck;
    01090                 }
    01091
    01092                 MiUnlockSystemSpace(OldIrql);
    01093                 return NULL;
    01094             }
    01095             Previous = PointerPte;
    01096             PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    01097             ASSERT (PointerPte > Previous);
    01098         }
    01099
    01100     } else {
    01101
    01102         //
    01103         // Deal with the alignment issues.
    01104         //
    01105
    01106         while (TRUE) {
    01107
    01108             if (PointerPte->u.List.OneEntry) {
    01109                 SizeInSet = 1;
    01110
    01111             } else {
    01112
    01113                 PointerFollowingPte = PointerPte + 1;
    01114                 SizeInSet = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry;
    01115             }
    01116
    01117             PtesToObtainAlignment = (ULONG)
    01118                 (((OffsetSum - ((ULONG_PTR)PointerPte & MaskSize)) & MaskSize) >>
    01119                     PTE_SHIFT);
    01120
    01121             NumberOfRequiredPtes = NumberOfPtes + PtesToObtainAlignment;
    01122
    01123             if (NumberOfRequiredPtes < SizeInSet) {
    01124
    01125                 //
    01126                 // Get the PTEs from this set and reduce the size of the
    01127                 // set.  Note that the size of the current set cannot be 1.
    01128                 //
    01129                 // This current block will be slit into 2 blocks if
    01130                 // the PointerPte does not match the alignment.
    01131                 //
    01132
    01133                 //
    01134                 // Check to see if the first PTE is on the proper
    01135                 // alignment, if so, eliminate this block.
    01136                 //
    01137
    01138                 LeftInSet = SizeInSet - NumberOfRequiredPtes;
    01139
    01140                 //
    01141                 // Set up the new set at the end of this block.
    01142                 //
    01143
    01144                 NextSetPointer = PointerPte + NumberOfRequiredPtes;
    01145                 NextSetPointer->u.List.NextEntry =
    01146                                        PointerPte->u.List.NextEntry;
    01147
    01148                 PteOffset = (ULONG_PTR)(NextSetPointer - MmSystemPteBase);
    01149
    01150                 if (PtesToObtainAlignment == 0) {
    01151
    01152                     Previous->u.List.NextEntry += NumberOfRequiredPtes;
    01153
    01154                 } else {
    01155
    01156                     //
    01157                     // Point to the new set at the end of the block
    01158                     // we are giving away.
    01159                     //
    01160
    01161                     PointerPte->u.List.NextEntry = PteOffset;
    01162
    01163                     //
    01164                     // Update the size of the current set.
    01165                     //
    01166
    01167                     if (PtesToObtainAlignment == 1) {
    01168
    01169                         //
    01170                         // Collapse to the single PTE format.
    01171                         //
    01172
    01173                         PointerPte->u.List.OneEntry = 1;
    01174
    01175                     } else {
    01176
    01177                         //
    01178                         // Set the set size in the next PTE.
    01179                         //
    01180
    01181                         PointerFollowingPte->u.List.NextEntry =
    01182                                                         PtesToObtainAlignment;
    01183                     }
    01184                 }
    01185
    01186                 //
    01187                 // Set up the new set at the end of the block.
    01188                 //
    01189
    01190                 if (LeftInSet == 1) {
    01191                     NextSetPointer->u.List.OneEntry = 1;
    01192                 } else {
    01193                     NextSetPointer->u.List.OneEntry = 0;
    01194                     NextSetPointer += 1;
    01195                     NextSetPointer->u.List.NextEntry = LeftInSet;
    01196                 }
    01197                 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes;
    01198 #if DBG
    01199                 if (MmDebug & MM_DBG_SYS_PTES) {
    01200                     ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01201                              MiCountFreeSystemPtes (SystemPtePoolType));
    01202                 }
    01203 #endif //DBG
    01204
    01205 #ifdef _MI_SYSPTE_DEBUG_
    01206                 MiCheckPteAllocation (PointerPte + PtesToObtainAlignment,
    01207                                       NumberOfPtes,
    01208                                       3,
    01209                                       0);
    01210 #endif
    01211
    01212                 MiUnlockSystemSpace(OldIrql);
    01213
    01214                 PointerPte = PointerPte + PtesToObtainAlignment;
    01215                 goto Flush;
    01216             }
    01217
    01218             if (NumberOfRequiredPtes == SizeInSet) {
    01219
    01220                 //
    01221                 // Satisfy the request with this complete set and change
    01222                 // the list to reflect the fact that this set is gone.
    01223                 //
    01224
    01225                 if (PtesToObtainAlignment == 0) {
    01226
    01227                     //
    01228                     // This block exactly satisfies the request.
    01229                     //
    01230
    01231                     Previous->u.List.NextEntry =
    01232                                             PointerPte->u.List.NextEntry;
    01233
    01234                 } else {
    01235
    01236                     //
    01237                     // A portion at the start of this block remains.
    01238                     //
    01239
    01240                     if (PtesToObtainAlignment == 1) {
    01241
    01242                         //
    01243                         // Collapse to the single PTE format.
    01244                         //
    01245
    01246                         PointerPte->u.List.OneEntry = 1;
    01247
    01248                     } else {
    01249                       PointerFollowingPte->u.List.NextEntry =
    01250                                                         PtesToObtainAlignment;
    01251
    01252                     }
    01253                 }
    01254
    01255                 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes;
    01256 #if DBG
    01257                 if (MmDebug & MM_DBG_SYS_PTES) {
    01258                     ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01259                              MiCountFreeSystemPtes (SystemPtePoolType));
    01260                 }
    01261 #endif //DBG
    01262
    01263 #ifdef _MI_SYSPTE_DEBUG_
    01264                 MiCheckPteAllocation (PointerPte + PtesToObtainAlignment,
    01265                                       NumberOfPtes,
    01266                                       4,
    01267                                       0);
    01268 #endif
    01269
    01270                 MiUnlockSystemSpace(OldIrql);
    01271
    01272                 PointerPte = PointerPte + PtesToObtainAlignment;
    01273                 goto Flush;
    01274             }
    01275
    01276             //
    01277             // Point to the next set and try again
    01278             //
    01279
    01280             if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    01281
    01282                 //
    01283                 // End of list and none found, return NULL or bugcheck.
    01284                 //
    01285
    01286                 if (BugCheckOnFailure) {
    01287                     goto IssueBugcheck;
    01288                 }
    01289
    01290                 MiUnlockSystemSpace(OldIrql);
    01291                 return NULL;
    01292             }
    01293             Previous = PointerPte;
    01294             PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    01295             ASSERT (PointerPte > Previous);
    01296         }
    01297     }
    01298 Flush:
    01299
    01300     if (SystemPtePoolType == SystemPteSpace) {
    01301         PVOID BaseAddress;
    01302         ULONG j;
    01303
    01304         PteFlushList.Count = 0;
    01305         Previous = PointerPte;
    01306         BaseAddress = MiGetVirtualAddressMappedByPte (Previous);
    01307
    01308         for (j = 0; j < NumberOfPtes ; j++) {
    01309             if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) {
    01310                 PteFlushList.FlushPte[PteFlushList.Count] = Previous;
    01311                 PteFlushList.FlushVa[PteFlushList.Count] = BaseAddress;
    01312                 PteFlushList.Count += 1;
    01313             }
    01314
    01315             //
    01316             // PTEs being freed better be invalid.
    01317             //
    01318             ASSERT (Previous->u.Hard.Valid == 0);
    01319
    01320             *Previous = ZeroKernelPte;
    01321             BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE);
    01322             Previous++;
    01323         }
    01324
    01325         KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
    01326         MiFlushPteList (&PteFlushList, TRUE, ZeroKernelPte);
    01327         KeLowerIrql (OldIrql);
    01328     }
    01329     return PointerPte;
    01330
    01331 IssueBugcheck:
    01332
    01333     if (SystemPtePoolType == SystemPteSpace) {
    01334
    01335         HighConsumer = MiGetHighestPteConsumer (&HighPteUse);
    01336
    01337         if (HighConsumer != NULL) {
    01338             KeBugCheckEx (DRIVER_USED_EXCESSIVE_PTES,
    01339                           (ULONG_PTR)HighConsumer,
    01340                           HighPteUse,
    01341                           MmTotalFreeSystemPtes[SystemPtePoolType],
    01342                           MmNumberOfSystemPtes);
    01343         }
    01344     }
    01345
    01346     KeBugCheckEx (NO_MORE_SYSTEM_PTES,
    01347                   (ULONG_PTR)SystemPtePoolType,
    01348                   NumberOfPtes,
    01349                   MmTotalFreeSystemPtes[SystemPtePoolType],
    01350                   MmNumberOfSystemPtes);
    01351 }
    01352
    01353 VOID
    01354 MiReleaseSystemPtes (
    01355     IN PMMPTE StartingPte,
    01356     IN ULONG NumberOfPtes,
    01357     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    01358     )
    01359
    01360 /*++
    01361
    01362 Routine Description:
    01363
    01364     This function releases the specified number of PTEs
    01365     within the non paged portion of system space.
    01366
    01367     Note that the PTEs must be invalid and the page frame number
    01368     must have been set to zero.
    01369
    01370 Arguments:
    01371
    01372     StartingPte - Supplies the address of the first PTE to release.
    01373
    01374     NumberOfPtes - Supplies the number of PTEs to release.
    01375
    01376     SystemPtePoolType - Supplies the PTE type of the pool to release PTEs to,
    01377                         one of SystemPteSpace or NonPagedPoolExpansion.
    01378
    01379 Return Value:
    01380
    01381     none.
    01382
    01383 Environment:
    01384
    01385     Kernel mode.
    01386
    01387 --*/
    01388
    01389 {
    01390     ULONG_PTR Size;
    01391     ULONG i;
    01392     ULONG_PTR PteOffset;
    01393     PMMPTE PointerPte;
    01394     PMMPTE PointerFollowingPte;
    01395     PMMPTE NextPte;
    01396     KIRQL OldIrql;
    01397     ULONG Index;
    01398 #if defined(_IA64_)
    01399     MMPTE_FLUSH_LIST PteFlushList;
    01400     PMMPTE Previous;
    01401     PVOID BaseAddress;
    01402 #endif
    01403
    01404     //
    01405     // Check to make sure the PTEs don't map anything.
    01406     //
    01407
    01408     ASSERT (NumberOfPtes != 0);
    01409
    01410 #ifdef _MI_GUARD_PTE_
    01411     if (NumberOfPtes == 0) {
    01412         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    01413                       0xD,
    01414                       (ULONG_PTR)StartingPte,
    01415                       NumberOfPtes,
    01416                       SystemPtePoolType);
    01417     }
    01418
    01419     if (SystemPtePoolType == SystemPteSpace) {
    01420         if ((StartingPte + NumberOfPtes)->u.Long != MM_KERNEL_NOACCESS_PTE) {
    01421             KeBugCheckEx (SYSTEM_PTE_MISUSE,
    01422                           0xE,
    01423                           (ULONG_PTR)StartingPte,
    01424                           NumberOfPtes,
    01425                           SystemPtePoolType);
    01426         }
    01427         NumberOfPtes += 1;
    01428     }
    01429 #endif
    01430
    01431 #if DBG
    01432     if (StartingPte < MmSystemPtesStart[SystemPtePoolType]) {
    01433         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    01434                       0xF,
    01435                       (ULONG_PTR)StartingPte,
    01436                       NumberOfPtes,
    01437                       SystemPtePoolType);
    01438     }
    01439
    01440     if (StartingPte > MmSystemPtesEnd[SystemPtePoolType]) {
    01441         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    01442                       0x10,
    01443                       (ULONG_PTR)StartingPte,
    01444                       NumberOfPtes,
    01445                       SystemPtePoolType);
    01446     }
    01447 #endif //DBG
    01448
    01449 #if 0
    01450     if (MmDebug & MM_DBG_SYS_PTES) {
    01451         DbgPrint("releasing 0x%lx system PTEs at location %lx\n",NumberOfPtes,StartingPte);
    01452     }
    01453 #endif //0
    01454
    01455 #if defined(_IA64_)
    01456
    01457     PteFlushList.Count = 0;
    01458     Previous = StartingPte;
    01459     BaseAddress = MiGetVirtualAddressMappedByPte (Previous);
    01460     for (i = 0; i < NumberOfPtes ; i++) {
    01461         if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) {
    01462             PteFlushList.FlushPte[PteFlushList.Count] = Previous;
    01463             PteFlushList.FlushVa[PteFlushList.Count] = BaseAddress;
    01464             PteFlushList.Count += 1;
    01465         }
    01466         *Previous = ZeroKernelPte;
    01467         BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE);
    01468         Previous++;
    01469     }
    01470
    01471     KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
    01472     MiFlushPteList (&PteFlushList, TRUE, ZeroKernelPte);
    01473     KeLowerIrql (OldIrql);
    01474
    01475 #else
    01476
    01477     //
    01478     // Zero PTEs.
    01479     //
    01480
    01481 #ifdef _MI_SYSPTE_DEBUG_
    01482     MiValidateSystemPtes (StartingPte, NumberOfPtes);
    01483 #endif
    01484
    01485     MiFillMemoryPte (StartingPte,
    01486                      NumberOfPtes * sizeof (MMPTE),
    01487                      ZeroKernelPte.u.Long);
    01488
    01489 #ifdef _MI_SYSPTE_DEBUG_
    01490
    01491     //
    01492     // Invalidate any TB entries that might have been mapped to
    01493     // immediately prevent bad callers from corrupting the system.
    01494     //
    01495
    01496     KeFlushEntireTb (TRUE, TRUE);
    01497 #endif
    01498
    01499 #endif
    01500
    01501     //
    01502     // Acquire system space spin lock to synchronize access.
    01503     //
    01504
    01505     PteOffset = (ULONG_PTR)(StartingPte - MmSystemPteBase);
    01506
    01507 #ifdef _MI_SYSPTE_DEBUG_
    01508     if (PteOffset == 0) {
    01509         KeBugCheckEx (SYSTEM_PTE_MISUSE,
    01510                       0x11,
    01511                       (ULONG_PTR)StartingPte,
    01512                       NumberOfPtes,
    01513                       SystemPtePoolType);
    01514     }
    01515 #endif
    01516
    01517     MiLockSystemSpace(OldIrql);
    01518
    01519 #ifdef _MI_SYSPTE_DEBUG_
    01520     MiCheckPteRelease (StartingPte, NumberOfPtes);
    01521 #endif
    01522
    01523 #ifndef _MI_GUARD_PTE_
    01524     if ((SystemPtePoolType == SystemPteSpace) &&
    01525         (NumberOfPtes <= MM_PTE_TABLE_LIMIT)) {
    01526
    01527         Index = MmSysPteTables [NumberOfPtes];
    01528         NumberOfPtes = MmSysPteIndex [Index];
    01529
    01530         if (MmTotalFreeSystemPtes[SystemPteSpace] >= MM_MIN_SYSPTE_FREE) {
    01531
    01532             //
    01533             // Don't add to the pool if the size is greater than 15 + the minimum.
    01534             //
    01535
    01536             i = MmSysPteMinimumFree[Index];
    01537             if (MmTotalFreeSystemPtes[SystemPteSpace] >= MM_MAX_SYSPTE_FREE) {
    01538
    01539                 //
    01540                 // Lots of free PTEs, quadruple the limit.
    01541                 //
    01542
    01543                 i = i * 4;
    01544             }
    01545             i += 15;
    01546             if (MmSysPteListBySizeCount[Index] <= i) {
    01547
    01548 #if DBG
    01549                 if (MmDebug & MM_DBG_SYS_PTES) {
    01550                     PMMPTE PointerPte1;
    01551
    01552                     PointerPte1 = &MmFreeSysPteListBySize[Index];
    01553                     while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    01554                         PMMPTE PointerFreedPte;
    01555                         ULONG j;
    01556
    01557                         PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry;
    01558                         PointerFreedPte = PointerPte1;
    01559                         for (j = 0; j < MmSysPteIndex[Index]; j++) {
    01560                             ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    01561                             PointerFreedPte++;
    01562                         }
    01563                     }
    01564                 }
    01565 #endif //DBG
    01566                 MmSysPteListBySizeCount [Index] += 1;
    01567                 PointerPte = MmLastSysPteListBySize[Index];
    01568                 ASSERT (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST);
    01569                 PointerPte->u.List.NextEntry = PteOffset;
    01570                 MmLastSysPteListBySize[Index] = StartingPte;
    01571                 StartingPte->u.List.NextEntry = MM_EMPTY_PTE_LIST;
    01572
    01573 #if DBG
    01574                 if (MmDebug & MM_DBG_SYS_PTES) {
    01575                     PMMPTE PointerPte1;
    01576                     PointerPte1 = &MmFreeSysPteListBySize[Index];
    01577                     while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) {
    01578                         PMMPTE PointerFreedPte;
    01579                         ULONG j;
    01580
    01581                         PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry;
    01582                         PointerFreedPte = PointerPte1;
    01583                         for (j = 0; j < MmSysPteIndex[Index]; j++) {
    01584                             ASSERT (PointerFreedPte->u.Hard.Valid == 0);
    01585                             PointerFreedPte++;
    01586                         }
    01587                     }
    01588                 }
    01589 #endif //DBG
    01590                 if (NumberOfPtes == 1) {
    01591                     if (MmFlushPte1 == NULL) {
    01592                         MmFlushPte1 = StartingPte;
    01593                     }
    01594                 } else {
    01595                     (StartingPte + 1)->u.List.NextEntry = MmFlushCounter;
    01596                 }
    01597
    01598                 MiUnlockSystemSpace(OldIrql);
    01599                 return;
    01600             }
    01601         }
    01602     }
    01603 #endif
    01604
    01605     MmTotalFreeSystemPtes[SystemPtePoolType] += NumberOfPtes;
    01606
    01607     PteOffset = (ULONG_PTR)(StartingPte - MmSystemPteBase);
    01608     PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType];
    01609
    01610     while (TRUE) {
    01611         NextPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    01612         if (PteOffset < PointerPte->u.List.NextEntry) {
    01613
    01614             //
    01615             // Insert in the list at this point.  The
    01616             // previous one should point to the new freed set and
    01617             // the new freed set should point to the place
    01618             // the previous set points to.
    01619             //
    01620             // Attempt to combine the clusters before we
    01621             // insert.
    01622             //
    01623             // Locate the end of the current structure.
    01624             //
    01625
    01626             ASSERT (((StartingPte + NumberOfPtes) <= NextPte) ||
    01627                     (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST));
    01628
    01629             PointerFollowingPte = PointerPte + 1;
    01630             if (PointerPte->u.List.OneEntry) {
    01631                 Size = 1;
    01632             } else {
    01633                 Size = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry;
    01634             }
    01635             if ((PointerPte + Size) == StartingPte) {
    01636
    01637                 //
    01638                 // We can combine the clusters.
    01639                 //
    01640
    01641                 NumberOfPtes += (ULONG)Size;
    01642                 PointerFollowingPte->u.List.NextEntry = NumberOfPtes;
    01643                 PointerPte->u.List.OneEntry = 0;
    01644
    01645                 //
    01646                 // Point the starting PTE to the beginning of
    01647                 // the new free set and try to combine with the
    01648                 // following free cluster.
    01649                 //
    01650
    01651                 StartingPte = PointerPte;
    01652
    01653             } else {
    01654
    01655                 //
    01656                 // Can't combine with previous. Make this Pte the
    01657                 // start of a cluster.
    01658                 //
    01659
    01660                 //
    01661                 // Point this cluster to the next cluster.
    01662                 //
    01663
    01664                 StartingPte->u.List.NextEntry = PointerPte->u.List.NextEntry;
    01665
    01666                 //
    01667                 // Point the current cluster to this cluster.
    01668                 //
    01669
    01670                 PointerPte->u.List.NextEntry = PteOffset;
    01671
    01672                 //
    01673                 // Set the size of this cluster.
    01674                 //
    01675
    01676                 if (NumberOfPtes == 1) {
    01677                     StartingPte->u.List.OneEntry = 1;
    01678
    01679                 } else {
    01680                     StartingPte->u.List.OneEntry = 0;
    01681                     PointerFollowingPte = StartingPte + 1;
    01682                     PointerFollowingPte->u.List.NextEntry = NumberOfPtes;
    01683                 }
    01684             }
    01685
    01686             //
    01687             // Attempt to combine the newly created cluster with
    01688             // the following cluster.
    01689             //
    01690
    01691             if ((StartingPte + NumberOfPtes) == NextPte) {
    01692
    01693                 //
    01694                 // Combine with following cluster.
    01695                 //
    01696
    01697                 //
    01698                 // Set the next cluster to the value contained in the
    01699                 // cluster we are merging into this one.
    01700                 //
    01701
    01702                 StartingPte->u.List.NextEntry = NextPte->u.List.NextEntry;
    01703                 StartingPte->u.List.OneEntry = 0;
    01704                 PointerFollowingPte = StartingPte + 1;
    01705
    01706                 if (NextPte->u.List.OneEntry) {
    01707                     Size = 1;
    01708
    01709                 } else {
    01710                     NextPte++;
    01711                     Size = (ULONG_PTR) NextPte->u.List.NextEntry;
    01712                 }
    01713                 PointerFollowingPte->u.List.NextEntry = NumberOfPtes + Size;
    01714             }
    01715 #if 0
    01716             if (MmDebug & MM_DBG_SYS_PTES) {
    01717                 MiDumpSystemPtes(SystemPtePoolType);
    01718             }
    01719 #endif //0
    01720
    01721 #if DBG
    01722             if (MmDebug & MM_DBG_SYS_PTES) {
    01723                 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01724                          MiCountFreeSystemPtes (SystemPtePoolType));
    01725             }
    01726 #endif //DBG
    01727             MiUnlockSystemSpace(OldIrql);
    01728             return;
    01729         }
    01730
    01731         //
    01732         // Point to next freed cluster.
    01733         //
    01734
    01735         PointerPte = NextPte;
    01736     }
    01737 }
    01738
    01739 VOID
    01740 MiInitializeSystemPtes (
    01741     IN PMMPTE StartingPte,
    01742     IN ULONG NumberOfPtes,
    01743     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    01744     )
    01745
    01746 /*++
    01747
    01748 Routine Description:
    01749
    01750     This routine initializes the system PTE pool.
    01751
    01752 Arguments:
    01753
    01754     StartingPte - Supplies the address of the first PTE to put in the pool.
    01755
    01756     NumberOfPtes - Supplies the number of PTEs to put in the pool.
    01757
    01758     SystemPtePoolType - Supplies the PTE type of the pool to initialize, one of
    01759                         SystemPteSpace or NonPagedPoolExpansion.
    01760
    01761 Return Value:
    01762
    01763     none.
    01764
    01765 Environment:
    01766
    01767     Kernel mode.
    01768
    01769 --*/
    01770
    01771 {
    01772     LONG i;
    01773     LONG j;
    01774 #ifdef _MI_SYSPTE_DEBUG_
    01775     PMMPTE_TRACKER Tracker;
    01776 #endif
    01777
    01778     //
    01779     // Set the base of the system PTE pool to this PTE.  This takes into
    01780     // account that systems may have additional PTE pools below the PTE_BASE.
    01781     //
    01782
    01783     MmSystemPteBase = MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS;
    01784
    01785     MmSystemPtesStart[SystemPtePoolType] = StartingPte;
    01786     MmSystemPtesEnd[SystemPtePoolType] = StartingPte + NumberOfPtes - 1;
    01787
    01788     //
    01789     // If there are no PTEs specified, then make a valid chain by indicating
    01790     // that the list is empty.
    01791     //
    01792
    01793     if (NumberOfPtes == 0) {
    01794         MmFirstFreeSystemPte[SystemPtePoolType] = ZeroKernelPte;
    01795         MmFirstFreeSystemPte[SystemPtePoolType].u.List.NextEntry =
    01796                                                                 MM_EMPTY_LIST;
    01797         return;
    01798     }
    01799
    01800     //
    01801     // Initialize the specified system pte pool.
    01802     //
    01803
    01804     MiFillMemoryPte (StartingPte,
    01805                      NumberOfPtes * sizeof (MMPTE),
    01806                      ZeroKernelPte.u.Long);
    01807
    01808     //
    01809     // The page frame field points to the next cluster.  As we only
    01810     // have one cluster at initialization time, mark it as the last
    01811     // cluster.
    01812     //
    01813
    01814     StartingPte->u.List.NextEntry = MM_EMPTY_LIST;
    01815
    01816     MmFirstFreeSystemPte[SystemPtePoolType] = ZeroKernelPte;
    01817     MmFirstFreeSystemPte[SystemPtePoolType].u.List.NextEntry =
    01818                                                 StartingPte - MmSystemPteBase;
    01819
    01820     //
    01821     // If there is only one PTE in the pool, then mark it as a one entry
    01822     // PTE. Otherwise, store the cluster size in the following PTE.
    01823     //
    01824
    01825     if (NumberOfPtes == 1) {
    01826         StartingPte->u.List.OneEntry = TRUE;
    01827
    01828     } else {
    01829         StartingPte += 1;
    01830         MI_WRITE_INVALID_PTE (StartingPte, ZeroKernelPte);
    01831         StartingPte->u.List.NextEntry = NumberOfPtes;
    01832     }
    01833
    01834     //
    01835     // Set the total number of free PTEs for the specified type.
    01836     //
    01837
    01838     MmTotalFreeSystemPtes[SystemPtePoolType] = NumberOfPtes;
    01839
    01840     ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] ==
    01841                          MiCountFreeSystemPtes (SystemPtePoolType));
    01842
    01843     if (SystemPtePoolType == SystemPteSpace) {
    01844
    01845         ULONG Lists[MM_SYS_PTE_TABLES_MAX] = {MM_PTE_LIST_1, MM_PTE_LIST_2, MM_PTE_LIST_4, MM_PTE_LIST_8, MM_PTE_LIST_16};
    01846         PMMPTE PointerPte;
    01847         ULONG total;
    01848
    01849 #ifdef _MI_SYSPTE_DEBUG_
    01850         Tracker = (PMMPTE_TRACKER) MiAllocatePoolPages (
    01851                                           NonPagedPool,
    01852                                           NumberOfPtes * sizeof (MMPTE_TRACKER),
    01853                                           0);
    01854
    01855         if (Tracker) {
    01856             RtlZeroMemory (Tracker, NumberOfPtes * sizeof (MMPTE_TRACKER));
    01857         }
    01858 #endif
    01859
    01860         for (j = 0; j < MM_SYS_PTE_TABLES_MAX ; j++) {
    01861             MmFreeSysPteListBySize [j].u.List.NextEntry = MM_EMPTY_PTE_LIST;
    01862             MmLastSysPteListBySize [j] = &MmFreeSysPteListBySize [j];
    01863         }
    01864         MmFlushCounter += 1;
    01865
    01866 #ifndef _MI_GUARD_PTE_
    01867
    01868         //
    01869         // Initialize the by size lists.
    01870         //
    01871
    01872         total = MM_PTE_LIST_1 * MmSysPteIndex[0] +
    01873                 MM_PTE_LIST_2 * MmSysPteIndex[1] +
    01874                 MM_PTE_LIST_4 * MmSysPteIndex[2] +
    01875                 MM_PTE_LIST_8 * MmSysPteIndex[3] +
    01876                 MM_PTE_LIST_16 * MmSysPteIndex[4];
    01877
    01878         PointerPte = MiReserveSystemPtes (total,
    01879                                           SystemPteSpace,
    01880                                           64*1024,
    01881                                           0,
    01882                                           TRUE);
    01883
    01884         for (i = (MM_SYS_PTE_TABLES_MAX - 1); i >= 0; i--) {
    01885             do {
    01886                 Lists[i] -= 1;
    01887                 MiReleaseSystemPtes (PointerPte,
    01888                                      MmSysPteIndex[i],
    01889                                      SystemPteSpace);
    01890                 PointerPte += MmSysPteIndex[i];
    01891             } while (Lists[i] != 0  );
    01892         }
    01893 #endif
    01894
    01895         MmFlushCounter += 1;
    01896         MmFlushPte1 = NULL;
    01897
    01898 #ifdef _MI_SYSPTE_DEBUG_
    01899         MiPteTracker = Tracker;
    01900 #endif
    01901     }
    01902
    01903     return;
    01904 }
    01905
    01906 VOID
    01907 MiAddSystemPtes(
    01908     IN PMMPTE StartingPte,
    01909     IN ULONG  NumberOfPtes,
    01910     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    01911     )
    01912
    01913 /*++
    01914
    01915 Routine Description:
    01916
    01917     This routine adds newly created PTEs to the specified pool.
    01918
    01919 Arguments:
    01920
    01921     StartingPte - Supplies the address of the first PTE to put in the pool.
    01922
    01923     NumberOfPtes - Supplies the number of PTEs to put in the pool.
    01924
    01925     SystemPtePoolType - Supplies the PTE type of the pool to expand, one of
    01926                         SystemPteSpace or NonPagedPoolExpansion.
    01927
    01928 Return Value:
    01929
    01930     None.
    01931
    01932 Environment:
    01933
    01934     Kernel mode.
    01935
    01936 --*/
    01937
    01938 {
    01939     PMMPTE EndingPte;
    01940
    01941     EndingPte = StartingPte + NumberOfPtes - 1;
    01942
    01943 #ifdef _MI_SYSPTE_DEBUG_
    01944     MiRebuildPteTracker (StartingPte, NumberOfPtes);
    01945 #endif
    01946
    01947     if (StartingPte < MmSystemPtesStart[SystemPtePoolType]) {
    01948         MmSystemPtesStart[SystemPtePoolType] = StartingPte;
    01949     }
    01950
    01951     if (EndingPte > MmSystemPtesEnd[SystemPtePoolType]) {
    01952         MmSystemPtesEnd[SystemPtePoolType] = EndingPte;
    01953     }
    01954
    01955 #ifdef _MI_SYSPTE_DEBUG_
    01956
    01957     if (SystemPtePoolType == SystemPteSpace && MiPteTracker != NULL) {
    01958
    01959         ULONG i;
    01960         ULONG_PTR Index;
    01961         PMMPTE_TRACKER Tracker;
    01962
    01963         Index = StartingPte - MmSystemPtesStart[SystemPteSpace];
    01964         Tracker = &MiPteTracker[Index];
    01965
    01966         ASSERT (NumberOfPtes < 0x10000);
    01967         Tracker->NumberOfPtes = (USHORT)NumberOfPtes;
    01968
    01969         for (i = 0; i < NumberOfPtes; i += 1) {
    01970             Tracker->InUse = TRUE;
    01971             Tracker += 1;
    01972         }
    01973     }
    01974
    01975     MiFillMemoryPte (StartingPte, NumberOfPtes * sizeof (MMPTE), MM_KERNEL_NOACCESS_PTE);
    01976 #endif
    01977
    01978 #ifdef _MI_GUARD_PTE_
    01979     MiReleaseSystemPtes (StartingPte, NumberOfPtes - 1, SystemPtePoolType);
    01980 #else
    01981     MiReleaseSystemPtes (StartingPte, NumberOfPtes, SystemPtePoolType);
    01982 #endif
    01983 }
    01984
    01985
    01986 ULONG
    01987 MiGetSystemPteListCount (
    01988     IN ULONG ListSize
    01989     )
    01990
    01991 /*++
    01992
    01993 Routine Description:
    01994
    01995     This routine returns the number of free entries of the list which
    01996     covers the specified size.  The size must be less than or equal to the
    01997     largest list index.
    01998
    01999 Arguments:
    02000
    02001     ListSize - Supplies the number of PTEs needed.
    02002
    02003 Return Value:
    02004
    02005     Number of free entries on the list which contains ListSize PTEs.
    02006
    02007 Environment:
    02008
    02009     Kernel mode.
    02010
    02011 --*/
    02012
    02013 {
    02014 #ifdef _MI_GUARD_PTE_
    02015     UNREFERENCED_PARAMETER (ListSize);
    02016
    02017     return 8;
    02018 #else
    02019     ULONG Index;
    02020
    02021     ASSERT (ListSize <= MM_PTE_TABLE_LIMIT);
    02022
    02023     Index = MmSysPteTables [ListSize];
    02024     return MmSysPteListBySizeCount[Index];
    02025 #endif
    02026 }
    02027
    02028
    02029 LOGICAL
    02030 MiGetSystemPteAvailability (
    02031     IN ULONG NumberOfPtes,
    02032     IN MM_PAGE_PRIORITY Priority
    02033     )
    02034
    02035 /*++
    02036
    02037 Routine Description:
    02038
    02039     This routine checks how many SystemPteSpace PTEs are available for the
    02040     requested size.  If plenty are available then TRUE is returned.
    02041     If we are reaching a low resource situation, then the request is evaluated
    02042     based on the argument priority.
    02043
    02044 Arguments:
    02045
    02046     NumberOfPtes - Supplies the number of PTEs needed.
    02047
    02048     Priority - Supplies the priority of the request.
    02049
    02050 Return Value:
    02051
    02052     TRUE if the caller should allocate the PTEs, FALSE if not.
    02053
    02054 Environment:
    02055
    02056     Kernel mode.
    02057
    02058 --*/
    02059
    02060 {
    02061     ULONG Index;
    02062     ULONG FreePtes;
    02063     ULONG FreeBinnedPtes;
    02064
    02065     if (Priority == HighPagePriority) {
    02066         return TRUE;
    02067     }
    02068
    02069 #ifdef _MI_GUARD_PTE_
    02070     NumberOfPtes += 1;
    02071 #endif
    02072
    02073     FreePtes = MmTotalFreeSystemPtes[SystemPteSpace];
    02074
    02075     if (NumberOfPtes <= MM_PTE_TABLE_LIMIT) {
    02076         Index = MmSysPteTables [NumberOfPtes];
    02077         FreeBinnedPtes = MmSysPteListBySizeCount[Index];
    02078
    02079         if (FreeBinnedPtes > MmSysPteMinimumFree[Index]) {
    02080             return TRUE;
    02081         }
    02082         if (FreeBinnedPtes != 0) {
    02083             if (Priority == NormalPagePriority) {
    02084                 if (FreeBinnedPtes > 1 || FreePtes > 512) {
    02085                     return TRUE;
    02086                 }
    02087                 return FALSE;
    02088             }
    02089             if (FreePtes > 2048) {
    02090                 return TRUE;
    02091             }
    02092             return FALSE;
    02093         }
    02094     }
    02095
    02096     if (Priority == NormalPagePriority) {
    02097         if ((LONG)NumberOfPtes < (LONG)FreePtes - 512) {
    02098             return TRUE;
    02099         }
    02100         return FALSE;
    02101     }
    02102
    02103     if ((LONG)NumberOfPtes < (LONG)FreePtes - 2048) {
    02104         return TRUE;
    02105     }
    02106     return FALSE;
    02107 }
    02108
    02109 #if DBG
    02110
    02111 VOID
    02112 MiDumpSystemPtes (
    02113     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    02114     )
    02115
    02116
    02117 {
    02118     PMMPTE PointerPte;
    02119     PMMPTE PointerNextPte;
    02120     ULONG_PTR ClusterSize;
    02121     PMMPTE EndOfCluster;
    02122
    02123     PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType];
    02124     if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    02125         return;
    02126     }
    02127
    02128     PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    02129
    02130     for (;;) {
    02131         if (PointerPte->u.List.OneEntry) {
    02132             ClusterSize = 1;
    02133         } else {
    02134             PointerNextPte = PointerPte + 1;
    02135             ClusterSize = (ULONG_PTR) PointerNextPte->u.List.NextEntry;
    02136         }
    02137
    02138         EndOfCluster = PointerPte + (ClusterSize - 1);
    02139
    02140         DbgPrint("System Pte at %p for %p entries (%p)\n",
    02141                 PointerPte, ClusterSize, EndOfCluster);
    02142
    02143         if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    02144             break;
    02145         }
    02146
    02147         PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    02148     }
    02149     return;
    02150 }
    02151
    02152 ULONG
    02153 MiCountFreeSystemPtes (
    02154     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
    02155     )
    02156
    02157 {
    02158     PMMPTE PointerPte;
    02159     PMMPTE PointerNextPte;
    02160     ULONG_PTR ClusterSize;
    02161     ULONG_PTR FreeCount;
    02162
    02163     PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType];
    02164     if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    02165         return 0;
    02166     }
    02167
    02168     FreeCount = 0;
    02169
    02170     PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    02171
    02172     for (;;) {
    02173         if (PointerPte->u.List.OneEntry) {
    02174             ClusterSize = 1;
    02175
    02176         } else {
    02177             PointerNextPte = PointerPte + 1;
    02178             ClusterSize = (ULONG_PTR) PointerNextPte->u.List.NextEntry;
    02179         }
    02180
    02181         FreeCount += ClusterSize;
    02182         if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) {
    02183             break;
    02184         }
    02185
    02186         PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry;
    02187     }
    02188
    02189     return (ULONG)FreeCount;
    02190 }
    02191
    02192 #endif //DBG
    02193