01122 :
01123
01124 This routine changes
the protection on a region of committed pages
01125 within
the virtual address space of
the subject process. Setting
01126
the protection on a range of pages causes
the old protection to be
01127 replaced by
the specified protection value.
01128
01129 Arguments:
01130
01131 Process - Supplies a pointer to
the current process.
01132
01133 FoundVad - Supplies a pointer to
the VAD containing
the range to protect.
01134
01135 StartingAddress - Supplies
the starting address to protect.
01136
01137 EndingAddress - Supplies
the ending address to protect.
01138
01139 NewProtect - Supplies
the new protection to set.
01140
01141 CapturedOldProtect - Supplies
the address of a kernel owned pointer to
01142 store (without probing)
the old protection into.
01143
01144 DontCharge - Supplies
TRUE if no quota or commitment should be charged.
01145
01146 Return Value:
01147
01148 Returns
TRUE if a locked page was removed from
the working set (protection
01149 was guard page or no-access, FALSE otherwise.
01150
01151 Exceptions raised
for page file quota or commitment violations.
01152
01153 Environment:
01154
01155 Kernel mode, working set mutex held, address creation mutex held
01156 APCs disabled.
01157
01158 --*/
01159
01160 {
01161
PMMPTE PointerPte;
01162
PMMPTE LastPte;
01163
PMMPTE PointerPde;
01164
PMMPTE PointerPpe;
01165
PMMPTE PointerProtoPte;
01166
PMMPFN Pfn1;
01167
MMPTE TempPte;
01168
MMPTE PreviousPte;
01169 ULONG Locked;
01170 ULONG ProtectionMask;
01171 ULONG ProtectionMaskNotCopy;
01172 ULONG NewProtectionMask;
01173
MMPTE PteContents;
01174 ULONG Index;
01175 PULONG Va;
01176 ULONG WriteCopy;
01177 ULONG DoAgain;
01178 ULONG Waited;
01179 SIZE_T QuotaCharge;
01180 PVOID UsedPageTableHandle;
01181 PVOID UsedPageDirectoryHandle;
01182 ULONG WorkingSetIndex;
01183
01184
PAGED_CODE();
01185
01186 Locked = FALSE;
01187 WriteCopy = FALSE;
01188 QuotaCharge = 0;
01189
01190
01191
01192
01193
01194 ASSERT (FoundVad->u.VadFlags.PrivateMemory == 0);
01195
01196 if ((FoundVad->u.VadFlags.ImageMap == 1) ||
01197 (FoundVad->u2.VadFlags2.CopyOnWrite == 1)) {
01198
01199 if (NewProtect & PAGE_READWRITE) {
01200 NewProtect &= ~PAGE_READWRITE;
01201 NewProtect |= PAGE_WRITECOPY;
01202 }
01203
01204
if (NewProtect & PAGE_EXECUTE_READWRITE) {
01205 NewProtect &= ~PAGE_EXECUTE_READWRITE;
01206 NewProtect |= PAGE_EXECUTE_WRITECOPY;
01207 }
01208 }
01209
01210 ProtectionMask = MiMakeProtectionMask (NewProtect);
01211
01212
01213
01214
01215
01216 ProtectionMaskNotCopy = ProtectionMask;
01217
if ((ProtectionMask & MM_COPY_ON_WRITE_MASK) == MM_COPY_ON_WRITE_MASK) {
01218 WriteCopy = TRUE;
01219 ProtectionMaskNotCopy &= ~MM_PROTECTION_COPY_MASK;
01220 }
01221
01222 #
if defined(_MIALT4K_)
01223
01224
if ((Process->Wow64Process != NULL) &&
01225 (FoundVad->u.VadFlags.ImageMap == 0) &&
01226 (FoundVad->u2.VadFlags2.CopyOnWrite == 0) &&
01227 (WriteCopy)) {
01228
01229 NTSTATUS status;
01230
01231 status = MiSetCopyPagesFor4kPage(Process,
01232 &FoundVad,
01233 &StartingAddress,
01234 &EndingAddress,
01235 ProtectionMask);
01236
01237
if (status != STATUS_SUCCESS) {
01238 ExRaiseStatus (status);
01239 }
01240
01241 }
01242
01243 #endif
01244
01245 PointerPpe = MiGetPpeAddress (StartingAddress);
01246 PointerPde = MiGetPdeAddress (StartingAddress);
01247 PointerPte = MiGetPteAddress (StartingAddress);
01248 LastPte = MiGetPteAddress (EndingAddress);
01249
01250 #
if defined (_WIN64)
01251 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE);
01252
if (PointerPde->u.Long == 0) {
01253 UsedPageDirectoryHandle =
MI_GET_USED_PTES_HANDLE (PointerPte);
01254 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
01255 }
01256 #endif
01257
01258
MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE);
01259
01260
01261
01262
01263
01264
if (PointerPte->u.Long != 0) {
01265
01266 *CapturedOldProtect =
MiGetPageProtection (PointerPte, Process);
01267
01268
01269
01270
01271
01272 PointerPpe = MiGetPteAddress (PointerPde);
01273
01274
do {
01275
01276 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, Process, FALSE, &Waited);
01277 Waited = 0;
01278
01279 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, Process, FALSE, &Waited);
01280 }
while (Waited != 0);
01281
01282 }
else {
01283
01284
01285
01286
01287
01288
if (FoundVad->u.VadFlags.ImageMap == 0) {
01289
01290
01291
01292
01293
01294 *CapturedOldProtect =
01295
MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection);
01296 }
else {
01297
01298
01299
01300
01301
01302
01303 PointerProtoPte =
MiGetProtoPteAddress (FoundVad,
01304 MI_VA_TO_VPN (
01305 MiGetVirtualAddressMappedByPte (PointerPte)));
01306
01307 TempPte =
MiCaptureSystemPte (PointerProtoPte, Process);
01308
01309 *CapturedOldProtect =
MiGetPageProtection (&TempPte,
01310 Process);
01311
01312
01313
01314
01315
01316 PointerPpe =
MiGetPteAddress (PointerPde);
01317
01318
do {
01319
01320 (
VOID)
MiDoesPpeExistAndMakeValid(PointerPpe, Process, FALSE, &Waited);
01321 Waited = 0;
01322
01323 (
VOID)
MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE, &Waited);
01324 }
while (Waited != 0);
01325 }
01326 }
01327
01328
01329
01330
01331
01332
01333
01334
01335
if (WriteCopy) {
01336
01337
01338
01339
01340
01341
01342
while (PointerPte <= LastPte) {
01343
01344
if (
MiIsPteOnPdeBoundary (PointerPte)) {
01345
01346 PointerPde =
MiGetPteAddress (PointerPte);
01347 PointerPpe =
MiGetPteAddress (PointerPde);
01348
01349
do {
01350
01351
while (!
MiDoesPpeExistAndMakeValid(PointerPpe, Process, FALSE, &Waited)) {
01352
01353
01354
01355
01356
01357
01358
01359 PointerPpe += 1;
01360 PointerPde =
MiGetVirtualAddressMappedByPte (PointerPpe);
01361 PointerProtoPte = PointerPte;
01362 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
01363
01364
if (PointerPte > LastPte) {
01365 QuotaCharge += 1 + LastPte - PointerProtoPte;
01366
goto Done;
01367 }
01368 QuotaCharge += PointerPte - PointerProtoPte;
01369 }
01370
01371 Waited = 0;
01372
01373
while (!
MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE, &Waited)) {
01374
01375
01376
01377
01378
01379
01380
01381 PointerPde += 1;
01382 PointerProtoPte = PointerPte;
01383 PointerPpe =
MiGetPteAddress (PointerPde);
01384 PointerPte =
MiGetVirtualAddressMappedByPte (PointerPde);
01385
01386
if (PointerPte > LastPte) {
01387 QuotaCharge += 1 + LastPte - PointerProtoPte;
01388
goto Done;
01389 }
01390 QuotaCharge += PointerPte - PointerProtoPte;
01391
#if defined (_WIN64)
01392
if (
MiIsPteOnPdeBoundary (PointerPde)) {
01393 Waited = 1;
01394
break;
01395 }
01396
#endif
01397
}
01398 }
while (Waited != 0);
01399 }
01400
01401 PteContents = *PointerPte;
01402
01403
if (PteContents.u.Long == 0) {
01404
01405
01406
01407
01408
01409 QuotaCharge += 1;
01410
01411 }
else if ((PteContents.u.Hard.Valid == 1) &&
01412 (PteContents.u.Hard.CopyOnWrite == 0)) {
01413
01414
01415
01416
01417
01418 Pfn1 =
MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
01419
01420
if (Pfn1->u3.e1.PrototypePte == 1) {
01421 QuotaCharge += 1;
01422 }
01423 }
else {
01424
01425
if (PteContents.u.Soft.Prototype == 1) {
01426
01427
01428
01429
01430
01431
01432
if (PteContents.u.Soft.PageFileHigh ==
MI_PTE_LOOKUP_NEEDED) {
01433
01434
01435
01436
01437
01438
if (!
MI_IS_PTE_PROTECTION_COPY_WRITE(PteContents.u.Soft.Protection)) {
01439 QuotaCharge += 1;
01440 }
01441 }
else {
01442
01443
01444
01445
01446
01447
01448 QuotaCharge += 1;
01449 }
01450 }
01451 }
01452 PointerPte += 1;
01453 }
01454
01455 Done:
01456 NOTHING;
01457
01458
01459
01460
01461
01462
if (!DontCharge) {
01463
MiChargePageFileQuota (QuotaCharge, Process);
01464
01465
if (Process->CommitChargeLimit) {
01466
if (Process->CommitCharge + QuotaCharge > Process->CommitChargeLimit) {
01467
MiReturnPageFileQuota (QuotaCharge, Process);
01468
if (Process->Job) {
01469
PsReportProcessMemoryLimitViolation ();
01470 }
01471
ExRaiseStatus (STATUS_COMMITMENT_LIMIT);
01472 }
01473 }
01474
if (Process->JobStatus &
PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
01475
if (
PsChangeJobMemoryUsage(QuotaCharge) ==
FALSE) {
01476
MiReturnPageFileQuota (QuotaCharge, Process);
01477
ExRaiseStatus (STATUS_COMMITMENT_LIMIT);
01478 }
01479 }
01480
01481
if (
MiChargeCommitment (QuotaCharge, Process) ==
FALSE) {
01482
if (Process->JobStatus &
PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
01483
01484
01485
01486
01487
01488
01489
01490 Process->CommitCharge += QuotaCharge;
01491
PsChangeJobMemoryUsage(-(SSIZE_T)QuotaCharge);
01492 Process->CommitCharge -= QuotaCharge;
01493 }
01494
MiReturnPageFileQuota (QuotaCharge, Process);
01495
ExRaiseStatus STATUS_COMMITMENT_LIMIT;
01496 }
01497
01498
01499
01500
01501
01502
MM_TRACK_COMMIT (MM_DBG_COMMIT_SET_PROTECTION, QuotaCharge);
01503 FoundVad->u.VadFlags.CommitCharge += QuotaCharge;
01504 Process->CommitCharge += QuotaCharge;
01505
if (Process->CommitCharge > Process->CommitChargePeak) {
01506 Process->CommitChargePeak = Process->CommitCharge;
01507 }
01508 }
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522 PointerPpe =
MiGetPpeAddress (StartingAddress);
01523 PointerPde =
MiGetPdeAddress (StartingAddress);
01524 PointerPte =
MiGetPteAddress (StartingAddress);
01525
01526
do {
01527
01528
MiDoesPpeExistAndMakeValid (PointerPpe, Process, FALSE, &Waited);
01529
01530 Waited = 0;
01531
01532
MiDoesPdeExistAndMakeValid (PointerPde, Process, FALSE, &Waited);
01533
01534 }
while (Waited != 0);
01535
01536 QuotaCharge = 0;
01537
01538
while (PointerPte <= LastPte) {
01539
01540
if (
MiIsPteOnPdeBoundary (PointerPte)) {
01541 PointerPde =
MiGetPteAddress (PointerPte);
01542 PointerPpe =
MiGetPdeAddress (PointerPte);
01543
01544
#if defined (_WIN64)
01545
MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE);
01546
if (PointerPde->u.Long == 0) {
01547 UsedPageDirectoryHandle =
MI_GET_USED_PTES_HANDLE (PointerPte);
01548
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
01549 }
01550
#endif
01551
01552
MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE);
01553 }
01554
01555 PteContents = *PointerPte;
01556
01557
if (PteContents.u.Long == 0) {
01558
01559
01560
01561
01562
01563
01564 TempPte =
PrototypePte;
01565 TempPte.
u.Soft.Protection = ProtectionMask;
01566
MI_WRITE_INVALID_PTE (PointerPte, TempPte);
01567
01568
01569
01570
01571
01572
01573
01574 UsedPageTableHandle =
MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte));
01575
01576
MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
01577
01578 }
else if (PteContents.u.Hard.Valid == 1) {
01579
01580
01581
01582
01583
01584
01585 NewProtectionMask = ProtectionMask;
01586
01587 Pfn1 =
MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber);
01588
01589
if ((NewProtect & PAGE_NOACCESS) ||
01590 (NewProtect & PAGE_GUARD)) {
01591
01592 Locked =
MiRemovePageFromWorkingSet (PointerPte,
01593 Pfn1,
01594 &Process->Vm );
01595
continue;
01596
01597 }
else {
01598
01599
if (Pfn1->u3.e1.PrototypePte == 1) {
01600
01601
01602
01603
01604
01605
01606 Va = (PULONG)
MiGetVirtualAddressMappedByPte (PointerPte);
01607
Index =
MiLocateWsle ((PVOID)Va, MmWorkingSetList,
01608 Pfn1->u1.WsIndex);
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
if (Pfn1->PteAddress !=
01619
MiGetProtoPteAddress (FoundVad,
01620 MI_VA_TO_VPN ((PVOID)Va))) {
01621
01622
01623
01624
01625
01626
01627
MiCopyOnWrite ((PVOID)Va, PointerPte);
01628
01629
if (WriteCopy) {
01630 QuotaCharge += 1;
01631 }
01632
01633
01634
01635
01636
01637
01638 PointerPpe =
MiGetPteAddress (PointerPde);
01639
01640
do {
01641
01642 (
VOID)
MiDoesPpeExistAndMakeValid (PointerPpe,
01643 Process,
01644 FALSE,
01645 &Waited);
01646
01647 Waited = 0;
01648
01649 (
VOID)
MiDoesPdeExistAndMakeValid (PointerPde,
01650 Process,
01651 FALSE,
01652 &Waited);
01653
01654 }
while (Waited != 0);
01655
01656
01657
01658
01659
01660
continue;
01661
01662 }
else {
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
if ((!WriteCopy) && (PteContents.u.Hard.CopyOnWrite == 1)) {
01674 QuotaCharge += 1;
01675 }
01676
01677
MmWsle[
Index].
u1.e1.Protection = ProtectionMask;
01678
MmWsle[
Index].
u1.e1.SameProtectAsProto = 0;
01679 }
01680
01681 }
else {
01682
01683
01684
01685
01686
01687
01688
#if PFN_CONSISTENCY
01689
MiSetOriginalPteProtection (Pfn1, ProtectionMaskNotCopy);
01690
#else
01691
Pfn1->OriginalPte.u.Soft.Protection = ProtectionMaskNotCopy;
01692
#endif
01693
NewProtectionMask = ProtectionMaskNotCopy;
01694 }
01695
01696
MI_MAKE_VALID_PTE (TempPte,
01697 PteContents.u.Hard.PageFrameNumber,
01698 NewProtectionMask,
01699 PointerPte);
01700
01701 WorkingSetIndex =
MI_GET_WORKING_SET_FROM_PTE (&PteContents);
01702
01703
MI_SET_PTE_IN_WORKING_SET (&TempPte, WorkingSetIndex);
01704 }
01705
01706
01707
01708
01709
01710
01711 PreviousPte.u.Flush =
MiFlushTbAndCapture (PointerPte,
01712 TempPte.u.Flush,
01713 Pfn1);
01714 }
else {
01715
01716
if (PteContents.u.Soft.Prototype == 1) {
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726 Va = (PULONG)
MiGetVirtualAddressMappedByPte (PointerPte);
01727
01728
if ((PteContents.u.Soft.PageFileHigh !=
MI_PTE_LOOKUP_NEEDED) &&
01729 (
MiPteToProto (PointerPte) !=
01730
MiGetProtoPteAddress (FoundVad,
01731 MI_VA_TO_VPN ((PVOID)Va)))) {
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745 DoAgain =
TRUE;
01746
01747
while (PteContents.u.Hard.Valid == 0) {
01748
01749
UNLOCK_WS_UNSAFE (Process);
01750
01751
try {
01752
01753 *(
volatile ULONG *)Va;
01754 } except (EXCEPTION_EXECUTE_HANDLER) {
01755
01756
if (GetExceptionCode() !=
01757 STATUS_GUARD_PAGE_VIOLATION) {
01758
01759
01760
01761
01762
01763 DoAgain =
MiChangeNoAccessForkPte (PointerPte,
01764 ProtectionMask);
01765 }
01766 }
01767
01768 PointerPpe =
MiGetPteAddress (PointerPde);
01769
01770
LOCK_WS_UNSAFE (Process);
01771
01772
do {
01773
01774 (
VOID)
MiDoesPpeExistAndMakeValid (PointerPpe,
01775 Process,
01776 FALSE,
01777 &Waited);
01778
01779 Waited = 0;
01780
01781 (
VOID)
MiDoesPdeExistAndMakeValid (PointerPde,
01782 Process,
01783 FALSE,
01784 &Waited);
01785
01786 }
while (Waited != 0);
01787
01788 PteContents = *(
volatile MMPTE *)PointerPte;
01789 }
01790
01791
if (DoAgain) {
01792
continue;
01793 }
01794
01795 }
else {
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
if ((!WriteCopy) &&
01806 (PteContents.u.Soft.PageFileHigh ==
MI_PTE_LOOKUP_NEEDED)) {
01807
if (
MI_IS_PTE_PROTECTION_COPY_WRITE(PteContents.u.Soft.Protection)) {
01808 QuotaCharge += 1;
01809 }
01810
01811 }
01812
01813
01814
01815
01816
01817
01818
01819
MI_WRITE_INVALID_PTE (PointerPte, PrototypePte);
01820 PointerPte->u.Soft.Protection = ProtectionMask;
01821 }
01822
01823 }
else {
01824
01825
if (PteContents.u.Soft.Transition == 1) {
01826
01827
01828
01829
01830
01831
if (
MiSetProtectionOnTransitionPte (
01832 PointerPte,
01833 ProtectionMaskNotCopy)) {
01834
continue;
01835 }
01836
01837 }
else {
01838
01839
01840
01841
01842
01843 PointerPte->u.Soft.Protection = ProtectionMaskNotCopy;
01844 }
01845 }
01846 }
01847
01848 PointerPte += 1;
01849 }
01850
01851
01852
01853
01854
01855
if ((QuotaCharge > 0) && (!DontCharge)) {
01856
01857
MiReturnCommitment (QuotaCharge);
01858
MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PROTECTION, QuotaCharge);
01859
MiReturnPageFileQuota (QuotaCharge, Process);
01860
01861
ASSERT (QuotaCharge <= FoundVad->u.VadFlags.CommitCharge);
01862
01863 FoundVad->u.VadFlags.CommitCharge -= QuotaCharge;
01864
if (Process->JobStatus &
PS_JOB_STATUS_REPORT_COMMIT_CHANGES) {
01865
PsChangeJobMemoryUsage(-(SSIZE_T)QuotaCharge);
01866 }
01867 Process->CommitCharge -= QuotaCharge;
01868 }
01869
01870
return Locked;
01871 }