00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
#include "mi.h"
00024
00025
#pragma alloc_text(INIT, MiInitializeSessionWsSupport)
00026
#pragma alloc_text(PAGE, MmAssignProcessToJob)
00027
#pragma alloc_text(PAGEHYDRA, MiSessionInitializeWorkingSetList)
00028
00029 #define MM_SYSTEM_CACHE_THRESHOLD ((1024*1024) / PAGE_SIZE)
00030
00031 extern ULONG
MmMaximumWorkingSetSize;
00032
00033 ULONG
MmFaultsTakenToGoAboveMaxWs = 100;
00034 ULONG
MmFaultsTakenToGoAboveMinWs = 16;
00035
00036 ULONG
MmSystemCodePage;
00037 ULONG
MmSystemCachePage;
00038 ULONG
MmPagedPoolPage;
00039 ULONG
MmSystemDriverPage;
00040
00041
#ifdef _MI_USE_CLAIMS_
00042
extern BOOLEAN MiReplacing;
00043
#endif
00044
00045 #define MM_RETRY_COUNT 2
00046
00047 extern ULONG
MmTransitionSharedPages;
00048 ULONG
MmTransitionSharedPagesPeak;
00049
00050 extern LOGICAL
MiTrimRemovalPagesOnly;
00051
00052 ULONG
00053
MiDoReplacement(
00054 IN
PMMSUPPORT WsInfo,
00055 IN BOOLEAN MustReplace
00056 );
00057
00058
#ifdef _MI_USE_CLAIMS_
00059
VOID
00060 MiReplaceWorkingSetEntryUsingClaim(
00061 IN
PMMSUPPORT WsInfo,
00062 IN BOOLEAN MustReplace
00063 );
00064
#else
00065
VOID
00066
MiReplaceWorkingSetEntryUsingFaultInfo(
00067 IN
PMMSUPPORT WsInfo,
00068 IN BOOLEAN MustReplace
00069 );
00070
#endif
00071
00072
VOID
00073
MiCheckWsleHash (
00074 IN
PMMWSL WorkingSetList
00075 );
00076
00077
VOID
00078
MiEliminateWorkingSetEntry (
00079 IN ULONG WorkingSetIndex,
00080 IN
PMMPTE PointerPte,
00081 IN
PMMPFN Pfn,
00082 IN
PMMWSLE Wsle
00083 );
00084
00085 ULONG
00086
MiAddWorkingSetPage (
00087 IN
PMMSUPPORT WsInfo
00088 );
00089
00090
VOID
00091
MiRemoveWorkingSetPages (
00092 IN
PMMWSL WorkingSetList,
00093 IN
PMMSUPPORT WsInfo
00094 );
00095
00096
VOID
00097
MiCheckNullIndex (
00098 IN
PMMWSL WorkingSetList
00099 );
00100
00101
VOID
00102
MiDumpWsleInCacheBlock (
00103 IN
PMMPTE CachePte
00104 );
00105
00106 ULONG
00107
MiDumpPteInCacheBlock (
00108 IN
PMMPTE PointerPte
00109 );
00110
00111
#ifdef ALLOC_PRAGMA
00112
#pragma alloc_text(PAGELK, MmAdjustWorkingSetSize)
00113
#endif // ALLOC_PRAGMA
00114
00115
00116
WSLE_NUMBER
00117 MiLocateAndReserveWsle (
00118 IN
PMMSUPPORT WsInfo
00119 )
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 {
00148
WSLE_NUMBER WorkingSetIndex;
00149
PMMWSL WorkingSetList;
00150
PMMWSLE Wsle;
00151 ULONG QuotaIncrement;
00152 BOOLEAN MustReplace;
00153
00154 MustReplace =
FALSE;
00155 WorkingSetList = WsInfo->VmWorkingSetList;
00156 Wsle = WorkingSetList->
Wsle;
00157
00158
00159
00160
00161
00162 WsInfo->PageFaultCount += 1;
00163
MmInfoCounters.
PageFaultCount += 1;
00164
00165
00166
00167
00168
00169
00170
00171 retry_replacement:
00172
00173 QuotaIncrement =
MiDoReplacement(WsInfo, MustReplace);
00174
00175
ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->
Quota);
00176 WsInfo->WorkingSetSize += 1;
00177
00178
if (WsInfo->WorkingSetSize > WorkingSetList->
Quota) {
00179
00180
00181
00182
00183
00184 WorkingSetList->
Quota += QuotaIncrement;
00185
00186 WsInfo->LastTrimFaultCount = WsInfo->PageFaultCount;
00187
00188
if (WorkingSetList->
Quota > WorkingSetList->
LastInitializedWsle) {
00189
00190
00191
00192
00193
00194
if (
MiAddWorkingSetPage (WsInfo) ==
TRUE) {
00195
ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->
Quota);
00196 }
00197
else {
00198
00199
00200
00201
00202
00203
00204 WsInfo->WorkingSetSize -= 1;
00205 MustReplace =
TRUE;
00206
goto retry_replacement;
00207 }
00208 }
00209 }
00210
00211
00212
00213
00214
00215
ASSERT (WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle);
00216
00217
ASSERT (WorkingSetList->
FirstFree >= WorkingSetList->
FirstDynamic);
00218
00219 WorkingSetIndex = WorkingSetList->
FirstFree;
00220 WorkingSetList->
FirstFree = (
WSLE_NUMBER)(Wsle[WorkingSetIndex].
u1.Long >>
MM_FREE_WSLE_SHIFT);
00221
00222
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
00223 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
00224
00225
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
00226
MmPagesAboveWsMinimum += 1;
00227 }
00228
00229
if (WsInfo->WorkingSetSize > WsInfo->PeakWorkingSetSize) {
00230 WsInfo->PeakWorkingSetSize = WsInfo->WorkingSetSize;
00231 }
00232
00233
if (WsInfo == &
MmSystemCacheWs) {
00234
if (WsInfo->WorkingSetSize +
MmTransitionSharedPages >
MmTransitionSharedPagesPeak) {
00235
MmTransitionSharedPagesPeak = WsInfo->WorkingSetSize +
MmTransitionSharedPages;
00236 }
00237 }
00238
00239
if (WorkingSetIndex > WorkingSetList->
LastEntry) {
00240 WorkingSetList->
LastEntry = WorkingSetIndex;
00241 }
00242
00243
00244
00245
00246
00247
ASSERT (Wsle[WorkingSetIndex].u1.
e1.
Valid == 0);
00248
00249
return WorkingSetIndex;
00250 }
00251
00252
00253 ULONG
00254 MiDoReplacement(
00255 IN
PMMSUPPORT WsInfo,
00256 IN BOOLEAN MustReplace
00257 )
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 {
00284
PMMWSL WorkingSetList;
00285 ULONG CurrentSize;
00286 LARGE_INTEGER CurrentTime;
00287
#if defined(_ALPHA_) && !defined(_AXP64_)
00288
KIRQL OldIrql;
00289
#endif
00290
ULONG QuotaIncrement;
00291 PFN_NUMBER AvailablePageThreshold;
00292
#ifdef _MI_USE_CLAIMS_
00293
PEPROCESS ProcessToTrim;
00294 ULONG Dummy1;
00295 ULONG Dummy2;
00296 ULONG Trim;
00297 ULONG TrimAge;
00298
#endif
00299
00300 WorkingSetList = WsInfo->VmWorkingSetList;
00301
00302
if (WsInfo == &
MmSystemCacheWs) {
00303
MM_SYSTEM_WS_LOCK_ASSERT();
00304 AvailablePageThreshold =
MM_SYSTEM_CACHE_THRESHOLD;
00305 }
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 recheck:
00316
00317 AvailablePageThreshold = 0;
00318 QuotaIncrement = 1;
00319
00320
if (WsInfo->WorkingSetSize >= WsInfo->MinimumWorkingSetSize) {
00321
00322
if (WsInfo->AllowWorkingSetAdjustment ==
MM_FORCE_TRIM) {
00323
00324
00325
00326
00327
00328
00329
00330
#ifdef _MI_USE_CLAIMS_
00331
00332 Trim = WsInfo->Claim >>
00333 ((WsInfo->MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND)
00334 ?
MI_FOREGROUND_CLAIM_AVAILABLE_SHIFT
00335 :
MI_BACKGROUND_CLAIM_AVAILABLE_SHIFT);
00336
00337
if (WsInfo == &
MmSystemCacheWs) {
00338 ProcessToTrim =
NULL;
00339 }
00340
else if (WsInfo->u.Flags.SessionSpace == 0) {
00341 ProcessToTrim = CONTAINING_RECORD(WsInfo,
EPROCESS, Vm);
00342 }
00343
else {
00344 ProcessToTrim =
NULL;
00345 }
00346
00347
if (
MmAvailablePages < 100) {
00348
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
00349 Trim = (WsInfo->WorkingSetSize - WsInfo->MinimumWorkingSetSize) >> 2;
00350 }
00351 TrimAge =
MI_PASS4_TRIM_AGE;
00352 }
00353
else {
00354 TrimAge =
MI_PASS0_TRIM_AGE;
00355 }
00356
00357
MiTrimWorkingSet (Trim, WsInfo, TrimAge);
00358
00359 MiAgeAndEstimateAvailableInWorkingSet (WsInfo,
00360
TRUE,
00361 &Dummy1,
00362 &Dummy2
00363 );
00364
#else
00365
MiTrimWorkingSet(20, WsInfo,
FALSE);
00366
#endif
00367
00368
KeQuerySystemTime (&CurrentTime);
00369 WsInfo->LastTrimTime = CurrentTime;
00370 WsInfo->LastTrimFaultCount = WsInfo->PageFaultCount;
00371
#if defined(_ALPHA_) && !defined(_AXP64_)
00372
LOCK_EXPANSION_IF_ALPHA (OldIrql);
00373
#endif
00374
WsInfo->AllowWorkingSetAdjustment =
TRUE;
00375
#if defined(_ALPHA_) && !defined(_AXP64_)
00376
UNLOCK_EXPANSION_IF_ALPHA (OldIrql);
00377
#endif
00378
00379
00380
00381
00382
00383 WorkingSetList->
Quota = WsInfo->WorkingSetSize;
00384
if (WorkingSetList->
Quota < WsInfo->MinimumWorkingSetSize) {
00385 WorkingSetList->
Quota = WsInfo->MinimumWorkingSetSize;
00386 }
00387
00388
goto recheck;
00389 }
00390
00391 CurrentSize = WsInfo->WorkingSetSize;
00392
ASSERT (CurrentSize <= (WorkingSetList->LastInitializedWsle + 1));
00393
00394
if ((WsInfo->u.Flags.WorkingSetHard) && (CurrentSize >= WsInfo->MaximumWorkingSetSize)) {
00395
00396
00397
00398
00399
00400
#ifdef _MI_USE_CLAIMS_
00401
MiReplaceWorkingSetEntryUsingClaim (WsInfo, MustReplace);
00402
#else
00403
MiReplaceWorkingSetEntryUsingFaultInfo (WsInfo, MustReplace);
00404
#endif
00405
return 0;
00406 }
00407
00408
#ifdef _MI_USE_CLAIMS_
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
if (CurrentSize >
MM_MAXIMUM_WORKING_SET ||
MmAvailablePages == 0 || MustReplace ==
TRUE) {
00420
00421
00422
00423
00424
00425 AvailablePageThreshold = 0xffffffff;
00426 MiReplacing =
TRUE;
00427 }
00428
#if defined (_X86PAE_)
00429
else if ((WsInfo->u.Flags.SessionSpace == 1) && (CurrentSize >
MI_SESSION_MAXIMUM_WORKING_SET)) {
00430
00431
00432
00433
00434
00435 AvailablePageThreshold = 0xffffffff;
00436 MiReplacing =
TRUE;
00437 }
00438
#endif
00439
else if (
MmAvailablePages < 10000 &&
MI_WS_GROWING_TOO_FAST(WsInfo)) {
00440
00441
00442
00443
00444
00445 AvailablePageThreshold = 0xffffffff;
00446 MiReplacing =
TRUE;
00447 }
00448
#else
00449
00450
00451
00452
00453
00454
if (MustReplace ==
TRUE) {
00455 AvailablePageThreshold = 0xffffffff;
00456 }
00457
if (CurrentSize < WorkingSetList->
Quota) {
00458
00459
00460
00461
00462
00463
00464 AvailablePageThreshold = 10;
00465 QuotaIncrement = 1;
00466 }
else if (CurrentSize < WsInfo->MaximumWorkingSetSize) {
00467
00468
00469
00470
00471
00472
00473
if ((WsInfo->PageFaultCount - WsInfo->LastTrimFaultCount) <
00474
MmFaultsTakenToGoAboveMinWs) {
00475 AvailablePageThreshold =
MmMoreThanEnoughFreePages + 200;
00476
if (WsInfo->MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND) {
00477 AvailablePageThreshold -= 250;
00478 }
00479 }
else {
00480 AvailablePageThreshold =
MmWsAdjustThreshold;
00481 }
00482 QuotaIncrement = (ULONG)
MmWorkingSetSizeIncrement;
00483 }
else {
00484
00485
00486
00487
00488
00489
if ((WsInfo->PageFaultCount - WsInfo->LastTrimFaultCount) <
00490 (CurrentSize >> 3))
00491 {
00492 AvailablePageThreshold =
MmMoreThanEnoughFreePages + 200;
00493
if (WsInfo->MemoryPriority ==
MEMORY_PRIORITY_FOREGROUND) {
00494 AvailablePageThreshold -= 250;
00495 }
00496 }
else {
00497 AvailablePageThreshold +=
MmWsExpandThreshold;
00498 }
00499 QuotaIncrement = (ULONG)
MmWorkingSetSizeExpansion;
00500
00501
if (CurrentSize >
MM_MAXIMUM_WORKING_SET) {
00502 AvailablePageThreshold = 0xffffffff;
00503 QuotaIncrement = 1;
00504 }
00505
#if defined (_X86PAE_)
00506
else if ((WsInfo->u.Flags.SessionSpace == 1) && (CurrentSize >
MI_SESSION_MAXIMUM_WORKING_SET)) {
00507 AvailablePageThreshold = 0xffffffff;
00508 QuotaIncrement = 1;
00509 }
00510
#endif
00511
}
00512
#endif
00513
}
00514
00515
00516
00517
00518
00519
00520
if (WsInfo->AddressSpaceBeingDeleted == 0 && AvailablePageThreshold != 0) {
00521
if ((
MmAvailablePages <= AvailablePageThreshold) ||
00522 (WsInfo->WorkingSetExpansionLinks.Flink ==
MM_NO_WS_EXPANSION)) {
00523
00524
#ifdef _MI_USE_CLAIMS_
00525
MiReplaceWorkingSetEntryUsingClaim (WsInfo, MustReplace);
00526
#else
00527
MiReplaceWorkingSetEntryUsingFaultInfo (WsInfo, MustReplace);
00528
#endif
00529
}
00530
else {
00531 WsInfo->GrowthSinceLastEstimate += 1;
00532 }
00533 }
00534
else {
00535 WsInfo->GrowthSinceLastEstimate += 1;
00536 }
00537
00538
return QuotaIncrement;
00539 }
00540
00541
00542 LOGICAL
00543 MmEnforceWorkingSetLimit(
00544 IN
PMMSUPPORT WsInfo,
00545 IN LOGICAL Enable
00546 )
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 {
00573 KIRQL OldIrql;
00574
00575 LOGICAL PreviousWorkingSetEnforcement;
00576
00577
LOCK_EXPANSION (OldIrql);
00578
00579 PreviousWorkingSetEnforcement = WsInfo->u.Flags.WorkingSetHard;
00580
00581 WsInfo->u.Flags.WorkingSetHard = Enable;
00582
00583
UNLOCK_EXPANSION (OldIrql);
00584
00585
#if 0
00586
00587
PEPROCESS CurrentProcess;
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
if (WsInfo == &
MmSystemCacheWs) {
00598
LOCK_SYSTEM_WS (OldIrql2);
00599
UNLOCK_SYSTEM_WS (OldIrql2);
00600 }
00601
else if (WsInfo->u.Flags.SessionSpace == 0) {
00602 CurrentProcess =
PsGetCurrentProcess ();
00603
LOCK_WS (CurrentProcess);
00604
00605
UNLOCK_WS (CurrentProcess);
00606 }
00607
#endif
00608
00609
return PreviousWorkingSetEnforcement;
00610 }
00611
00612
#ifdef _MI_USE_CLAIMS_
00613
00614
VOID
00615 MiReplaceWorkingSetEntryUsingClaim(
00616 IN
PMMSUPPORT WsInfo,
00617 IN BOOLEAN MustReplace
00618 )
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 {
00643 ULONG WorkingSetIndex;
00644 ULONG FirstDynamic;
00645 ULONG LastEntry;
00646
PMMWSL WorkingSetList;
00647
PMMWSLE Wsle;
00648 ULONG NumberOfCandidates;
00649
PMMPTE PointerPte;
00650 ULONG TheNextSlot;
00651 ULONG OldestWorkingSetIndex;
00652 LONG OldestAge;
00653
00654 WorkingSetList = WsInfo->VmWorkingSetList;
00655 Wsle = WorkingSetList->
Wsle;
00656
00657
00658
00659
00660
00661 LastEntry = WorkingSetList->
LastEntry;
00662 FirstDynamic = WorkingSetList->
FirstDynamic;
00663 WorkingSetIndex = WorkingSetList->
NextSlot;
00664
if (WorkingSetIndex > LastEntry || WorkingSetIndex < FirstDynamic) {
00665 WorkingSetIndex = FirstDynamic;
00666 }
00667 TheNextSlot = WorkingSetIndex;
00668 NumberOfCandidates = 0;
00669
00670 OldestWorkingSetIndex =
WSLE_NULL_INDEX;
00671
00672
while (
TRUE) {
00673
00674
00675
00676
00677
00678
00679
00680
00681
while (Wsle[WorkingSetIndex].
u1.e1.Valid == 0) {
00682 WorkingSetIndex += 1;
00683
if (WorkingSetIndex > LastEntry) {
00684 WorkingSetIndex = FirstDynamic;
00685 }
00686
if (WorkingSetIndex == TheNextSlot && MustReplace ==
FALSE) {
00687
00688
00689
00690
00691
00692
00693 WsInfo->GrowthSinceLastEstimate += 1;
00694
return;
00695 }
00696 }
00697
00698
if (OldestWorkingSetIndex ==
WSLE_NULL_INDEX) {
00699
00700
00701
00702
00703
00704
00705
00706 OldestWorkingSetIndex = WorkingSetIndex;
00707 OldestAge = -1;
00708 }
00709
00710 PointerPte =
MiGetPteAddress(Wsle[WorkingSetIndex].u1.VirtualAddress);
00711
00712
if (MustReplace ==
TRUE ||
00713 ((
MI_GET_ACCESSED_IN_PTE(PointerPte) == 0) &&
00714 (OldestAge < (LONG)
MI_GET_WSLE_AGE(PointerPte, &Wsle[WorkingSetIndex])))) {
00715
00716
00717
00718
00719
00720 OldestAge =
MI_GET_WSLE_AGE(PointerPte, &Wsle[WorkingSetIndex]);
00721 OldestWorkingSetIndex = WorkingSetIndex;
00722 }
00723
00724
00725
00726
00727
00728
if (MustReplace ==
TRUE ||
00729 OldestAge >=
MI_IMMEDIATE_REPLACEMENT_AGE ||
00730 NumberOfCandidates >
MM_WORKING_SET_LIST_SEARCH) {
00731
00732
PERFINFO_PAGE_INFO_REPLACEMENT_DECL();
00733
00734
if (OldestWorkingSetIndex != WorkingSetIndex) {
00735 WorkingSetIndex = OldestWorkingSetIndex;
00736 PointerPte =
MiGetPteAddress(Wsle[WorkingSetIndex].u1.VirtualAddress);
00737 }
00738
00739
PERFINFO_GET_PAGE_INFO_REPLACEMENT(PointerPte);
00740
00741
if (
MiFreeWsle(WorkingSetIndex, WsInfo, PointerPte)) {
00742
00743
PERFINFO_LOG_WS_REPLACEMENT(WsInfo);
00744
00745
00746
00747
00748
00749 WorkingSetList->
NextSlot = WorkingSetIndex + 1;
00750
break;
00751 }
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 WorkingSetIndex = OldestWorkingSetIndex + 1;
00762
00763 OldestWorkingSetIndex =
WSLE_NULL_INDEX;
00764 }
00765
else {
00766 WorkingSetIndex += 1;
00767 }
00768
00769
if (WorkingSetIndex > LastEntry) {
00770 WorkingSetIndex = FirstDynamic;
00771 }
00772
00773 NumberOfCandidates += 1;
00774
00775
if (WorkingSetIndex == TheNextSlot && MustReplace ==
FALSE) {
00776
00777
00778
00779
00780
00781
00782 WsInfo->GrowthSinceLastEstimate += 1;
00783
break;
00784 }
00785 }
00786 }
00787
#else
00788
00789
VOID
00790 MiReplaceWorkingSetEntryUsingFaultInfo(
00791 IN
PMMSUPPORT WsInfo,
00792 IN BOOLEAN MustReplace
00793 )
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817 {
00818 ULONG WorkingSetIndex;
00819 ULONG FirstDynamic;
00820 ULONG LastEntry;
00821
PMMWSL WorkingSetList;
00822
PMMWSLE Wsle;
00823 ULONG NumberOfCandidates;
00824
PMMPTE PointerPte;
00825 ULONG TheNextSlot;
00826
00827 WorkingSetList = WsInfo->VmWorkingSetList;
00828 Wsle = WorkingSetList->
Wsle;
00829
00830
00831
00832
00833
00834 LastEntry = WorkingSetList->
LastEntry;
00835 FirstDynamic = WorkingSetList->
FirstDynamic;
00836 WorkingSetIndex = WorkingSetList->
NextSlot;
00837
00838
if ((WorkingSetIndex > LastEntry) || (WorkingSetIndex < FirstDynamic)) {
00839 WorkingSetIndex = FirstDynamic;
00840 }
00841
00842 TheNextSlot = WorkingSetIndex;
00843 NumberOfCandidates = 0;
00844
00845
do {
00846
00847
00848
00849
00850
00851
if (Wsle[WorkingSetIndex].
u1.e1.Valid != 0) {
00852
00853 PointerPte =
MiGetPteAddress (
00854 Wsle[WorkingSetIndex].u1.
VirtualAddress);
00855
00856
if ((
MI_GET_ACCESSED_IN_PTE(PointerPte) == 0) ||
00857 (NumberOfCandidates >
MM_WORKING_SET_LIST_SEARCH)) {
00858
00859
PERFINFO_PAGE_INFO_REPLACEMENT_DECL();
00860
PERFINFO_GET_PAGE_INFO_REPLACEMENT(PointerPte);
00861
00862
00863
00864
00865
00866
00867
if ((WorkingSetIndex != TheNextSlot || MustReplace ==
TRUE) &&
00868
MiFreeWsle (WorkingSetIndex, WsInfo, PointerPte)) {
00869
00870
PERFINFO_LOG_WS_REPLACEMENT(WsInfo);
00871
00872
00873
00874
00875
00876 WorkingSetList->
NextSlot = WorkingSetIndex + 1;
00877
break;
00878 }
00879 }
00880
MI_SET_ACCESSED_IN_PTE (PointerPte, 0);
00881 NumberOfCandidates += 1;
00882 }
00883
00884 WorkingSetIndex += 1;
00885
if (WorkingSetIndex > LastEntry) {
00886 WorkingSetIndex = FirstDynamic;
00887 }
00888
00889 }
while (WorkingSetIndex != TheNextSlot || MustReplace ==
TRUE);
00890
00891
00892
00893
00894
00895 }
00896
#endif
00897
00898 ULONG
00899 MiRemovePageFromWorkingSet (
00900 IN
PMMPTE PointerPte,
00901 IN
PMMPFN Pfn1,
00902 IN
PMMSUPPORT WsInfo
00903 )
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 {
00932
WSLE_NUMBER WorkingSetIndex;
00933 PVOID VirtualAddress;
00934
WSLE_NUMBER Entry;
00935 PVOID SwapVa;
00936
MMWSLENTRY Locked;
00937
PMMWSL WorkingSetList;
00938
PMMWSLE Wsle;
00939 KIRQL OldIrql;
00940
00941 WorkingSetList = WsInfo->VmWorkingSetList;
00942 Wsle = WorkingSetList->
Wsle;
00943
00944 VirtualAddress =
MiGetVirtualAddressMappedByPte (PointerPte);
00945 WorkingSetIndex =
MiLocateWsle (VirtualAddress,
00946 WorkingSetList,
00947 Pfn1->u1.WsIndex);
00948
00949
ASSERT (WorkingSetIndex !=
WSLE_NULL_INDEX);
00950
LOCK_PFN (OldIrql);
00951
MiEliminateWorkingSetEntry (WorkingSetIndex,
00952 PointerPte,
00953 Pfn1,
00954 Wsle);
00955
00956
UNLOCK_PFN (OldIrql);
00957
00958
00959
00960
00961
00962
00963 Locked = Wsle[WorkingSetIndex].
u1.e1;
00964
MiRemoveWsle (WorkingSetIndex, WorkingSetList);
00965
00966
00967
00968
00969
00970
00971
MiReleaseWsle ((
WSLE_NUMBER)WorkingSetIndex, WsInfo);
00972
00973
if ((Locked.
LockedInWs == 1) || (Locked.
LockedInMemory == 1)) {
00974
00975
00976
00977
00978
00979 WorkingSetList->
FirstDynamic -= 1;
00980
00981
if (WorkingSetIndex != WorkingSetList->
FirstDynamic) {
00982
00983 SwapVa = Wsle[WorkingSetList->
FirstDynamic].u1.VirtualAddress;
00984 SwapVa =
PAGE_ALIGN (SwapVa);
00985
00986 PointerPte =
MiGetPteAddress (SwapVa);
00987 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
00988
#if 0
00989
Entry = MiLocateWsleAndParent (SwapVa,
00990 &Parent,
00991 WorkingSetList,
00992 Pfn1->u1.WsIndex);
00993
00994
00995
00996
00997
00998
00999
MiSwapWslEntries (Entry, Parent, WorkingSetIndex, WorkingSetList);
01000
#endif //0
01001
01002 Entry =
MiLocateWsle (SwapVa, WorkingSetList, Pfn1->u1.WsIndex);
01003
01004
MiSwapWslEntries (Entry, WorkingSetIndex, WsInfo);
01005
01006 }
01007
return TRUE;
01008 }
else {
01009
ASSERT (WorkingSetIndex >= WorkingSetList->
FirstDynamic);
01010 }
01011
return FALSE;
01012 }
01013
01014
01015
VOID
01016 MiReleaseWsle (
01017 IN WSLE_NUMBER WorkingSetIndex,
01018 IN
PMMSUPPORT WsInfo
01019 )
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044 {
01045
PMMWSL WorkingSetList;
01046
PMMWSLE Wsle;
01047
01048 WorkingSetList = WsInfo->VmWorkingSetList;
01049 Wsle = WorkingSetList->
Wsle;
01050
#if DBG
01051
if (WsInfo == &
MmSystemCacheWs) {
01052
MM_SYSTEM_WS_LOCK_ASSERT();
01053 }
01054
#endif //DBG
01055
01056
ASSERT (WorkingSetIndex <= WorkingSetList->LastInitializedWsle);
01057
01058
01059
01060
01061
01062
01063
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
01064 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
01065 Wsle[WorkingSetIndex].
u1.Long = WorkingSetList->
FirstFree <<
MM_FREE_WSLE_SHIFT;
01066 WorkingSetList->
FirstFree = WorkingSetIndex;
01067
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
01068 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
01069
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
01070
MmPagesAboveWsMinimum -= 1;
01071 }
01072 WsInfo->WorkingSetSize -= 1;
01073
return;
01074
01075 }
01076
01077
VOID
01078 MiUpdateWsle (
01079 IN OUT
PWSLE_NUMBER DesiredIndex,
01080 IN PVOID VirtualAddress,
01081
PMMWSL WorkingSetList,
01082 IN
PMMPFN Pfn
01083 )
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 {
01115
PMMWSLE Wsle;
01116
WSLE_NUMBER Index;
01117
WSLE_NUMBER WorkingSetIndex;
01118
#if PFN_CONSISTENCY
01119
KIRQL OldIrql;
01120
#endif
01121
01122 WorkingSetIndex = *DesiredIndex;
01123 Wsle = WorkingSetList->
Wsle;
01124
01125
if (WorkingSetList ==
MmSystemCacheWorkingSetList) {
01126
01127
01128
01129
01130
01131
01132
ASSERT32 ((VirtualAddress < (PVOID)PTE_BASE) ||
01133 (VirtualAddress >= (PVOID)
MM_SYSTEM_SPACE_START));
01134 }
else {
01135
ASSERT ((VirtualAddress < (PVOID)
MM_SYSTEM_SPACE_START) ||
01136 (
MI_IS_SESSION_ADDRESS (VirtualAddress)));
01137 }
01138
01139
ASSERT (WorkingSetIndex >= WorkingSetList->
FirstDynamic);
01140
01141
if (WorkingSetList ==
MmSystemCacheWorkingSetList) {
01142
01143
MM_SYSTEM_WS_LOCK_ASSERT();
01144
01145
01146
01147
01148
01149
#if defined(_X86_)
01150
if (
MI_IS_SYSTEM_CACHE_ADDRESS(VirtualAddress)) {
01151
MmSystemCachePage += 1;
01152 }
else
01153
#endif
01154
if (VirtualAddress <
MmSystemCacheStart) {
01155
MmSystemCodePage += 1;
01156 }
else if (VirtualAddress <
MM_PAGED_POOL_START) {
01157
MmSystemCachePage += 1;
01158 }
else if (VirtualAddress <
MmNonPagedSystemStart) {
01159
MmPagedPoolPage += 1;
01160 }
else {
01161
MmSystemDriverPage += 1;
01162 }
01163 }
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
ASSERT (Pfn->u1.WsIndex != 0);
01180
01181
#if DBG
01182
if (Pfn->u1.WsIndex <= WorkingSetList->
LastInitializedWsle) {
01183
ASSERT ((
PAGE_ALIGN(VirtualAddress) !=
01184
PAGE_ALIGN(Wsle[Pfn->
u1.WsIndex].u1.VirtualAddress)) ||
01185 (Wsle[Pfn->u1.WsIndex].u1.e1.Valid == 0));
01186 }
01187
#endif //DBG
01188
01189 Wsle[WorkingSetIndex].
u1.VirtualAddress = VirtualAddress;
01190 Wsle[WorkingSetIndex].
u1.Long &= ~(
PAGE_SIZE - 1);
01191 Wsle[WorkingSetIndex].
u1.e1.Valid = 1;
01192
01193
if ((ULONG_PTR)Pfn->u1.Event == (ULONG_PTR)
PsGetCurrentThread()) {
01194
01195
01196
01197
01198
01199
01200
CONSISTENCY_LOCK_PFN (OldIrql);
01201
01202
#if defined(_WIN64)
01203
01204
01205
01206
01207
01208
MI_ZERO_WSINDEX (Pfn);
01209
01210
#endif
01211
01212 Pfn->u1.WsIndex = WorkingSetIndex;
01213
01214
CONSISTENCY_UNLOCK_PFN (OldIrql);
01215
01216 Wsle[WorkingSetIndex].
u1.e1.Direct = 1;
01217
01218
return;
01219
01220 }
else if (WorkingSetList->
HashTable ==
NULL) {
01221
01222
01223
01224
01225
01226
Index = Pfn->u1.WsIndex;
01227
01228
if ((
Index < WorkingSetList->
LastInitializedWsle) &&
01229 (
Index > WorkingSetList->
FirstDynamic) &&
01230 (
Index != WorkingSetIndex)) {
01231
01232
if (Wsle[
Index].
u1.e1.Valid) {
01233
01234
if (Wsle[
Index].
u1.e1.Direct) {
01235
01236
01237
01238
01239
01240
PMMSUPPORT WsInfo;
01241
01242
if (Wsle ==
MmWsle) {
01243 WsInfo = &
PsGetCurrentProcess()->Vm;
01244 }
01245
else if (Wsle ==
MmSystemCacheWsle) {
01246 WsInfo = &
MmSystemCacheWs;
01247 }
01248
else {
01249 WsInfo = &
MmSessionSpace->
Vm;
01250 }
01251
01252
MiSwapWslEntries (
Index, WorkingSetIndex, WsInfo);
01253 WorkingSetIndex =
Index;
01254 }
01255 }
else {
01256
01257
01258
01259
01260
01261
01262 ULONG FreeIndex;
01263
MMWSLE Temp;
01264
01265 FreeIndex = 0;
01266
01267
ASSERT (WorkingSetList->
FirstFree >= WorkingSetList->
FirstDynamic);
01268
ASSERT (WorkingSetIndex >= WorkingSetList->
FirstDynamic);
01269
01270
if (WorkingSetList->
FirstFree ==
Index) {
01271 WorkingSetList->
FirstFree = WorkingSetIndex;
01272 Temp = Wsle[WorkingSetIndex];
01273 Wsle[WorkingSetIndex] = Wsle[
Index];
01274 Wsle[
Index] = Temp;
01275 WorkingSetIndex =
Index;
01276
ASSERT (((Wsle[WorkingSetList->
FirstFree].u1.Long >>
MM_FREE_WSLE_SHIFT)
01277 <= WorkingSetList->
LastInitializedWsle) ||
01278 ((Wsle[WorkingSetList->
FirstFree].u1.Long >>
MM_FREE_WSLE_SHIFT)
01279 ==
WSLE_NULL_INDEX));
01280 }
else if (Wsle[
Index - 1].
u1.e1.Valid == 0) {
01281
if ((Wsle[
Index - 1].
u1.Long >>
MM_FREE_WSLE_SHIFT) ==
Index) {
01282 FreeIndex =
Index - 1;
01283 }
01284 }
else if (Wsle[
Index + 1].
u1.e1.Valid == 0) {
01285
if ((Wsle[
Index + 1].
u1.Long >>
MM_FREE_WSLE_SHIFT) ==
Index) {
01286 FreeIndex =
Index + 1;
01287 }
01288 }
01289
if (FreeIndex != 0) {
01290
01291
01292
01293
01294
01295 Temp = Wsle[WorkingSetIndex];
01296 Wsle[FreeIndex].
u1.Long = WorkingSetIndex <<
MM_FREE_WSLE_SHIFT;
01297 Wsle[WorkingSetIndex] = Wsle[
Index];
01298 Wsle[
Index] = Temp;
01299 WorkingSetIndex =
Index;
01300
01301
ASSERT (((Wsle[FreeIndex].u1.Long >>
MM_FREE_WSLE_SHIFT)
01302 <= WorkingSetList->
LastInitializedWsle) ||
01303 ((Wsle[FreeIndex].u1.Long >>
MM_FREE_WSLE_SHIFT)
01304 ==
WSLE_NULL_INDEX));
01305 }
01306
01307 }
01308 *DesiredIndex = WorkingSetIndex;
01309
01310
if (WorkingSetIndex > WorkingSetList->
LastEntry) {
01311 WorkingSetList->
LastEntry = WorkingSetIndex;
01312 }
01313 }
01314 }
01315
01316
01317
01318
01319
01320
MiInsertWsle (WorkingSetIndex, WorkingSetList);
01321
return;
01322 }
01323
01324
01325 ULONG
01326 MiFreeWsle (
01327 IN WSLE_NUMBER WorkingSetIndex,
01328 IN
PMMSUPPORT WsInfo,
01329 IN
PMMPTE PointerPte
01330 )
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361 {
01362
PMMPFN Pfn1;
01363
PMMWSL WorkingSetList;
01364
PMMWSLE Wsle;
01365 KIRQL OldIrql;
01366
01367 WorkingSetList = WsInfo->VmWorkingSetList;
01368 Wsle = WorkingSetList->
Wsle;
01369
01370
#if DBG
01371
if (WsInfo == &
MmSystemCacheWs) {
01372
MM_SYSTEM_WS_LOCK_ASSERT();
01373 }
01374
#endif //DBG
01375
01376
ASSERT (Wsle[WorkingSetIndex].u1.
e1.
Valid == 1);
01377
01378
01379
01380
01381
01382
ASSERT (PointerPte->u.Hard.Valid == 1);
01383
01384
ASSERT (WorkingSetIndex >= WorkingSetList->
FirstDynamic);
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
01395
01396
LOCK_PFN (OldIrql);
01397
01398
01399
01400
01401
01402
01403
01404
if (WsInfo == &
MmSystemCacheWs) {
01405
if (Pfn1->
u3.e2.ReferenceCount > 1) {
01406
UNLOCK_PFN (OldIrql);
01407
return FALSE;
01408 }
01409 }
else {
01410
if ((Pfn1->
u2.ShareCount > 1) &&
01411 (Pfn1->
u3.e1.PrototypePte == 0)) {
01412
01413
#if DBG
01414
if (WsInfo->u.Flags.SessionSpace == 1) {
01415
ASSERT (
MI_IS_SESSION_ADDRESS (Wsle[WorkingSetIndex].u1.
VirtualAddress));
01416 }
01417
else {
01418
ASSERT ((Wsle[WorkingSetIndex].u1.
VirtualAddress >= (PVOID)PTE_BASE) &&
01419 (Wsle[WorkingSetIndex].
u1.VirtualAddress<= (PVOID)
PDE_TOP));
01420 }
01421
#endif
01422
01423
01424
01425
01426
01427
01428
UNLOCK_PFN (OldIrql);
01429
return FALSE;
01430 }
01431 }
01432
01433
01434
01435
01436
01437
MiEliminateWorkingSetEntry (WorkingSetIndex,
01438 PointerPte,
01439 Pfn1,
01440 Wsle);
01441
01442
UNLOCK_PFN (OldIrql);
01443
01444
01445
01446
01447
01448
MiRemoveWsle (WorkingSetIndex, WorkingSetList);
01449
01450
ASSERT (WorkingSetList->
FirstFree >= WorkingSetList->
FirstDynamic);
01451
01452
ASSERT (WorkingSetIndex >= WorkingSetList->
FirstDynamic);
01453
01454
01455
01456
01457
01458
01459
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
01460 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
01461 Wsle[WorkingSetIndex].
u1.Long = WorkingSetList->
FirstFree <<
MM_FREE_WSLE_SHIFT;
01462 WorkingSetList->
FirstFree = WorkingSetIndex;
01463
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
01464 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
01465
01466
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
01467
MmPagesAboveWsMinimum -= 1;
01468 }
01469 WsInfo->WorkingSetSize -= 1;
01470
01471
#if 0
01472
if ((WsInfo == &
MmSystemCacheWs) &&
01473 (Pfn1->
u3.e1.Modified == 1)) {
01474
MiDumpWsleInCacheBlock (PointerPte);
01475 }
01476
#endif //0
01477
return TRUE;
01478 }
01479
01480
VOID
01481 MiInitializeWorkingSetList (
01482 IN
PEPROCESS CurrentProcess
01483 )
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506 {
01507 ULONG i;
01508
PMMWSLE WslEntry;
01509 ULONG CurrentEntry;
01510
PMMPTE PointerPte;
01511
PMMPFN Pfn1;
01512
WSLE_NUMBER NumberOfEntriesMapped;
01513 ULONG_PTR CurrentVa;
01514 PFN_NUMBER WorkingSetPage;
01515
MMPTE TempPte;
01516 KIRQL OldIrql;
01517
01518 WslEntry =
MmWsle;
01519
01520
01521
01522
01523
01524
01525
01526
01527
MmWorkingSetList->
LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
01528
MmWorkingSetList->
Quota =
MmWorkingSetList->
LastEntry;
01529
MmWorkingSetList->
WaitingForImageMapping = (
PKEVENT)
NULL;
01530
MmWorkingSetList->
HashTable =
NULL;
01531
MmWorkingSetList->
HashTableSize = 0;
01532
MmWorkingSetList->
Wsle =
MmWsle;
01533
MmWorkingSetList->
HashTableStart =
01534 (PVOID)((PCHAR)
PAGE_ALIGN (&
MmWsle[
MM_MAXIMUM_WORKING_SET]) +
PAGE_SIZE);
01535
01536
MmWorkingSetList->
HighestPermittedHashAddress = (PVOID)(
HYPER_SPACE_END + 1);
01537
01538
01539
01540
01541
01542
#if !defined (_X86PAE_)
01543
01544 WslEntry->
u1.Long = PDE_BASE;
01545 WslEntry->
u1.e1.Valid = 1;
01546 WslEntry->
u1.e1.LockedInWs = 1;
01547 WslEntry->
u1.e1.Direct = 1;
01548
01549 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01550 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01551
01552
CONSISTENCY_LOCK_PFN (OldIrql);
01553
01554
#if !defined (_WIN64)
01555
Pfn1->
u1.Event = (PVOID)CurrentProcess;
01556
#endif
01557
01558
CONSISTENCY_UNLOCK_PFN (OldIrql);
01559
01560
#else
01561
01562
01563
01564
01565
01566
for (i = 0; i < PD_PER_SYSTEM; i += 1) {
01567
01568 WslEntry->
u1.VirtualAddress = (PVOID)(PDE_BASE + i *
PAGE_SIZE);
01569 WslEntry->
u1.e1.Valid = 1;
01570 WslEntry->
u1.e1.LockedInWs = 1;
01571 WslEntry->
u1.e1.Direct = 1;
01572
01573 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01574 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01575
01576
ASSERT (Pfn1->
u1.WsIndex == 0);
01577
01578
CONSISTENCY_LOCK_PFN (OldIrql);
01579
01580 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01581
01582
CONSISTENCY_UNLOCK_PFN (OldIrql);
01583
01584 WslEntry += 1;
01585 }
01586 WslEntry -= 1;
01587
01588
#endif
01589
01590
01591
#if defined (_WIN64)
01592
01593
01594
01595
01596
01597 WslEntry += 1;
01598
01599 WslEntry->
u1.Long = PDE_TBASE;
01600 WslEntry->
u1.e1.Valid = 1;
01601 WslEntry->
u1.e1.LockedInWs = 1;
01602 WslEntry->
u1.e1.Direct = 1;
01603
01604 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01605 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01606
01607
ASSERT (Pfn1->
u1.WsIndex == 0);
01608
01609
CONSISTENCY_LOCK_PFN (OldIrql);
01610
01611 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01612
01613
CONSISTENCY_UNLOCK_PFN (OldIrql);
01614
01615
01616
01617
01618
01619 WslEntry += 1;
01620
01621 WslEntry->
u1.VirtualAddress = (PVOID)
MiGetPdeAddress (
HYPER_SPACE);
01622 WslEntry->
u1.e1.Valid = 1;
01623 WslEntry->
u1.e1.LockedInWs = 1;
01624 WslEntry->
u1.e1.Direct = 1;
01625
01626 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01627 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01628
01629
ASSERT (Pfn1->
u1.WsIndex == 0);
01630
01631
CONSISTENCY_LOCK_PFN (OldIrql);
01632
01633 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01634
01635
CONSISTENCY_UNLOCK_PFN (OldIrql);
01636
01637
#if defined (_IA64_)
01638
01639
01640
01641
01642
01643 WslEntry += 1;
01644
01645 WslEntry->
u1.VirtualAddress = (PVOID)
MiGetPpeAddress (
MM_SESSION_SPACE_DEFAULT);
01646 WslEntry->
u1.e1.Valid = 1;
01647 WslEntry->
u1.e1.LockedInWs = 1;
01648 WslEntry->
u1.e1.Direct = 1;
01649
01650 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01651 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01652
01653
ASSERT (Pfn1->
u1.WsIndex == 0);
01654
01655
CONSISTENCY_LOCK_PFN (OldIrql);
01656
01657 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01658
01659
CONSISTENCY_UNLOCK_PFN (OldIrql);
01660
01661
#endif
01662
01663
#endif
01664
01665
01666
01667
01668
01669 WslEntry += 1;
01670
01671 WslEntry->
u1.VirtualAddress = (PVOID)
MiGetPteAddress (
HYPER_SPACE);
01672 WslEntry->
u1.e1.Valid = 1;
01673 WslEntry->
u1.e1.LockedInWs = 1;
01674 WslEntry->
u1.e1.Direct = 1;
01675
01676 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01677 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01678
01679
ASSERT (Pfn1->
u1.WsIndex == 0);
01680
01681
CONSISTENCY_LOCK_PFN (OldIrql);
01682
01683 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01684
01685
CONSISTENCY_UNLOCK_PFN (OldIrql);
01686
01687
#if defined (_X86PAE_)
01688
01689
01690
01691
01692
01693 WslEntry += 1;
01694
01695 WslEntry->
u1.VirtualAddress = (PVOID)
MiGetPteAddress (HYPER_SPACE2);
01696 WslEntry->
u1.e1.Valid = 1;
01697 WslEntry->
u1.e1.LockedInWs = 1;
01698 WslEntry->
u1.e1.Direct = 1;
01699
01700 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01701 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01702
01703
ASSERT (Pfn1->
u1.WsIndex == 0);
01704
01705
CONSISTENCY_LOCK_PFN (OldIrql);
01706
01707 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01708
01709
CONSISTENCY_UNLOCK_PFN (OldIrql);
01710
01711
#endif
01712
01713
01714
01715
01716
01717 WslEntry += 1;
01718
01719 WslEntry->
u1.VirtualAddress = (PVOID)
MmWorkingSetList;
01720 WslEntry->
u1.e1.Valid = 1;
01721 WslEntry->
u1.e1.LockedInWs = 1;
01722 WslEntry->
u1.e1.Direct = 1;
01723
01724 PointerPte =
MiGetPteAddress (WslEntry->
u1.VirtualAddress);
01725 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
01726
01727
ASSERT (Pfn1->
u1.WsIndex == 0);
01728
01729
CONSISTENCY_LOCK_PFN (OldIrql);
01730
01731 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmWsle);
01732
01733
CONSISTENCY_UNLOCK_PFN (OldIrql);
01734
01735 CurrentEntry = (
WSLE_NUMBER)((WslEntry -
MmWsle) + 1);
01736
01737
01738
01739
01740
01741
01742 NumberOfEntriesMapped = (
WSLE_NUMBER)(((
PMMWSLE)((PCHAR)
WORKING_SET_LIST +
PAGE_SIZE)) -
01743
MmWsle);
01744
01745
if (CurrentProcess->Vm.MaximumWorkingSetSize >= NumberOfEntriesMapped) {
01746
01747 PointerPte =
MiGetPteAddress (&
MmWsle[0]);
01748
01749 CurrentVa = (ULONG_PTR)
MmWorkingSetList +
PAGE_SIZE;
01750
01751
01752
01753
01754
01755
LOCK_PFN (OldIrql);
01756
01757
do {
01758
01759
MiEnsureAvailablePageOrWait (
NULL,
NULL);
01760
01761 PointerPte += 1;
01762 WorkingSetPage =
MiRemoveZeroPage (
01763
MI_PAGE_COLOR_PTE_PROCESS (PointerPte,
01764 &CurrentProcess->NextPageColor));
01765 PointerPte->u.Long =
MM_DEMAND_ZERO_WRITE_PTE;
01766
01767
MiInitializePfn (WorkingSetPage, PointerPte, 1);
01768
01769
MI_MAKE_VALID_PTE (TempPte,
01770 WorkingSetPage,
01771
MM_READWRITE,
01772 PointerPte );
01773
01774
MI_SET_PTE_DIRTY (TempPte);
01775
01776
MI_SET_PTE_IN_WORKING_SET (&TempPte, CurrentEntry);
01777
01778
MI_WRITE_VALID_PTE (PointerPte, TempPte);
01779
01780 WslEntry += 1;
01781
01782 WslEntry->
u1.Long = CurrentVa;
01783 WslEntry->
u1.e1.Valid = 1;
01784 WslEntry->
u1.e1.LockedInWs = 1;
01785 WslEntry->
u1.e1.Direct = 1;
01786
01787 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
01788
01789
ASSERT (Pfn1->
u1.WsIndex == 0);
01790 Pfn1->
u1.WsIndex = CurrentEntry;
01791
01792
01793
01794 CurrentEntry += 1;
01795 CurrentVa +=
PAGE_SIZE;
01796
01797 NumberOfEntriesMapped +=
PAGE_SIZE /
sizeof(
MMWSLE);
01798
01799 }
while (CurrentProcess->Vm.MaximumWorkingSetSize >= NumberOfEntriesMapped);
01800
01801
UNLOCK_PFN (OldIrql);
01802 }
01803
01804 CurrentProcess->Vm.WorkingSetSize = CurrentEntry;
01805
MmWorkingSetList->
FirstFree = CurrentEntry;
01806
MmWorkingSetList->
FirstDynamic = CurrentEntry;
01807
MmWorkingSetList->
NextSlot = CurrentEntry;
01808
01809
01810
01811
01812
01813 i = CurrentEntry + 1;
01814
do {
01815
01816
01817
01818
01819
01820
01821
01822
01823 WslEntry += 1;
01824 WslEntry->
u1.Long = i <<
MM_FREE_WSLE_SHIFT;
01825 i += 1;
01826 }
while (i <= NumberOfEntriesMapped);
01827
01828 WslEntry->
u1.Long =
WSLE_NULL_INDEX <<
MM_FREE_WSLE_SHIFT;
01829
01830
MmWorkingSetList->
LastInitializedWsle =
01831 NumberOfEntriesMapped - 1;
01832
01833
if (CurrentProcess->Vm.MaximumWorkingSetSize > ((1536*1024) >>
PAGE_SHIFT)) {
01834
01835
01836
01837
01838
01839
MiGrowWsleHash (&CurrentProcess->Vm);
01840 }
01841
01842
return;
01843 }
01844
01845
01846
VOID
01847 MiInitializeSessionWsSupport(
01848 VOID
01849 )
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871 {
01872
01873
01874
01875
01876 InitializeListHead (&
MiSessionWsList);
01877 }
01878
01879
01880
NTSTATUS
01881 MiSessionInitializeWorkingSetList (
01882 VOID
01883 )
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905
01906 {
01907 ULONG i;
01908 KIRQL OldIrql;
01909
PMMPTE PointerPte;
01910
PMMPTE PointerPde;
01911
MMPTE TempPte;
01912
PMMWSLE WslEntry;
01913
PMMPFN Pfn1;
01914 ULONG PageColor;
01915 PFN_NUMBER ResidentPages;
01916 ULONG
Index;
01917 PFN_NUMBER PageFrameIndex;
01918 ULONG CurrentEntry;
01919 ULONG NumberOfEntriesMapped;
01920 ULONG_PTR AdditionalBytes;
01921 ULONG NumberOfEntriesMappedByFirstPage;
01922 ULONG WorkingSetMaximum;
01923
PMM_SESSION_SPACE SessionGlobal;
01924 LOGICAL AllocatedPageTable;
01925
01926
01927
01928
01929
01930
01931 SessionGlobal =
SESSION_GLOBAL (
MmSessionSpace);
01932
01933
01934
01935
01936
01937 WorkingSetMaximum =
MI_SESSION_SPACE_WORKING_SET_MAXIMUM;
01938
01939
MmSessionSpace->
Vm.
VmWorkingSetList = (
PMMWSL)
MI_SESSION_SPACE_WS;
01940
#if defined (_WIN64)
01941
MmSessionSpace->
Wsle = (
PMMWSLE)(
MmSessionSpace->
Vm.
VmWorkingSetList + 1);
01942
#else
01943
MmSessionSpace->
Wsle =
01944 (
PMMWSLE)(&
MmSessionSpace->
Vm.
VmWorkingSetList->
UsedPageTableEntries[0]);
01945
#endif
01946
01947
ASSERT (
MmSessionSpace->
WorkingSetLockOwner ==
NULL);
01948
ASSERT (
MmSessionSpace->WorkingSetLockOwnerCount == 0);
01949
01950
01951
01952
01953
01954
01955 PointerPde =
MiGetPdeAddress (
MmSessionSpace->
Vm.
VmWorkingSetList);
01956
01957
01958
01959
01960
01961
01962
if (PointerPde->
u.Hard.Valid == 1) {
01963
01964
01965
01966
01967
01968
01969
#ifndef _IA64_
01970
ASSERT (PointerPde->
u.Hard.Global == 0);
01971
#endif
01972
AllocatedPageTable =
FALSE;
01973 ResidentPages = 1;
01974 }
01975
else {
01976 AllocatedPageTable =
TRUE;
01977 ResidentPages = 2;
01978 }
01979
01980
01981 PointerPte =
MiGetPteAddress (
MmSessionSpace->
Vm.
VmWorkingSetList);
01982
01983
01984
01985
01986
01987
01988 NumberOfEntriesMappedByFirstPage = (
WSLE_NUMBER)(
01989 ((
PMMWSLE)((ULONG_PTR)
MmSessionSpace->
Vm.
VmWorkingSetList +
PAGE_SIZE)) -
01990
MmSessionSpace->
Wsle);
01991
01992
if (WorkingSetMaximum > NumberOfEntriesMappedByFirstPage) {
01993 AdditionalBytes = (WorkingSetMaximum - NumberOfEntriesMappedByFirstPage) *
sizeof (
MMWSLE);
01994 ResidentPages +=
BYTES_TO_PAGES (AdditionalBytes);
01995 }
01996
01997
if (
MiChargeCommitment (ResidentPages,
NULL) ==
FALSE) {
01998
#if DBG
01999
DbgPrint(
"MiSessionInitializeWorkingSetList: No commit for %d pages\n",
02000 ResidentPages);
02001
02002
#endif
02003
MM_BUMP_SESSION_FAILURES (
MM_SESSION_FAILURE_NO_COMMIT);
02004
return STATUS_NO_MEMORY;
02005 }
02006
02007
MM_TRACK_COMMIT (
MM_DBG_COMMIT_SESSION_WS_INIT, ResidentPages);
02008
02009
02010
02011
02012
02013
02014
ExInitializeResource (&SessionGlobal->
WsLock);
02015
02016
LOCK_PFN (OldIrql);
02017
02018
02019
02020
02021
02022
if ((SPFN_NUMBER)ResidentPages >
MI_NONPAGABLE_MEMORY_AVAILABLE() - 20) {
02023
#if DBG
02024
DbgPrint(
"MiSessionInitializeWorkingSetList: No Resident Pages %d, Need %d\n",
02025
MmResidentAvailablePages,
02026 ResidentPages);
02027
#endif
02028
UNLOCK_PFN (OldIrql);
02029
02030
MiReturnCommitment (ResidentPages);
02031
MM_TRACK_COMMIT (
MM_DBG_COMMIT_RETURN_SESSION_WSL_FAILURE, ResidentPages);
02032
ExDeleteResource (&SessionGlobal->
WsLock);
02033
MM_BUMP_SESSION_FAILURES (
MM_SESSION_FAILURE_NO_RESIDENT);
02034
return STATUS_NO_MEMORY;
02035 }
02036
02037
MmResidentAvailablePages -= ResidentPages;
02038
02039
MM_BUMP_COUNTER(50, ResidentPages);
02040
02041
if (AllocatedPageTable ==
TRUE) {
02042
02043
MM_BUMP_SESS_COUNTER (
MM_DBG_SESSION_WS_PAGETABLE_ALLOC, 1);
02044
02045
MiEnsureAvailablePageOrWait (
NULL,
NULL);
02046
02047 PageColor =
MI_GET_PAGE_COLOR_FROM_VA (
NULL);
02048
02049 PageFrameIndex =
MiRemoveZeroPageIfAny (PageColor);
02050
if (PageFrameIndex == 0) {
02051 PageFrameIndex =
MiRemoveAnyPage (PageColor);
02052
UNLOCK_PFN (OldIrql);
02053
MiZeroPhysicalPage (PageFrameIndex, PageColor);
02054
LOCK_PFN (OldIrql);
02055 }
02056
02057
02058
02059
02060
02061
02062 TempPte.
u.Long =
ValidKernelPdeLocal.
u.Long;
02063 TempPte.
u.Hard.PageFrameNumber = PageFrameIndex;
02064
MI_WRITE_VALID_PTE (PointerPde, TempPte);
02065
02066
#if !defined (_WIN64)
02067
02068
02069
02070
02071
02072
Index =
MiGetPdeSessionIndex (
MmSessionSpace->
Vm.
VmWorkingSetList);
02073
02074
MmSessionSpace->
PageTables[
Index] = TempPte;
02075
02076
#endif
02077
02078
02079
02080
02081
02082
MiInitializePfnForOtherProcess (PageFrameIndex,
02083 PointerPde,
02084
MmSessionSpace->
SessionPageDirectoryIndex);
02085
02086
MiFillMemoryPte (PointerPte,
PAGE_SIZE,
ZeroKernelPte.
u.Long);
02087
02088 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
02089
02090
02091
02092
02093
02094
02095
ASSERT (Pfn1->
u1.WsIndex == 0);
02096
02097 KeFillEntryTb ((PHARDWARE_PTE) PointerPde, PointerPte,
FALSE);
02098 }
02099
02100
MiEnsureAvailablePageOrWait (
NULL,
NULL);
02101
02102 PageColor =
MI_GET_PAGE_COLOR_FROM_VA (
NULL);
02103
02104 PageFrameIndex =
MiRemoveZeroPageIfAny (PageColor);
02105
if (PageFrameIndex == 0) {
02106 PageFrameIndex =
MiRemoveAnyPage (PageColor);
02107
UNLOCK_PFN (OldIrql);
02108
MiZeroPhysicalPage (PageFrameIndex, PageColor);
02109
LOCK_PFN (OldIrql);
02110 }
02111
02112
MM_BUMP_SESS_COUNTER (
MM_DBG_SESSION_WS_PAGE_ALLOC, ResidentPages - 1);
02113
02114
#if DBG
02115
Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
02116
ASSERT (Pfn1->
u1.WsIndex == 0);
02117
#endif
02118
02119
02120
02121
02122
02123
02124 TempPte.
u.Long =
ValidKernelPteLocal.
u.Long;
02125
MI_SET_PTE_DIRTY (TempPte);
02126 TempPte.
u.Hard.PageFrameNumber = PageFrameIndex;
02127
02128
MI_WRITE_VALID_PTE (PointerPte, TempPte);
02129
02130
MiInitializePfn (PageFrameIndex, PointerPte, 1);
02131
02132
#if DBG
02133
Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
02134
ASSERT (Pfn1->
u1.WsIndex == 0);
02135
#endif
02136
02137
UNLOCK_PFN (OldIrql);
02138
02139 KeFillEntryTb ((PHARDWARE_PTE) PointerPte,
02140 (
PMMPTE)
MmSessionSpace->
Vm.
VmWorkingSetList,
02141
FALSE);
02142
02143
02144
02145
02146
02147 WslEntry =
MmSessionSpace->
Wsle;
02148
02149 WslEntry->
u1.VirtualAddress = (PVOID)
MmSessionSpace;
02150 WslEntry->
u1.e1.Valid = 1;
02151 WslEntry->
u1.e1.LockedInWs = 1;
02152 WslEntry->
u1.e1.Direct = 1;
02153
02154 Pfn1 =
MI_PFN_ELEMENT (
MiGetPteAddress (WslEntry->
u1.VirtualAddress)->u.Hard.PageFrameNumber);
02155
02156
ASSERT (Pfn1->
u1.WsIndex == 0);
02157
02158
02159
02160
02161
02162
02163 WslEntry += 1;
02164
02165 WslEntry->
u1.VirtualAddress =
MiGetPteAddress (
MmSessionSpace);
02166 WslEntry->
u1.e1.Valid = 1;
02167 WslEntry->
u1.e1.LockedInWs = 1;
02168 WslEntry->
u1.e1.Direct = 1;
02169
02170 Pfn1 =
MI_PFN_ELEMENT (
MiGetPteAddress (WslEntry->
u1.VirtualAddress)->u.Hard.PageFrameNumber);
02171
02172
ASSERT (Pfn1->
u1.WsIndex == 0);
02173
02174
CONSISTENCY_LOCK_PFN (OldIrql);
02175
02176 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmSessionSpace->
Wsle);
02177
02178
CONSISTENCY_UNLOCK_PFN (OldIrql);
02179
02180
02181
02182
02183
02184 WslEntry += 1;
02185
02186 WslEntry->
u1.VirtualAddress =
MmSessionSpace->
Vm.
VmWorkingSetList;
02187 WslEntry->
u1.e1.Valid = 1;
02188 WslEntry->
u1.e1.LockedInWs = 1;
02189 WslEntry->
u1.e1.Direct = 1;
02190
02191 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
02192
02193
ASSERT (Pfn1->
u1.WsIndex == 0);
02194
02195
CONSISTENCY_LOCK_PFN (OldIrql);
02196
02197 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmSessionSpace->
Wsle);
02198
02199
CONSISTENCY_UNLOCK_PFN (OldIrql);
02200
02201
if (AllocatedPageTable ==
TRUE) {
02202
02203
02204
02205
02206
02207
02208 WslEntry += 1;
02209
02210 WslEntry->
u1.VirtualAddress = (PVOID)PointerPte;
02211 WslEntry->
u1.e1.Valid = 1;
02212 WslEntry->
u1.e1.LockedInWs = 1;
02213 WslEntry->
u1.e1.Direct = 1;
02214
02215 Pfn1 =
MI_PFN_ELEMENT (
MiGetPteAddress (WslEntry->
u1.VirtualAddress)->u.Hard.PageFrameNumber);
02216
02217
ASSERT (Pfn1->
u1.WsIndex == 0);
02218
02219
CONSISTENCY_LOCK_PFN (OldIrql);
02220
02221 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmSessionSpace->
Wsle);
02222
02223
CONSISTENCY_UNLOCK_PFN (OldIrql);
02224 }
02225
02226
02227
02228
02229
02230
02231 WslEntry += 1;
02232
02233 WslEntry->
u1.VirtualAddress = (PVOID)
MiGetPteAddress (
MmSessionSpace->
PagedPoolStart);
02234 WslEntry->
u1.e1.Valid = 1;
02235 WslEntry->
u1.e1.LockedInWs = 1;
02236 WslEntry->
u1.e1.Direct = 1;
02237
02238 Pfn1 =
MI_PFN_ELEMENT (
MiGetPteAddress (WslEntry->
u1.VirtualAddress)->u.Hard.PageFrameNumber);
02239
02240
ASSERT (Pfn1->
u1.WsIndex == 0);
02241
02242
CONSISTENCY_LOCK_PFN (OldIrql);
02243
02244 Pfn1->
u1.WsIndex = (
WSLE_NUMBER)(WslEntry -
MmSessionSpace->
Wsle);
02245
02246
CONSISTENCY_UNLOCK_PFN (OldIrql);
02247
02248 CurrentEntry = (
WSLE_NUMBER)(WslEntry + 1 -
MmSessionSpace->
Wsle);
02249
02250
MmSessionSpace->
Vm.
u.Flags.SessionSpace = 1;
02251
MmSessionSpace->
Vm.
MinimumWorkingSetSize =
MI_SESSION_SPACE_WORKING_SET_MINIMUM;
02252
MmSessionSpace->
Vm.
MaximumWorkingSetSize = WorkingSetMaximum;
02253
02254
02255
02256
02257
02258
02259
MmSessionSpace->
Vm.
AllowWorkingSetAdjustment =
FALSE;
02260
02261
MmSessionSpace->
Vm.
VmWorkingSetList->
LastEntry =
MI_SESSION_SPACE_WORKING_SET_MINIMUM;
02262
MmSessionSpace->
Vm.
VmWorkingSetList->
Quota =
MmSessionSpace->
Vm.
VmWorkingSetList->
LastEntry;
02263
MmSessionSpace->
Vm.
VmWorkingSetList->
HashTable =
NULL;
02264
MmSessionSpace->
Vm.
VmWorkingSetList->
HashTableSize = 0;
02265
MmSessionSpace->
Vm.
VmWorkingSetList->
Wsle =
MmSessionSpace->
Wsle;
02266
02267
MmSessionSpace->
Vm.
VmWorkingSetList->
HashTableStart =
02268 (PVOID)((PCHAR)
PAGE_ALIGN (&
MmSessionSpace->
Wsle[
MI_SESSION_MAXIMUM_WORKING_SET]) +
PAGE_SIZE);
02269
02270
#if defined (_X86PAE_)
02271
02272
02273
02274
02275
02276
MmSessionSpace->
Vm.
VmWorkingSetList->
HighestPermittedHashAddress =
02277 (PVOID)(
MI_SESSION_VIEW_START -
MM_VA_MAPPED_BY_PDE);
02278
#else
02279
MmSessionSpace->
Vm.
VmWorkingSetList->
HighestPermittedHashAddress =
02280 (PVOID)
MI_SESSION_VIEW_START;
02281
#endif
02282
02283 NumberOfEntriesMapped = (
WSLE_NUMBER)(((
PMMWSLE)((ULONG_PTR)
MmSessionSpace->
Vm.
VmWorkingSetList +
02284
PAGE_SIZE)) -
MmSessionSpace->
Wsle);
02285
02286
LOCK_PFN (OldIrql);
02287
02288
while (NumberOfEntriesMapped < WorkingSetMaximum) {
02289
02290 PointerPte += 1;
02291
02292
MiEnsureAvailablePageOrWait (
NULL,
NULL);
02293
02294 PageFrameIndex =
MiRemoveZeroPage(
MI_GET_PAGE_COLOR_FROM_VA (
NULL));
02295
02296 PointerPte->u.Long =
MM_DEMAND_ZERO_WRITE_PTE;
02297
02298
MiInitializePfn (PageFrameIndex, PointerPte, 1);
02299
02300 TempPte.
u.Hard.PageFrameNumber = PageFrameIndex;
02301
02302
MI_SET_PTE_IN_WORKING_SET (&TempPte, CurrentEntry);
02303
02304
MI_WRITE_VALID_PTE (PointerPte, TempPte);
02305
02306 WslEntry += 1;
02307
02308 WslEntry->
u1.VirtualAddress =
MiGetVirtualAddressMappedByPte (PointerPte);
02309 WslEntry->
u1.e1.Valid = 1;
02310 WslEntry->
u1.e1.LockedInWs = 1;
02311 WslEntry->
u1.e1.Direct = 1;
02312
02313 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
02314
02315
ASSERT (Pfn1->
u1.WsIndex == 0);
02316 Pfn1->
u1.WsIndex = CurrentEntry;
02317
02318
02319
02320 CurrentEntry += 1;
02321
02322 NumberOfEntriesMapped +=
PAGE_SIZE /
sizeof(
MMWSLE);
02323 }
02324
02325
UNLOCK_PFN (OldIrql);
02326
02327
MmSessionSpace->
Vm.
WorkingSetSize = CurrentEntry;
02328
MmSessionSpace->
Vm.
VmWorkingSetList->
FirstFree = CurrentEntry;
02329
MmSessionSpace->
Vm.
VmWorkingSetList->
FirstDynamic = CurrentEntry;
02330
MmSessionSpace->
Vm.
VmWorkingSetList->
NextSlot = CurrentEntry;
02331
02332
MmSessionSpace->
NonPagablePages += ResidentPages;
02333
MmSessionSpace->
CommittedPages += ResidentPages;
02334
02335
02336
02337
02338
02339 WslEntry =
MmSessionSpace->
Wsle + CurrentEntry;
02340
02341
for (i = CurrentEntry + 1; i < NumberOfEntriesMapped; i += 1) {
02342
02343
02344
02345
02346
02347
02348
02349
02350 WslEntry->
u1.Long = i <<
MM_FREE_WSLE_SHIFT;
02351 WslEntry += 1;
02352 }
02353
02354 WslEntry->
u1.Long =
WSLE_NULL_INDEX <<
MM_FREE_WSLE_SHIFT;
02355
02356
MmSessionSpace->
Vm.
VmWorkingSetList->
LastInitializedWsle = NumberOfEntriesMapped - 1;
02357
02358
if (WorkingSetMaximum > ((1536*1024) >>
PAGE_SHIFT)) {
02359
02360
02361
02362
02363
02364
MiGrowWsleHash (&
MmSessionSpace->
Vm);
02365 }
02366
02367
02368
02369
02370
02371
LOCK_EXPANSION (OldIrql);
02372
02373 InsertTailList (&
MiSessionWsList, &SessionGlobal->
WsListEntry);
02374
02375
MmSessionSpace->
u.Flags.HasWsLock = 1;
02376
02377
MmSessionSpace->
u.Flags.SessionListInserted = 1;
02378
02379
UNLOCK_EXPANSION (OldIrql);
02380
02381
return STATUS_SUCCESS;
02382 }
02383
02384
02385 LOGICAL
02386 MmAssignProcessToJob (
02387 IN
PEPROCESS Process
02388 )
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415 {
02416 LOGICAL Attached;
02417 LOGICAL
Status;
02418
02419
PAGED_CODE ();
02420
02421 Attached =
FALSE;
02422
02423
if (
PsGetCurrentProcess() != Process) {
02424
KeAttachProcess (&Process->Pcb);
02425 Attached =
TRUE;
02426 }
02427
02428
LOCK_WS_AND_ADDRESS_SPACE (Process);
02429
02430
Status =
PsChangeJobMemoryUsage (Process->CommitCharge);
02431
02432
02433
02434
02435
02436
02437 Process->JobStatus |=
PS_JOB_STATUS_REPORT_COMMIT_CHANGES;
02438
02439
UNLOCK_WS_AND_ADDRESS_SPACE (Process);
02440
02441
if (Attached) {
02442
KeDetachProcess();
02443 }
02444
02445
return TRUE;
02446 }
02447
02448
02449
NTSTATUS
02450 MmAdjustWorkingSetSize (
02451 IN SIZE_T WorkingSetMinimumInBytes,
02452 IN SIZE_T WorkingSetMaximumInBytes,
02453 IN ULONG SystemCache
02454 )
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493 {
02494
PEPROCESS CurrentProcess;
02495 ULONG Entry;
02496 ULONG LastFreed;
02497
PMMWSLE Wsle;
02498 KIRQL OldIrql;
02499 KIRQL OldIrql2;
02500 SPFN_NUMBER i;
02501
PMMPTE PointerPte;
02502
NTSTATUS ReturnStatus;
02503 LONG PagesAbove;
02504 LONG NewPagesAbove;
02505 ULONG FreeTryCount;
02506
PMMSUPPORT WsInfo;
02507
PMMWSL WorkingSetList;
02508
WSLE_NUMBER WorkingSetMinimum;
02509
WSLE_NUMBER WorkingSetMaximum;
02510
02511
PERFINFO_PAGE_INFO_DECL();
02512
02513 FreeTryCount = 0;
02514
02515
if (SystemCache) {
02516 WsInfo = &
MmSystemCacheWs;
02517 }
else {
02518 CurrentProcess =
PsGetCurrentProcess ();
02519 WsInfo = &CurrentProcess->
Vm;
02520 }
02521
02522
if ((WorkingSetMinimumInBytes == (SIZE_T)-1) &&
02523 (WorkingSetMaximumInBytes == (SIZE_T)-1)) {
02524
return MiEmptyWorkingSet (WsInfo,
TRUE);
02525 }
02526
02527
if (WorkingSetMinimumInBytes == 0) {
02528 WorkingSetMinimum = WsInfo->
MinimumWorkingSetSize;
02529 }
02530
else {
02531 WorkingSetMinimum = (
WSLE_NUMBER)(WorkingSetMinimumInBytes >>
PAGE_SHIFT);
02532 }
02533
02534
if (WorkingSetMaximumInBytes == 0) {
02535 WorkingSetMaximum = WsInfo->
MaximumWorkingSetSize;
02536 }
02537
else {
02538 WorkingSetMaximum = (
WSLE_NUMBER)(WorkingSetMaximumInBytes >>
PAGE_SHIFT);
02539 }
02540
02541
if (WorkingSetMinimum > WorkingSetMaximum) {
02542
return STATUS_BAD_WORKING_SET_LIMIT;
02543 }
02544
02545
MmLockPagableSectionByHandle(
ExPageLockHandle);
02546
02547 ReturnStatus = STATUS_SUCCESS;
02548
02549
02550
02551
02552
02553
if (SystemCache) {
02554
LOCK_SYSTEM_WS (OldIrql2);
02555 }
else {
02556
LOCK_WS (CurrentProcess);
02557
02558
if (CurrentProcess->
AddressSpaceDeleted != 0) {
02559 ReturnStatus = STATUS_PROCESS_IS_TERMINATING;
02560
goto Returns;
02561 }
02562 }
02563
02564
if (WorkingSetMaximum >
MmMaximumWorkingSetSize) {
02565 WorkingSetMaximum =
MmMaximumWorkingSetSize;
02566 ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
02567 }
02568
02569
if (WorkingSetMinimum >
MmMaximumWorkingSetSize) {
02570 WorkingSetMinimum =
MmMaximumWorkingSetSize;
02571 ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
02572 }
02573
02574
if (WorkingSetMinimum <
MmMinimumWorkingSetSize) {
02575 WorkingSetMinimum = (ULONG)
MmMinimumWorkingSetSize;
02576 ReturnStatus = STATUS_WORKING_SET_LIMIT_RANGE;
02577 }
02578
02579
02580
02581
02582
02583
02584
if ((WsInfo->
VmWorkingSetList->
FirstDynamic +
MM_FLUID_WORKING_SET) >=
02585 WorkingSetMaximum) {
02586 ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
02587
goto Returns;
02588 }
02589
02590 WorkingSetList = WsInfo->
VmWorkingSetList;
02591 Wsle = WorkingSetList->
Wsle;
02592
02593
02594
02595
02596
02597
02598
LOCK_PFN (OldIrql);
02599
02600 i = WorkingSetMinimum - WsInfo->
MinimumWorkingSetSize;
02601
02602
if (i > 0) {
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
if (
MmAvailablePages < (20 + (i / (
PAGE_SIZE /
sizeof (
MMWSLE))))) {
02613
UNLOCK_PFN (OldIrql);
02614 ReturnStatus = STATUS_INSUFFICIENT_RESOURCES;
02615
goto Returns;
02616 }
02617
02618
if (
MI_NONPAGABLE_MEMORY_AVAILABLE() - 100 < i) {
02619
UNLOCK_PFN (OldIrql);
02620 ReturnStatus = STATUS_INSUFFICIENT_RESOURCES;
02621
goto Returns;
02622 }
02623 }
02624
02625
02626
02627
02628
02629
02630
02631
MmResidentAvailablePages -= i;
02632
MM_BUMP_COUNTER(27, i);
02633
02634
UNLOCK_PFN (OldIrql);
02635
02636
if (WsInfo->
AllowWorkingSetAdjustment ==
FALSE) {
02637
MmAllowWorkingSetExpansion ();
02638 }
02639
02640
if (WorkingSetMaximum > WorkingSetList->
LastInitializedWsle) {
02641
02642
do {
02643
02644
02645
02646
02647
02648
02649
02650
if (!
MiAddWorkingSetPage (WsInfo)) {
02651 WorkingSetMaximum = WorkingSetList->
LastInitializedWsle - 1;
02652
break;
02653 }
02654 }
while (WorkingSetMaximum > WorkingSetList->
LastInitializedWsle);
02655
02656 }
else {
02657
02658
02659
02660
02661
02662
02663
if (WsInfo->
WorkingSetSize > WorkingSetMaximum) {
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
if ((WorkingSetList->
FirstDynamic +
MM_FLUID_WORKING_SET) >=
02675 WorkingSetMaximum) {
02676
02677 ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
02678
02679
LOCK_PFN (OldIrql);
02680
02681
MmResidentAvailablePages += i;
02682
MM_BUMP_COUNTER(54, i);
02683
02684
UNLOCK_PFN (OldIrql);
02685
02686
goto Returns;
02687 }
02688
02689
02690
02691
02692
02693 LastFreed = WorkingSetList->
LastEntry;
02694
if (WorkingSetList->
LastEntry > WorkingSetMaximum) {
02695
02696
while (LastFreed >= WorkingSetMaximum) {
02697
02698 PointerPte =
MiGetPteAddress(
02699 Wsle[LastFreed].u1.
VirtualAddress);
02700
02701
PERFINFO_GET_PAGE_INFO(PointerPte);
02702
02703
if ((Wsle[LastFreed].
u1.e1.Valid != 0) &&
02704 (!
MiFreeWsle (LastFreed,
02705 WsInfo,
02706 PointerPte))) {
02707
02708
02709
02710
02711
02712
break;
02713 }
02714
PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_ADJUSTWS, WsInfo);
02715 LastFreed -= 1;
02716 }
02717 WorkingSetList->
LastEntry = LastFreed;
02718 }
02719
02720
02721
02722
02723
02724 Entry = WorkingSetList->
FirstDynamic;
02725
02726
while (WsInfo->
WorkingSetSize > WorkingSetMaximum) {
02727
if (Wsle[Entry].
u1.e1.Valid != 0) {
02728 PointerPte =
MiGetPteAddress (
02729 Wsle[Entry].u1.
VirtualAddress);
02730
PERFINFO_GET_PAGE_INFO(PointerPte);
02731
02732
if (
MiFreeWsle(Entry, WsInfo, PointerPte)) {
02733
PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_ADJUSTWS,
02734 WsInfo);
02735 }
02736 }
02737 Entry += 1;
02738
if (Entry > LastFreed) {
02739 FreeTryCount += 1;
02740
if (FreeTryCount >
MM_RETRY_COUNT) {
02741
02742
02743
02744
02745
02746
02747 ReturnStatus = STATUS_BAD_WORKING_SET_LIMIT;
02748
02749
break;
02750 }
02751 Entry = WorkingSetList->
FirstDynamic;
02752 }
02753 }
02754
02755
if (FreeTryCount <=
MM_RETRY_COUNT) {
02756 WorkingSetList->
Quota = WorkingSetMaximum;
02757 }
02758 }
02759 }
02760
02761
02762
02763
02764
02765 PagesAbove = (LONG)WsInfo->
WorkingSetSize -
02766 (LONG)WsInfo->
MinimumWorkingSetSize;
02767 NewPagesAbove = (LONG)WsInfo->
WorkingSetSize -
02768 (LONG)WorkingSetMinimum;
02769
02770
LOCK_PFN (OldIrql);
02771
if (PagesAbove > 0) {
02772
MmPagesAboveWsMinimum -= (ULONG)PagesAbove;
02773 }
02774
if (NewPagesAbove > 0) {
02775
MmPagesAboveWsMinimum += (ULONG)NewPagesAbove;
02776 }
02777
UNLOCK_PFN (OldIrql);
02778
02779
if (FreeTryCount <=
MM_RETRY_COUNT) {
02780 WsInfo->
MaximumWorkingSetSize = WorkingSetMaximum;
02781 WsInfo->
MinimumWorkingSetSize = WorkingSetMinimum;
02782
02783
if (WorkingSetMinimum >= WorkingSetList->
Quota) {
02784 WorkingSetList->
Quota = WorkingSetMinimum;
02785 }
02786 }
02787
else {
02788
LOCK_PFN (OldIrql);
02789
02790
MmResidentAvailablePages += i;
02791
MM_BUMP_COUNTER(55, i);
02792
02793
UNLOCK_PFN (OldIrql);
02794 }
02795
02796
02797
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
02798 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
02799
02800
if ((WorkingSetList->
HashTable ==
NULL) &&
02801 (WsInfo->
MaximumWorkingSetSize > ((1536*1024) >>
PAGE_SHIFT))) {
02802
02803
02804
02805
02806
02807
MiGrowWsleHash (WsInfo);
02808 }
02809
02810 Returns:
02811
02812
if (SystemCache) {
02813
UNLOCK_SYSTEM_WS (OldIrql2);
02814 }
else {
02815
UNLOCK_WS (CurrentProcess);
02816 }
02817
02818
MmUnlockPagableImageSection(
ExPageLockHandle);
02819
02820
return ReturnStatus;
02821 }
02822
02823 ULONG
02824 MiAddWorkingSetPage (
02825 IN
PMMSUPPORT WsInfo
02826 )
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850 {
02851 ULONG SwapEntry;
02852 ULONG CurrentEntry;
02853
PMMWSLE WslEntry;
02854 ULONG i;
02855
PMMPTE PointerPte;
02856
PMMPTE PointerPde;
02857
PMMPTE Va;
02858
MMPTE TempPte;
02859
WSLE_NUMBER NumberOfEntriesMapped;
02860 PFN_NUMBER WorkingSetPage;
02861
WSLE_NUMBER WorkingSetIndex;
02862
PMMWSL WorkingSetList;
02863
PMMWSLE Wsle;
02864
PMMPFN Pfn1;
02865 KIRQL OldIrql;
02866 LOGICAL PageTablePageAllocated;
02867
02868 WorkingSetList = WsInfo->VmWorkingSetList;
02869 Wsle = WorkingSetList->
Wsle;
02870
02871
#if DBG
02872
if (WsInfo == &
MmSystemCacheWs) {
02873
MM_SYSTEM_WS_LOCK_ASSERT();
02874 }
02875
#endif //DBG
02876
02877
02878
02879
02880
02881
02882
02883 PointerPte =
MiGetPteAddress (&Wsle[WorkingSetList->
LastInitializedWsle]);
02884
02885
ASSERT (PointerPte->
u.Hard.Valid == 1);
02886
02887 PointerPte += 1;
02888
02889 Va = (
PMMPTE)
MiGetVirtualAddressMappedByPte (PointerPte);
02890
02891
if ((PVOID)Va >= WorkingSetList->
HashTableStart) {
02892
02893
02894
02895
02896
02897
02898 WorkingSetList->
Quota = WorkingSetList->
LastInitializedWsle;
02899
return FALSE;
02900 }
02901
02902 PageTablePageAllocated =
FALSE;
02903
02904
#if defined (_WIN64)
02905
PointerPde =
MiGetPteAddress (PointerPte);
02906
if (PointerPde->
u.Hard.Valid == 0) {
02907
02908
ASSERT (WsInfo->u.Flags.SessionSpace == 0);
02909
02910
02911
02912
02913
02914
LOCK_PFN (OldIrql);
02915
if (
MmAvailablePages < 21) {
02916
02917
02918
02919
02920
02921
02922 WorkingSetList->
Quota = WorkingSetList->
LastInitializedWsle;
02923
UNLOCK_PFN (OldIrql);
02924
return FALSE;
02925 }
02926
02927 PageTablePageAllocated =
TRUE;
02928 WorkingSetPage =
MiRemoveZeroPage (
MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
02929 PointerPde->u.Long =
MM_DEMAND_ZERO_WRITE_PTE;
02930
MiInitializePfn (WorkingSetPage, PointerPde, 1);
02931
UNLOCK_PFN (OldIrql);
02932
02933
MI_MAKE_VALID_PTE (TempPte,
02934 WorkingSetPage,
02935
MM_READWRITE,
02936 PointerPde);
02937
02938
MI_SET_PTE_DIRTY (TempPte);
02939
MI_WRITE_VALID_PTE (PointerPde, TempPte);
02940
02941
02942
02943
02944
02945
02946
02947
02948 }
02949
#endif
02950
02951
ASSERT (PointerPte->
u.Hard.Valid == 0);
02952
02953 NumberOfEntriesMapped = (
WSLE_NUMBER)(((
PMMWSLE)((PCHAR)Va +
PAGE_SIZE)) - Wsle);
02954
02955
02956
02957
02958
02959
LOCK_PFN (OldIrql);
02960
if ((PageTablePageAllocated ==
FALSE) && (
MmAvailablePages < 20)) {
02961
02962
02963
02964
02965
02966
02967 WorkingSetList->
Quota = WorkingSetList->
LastInitializedWsle;
02968
UNLOCK_PFN (OldIrql);
02969
return FALSE;
02970 }
02971
02972 WorkingSetPage =
MiRemoveZeroPage (
MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
02973 PointerPte->u.Long =
MM_DEMAND_ZERO_WRITE_PTE;
02974
MiInitializePfn (WorkingSetPage, PointerPte, 1);
02975
UNLOCK_PFN (OldIrql);
02976
02977
MI_MAKE_VALID_PTE (TempPte,
02978 WorkingSetPage,
02979
MM_READWRITE,
02980 PointerPte);
02981
02982
MI_SET_PTE_DIRTY (TempPte);
02983
MI_WRITE_VALID_PTE (PointerPte, TempPte);
02984
02985
if (WsInfo->u.Flags.SessionSpace == 1) {
02986
MM_BUMP_SESS_COUNTER (
MM_DBG_SESSION_WS_PAGE_ALLOC_GROWTH, 1);
02987
MmSessionSpace->
NonPagablePages += 1;
02988
MmSessionSpace->
CommittedPages += 1;
02989
MiChargeCommitmentCantExpand (1,
TRUE);
02990
LOCK_PFN (OldIrql);
02991
MM_BUMP_COUNTER (48, 1);
02992
MmResidentAvailablePages -= 1;
02993
UNLOCK_PFN (OldIrql);
02994
MM_TRACK_COMMIT (
MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_PAGES, 1);
02995 }
02996
02997 CurrentEntry = WorkingSetList->
LastInitializedWsle + 1;
02998
02999
ASSERT (NumberOfEntriesMapped > CurrentEntry);
03000
03001 WslEntry = &Wsle[CurrentEntry - 1];
03002
03003
for (i = CurrentEntry; i < NumberOfEntriesMapped; i += 1) {
03004
03005
03006
03007
03008
03009
03010
03011
03012 WslEntry += 1;
03013 WslEntry->
u1.Long = (i + 1) <<
MM_FREE_WSLE_SHIFT;
03014 }
03015
03016 WslEntry->
u1.Long = WorkingSetList->
FirstFree <<
MM_FREE_WSLE_SHIFT;
03017
03018
ASSERT (CurrentEntry >= WorkingSetList->
FirstDynamic);
03019
03020 WorkingSetList->
FirstFree = CurrentEntry;
03021
03022 WorkingSetList->
LastInitializedWsle = (NumberOfEntriesMapped - 1);
03023
03024
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
03025 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
03026
03027
03028
03029
03030
03031
03032 WorkingSetList->
Quota += 1;
03033
03034 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
03035
03036
CONSISTENCY_LOCK_PFN (OldIrql);
03037
03038 Pfn1->
u1.Event = (PVOID)
PsGetCurrentThread();
03039
03040
CONSISTENCY_UNLOCK_PFN (OldIrql);
03041
03042
03043
03044
03045
03046 WsInfo->WorkingSetSize += 1;
03047
03048
ASSERT (WorkingSetList->
FirstFree !=
WSLE_NULL_INDEX);
03049
ASSERT (WorkingSetList->
FirstFree >= WorkingSetList->
FirstDynamic);
03050
03051 WorkingSetIndex = WorkingSetList->
FirstFree;
03052 WorkingSetList->
FirstFree = (
WSLE_NUMBER)(Wsle[WorkingSetIndex].u1.Long >>
MM_FREE_WSLE_SHIFT);
03053
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
03054 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
03055
03056
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
03057
MmPagesAboveWsMinimum += 1;
03058 }
03059
if (WorkingSetIndex > WorkingSetList->
LastEntry) {
03060 WorkingSetList->
LastEntry = WorkingSetIndex;
03061 }
03062
03063
MiUpdateWsle (&WorkingSetIndex, Va, WorkingSetList, Pfn1);
03064
03065
MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex);
03066
03067
03068
03069
03070
03071
if (WorkingSetIndex >= WorkingSetList->
FirstDynamic) {
03072
03073 SwapEntry = WorkingSetList->
FirstDynamic;
03074
03075
if (WorkingSetIndex != WorkingSetList->
FirstDynamic) {
03076
03077
03078
03079
03080
03081
MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
03082 }
03083
03084 WorkingSetList->
FirstDynamic += 1;
03085
03086 Wsle[SwapEntry].u1.e1.LockedInWs = 1;
03087
ASSERT (Wsle[SwapEntry].u1.e1.Valid == 1);
03088 }
03089
03090
#if defined (_WIN64)
03091
if (PageTablePageAllocated ==
TRUE) {
03092
03093
03094
03095
03096
03097
03098 WorkingSetList->
Quota += 1;
03099
03100 Pfn1 =
MI_PFN_ELEMENT (PointerPde->
u.Hard.PageFrameNumber);
03101
03102
CONSISTENCY_LOCK_PFN (OldIrql);
03103
03104 Pfn1->
u1.Event = (PVOID)
PsGetCurrentThread();
03105
03106
CONSISTENCY_UNLOCK_PFN (OldIrql);
03107
03108
03109
03110
03111
03112 WsInfo->WorkingSetSize += 1;
03113
03114
ASSERT (WorkingSetList->
FirstFree !=
WSLE_NULL_INDEX);
03115
ASSERT (WorkingSetList->
FirstFree >= WorkingSetList->
FirstDynamic);
03116
03117 WorkingSetIndex = WorkingSetList->
FirstFree;
03118 WorkingSetList->
FirstFree = (
WSLE_NUMBER)(Wsle[WorkingSetIndex].u1.Long >>
MM_FREE_WSLE_SHIFT);
03119
ASSERT ((WorkingSetList->
FirstFree <= WorkingSetList->
LastInitializedWsle) ||
03120 (WorkingSetList->
FirstFree ==
WSLE_NULL_INDEX));
03121
03122
if (WsInfo->WorkingSetSize > WsInfo->MinimumWorkingSetSize) {
03123
MmPagesAboveWsMinimum += 1;
03124 }
03125
if (WorkingSetIndex > WorkingSetList->
LastEntry) {
03126 WorkingSetList->
LastEntry = WorkingSetIndex;
03127 }
03128
03129
MiUpdateWsle (&WorkingSetIndex, PointerPte, WorkingSetList, Pfn1);
03130
03131
MI_SET_PTE_IN_WORKING_SET (PointerPde, WorkingSetIndex);
03132
03133
03134
03135
03136
03137
if (WorkingSetIndex >= WorkingSetList->
FirstDynamic) {
03138
03139 SwapEntry = WorkingSetList->
FirstDynamic;
03140
03141
if (WorkingSetIndex != WorkingSetList->
FirstDynamic) {
03142
03143
03144
03145
03146
03147
MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
03148 }
03149
03150 WorkingSetList->
FirstDynamic += 1;
03151
03152 Wsle[SwapEntry].u1.e1.LockedInWs = 1;
03153
ASSERT (Wsle[SwapEntry].u1.e1.Valid == 1);
03154 }
03155 }
03156
#endif
03157
03158
ASSERT ((
MiGetPteAddress(&Wsle[WorkingSetList->
LastInitializedWsle]))->u.Hard.Valid == 1);
03159
03160
if ((WorkingSetList->
HashTable ==
NULL) &&
03161 (
MmAvailablePages > 20)) {
03162
03163
03164
03165
03166
03167
03168
LOCK_EXPANSION_IF_ALPHA (OldIrql);
03169
ASSERT (WsInfo->AllowWorkingSetAdjustment !=
FALSE);
03170 WsInfo->AllowWorkingSetAdjustment =
MM_GROW_WSLE_HASH;
03171
UNLOCK_EXPANSION_IF_ALPHA (OldIrql);
03172 }
03173
03174
ASSERT (WsInfo->WorkingSetSize <= WorkingSetList->
Quota);
03175
return TRUE;
03176 }
03177
03178 LOGICAL
03179 MiAddWsleHash (
03180 IN
PMMSUPPORT WsInfo,
03181 IN
PMMPTE PointerPte
03182 )
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207 {
03208 KIRQL OldIrql;
03209
PMMPFN Pfn1;
03210 ULONG SwapEntry;
03211
MMPTE TempPte;
03212 PVOID Va;
03213
PMMWSLE Wsle;
03214 PFN_NUMBER WorkingSetPage;
03215
WSLE_NUMBER WorkingSetIndex;
03216
PMMWSL WorkingSetList;
03217
03218 WorkingSetList = WsInfo->VmWorkingSetList;
03219 Wsle = WorkingSetList->
Wsle;
03220
03221
ASSERT (PointerPte->u.Hard.Valid == 0);
03222
03223
LOCK_PFN (OldIrql);
03224
03225
if (
MmAvailablePages < 10) {
03226
UNLOCK_PFN (OldIrql);
03227
return FALSE;
03228 }
03229
03230 WorkingSetPage =
MiRemoveZeroPage (
03231
MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
03232
03233 PointerPte->u.Long =
MM_DEMAND_ZERO_WRITE_PTE;
03234
MiInitializePfn (WorkingSetPage, PointerPte, 1);
03235
03236
MI_MAKE_VALID_PTE (TempPte,
03237 WorkingSetPage,
03238
MM_READWRITE,
03239 PointerPte );
03240
03241
MI_SET_PTE_DIRTY (TempPte);
03242
MI_WRITE_VALID_PTE (PointerPte, TempPte);
03243
03244
UNLOCK_PFN (OldIrql);
03245
03246
03247
03248
03249
03250
03251
03252 Pfn1 =
MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
03253
03254
CONSISTENCY_LOCK_PFN (OldIrql);
03255
03256 Pfn1->
u1.Event = (PVOID)
PsGetCurrentThread();
03257
03258
CONSISTENCY_UNLOCK_PFN (OldIrql);
03259
03260 Va = (
PMMPTE)
MiGetVirtualAddressMappedByPte (PointerPte);
03261
03262 WorkingSetIndex =
MiLocateAndReserveWsle (WsInfo);
03263
MiUpdateWsle (&WorkingSetIndex, Va, WorkingSetList, Pfn1);
03264
MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex);
03265
03266
03267
03268
03269
03270
if (WorkingSetIndex >= WorkingSetList->
FirstDynamic) {
03271
03272 SwapEntry = WorkingSetList->
FirstDynamic;
03273
03274
if (WorkingSetIndex != WorkingSetList->
FirstDynamic) {
03275
03276
03277
03278
03279
03280
MiSwapWslEntries (WorkingSetIndex, SwapEntry, WsInfo);
03281 }
03282
03283 WorkingSetList->
FirstDynamic += 1;
03284
03285 Wsle[SwapEntry].
u1.e1.LockedInWs = 1;
03286
ASSERT (Wsle[SwapEntry].u1.
e1.
Valid == 1);
03287 }
03288
03289
if (WsInfo->u.Flags.SessionSpace == 1) {
03290
MM_BUMP_SESS_COUNTER (
MM_DBG_SESSION_WS_HASHPAGE_ALLOC, 1);
03291
MmSessionSpace->
NonPagablePages += 1;
03292
MmSessionSpace->
CommittedPages += 1;
03293
MiChargeCommitmentCantExpand (1,
TRUE);
03294
MM_TRACK_COMMIT (
MM_DBG_COMMIT_SESSION_ADDITIONAL_WS_HASHPAGES, 1);
03295 }
03296
return TRUE;
03297 }
03298
03299
VOID
03300 MiGrowWsleHash (
03301 IN
PMMSUPPORT WsInfo
03302 )
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334 {
03335 LONG
Size;
03336
PMMWSLE Wsle;
03337
PMMPTE StartPte;
03338
PMMPTE EndPte;
03339
PMMPTE PointerPte;
03340
PMMPTE PointerPde;
03341
PMMPTE PointerPpe;
03342
PMMPTE AllocatedPde;
03343
PMMPTE AllocatedPpe;
03344 ULONG First;
03345 ULONG Hash;
03346 ULONG NewSize;
03347
PMMWSLE_HASH Table;
03348
PMMWSLE_HASH OriginalTable;
03349 ULONG j;
03350
PMMWSL WorkingSetList;
03351 KIRQL OldIrql;
03352 ULONG
Count;
03353 LOGICAL LoopStart;
03354 PVOID EntryHashTableEnd;
03355 PVOID TempVa;
03356
PEPROCESS CurrentProcess;
03357
03358 WorkingSetList = WsInfo->VmWorkingSetList;
03359 Wsle = WorkingSetList->
Wsle;
03360
03361 Table = WorkingSetList->
HashTable;
03362 OriginalTable = WorkingSetList->
HashTable;
03363
03364 First = WorkingSetList->
HashTableSize;
03365
03366
if (Table ==
NULL) {
03367
03368 NewSize = PtrToUlong(
PAGE_ALIGN (((1 + WorkingSetList->
NonDirectCount) *
03369 2 *
sizeof(
MMWSLE_HASH)) +
PAGE_SIZE - 1));
03370
03371
03372
03373
03374
03375
03376 j = First *
sizeof(
MMWSLE_HASH);
03377
03378
03379
03380
03381
03382
03383
if ((j +
PAGE_SIZE > NewSize) && (j != 0)) {
03384
return;
03385 }
03386
03387 Table = (
PMMWSLE_HASH)(WorkingSetList->
HashTableStart);
03388 EntryHashTableEnd = &Table[WorkingSetList->
HashTableSize];
03389
03390 WorkingSetList->
HashTableSize = 0;
03391
03392 }
else {
03393
03394
03395
03396
03397
03398
03399
if ((WorkingSetList->
LastInitializedWsle + 5) > WsInfo->WorkingSetSize) {
03400 NewSize =
PAGE_SIZE * 4;
03401 }
else {
03402 NewSize =
PAGE_SIZE;
03403 }
03404 EntryHashTableEnd = &Table[WorkingSetList->
HashTableSize];
03405 }
03406
03407
if ((PCHAR)EntryHashTableEnd + NewSize > (PCHAR)WorkingSetList->
HighestPermittedHashAddress) {
03408 NewSize =
03409 (ULONG)((PCHAR)(WorkingSetList->
HighestPermittedHashAddress) -
03410 ((PCHAR)EntryHashTableEnd));
03411
if (NewSize == 0) {
03412
if (OriginalTable ==
NULL) {
03413 WorkingSetList->
HashTableSize = First;
03414 }
03415
return;
03416 }
03417 }
03418
03419
ASSERT64 ((
MiGetPpeAddress(EntryHashTableEnd)->u.Hard.Valid == 0) ||
03420 (
MiGetPdeAddress(EntryHashTableEnd)->u.Hard.Valid == 0) ||
03421 (
MiGetPteAddress(EntryHashTableEnd)->u.Hard.Valid == 0));
03422
03423
ASSERT32 (
MiGetPteAddress(EntryHashTableEnd)->u.Hard.Valid == 0);
03424
03425
Size = NewSize;
03426 PointerPte =
MiGetPteAddress (EntryHashTableEnd);
03427 StartPte = PointerPte;
03428 EndPte = PointerPte + (NewSize >>
PAGE_SHIFT);
03429
03430
#if defined (_WIN64)
03431
LoopStart =
TRUE;
03432 AllocatedPde =
NULL;
03433 AllocatedPpe =
NULL;
03434
#endif
03435
03436
do {
03437
03438
#if defined (_WIN64)
03439
if (LoopStart ==
TRUE ||
MiIsPteOnPdeBoundary(PointerPte)) {
03440
03441 PointerPpe =
MiGetPdeAddress(PointerPte);
03442 PointerPde =
MiGetPteAddress(PointerPte);
03443
03444
if (PointerPpe->
u.Hard.Valid == 0) {
03445
if (
MiAddWsleHash (WsInfo, PointerPpe) ==
FALSE) {
03446
break;
03447 }
03448 AllocatedPpe = PointerPpe;
03449 }
03450
03451
if (PointerPde->
u.Hard.Valid == 0) {
03452
if (
MiAddWsleHash (WsInfo, PointerPde) ==
FALSE) {
03453
break;
03454 }
03455 AllocatedPde = PointerPde;
03456 }
03457
03458 LoopStart =
FALSE;
03459 }
03460
else {
03461 AllocatedPde =
NULL;
03462 AllocatedPpe =
NULL;
03463 }
03464
#endif
03465
03466
if (PointerPte->u.Hard.Valid == 0) {
03467
if (
MiAddWsleHash (WsInfo, PointerPte) ==
FALSE) {
03468
break;
03469 }
03470 }
03471
03472 PointerPte += 1;
03473
Size -=
PAGE_SIZE;
03474 }
while (
Size > 0);
03475
03476
03477
03478
03479
03480
03481
03482
#if !defined (_WIN64)
03483
if (PointerPte == StartPte) {
03484
if (OriginalTable ==
NULL) {
03485 WorkingSetList->
HashTableSize = First;
03486 }
03487
return;
03488 }
03489
#else
03490
if (PointerPte != EndPte) {
03491
03492
03493
03494
03495
03496
03497
03498
03499
if (WsInfo != &
MmSystemCacheWs && WsInfo->
u.Flags.SessionSpace == 0) {
03500 CurrentProcess =
PsGetCurrentProcess();
03501
03502
if (AllocatedPde !=
NULL) {
03503
ASSERT (AllocatedPde->
u.Hard.Valid == 1);
03504 TempVa =
MiGetVirtualAddressMappedByPte(AllocatedPde);
03505
LOCK_PFN (OldIrql);
03506
MiDeletePte (AllocatedPde,
03507 TempVa,
03508
FALSE,
03509 CurrentProcess,
03510
NULL,
03511
NULL);
03512
03513
03514
03515
03516 CurrentProcess->
NumberOfPrivatePages += 1;
03517
UNLOCK_PFN (OldIrql);
03518 }
03519
03520
if (AllocatedPpe !=
NULL) {
03521
ASSERT (AllocatedPpe->
u.Hard.Valid == 1);
03522 TempVa =
MiGetVirtualAddressMappedByPte(AllocatedPpe);
03523
LOCK_PFN (OldIrql);
03524
MiDeletePte (AllocatedPpe,
03525 TempVa,
03526
FALSE,
03527 CurrentProcess,
03528
NULL,
03529
NULL);
03530
03531
03532
03533
03534 CurrentProcess->
NumberOfPrivatePages += 1;
03535
UNLOCK_PFN (OldIrql);
03536 }
03537 }
03538
03539
if (PointerPte == StartPte) {
03540
if (OriginalTable ==
NULL) {
03541 WorkingSetList->
HashTableSize = First;
03542 }
03543 }
03544
03545
return;
03546 }
03547
#endif
03548
03549 NewSize = (ULONG)((PointerPte - StartPte) <<
PAGE_SHIFT);
03550
03551
ASSERT ((
MiGetVirtualAddressMappedByPte(PointerPte) == WorkingSetList->
HighestPermittedHashAddress) ||
03552 (PointerPte->u.Hard.Valid == 0));
03553
03554 WorkingSetList->
HashTableSize = First + NewSize /
sizeof (
MMWSLE_HASH);
03555 WorkingSetList->
HashTable = Table;
03556
03557
ASSERT ((&Table[WorkingSetList->
HashTableSize] == WorkingSetList->
HighestPermittedHashAddress) ||
03558 (
MiGetPteAddress(&Table[WorkingSetList->
HashTableSize])->u.Hard.Valid == 0));
03559
03560
if (First != 0) {
03561 RtlZeroMemory (Table, First *
sizeof(
MMWSLE_HASH));
03562 }
03563
03564
03565
03566
03567
03568 j = 0;
03569
Count = WorkingSetList->
NonDirectCount;
03570
03571
Size = WorkingSetList->
HashTableSize;
03572
03573
do {
03574
if ((Wsle[j].
u1.e1.Valid == 1) &&
03575 (Wsle[j].
u1.e1.Direct == 0)) {
03576
03577
03578
03579
03580
03581
Count -= 1;
03582
03583 Hash =
MI_WSLE_HASH(Wsle[j].u1.
Long, WorkingSetList);
03584
03585
while (Table[Hash].Key != 0) {
03586 Hash += 1;
03587
if (Hash >= (ULONG)
Size) {
03588 Hash = 0;
03589 }
03590 }
03591
03592 Table[Hash].Key = Wsle[j].
u1.Long & ~(
PAGE_SIZE - 1);
03593 Table[Hash].Index = j;
03594
#if DBG
03595
PointerPte =
MiGetPteAddress(Wsle[j].u1.
VirtualAddress);
03596
ASSERT (PointerPte->u.Hard.Valid);
03597
#endif //DBG
03598
03599 }
03600
ASSERT (j <= WorkingSetList->LastEntry);
03601 j += 1;
03602 }
while (
Count);
03603
03604
#if DBG
03605
MiCheckWsleHash (WorkingSetList);
03606
#endif //DBG
03607
return;
03608 }
03609
03610
03611 ULONG
03612 MiTrimWorkingSet (
03613 ULONG Reduction,
03614 IN
PMMSUPPORT WsInfo,
03615 IN ULONG ForcedReductionOrTrimAge
03616 )
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633
03634
03635
03636
03637
03638
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654 {
03655 ULONG TryToFree;
03656 ULONG StartEntry;
03657 ULONG LastEntry;
03658
PMMWSL WorkingSetList;
03659
PMMWSLE Wsle;
03660
PMMPTE PointerPte;
03661 ULONG NumberLeftToRemove;
03662 ULONG LoopCount;
03663 ULONG EndCount;
03664 BOOLEAN StartFromZero;
03665
03666 NumberLeftToRemove = Reduction;
03667 WorkingSetList = WsInfo->VmWorkingSetList;
03668 Wsle = WorkingSetList->
Wsle;
03669
03670
#if DBG
03671
if (WsInfo == &
MmSystemCacheWs) {
03672
MM_SYSTEM_WS_LOCK_ASSERT();
03673 }
03674
#endif //DBG
03675
03676 LastEntry = WorkingSetList->
LastEntry;
03677
03678 TryToFree = WorkingSetList->
NextSlot;
03679
if (TryToFree > LastEntry || TryToFree < WorkingSetList->
FirstDynamic) {
03680 TryToFree = WorkingSetList->
FirstDynamic;
03681 }
03682
03683 StartEntry = TryToFree;
03684
03685
#ifdef _MI_USE_CLAIMS_
03686
03687
while (NumberLeftToRemove != 0) {
03688
if (Wsle[TryToFree].
u1.e1.Valid == 1) {
03689 PointerPte =
MiGetPteAddress (Wsle[TryToFree].u1.
VirtualAddress);
03690
03691
if ((ForcedReductionOrTrimAge == 0) ||
03692 ((
MI_GET_ACCESSED_IN_PTE (PointerPte) == 0) &&
03693 (
MI_GET_WSLE_AGE(PointerPte, &Wsle[TryToFree]) >= ForcedReductionOrTrimAge))) {
03694
03695
PERFINFO_GET_PAGE_INFO_WITH_DECL(PointerPte);
03696
03697
if (
MiFreeWsle (TryToFree, WsInfo, PointerPte)) {
03698
PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_VOLUNTRIM, WsInfo);
03699 NumberLeftToRemove -= 1;
03700 }
03701 }
03702 }
03703 TryToFree += 1;
03704
03705
if (TryToFree > LastEntry) {
03706 TryToFree = WorkingSetList->
FirstDynamic;
03707 }
03708
03709
if (TryToFree == StartEntry) {
03710
break;
03711 }
03712 }
03713
03714
#else
03715
03716 LoopCount = 0;
03717
03718
if (ForcedReductionOrTrimAge) {
03719 EndCount = 4;
03720 }
else {
03721 EndCount = 1;
03722 }
03723
03724 StartFromZero =
FALSE;
03725
03726
while (NumberLeftToRemove != 0 && LoopCount != EndCount) {
03727
while ((NumberLeftToRemove != 0) && (TryToFree <= LastEntry)) {
03728
03729
if (Wsle[TryToFree].
u1.e1.Valid == 1) {
03730 PointerPte =
MiGetPteAddress (Wsle[TryToFree].u1.
VirtualAddress);
03731
if (
MI_GET_ACCESSED_IN_PTE (PointerPte)) {
03732
03733
03734
03735
03736
03737
03738
MI_SET_ACCESSED_IN_PTE (PointerPte, 0);
03739 }
else {
03740
PERFINFO_GET_PAGE_INFO_WITH_DECL(PointerPte);
03741
if (
MiFreeWsle (TryToFree, WsInfo, PointerPte)) {
03742
PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_VOLUNTRIM, WsInfo);
03743 NumberLeftToRemove -= 1;
03744 }
03745 }
03746 }
03747 TryToFree += 1;
03748
03749
if (StartFromZero ==
TRUE && EndCount == 1 && TryToFree >= StartEntry) {
03750 LoopCount = EndCount;
03751
if (TryToFree > LastEntry) {
03752 TryToFree = WorkingSetList->
FirstDynamic;
03753 }
03754
break;
03755 }
03756 }
03757
03758
if (TryToFree > LastEntry) {
03759 TryToFree = WorkingSetList->
FirstDynamic;
03760
if (StartFromZero ==
TRUE) {
03761
03762
03763
03764
03765
03766
03767 StartEntry = TryToFree;
03768 }
03769
else {
03770 StartFromZero =
TRUE;
03771 }
03772
03773
if (TryToFree >= StartEntry) {
03774
03775
03776
03777
03778
03779
03780
03781
03782 LoopCount += 1;
03783 StartFromZero =
FALSE;
03784 }
03785 }
03786 }
03787
03788
#endif
03789
03790 WorkingSetList->
NextSlot = TryToFree;
03791
03792
03793
03794
03795
03796
03797
if (WsInfo != &
MmSystemCacheWs && WsInfo->
u.Flags.SessionSpace == 0) {
03798
03799
03800
03801
03802
03803
if (WorkingSetList->
FirstDynamic == WsInfo->WorkingSetSize) {
03804
MiRemoveWorkingSetPages (WorkingSetList, WsInfo);
03805 }
else {
03806
03807
if ((WorkingSetList->
Quota + 15 + (
PAGE_SIZE /
sizeof(
MMWSLE))) <
03808 WorkingSetList->
LastEntry) {
03809
if ((WsInfo->MaximumWorkingSetSize + 15 + (
PAGE_SIZE /
sizeof(
MMWSLE))) <
03810 WorkingSetList->
LastEntry ) {
03811
MiRemoveWorkingSetPages (WorkingSetList, WsInfo);
03812 }
03813 }
03814 }
03815 }
03816
return Reduction - NumberLeftToRemove;
03817 }
03818
03819
#if 0 //COMMENTED OUT.
03820
VOID
03821
MmPurgeWorkingSet (
03822 IN
PEPROCESS Process,
03823 IN PVOID BaseAddress,
03824 IN ULONG RegionSize
03825 )
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853
03854
03855 {
03856
PMMSUPPORT WsInfo;
03857
PMMPTE PointerPte;
03858
PMMPTE PointerPde;
03859
PMMPTE LastPte;
03860
PMMPFN Pfn1;
03861
MMPTE PteContents;
03862
PEPROCESS CurrentProcess;
03863 PVOID EndingAddress;
03864 ULONG SystemCache;
03865 KIRQL OldIrql;
03866
03867
03868
03869
03870
03871
03872
03873
03874 CurrentProcess =
PsGetCurrentProcess ();
03875
03876
ASSERT (RegionSize != 0);
03877
03878 EndingAddress = (PVOID)((PCHAR)BaseAddress + RegionSize - 1);
03879
03880
if ((BaseAddress <= MM_HIGHEST_USER_ADDRESS) ||
03881 ((BaseAddress >= (PVOID)PTE_BASE) &&
03882 (BaseAddress < (PVOID)
MM_SYSTEM_SPACE_START)) ||
03883 ((BaseAddress >=
MM_PAGED_POOL_START) &&
03884 (BaseAddress <=
MmPagedPoolEnd))) {
03885
03886 SystemCache =
FALSE;
03887
03888
03889
03890
03891
03892
KeAttachProcess (&Process->Pcb);
03893
03894 WsInfo = &Process->Vm,
03895
03896
LOCK_WS (Process);
03897 }
else {
03898
03899 SystemCache =
TRUE;
03900 Process = CurrentProcess;
03901 WsInfo = &
MmSystemCacheWs;
03902 }
03903
03904 PointerPde =
MiGetPdeAddress (BaseAddress);
03905 PointerPte =
MiGetPteAddress (BaseAddress);
03906 LastPte =
MiGetPteAddress (EndingAddress);
03907
03908
while (!
MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE)) {
03909
03910
03911
03912
03913
03914 PointerPde += 1;
03915
03916 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
03917
03918
if (PointerPte > LastPte) {
03919
break;
03920 }
03921 }
03922
03923
LOCK_PFN (OldIrql);
03924
03925
while (PointerPte <= LastPte) {
03926
03927 PteContents = *PointerPte;
03928
03929
if (PteContents.
u.Hard.Valid == 1) {
03930
03931
03932
03933
03934
03935 Pfn1 =
MI_PFN_ELEMENT (PteContents.
u.Hard.PageFrameNumber);
03936
03937
if (Pfn1->
u3.e2.ReferenceCount == 1) {
03938
MiRemovePageFromWorkingSet (PointerPte, Pfn1, WsInfo);
03939 }
03940 }
03941
03942 PointerPte += 1;
03943
03944
if (((ULONG_PTR)PointerPte & (
PAGE_SIZE - 1)) == 0) {
03945
03946 PointerPde =
MiGetPteAddress (PointerPte);
03947
03948
while ((PointerPte <= LastPte) &&
03949 (!
MiDoesPdeExistAndMakeValid(PointerPde, Process, TRUE))) {
03950
03951
03952
03953
03954
03955 PointerPde += 1;
03956
03957 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
03958 }
03959 }
03960 }
03961
03962
UNLOCK_PFN (OldIrql);
03963
03964
if (!SystemCache) {
03965
03966
UNLOCK_WS (Process);
03967
KeDetachProcess();
03968 }
03969
return;
03970 }
03971
#endif //0
03972
03973
VOID
03974 MiEliminateWorkingSetEntry (
03975 IN ULONG WorkingSetIndex,
03976 IN
PMMPTE PointerPte,
03977 IN
PMMPFN Pfn,
03978 IN
PMMWSLE Wsle
03979 )
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012 {
04013
PMMPTE ContainingPageTablePage;
04014
MMPTE TempPte;
04015
MMPTE PreviousPte;
04016 PFN_NUMBER PageFrameIndex;
04017
PEPROCESS Process;
04018 PVOID VirtualAddress;
04019
04020
04021
04022
04023
04024
MM_PFN_LOCK_ASSERT ();
04025
04026 TempPte = *PointerPte;
04027 PageFrameIndex =
MI_GET_PAGE_FRAME_FROM_PTE (&TempPte);
04028
04029
#ifdef _X86_
04030
#if DBG
04031
#if !defined(NT_UP)
04032
if (TempPte.
u.Hard.Writable == 1) {
04033
ASSERT (TempPte.
u.Hard.Dirty == 1);
04034 }
04035
ASSERT (TempPte.
u.Hard.Accessed == 1);
04036
#endif //NTUP
04037
#endif //DBG
04038
#endif //X86
04039
04040
MI_MAKING_VALID_PTE_INVALID (
FALSE);
04041
04042
if (Pfn->u3.e1.PrototypePte) {
04043
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
if (Wsle[WorkingSetIndex].u1.e1.SameProtectAsProto == 0) {
04055
04056
04057
04058
04059
04060
04061
ASSERT (Wsle[WorkingSetIndex].u1.e1.Protection != 0);
04062
04063
if (!
MI_IS_SESSION_IMAGE_ADDRESS (
MiGetVirtualAddressMappedByPte(PointerPte))) {
04064 TempPte.
u.Long = 0;
04065 TempPte.
u.Soft.Protection =
04066
MI_GET_PROTECTION_FROM_WSLE (&Wsle[WorkingSetIndex]);
04067 TempPte.
u.Soft.PageFileHigh =
MI_PTE_LOOKUP_NEEDED;
04068 }
04069
else {
04070
04071
04072
04073
04074
04075 TempPte.
u.Long =
MiProtoAddressForPte (Pfn->PteAddress);
04076 }
04077 }
else {
04078
04079
04080
04081
04082
04083 TempPte.
u.Long =
MiProtoAddressForPte (Pfn->PteAddress);
04084
04085
if (
MI_IS_SESSION_IMAGE_ADDRESS (
MiGetVirtualAddressMappedByPte(PointerPte))) {
04086
04087
04088
04089
04090
04091 TempPte.
u.Proto.ReadOnly = 1;
04092 }
04093 }
04094
04095 TempPte.
u.Proto.Prototype = 1;
04096
04097
04098
04099
04100
04101
04102
04103 ContainingPageTablePage =
MiGetPteAddress (PointerPte);
04104
#if defined (_WIN64)
04105
ASSERT (ContainingPageTablePage->
u.Hard.Valid == 1);
04106
#else
04107
if (ContainingPageTablePage->
u.Hard.Valid == 0) {
04108
if (!
NT_SUCCESS(
MiCheckPdeForPagedPool (PointerPte))) {
04109
KeBugCheckEx (MEMORY_MANAGEMENT,
04110 0x61940,
04111 (ULONG_PTR)PointerPte,
04112 (ULONG_PTR)ContainingPageTablePage->
u.Long,
04113 (ULONG_PTR)
MiGetVirtualAddressMappedByPte(PointerPte));
04114 }
04115 }
04116
#endif
04117
MiDecrementShareAndValidCount (
MI_GET_PAGE_FRAME_FROM_PTE (ContainingPageTablePage));
04118
04119 }
else {
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
ASSERT ((Pfn->u2.ShareCount == 1) ||
04130 (Wsle[WorkingSetIndex].u1.VirtualAddress >
04131 (PVOID)MM_HIGHEST_USER_ADDRESS));
04132
04133
04134
04135
04136
04137
04138
ASSERT (Pfn->u1.WsIndex != 0);
04139
MI_ZERO_WSINDEX (Pfn);
04140
MI_MAKE_VALID_PTE_TRANSITION (TempPte,
04141 Pfn->OriginalPte.
u.Soft.Protection);
04142 }
04143
04144
if (Wsle ==
MmWsle) {
04145 PreviousPte.
u.Flush =
KeFlushSingleTb (
04146 Wsle[WorkingSetIndex].u1.VirtualAddress,
04147
TRUE,
04148
FALSE,
04149 (PHARDWARE_PTE)PointerPte,
04150 TempPte.
u.Flush);
04151 }
04152
else if (Wsle ==
MmSystemCacheWsle) {
04153
04154
04155
04156
04157
04158 PreviousPte.
u.Flush =
KeFlushSingleTb (
04159 Wsle[WorkingSetIndex].u1.VirtualAddress,
04160
TRUE,
04161
TRUE,
04162 (PHARDWARE_PTE)PointerPte,
04163 TempPte.
u.Flush);
04164 }
04165
else {
04166
04167
04168
04169
04170
04171
MI_FLUSH_SINGLE_SESSION_TB (Wsle[WorkingSetIndex].u1.VirtualAddress,
04172
TRUE,
04173
FALSE,
04174 (PHARDWARE_PTE)PointerPte,
04175 TempPte.
u.Flush,
04176 PreviousPte);
04177 }
04178
04179
ASSERT (PreviousPte.
u.Hard.Valid == 1);
04180
04181
04182
04183
04184
04185
04186
04187
MI_CAPTURE_DIRTY_BIT_TO_PFN (&PreviousPte, Pfn);
04188
04189
04190
04191
04192
04193
04194
04195
if (
MiActiveWriteWatch != 0) {
04196
if ((Pfn->u3.e1.PrototypePte == 0) &&
04197 (
MI_IS_PTE_DIRTY(PreviousPte))) {
04198
04199 Process =
PsGetCurrentProcess();
04200
04201
if (Process->
Vm.
u.Flags.WriteWatch == 1) {
04202
04203
04204
04205
04206
04207
04208
04209 VirtualAddress =
MiGetVirtualAddressMappedByPte (PointerPte);
04210
MiCaptureWriteWatchDirtyBit (Process, VirtualAddress);
04211 }
04212 }
04213 }
04214
04215
04216
04217
04218
04219
04220
04221
04222
MiDecrementShareCount (PageFrameIndex);
04223
04224
return;
04225 }
04226
04227
VOID
04228 MiRemoveWorkingSetPages (
04229 IN
PMMWSL WorkingSetList,
04230 IN
PMMSUPPORT WsInfo
04231 )
04232
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253
04254 {
04255
PMMWSLE FreeEntry;
04256
PMMWSLE LastEntry;
04257
PMMWSLE Wsle;
04258 ULONG FreeIndex;
04259 ULONG LastIndex;
04260 ULONG LastInvalid;
04261
PMMPTE LastPte;
04262
PMMPTE PointerPte;
04263
PMMPTE PointerPde;
04264
PMMPTE PointerPpe;
04265
PMMPTE WsPte;
04266
PMMPFN Pfn1;
04267
PEPROCESS CurrentProcess;
04268
MMPTE_FLUSH_LIST PteFlushList;
04269 ULONG NewSize;
04270
PMMWSLE_HASH Table;
04271 KIRQL OldIrql;
04272
04273
ASSERT (WsInfo != &
MmSystemCacheWs && WsInfo->
u.Flags.SessionSpace == 0);
04274
04275 PteFlushList.
Count = 0;
04276 CurrentProcess =
PsGetCurrentProcess();
04277
04278
#if DBG
04279
MiCheckNullIndex (WorkingSetList);
04280
#endif //DBG
04281
04282
04283
04284
04285
04286
if (WorkingSetList->HashTable) {
04287
04288 Table = WorkingSetList->HashTable;
04289
04290
#if DBG
04291
if ((PVOID)(&Table[WorkingSetList->HashTableSize]) < WorkingSetList->HighestPermittedHashAddress) {
04292
ASSERT (
MiGetPteAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0);
04293 }
04294
#endif
04295
04296
if (WsInfo->WorkingSetSize < 200) {
04297 NewSize = 0;
04298 }
04299
else {
04300 NewSize = PtrToUlong(
PAGE_ALIGN ((WorkingSetList->NonDirectCount * 2 *
04301
sizeof(
MMWSLE_HASH)) +
PAGE_SIZE - 1));
04302
04303 NewSize = NewSize /
sizeof(
MMWSLE_HASH);
04304 }
04305
04306
if (NewSize < WorkingSetList->HashTableSize) {
04307
04308
#if defined(_ALPHA_) && !defined(_AXP64_)
04309
LOCK_EXPANSION_IF_ALPHA (OldIrql);
04310
#endif
04311
if (NewSize && WsInfo->AllowWorkingSetAdjustment) {
04312 WsInfo->AllowWorkingSetAdjustment =
MM_GROW_WSLE_HASH;
04313 }
04314
#if defined(_ALPHA_) && !defined(_AXP64_)
04315
UNLOCK_EXPANSION_IF_ALPHA (OldIrql);
04316
#endif
04317
04318
04319
04320
04321
04322
ASSERT (((ULONG_PTR)&WorkingSetList->HashTable[NewSize] &
04323 (
PAGE_SIZE - 1)) == 0);
04324
04325 PointerPte =
MiGetPteAddress (&WorkingSetList->HashTable[NewSize]);
04326
04327 LastPte =
MiGetPteAddress (WorkingSetList->HighestPermittedHashAddress);
04328
04329
04330
04331
04332
04333 WorkingSetList->HashTable =
NULL;
04334 WorkingSetList->HashTableSize = NewSize;
04335
04336
LOCK_PFN (OldIrql);
04337
while ((PointerPte < LastPte) && (PointerPte->
u.Hard.Valid == 1)) {
04338
04339
MiDeletePte (PointerPte,
04340
MiGetVirtualAddressMappedByPte (PointerPte),
04341
FALSE,
04342 CurrentProcess,
04343
NULL,
04344 &PteFlushList);
04345
04346
04347
04348
04349
04350 CurrentProcess->
NumberOfPrivatePages += 1;
04351
04352 PointerPte += 1;
04353
04354
#if defined (_WIN64)
04355
04356
04357
04358
04359
04360
04361
if ((
MiIsPteOnPdeBoundary(PointerPte)) ||
04362 ((
MiGetPdeAddress(PointerPte))->u.Hard.Valid == 0) ||
04363 ((
MiGetPteAddress(PointerPte))->u.Hard.Valid == 0) ||
04364 (PointerPte->u.Hard.Valid == 0)) {
04365
04366
MiFlushPteList (&PteFlushList,
FALSE,
ZeroPte);
04367
04368 PointerPde =
MiGetPteAddress (PointerPte - 1);
04369
04370
ASSERT (PointerPde->
u.Hard.Valid == 1);
04371
04372 Pfn1 =
MI_PFN_ELEMENT (
MI_GET_PAGE_FRAME_FROM_PTE (PointerPde));
04373
04374
if (Pfn1->
u2.ShareCount == 1 && Pfn1->
u3.e2.ReferenceCount == 1)
04375 {
04376
MiDeletePte (PointerPde,
04377 PointerPte - 1,
04378
FALSE,
04379 CurrentProcess,
04380
NULL,
04381
NULL);
04382
04383
04384
04385
04386
04387 CurrentProcess->
NumberOfPrivatePages += 1;
04388 }
04389
04390
if (
MiIsPteOnPpeBoundary(PointerPte)) {
04391
04392 PointerPpe =
MiGetPteAddress (PointerPde);
04393
04394
ASSERT (PointerPpe->
u.Hard.Valid == 1);
04395
04396 Pfn1 =
MI_PFN_ELEMENT (
MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe));
04397
04398
if (Pfn1->
u2.ShareCount == 1 && Pfn1->
u3.e2.ReferenceCount == 1)
04399 {
04400
MiDeletePte (PointerPpe,
04401 PointerPde,
04402
FALSE,
04403 CurrentProcess,
04404
NULL,
04405
NULL);
04406
04407
04408
04409
04410
04411 CurrentProcess->
NumberOfPrivatePages += 1;
04412 }
04413 }
04414 PointerPde =
MiGetPteAddress (PointerPte);
04415 PointerPpe =
MiGetPdeAddress (PointerPte);
04416
if ((PointerPpe->
u.Hard.Valid == 0) ||
04417 (PointerPde->u.Hard.Valid == 0)) {
04418
break;
04419 }
04420 }
04421
#endif
04422
}
04423
MiFlushPteList (&PteFlushList,
FALSE,
ZeroPte);
04424
04425
if (WsInfo->u.Flags.SessionSpace == 1) {
04426
04427
04428
04429
04430
04431
MI_FLUSH_ENTIRE_SESSION_TB (
TRUE,
TRUE);
04432 }
04433
04434
UNLOCK_PFN (OldIrql);
04435 }
04436
#if defined (_WIN64)
04437
04438
04439
04440
04441
04442
04443
ASSERT ((
MiGetPpeAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0) ||
04444 (
MiGetPdeAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0) ||
04445 (
MiGetPteAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0));
04446
04447
#else
04448
04449
ASSERT (
MiGetPteAddress(&Table[WorkingSetList->HashTableSize])->u.Hard.Valid == 0);
04450
04451
#endif
04452
}
04453
04454
04455
04456
04457
04458
04459
04460 Wsle = WorkingSetList->Wsle;
04461
if (WorkingSetList->FirstDynamic == WsInfo->WorkingSetSize) {
04462
04463 LastIndex = WorkingSetList->FirstDynamic;
04464 LastEntry = &Wsle[LastIndex];
04465
04466 }
else {
04467
04468
04469
04470
04471
04472
04473
04474 LastInvalid = 0;
04475 FreeIndex = WorkingSetList->FirstDynamic;
04476 FreeEntry = &Wsle[FreeIndex];
04477 LastIndex = WorkingSetList->LastEntry;
04478 LastEntry = &Wsle[LastIndex];
04479
04480
while (FreeEntry < LastEntry) {
04481
if (FreeEntry->
u1.e1.Valid == 1) {
04482 FreeEntry += 1;
04483 FreeIndex += 1;
04484 }
else if (LastEntry->
u1.e1.Valid == 0) {
04485 LastEntry -= 1;
04486 LastIndex -= 1;
04487 }
else {
04488
04489
04490
04491
04492
04493 LastInvalid = 1;
04494 *FreeEntry = *LastEntry;
04495 PointerPte =
MiGetPteAddress (LastEntry->u1.VirtualAddress);
04496
04497
if (LastEntry->u1.e1.Direct) {
04498
04499 Pfn1 =
MI_PFN_ELEMENT (PointerPte->
u.Hard.PageFrameNumber);
04500
04501
CONSISTENCY_LOCK_PFN (OldIrql);
04502
04503 Pfn1->
u1.WsIndex = FreeIndex;
04504
04505
CONSISTENCY_UNLOCK_PFN (OldIrql);
04506
04507 }
else {
04508
04509
04510
04511
04512
04513
04514
MiRemoveWsle (LastIndex, WorkingSetList);
04515
MiInsertWsle (FreeIndex, WorkingSetList);
04516 }
04517
04518
MI_SET_PTE_IN_WORKING_SET (PointerPte, FreeIndex);
04519 LastEntry->u1.Long = 0;
04520 LastEntry -= 1;
04521 LastIndex -= 1;
04522 FreeEntry += 1;
04523 FreeIndex += 1;
04524 }
04525 }
04526
04527
04528
04529
04530
04531
if (LastInvalid == 0) {
04532
#if DBG
04533
MiCheckNullIndex (WorkingSetList);
04534
#endif //DBG
04535
return;
04536 }
04537 }
04538
04539
04540
04541
04542
04543
ASSERT ((LastEntry - 1)->u1.e1.Valid == 1);
04544
04545
if (LastEntry->
u1.e1.Valid == 1) {
04546 LastEntry += 1;
04547 LastIndex += 1;
04548 }
04549
04550 WorkingSetList->LastEntry = LastIndex - 1;
04551 WorkingSetList->FirstFree = LastIndex;
04552
04553
ASSERT ((LastEntry - 1)->u1.e1.Valid == 1);
04554
ASSERT ((LastEntry)->u1.e1.Valid == 0);
04555
04556
04557
04558
04559
04560 FreeEntry = LastEntry;
04561
04562
while (LastIndex < WorkingSetList->LastInitializedWsle) {
04563
04564
04565
04566
04567
04568
ASSERT (LastEntry->u1.e1.Valid == 0);
04569 LastIndex += 1;
04570 LastEntry->u1.Long = LastIndex <<
MM_FREE_WSLE_SHIFT;
04571 LastEntry += 1;
04572 }
04573
04574
04575
04576
04577
04578
04579
04580 PointerPte =
MiGetPteAddress (&Wsle[WorkingSetList->LastInitializedWsle]);
04581
if (&Wsle[WsInfo->MinimumWorkingSetSize] > FreeEntry) {
04582 FreeEntry = &Wsle[WsInfo->MinimumWorkingSetSize];
04583 }
04584
04585 WsPte =
MiGetPteAddress (FreeEntry);
04586
04587
#if 0
04588
if (
MiGetPteAddress (FreeEntry) !=
MiGetPteAddress (FreeEntry + 1)) {
04589
DbgPrint (
"MiRemoveWorkingSetPages caught boundary case %x\n", FreeEntry);
04590 DbgBreakPoint();
04591
04592 WsPte =
MiGetPteAddress (FreeEntry + 1);
04593 }
04594
#endif
04595
04596
ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
04597
04598
LOCK_PFN (OldIrql);
04599
while (PointerPte > WsPte) {
04600
ASSERT (PointerPte->
u.Hard.Valid == 1);
04601
04602
MiDeletePte (PointerPte,
04603
MiGetVirtualAddressMappedByPte (PointerPte),
04604
FALSE,
04605 CurrentProcess,
04606
NULL,
04607 &PteFlushList);
04608
04609
04610
04611
04612
04613 CurrentProcess->
NumberOfPrivatePages += 1;
04614
04615
#if defined (_WIN64)
04616
04617
04618
04619
04620
04621
04622
if (
MiIsPteOnPdeBoundary(PointerPte)) {
04623
04624 PointerPde =
MiGetPteAddress (PointerPte);
04625
04626
ASSERT (PointerPde->
u.Hard.Valid == 1);
04627
04628 Pfn1 =
MI_PFN_ELEMENT (
MI_GET_PAGE_FRAME_FROM_PTE (PointerPde));
04629
04630
if (Pfn1->
u2.ShareCount == 1 && Pfn1->
u3.e2.ReferenceCount == 1) {
04631
04632
MiFlushPteList (&PteFlushList,
FALSE,
ZeroPte);
04633
04634
MiDeletePte (PointerPde,
04635 PointerPte,
04636
FALSE,
04637 CurrentProcess,
04638
NULL,
04639
NULL);
04640
04641
04642
04643
04644
04645 CurrentProcess->
NumberOfPrivatePages += 1;
04646 }
04647
04648
if (
MiIsPteOnPpeBoundary(PointerPte)) {
04649
04650 PointerPpe =
MiGetPteAddress (PointerPde);
04651
04652
ASSERT (PointerPpe->
u.Hard.Valid == 1);
04653
04654 Pfn1 =
MI_PFN_ELEMENT (
MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe));
04655
04656
if (Pfn1->
u2.ShareCount == 1 && Pfn1->
u3.e2.ReferenceCount == 1)
04657 {
04658
04659
MiFlushPteList (&PteFlushList,
FALSE,
ZeroPte);
04660
04661
MiDeletePte (PointerPpe,
04662 PointerPde,
04663
FALSE,
04664 CurrentProcess,
04665
NULL,
04666
NULL);
04667
04668
04669
04670
04671
04672 CurrentProcess->
NumberOfPrivatePages += 1;
04673 }
04674 }
04675 }
04676
#endif
04677
04678 PointerPte -= 1;
04679 }
04680
04681
MiFlushPteList (&PteFlushList,
FALSE,
ZeroPte);
04682
04683
if (WsInfo->u.Flags.SessionSpace == 1) {
04684
04685
04686
04687
04688
04689
MI_FLUSH_ENTIRE_SESSION_TB (
TRUE,
TRUE);
04690 }
04691
04692
UNLOCK_PFN (OldIrql);
04693
04694
ASSERT (WorkingSetList->FirstFree >= WorkingSetList->FirstDynamic);
04695
04696
04697
04698
04699
04700 LastEntry = (
PMMWSLE)((PCHAR)(
PAGE_ALIGN(FreeEntry)) +
PAGE_SIZE);
04701 LastEntry -= 1;
04702
04703
ASSERT (LastEntry->u1.e1.Valid == 0);
04704 LastEntry->u1.Long =
WSLE_NULL_INDEX <<
MM_FREE_WSLE_SHIFT;
04705
ASSERT (LastEntry > &Wsle[0]);
04706 WorkingSetList->LastInitializedWsle = (
WSLE_NUMBER)(LastEntry - &Wsle[0]);
04707 WorkingSetList->NextSlot = WorkingSetList->FirstDynamic;
04708
04709
ASSERT (WorkingSetList->LastEntry <= WorkingSetList->LastInitializedWsle);
04710
04711
if (WorkingSetList->Quota < WorkingSetList->LastInitializedWsle) {
04712 WorkingSetList->Quota = WorkingSetList->LastInitializedWsle;
04713 }
04714
04715
ASSERT ((
MiGetPteAddress(&Wsle[WorkingSetList->LastInitializedWsle]))->u.Hard.Valid == 1);
04716
ASSERT ((WorkingSetList->FirstFree <= WorkingSetList->LastInitializedWsle) ||
04717 (WorkingSetList->FirstFree ==
WSLE_NULL_INDEX));
04718
#if DBG
04719
MiCheckNullIndex (WorkingSetList);
04720
#endif //DBG
04721
return;
04722 }
04723
04724
04725
NTSTATUS
04726 MiEmptyWorkingSet (
04727 IN
PMMSUPPORT WsInfo,
04728 IN LOGICAL WaitOk
04729 )
04730
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740
04741
04742
04743
04744
04745
04746
04747
04748
04749
04750
04751
04752
04753
04754 {
04755
PEPROCESS Process;
04756 KIRQL OldIrql;
04757
PMMPTE PointerPte;
04758 ULONG Entry;
04759 ULONG
Count;
04760 ULONG LastFreed;
04761
PMMWSL WorkingSetList;
04762
PMMWSLE Wsle;
04763
PMMPFN Pfn1;
04764 PFN_NUMBER PageFrameIndex;
04765 ULONG Last;
04766
NTSTATUS Status;
04767
PMM_SESSION_SPACE SessionSpace;
04768
04769
if (WsInfo == &
MmSystemCacheWs) {
04770
if (WaitOk ==
TRUE) {
04771
LOCK_SYSTEM_WS (OldIrql);
04772 }
04773
else {
04774
KeRaiseIrql (
APC_LEVEL, &OldIrql);
04775
if (!
ExTryToAcquireResourceExclusiveLite (&
MmSystemWsLock)) {
04776
04777
04778
04779
04780
04781
04782
KeLowerIrql (OldIrql);
04783
return STATUS_SUCCESS;
04784 }
04785
04786
MmSystemLockOwner =
PsGetCurrentThread();
04787 }
04788 }
04789
else if (WsInfo->u.Flags.SessionSpace == 0) {
04790 Process =
PsGetCurrentProcess ();
04791
if (WaitOk ==
TRUE) {
04792
LOCK_WS (Process);
04793 }
04794
else {
04795
Count = 0;
04796
do {
04797
if (ExTryToAcquireFastMutex(&Process->
WorkingSetLock) !=
FALSE) {
04798
break;
04799 }
04800
KeDelayExecutionThread (
KernelMode,
FALSE, &
MmShortTime);
04801
Count += 1;
04802
if (
Count == 5) {
04803
04804
04805
04806
04807
04808
return STATUS_SUCCESS;
04809 }
04810 }
while (
TRUE);
04811 }
04812
if (Process->
AddressSpaceDeleted != 0) {
04813
Status = STATUS_PROCESS_IS_TERMINATING;
04814
goto Deleted;
04815 }
04816 }
04817
else {
04818
if (WaitOk ==
TRUE) {
04819
LOCK_SESSION_SPACE_WS (OldIrql);
04820 }
04821
else {
04822
ASSERT (
MiHydra ==
TRUE);
04823 SessionSpace = CONTAINING_RECORD(WsInfo,
04824
MM_SESSION_SPACE,
04825 Vm);
04826
04827
KeRaiseIrql (
APC_LEVEL, &OldIrql);
04828
04829
if (!
ExTryToAcquireResourceExclusiveLite (&SessionSpace->
WsLock)) {
04830
04831
04832
04833
04834
04835
04836
KeLowerIrql (OldIrql);
04837
return STATUS_SUCCESS;
04838 }
04839
04840
MM_SET_SESSION_RESOURCE_OWNER();
04841 }
04842 }
04843
04844 WorkingSetList = WsInfo->VmWorkingSetList;
04845 Wsle = WorkingSetList->
Wsle;
04846
04847
04848
04849
04850
04851 LastFreed = WorkingSetList->
LastEntry;
04852
for (Entry = WorkingSetList->
FirstDynamic; Entry <= LastFreed; Entry += 1) {
04853
04854
if (Wsle[Entry].
u1.e1.Valid != 0) {
04855
PERFINFO_PAGE_INFO_DECL();
04856
04857 PointerPte =
MiGetPteAddress (Wsle[Entry].u1.
VirtualAddress);
04858
04859
PERFINFO_GET_PAGE_INFO(PointerPte);
04860
04861
if (
MiTrimRemovalPagesOnly ==
TRUE) {
04862 PageFrameIndex =
MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
04863 Pfn1 =
MI_PFN_ELEMENT (PageFrameIndex);
04864
if (Pfn1->
u3.e1.RemovalRequested == 0) {
04865 Pfn1 =
MI_PFN_ELEMENT (Pfn1->
PteFrame);
04866
if (Pfn1->
u3.e1.RemovalRequested == 0) {
04867
#if defined (_WIN64)
04868
Pfn1 =
MI_PFN_ELEMENT (Pfn1->
PteFrame);
04869
if (Pfn1->
u3.e1.RemovalRequested == 0) {
04870
continue;
04871 }
04872
#else
04873
continue;
04874
#endif
04875
}
04876 }
04877 }
04878
04879
if (
MiFreeWsle (Entry, WsInfo, PointerPte)) {
04880
PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_EMPTYQ, WsInfo);
04881 }
04882 }
04883 }
04884
04885
if (WsInfo != &
MmSystemCacheWs && WsInfo->
u.Flags.SessionSpace == 0) {
04886
MiRemoveWorkingSetPages (WorkingSetList,WsInfo);
04887 }
04888 WorkingSetList->
Quota = WsInfo->WorkingSetSize;
04889 WorkingSetList->
NextSlot = WorkingSetList->
FirstDynamic;
04890
04891
04892
04893
04894
04895
04896
04897
04898
04899 Last = 0;
04900 Entry = WorkingSetList->
FirstDynamic;
04901 LastFreed = WorkingSetList->
LastInitializedWsle;
04902
while (Entry <= LastFreed) {
04903
if (Wsle[Entry].
u1.e1.Valid == 0) {
04904
if (Last == 0) {
04905 WorkingSetList->
FirstFree = Entry;
04906 }
else {
04907 Wsle[Last].
u1.Long = Entry <<
MM_FREE_WSLE_SHIFT;
04908 }
04909 Last = Entry;
04910 }
04911 Entry += 1;
04912 }
04913
if (Last != 0) {
04914 Wsle[Last].
u1.Long =
WSLE_NULL_INDEX <<
MM_FREE_WSLE_SHIFT;
04915 }
04916
Status = STATUS_SUCCESS;
04917 Deleted:
04918
04919
if (WsInfo == &
MmSystemCacheWs) {
04920
UNLOCK_SYSTEM_WS (OldIrql);
04921 }
04922
else if (WsInfo->u.Flags.SessionSpace == 0) {
04923
UNLOCK_WS (Process);
04924 }
04925
else {
04926
UNLOCK_SESSION_SPACE_WS (OldIrql);
04927 }
04928
04929
return Status;
04930 }
04931
04932
#if 0
04933
04934
#define x256k_pte_mask (((256*1024) >> (PAGE_SHIFT - PTE_SHIFT)) - (sizeof(MMPTE)))
04935
04936
VOID
04937
MiDumpWsleInCacheBlock (
04938 IN
PMMPTE CachePte
04939 )
04940
04941
04942
04943
04944
04945
04946
04947
04948
04949
04950
04951
04952
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964 {
04965
PMMPTE LoopPte;
04966
PMMPTE PointerPte;
04967
04968 LoopPte = (
PMMPTE)((ULONG_PTR)CachePte & ~x256k_pte_mask);
04969 PointerPte = CachePte - 1;
04970
04971
while (PointerPte >= LoopPte ) {
04972
04973
if (
MiDumpPteInCacheBlock (PointerPte) ==
FALSE) {
04974
break;
04975 }
04976 PointerPte -= 1;
04977 }
04978
04979 PointerPte = CachePte + 1;
04980 LoopPte = (
PMMPTE)((ULONG_PTR)CachePte | x256k_pte_mask);
04981
04982
while (PointerPte <= LoopPte ) {
04983
04984
if (
MiDumpPteInCacheBlock (PointerPte) ==
FALSE) {
04985
break;
04986 }
04987 PointerPte += 1;
04988 }
04989
return;
04990 }
04991
04992 ULONG
04993
MiDumpPteInCacheBlock (
04994 IN
PMMPTE PointerPte
04995 )
04996
04997 {
04998
PMMPFN Pfn1;
04999
MMPTE PteContents;
05000 ULONG WorkingSetIndex;
05001
05002 PteContents = *PointerPte;
05003
05004
if (PteContents.
u.Hard.Valid == 1) {
05005
05006 Pfn1 =
MI_PFN_ELEMENT (PteContents.
u.Hard.PageFrameNumber);
05007
05008
05009
05010
05011
05012
05013
05014
05015
if ((Pfn1->
u3.e2.ReferenceCount == 1) &&
05016 ((Pfn1->
u3.e1.Modified == 1) ||
05017 (
MI_IS_PTE_DIRTY (PteContents))) &&
05018 (
MiGetPteAddress (
05019 MmSystemCacheWsle[Pfn1->
u1.WsIndex].u1.VirtualAddress) ==
05020 PointerPte)) {
05021
05022
05023
05024
05025
05026 WorkingSetIndex = Pfn1->
u1.WsIndex;
05027
LOCK_PFN (OldIrql);
05028
MiEliminateWorkingSetEntry (WorkingSetIndex,
05029 PointerPte,
05030 Pfn1,
05031 MmSystemCacheWsle);
05032
UNLOCK_PFN (OldIrql);
05033
05034
05035
05036
05037
05038
MiRemoveWsle (WorkingSetIndex, MmSystemCacheWorkingSetList);
05039
05040
05041
05042
05043
05044
05045
MmSystemCacheWsle[WorkingSetIndex].
u1.Long =
05046
MmSystemCacheWorkingSetList->
FirstFree <<
MM_FREE_WSLE_SHIFT;
05047
MmSystemCacheWorkingSetList->
FirstFree = WorkingSetIndex;
05048
05049
if (
MmSystemCacheWs.
WorkingSetSize >
MmSystemCacheWs.
MinimumWorkingSetSize) {
05050
MmPagesAboveWsMinimum -= 1;
05051 }
05052
MmSystemCacheWs.
WorkingSetSize -= 1;
05053
return TRUE;
05054 }
05055 }
05056
return FALSE;
05057 }
05058
#endif //0
05059
05060
#if DBG
05061
VOID
05062
MiCheckNullIndex (
05063 IN
PMMWSL WorkingSetList
05064 )
05065
05066 {
05067
PMMWSLE Wsle;
05068 ULONG j;
05069 ULONG Nulls = 0;
05070
05071 Wsle = WorkingSetList->Wsle;
05072
for (j = 0;j <= WorkingSetList->LastInitializedWsle; j += 1) {
05073
if ((((Wsle[j].
u1.Long)) >>
MM_FREE_WSLE_SHIFT) ==
WSLE_NULL_INDEX) {
05074 Nulls += 1;
05075 }
05076 }
05077
ASSERT (Nulls == 1);
05078
return;
05079 }
05080
05081
#endif //DBG