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

altperm.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Module Name: 00004 00005 altperm.c 00006 00007 Abstract: 00008 00009 This module contains the routines needed to implement 4K pages on IA64 00010 00011 The idea is for an alternate set of permissions be kept that are on 00012 4K boundaries. Permissions are kept for all memory, not just split pages 00013 and the information is updated on any call to NtVirtualProtect() 00014 and NtVirtualAllocate(). 00015 00016 00017 Author: 00018 00019 ky 18-Aug-98 00020 00021 Revision History: 00022 00023 00024 --*/ 00025 00026 #include "mi.h" 00027 00028 extern ULONG MMVADKEY; 00029 00030 #if defined(_MIALT4K_) 00031 00032 VOID 00033 MiCheckPoint(ULONG Number); 00034 00035 VOID 00036 MiCheckPointBreak(VOID); 00037 00038 00039 ULONG MmCheckPointNumber = 100; 00040 PVOID MmAddressBreak = (PVOID)0x7ecd0000; 00041 LOGICAL _MiMakeRtlBoot = FALSE; 00042 00043 ULONG 00044 MiFindProtectionForNativePte( 00045 PVOID VirtualAddress 00046 ); 00047 00048 VOID 00049 MiFillZeroFor4kPage ( 00050 IN PVOID BaseAddress, 00051 IN PEPROCESS Process 00052 ); 00053 00054 MiCheckPointBreakVirtualAddress ( 00055 PVOID VirtualAddress 00056 ); 00057 00058 VOID 00059 MiResetAccessBitForNativePtes( 00060 IN PVOID StartVirtual, 00061 IN PVOID EndVirtual, 00062 IN PEPROCESS Process 00063 ); 00064 00065 NTSTATUS 00066 MiMapViewOfDataSection ( 00067 IN PCONTROL_AREA ControlArea, 00068 IN PEPROCESS Process, 00069 IN PVOID *CapturedBase, 00070 IN PLARGE_INTEGER SectionOffset, 00071 IN PSIZE_T CapturedViewSize, 00072 IN PSECTION Section, 00073 IN SECTION_INHERIT InheritDisposition, 00074 IN ULONG ProtectionMask, 00075 IN SIZE_T CommitSize, 00076 IN ULONG_PTR ZeroBits, 00077 IN ULONG AllocationType, 00078 OUT PBOOLEAN ReleasedWsMutex 00079 ); 00080 00081 BOOLEAN 00082 MiIsSplitPage( 00083 IN PVOID Virtual 00084 ); 00085 00086 VOID 00087 MiCopyOnWriteFor4kPage( 00088 PVOID VirtualAddress, 00089 PEPROCESS Process 00090 00091 ); 00092 00093 VOID 00094 MiCheckDemandZeroCopyOnWriteFor4kPage( 00095 PVOID VirtualAddress, 00096 PEPROCESS Process 00097 ); 00098 00099 VOID 00100 MiCheckVirtualAddressFor4kPage( 00101 PVOID VirtualAddress, 00102 PEPROCESS Process 00103 ); 00104 00105 MmX86Fault ( 00106 IN BOOLEAN StoreInstruction, 00107 IN PVOID VirtualAddress, 00108 IN KPROCESSOR_MODE PreviousMode, 00109 IN PVOID TrapInformation 00110 ) 00111 00112 /*++ 00113 00114 Routine Description: 00115 00116 This function is called by the kernel on data or instruction 00117 access faults if CurrentProcess->Vm.u.Flags.AltPerm is set. 00118 00119 This routine determines what type of fault by checking the alternate 00120 4Kb granular page table and calls MmAccessFault() if necessary to 00121 handle the page fault or the write fault. 00122 00123 Arguments: 00124 00125 StoreInstruction - Supplies TRUE (1) if the operation causes a write into 00126 memory. Note this value must be 1 or 0. 00127 00128 VirtualAddress - Supplies the virtual address which caused the fault. 00129 00130 PreviousMode - Supplies the mode (kernel or user) in which the fault 00131 occurred. 00132 00133 TrapInformation - Opaque information about the trap, interpreted by the 00134 kernel, not Mm. Needed to allow fast interlocked access 00135 to operate correctly. 00136 00137 Return Value: 00138 00139 Returns the status of the fault handling operation. Can be one of: 00140 - Success. 00141 - Access Violation. 00142 - Guard Page Violation. 00143 - In-page Error. 00144 00145 Environment: 00146 00147 Kernel mode, APCs disabled. 00148 00149 --*/ 00150 00151 { 00152 PMMPTE PointerAltPte; 00153 MMPTE AltPteContents; 00154 MMPTE PteContents; 00155 PMMPTE PointerPte; 00156 PMMPTE PointerPde; 00157 PMMPTE PointerPpe; 00158 PMMPTE PointerProtoPte = (PMMPTE)NULL; 00159 ULONG ProtectCode; 00160 MMPTE TempPte; 00161 ULONG NewPteProtection = 0; 00162 ULONG AteProtection; 00163 LOGICAL ExecutionFault = FALSE; 00164 LOGICAL FillZero = FALSE; 00165 LOGICAL SetNewProtection = FALSE; 00166 LOGICAL PageIsSplit = FALSE; 00167 PEPROCESS CurrentProcess; 00168 PWOW64_PROCESS Wow64Process; 00169 KIRQL PreviousIrql; 00170 KIRQL OldIrql; 00171 NTSTATUS status; 00172 PMMINPAGE_SUPPORT ReadBlock; 00173 ULONG Waited; 00174 ULONG OriginalProtection; 00175 ULONGLONG ProtectionMaskOriginal; 00176 PMMPTE ProtoPte; 00177 PMMPFN Pfn1; 00178 ULONG i; 00179 00180 // 00181 // debug checking 00182 // 00183 00184 MiCheckPointBreakVirtualAddress (VirtualAddress); 00185 00186 PreviousIrql = KeGetCurrentIrql (); 00187 00188 ASSERT (PreviousIrql <= APC_LEVEL); 00189 00190 CurrentProcess = PsGetCurrentProcess (); 00191 00192 Wow64Process = CurrentProcess->Wow64Process; 00193 00194 ASSERT (VirtualAddress < (PVOID)_MAX_WOW64_ADDRESS); 00195 00196 if (StoreInstruction == 2) { 00197 ExecutionFault = TRUE; 00198 StoreInstruction = FALSE; 00199 } 00200 00201 // 00202 // lock the alternate table and this also blocks APCs. 00203 // 00204 00205 LOCK_ALTERNATE_TABLE (Wow64Process); 00206 00207 // 00208 // check to see if the protection is registered in the alternate entry 00209 // 00210 00211 if (MI_CHECK_BIT(Wow64Process->AltPermBitmap, 00212 MI_VA_TO_VPN(VirtualAddress)) == 0) { 00213 00214 MiCheckVirtualAddressFor4kPage(VirtualAddress, CurrentProcess); 00215 00216 } 00217 00218 // 00219 // 00220 // 00221 00222 PointerPte = MiGetPteAddress(VirtualAddress); 00223 PointerAltPte = MiGetAltPteAddress(VirtualAddress); 00224 00225 // 00226 // read alternate PTE contents 00227 // 00228 00229 AltPteContents = *PointerAltPte; 00230 00231 // 00232 // check to see if alternate entry is empty 00233 // 00234 00235 if (AltPteContents.u.Long == 0) { 00236 00237 MiCheckPoint(10); 00238 00239 // 00240 // if empty, get the protection info from OS and fill the entry 00241 // 00242 00243 LOCK_WS (CurrentProcess); 00244 00245 ProtoPte = MiCheckVirtualAddress (VirtualAddress, &OriginalProtection); 00246 00247 if (OriginalProtection == MM_UNKNOWN_PROTECTION) { 00248 00249 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 00250 PointerPde = MiGetPteAddress (ProtoPte); 00251 LOCK_PFN (OldIrql); 00252 if (PointerPde->u.Hard.Valid == 0) { 00253 MiMakeSystemAddressValidPfn (ProtoPte); 00254 } 00255 Pfn1 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 00256 Pfn1->u3.e2.ReferenceCount += 1; 00257 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 00258 UNLOCK_PFN (OldIrql); 00259 } 00260 00261 OriginalProtection = 00262 MiMakeProtectionMask(MiGetPageProtection(ProtoPte, CurrentProcess)); 00263 00264 // 00265 // Unlock page containing prototype PTEs. 00266 // 00267 00268 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 00269 LOCK_PFN (OldIrql); 00270 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 00271 Pfn1->u3.e2.ReferenceCount -= 1; 00272 UNLOCK_PFN (OldIrql); 00273 } 00274 } 00275 00276 UNLOCK_WS (CurrentProcess); 00277 00278 if (OriginalProtection != MM_NOACCESS) { 00279 00280 ProtectionMaskOriginal = MiMakeProtectionAteMask (OriginalProtection); 00281 ProtectionMaskOriginal |= MM_ATE_COMMIT; 00282 00283 AltPteContents.u.Long = ProtectionMaskOriginal; 00284 AltPteContents.u.Alt.Protection = OriginalProtection; 00285 00286 // 00287 // atomic PTE update 00288 // 00289 00290 PointerAltPte->u.Long = AltPteContents.u.Long; 00291 } 00292 } 00293 00294 if (AltPteContents.u.Alt.NoAccess != 0) { 00295 00296 // 00297 // this 4KB page is no access 00298 // 00299 00300 status = STATUS_ACCESS_VIOLATION; 00301 00302 goto return_status; 00303 00304 } 00305 00306 if (AltPteContents.u.Alt.PteIndirect != 0) { 00307 00308 MiCheckPoint(3); 00309 00310 // 00311 // make PPE and PDE exist and valid 00312 // 00313 00314 PointerPde = MiGetPdeAddress(VirtualAddress); 00315 PointerPpe = MiGetPpeAddress(VirtualAddress); 00316 00317 // 00318 // make the page table for the original PTE exit to satisfy 00319 // the TLB forward progress for the TLB indirect fault 00320 // 00321 00322 LOCK_WS (CurrentProcess); 00323 00324 (VOID)MiMakePpeExistAndMakeValid (PointerPpe, 00325 CurrentProcess, 00326 FALSE); 00327 00328 (VOID)MiMakePdeExistAndMakeValid (PointerPde, 00329 CurrentProcess, 00330 FALSE); 00331 00332 UNLOCK_WS (CurrentProcess); 00333 00334 PointerPte = (PMMPTE)(AltPteContents.u.Alt.PteOffset + PTE_UBASE); 00335 00336 VirtualAddress = MiGetVirtualAddressMappedByPte(PointerPte); 00337 00338 goto Check_Pte; 00339 00340 } 00341 00342 if ((_MiMakeRtlBoot == TRUE) && (AltPteContents.u.Alt.Commit == 0)) { 00343 00344 // 00345 // This is supposed to be an access to an uncommmitted page and should 00346 // result in STATUS_ACCESS_VIOLATION. As long as we test in IA64, 00347 // we cannot make a fault here. Some code assume PAGE_SIZE is given at least 00348 // for commitment. 00349 // 00350 00351 MiCheckPoint(0); 00352 00353 PointerAltPte->u.Alt.Commit = 1; 00354 00355 AltPteContents = *PointerAltPte; 00356 00357 } 00358 00359 if (AltPteContents.u.Alt.Commit == 0) { 00360 00361 // 00362 // if the page is no commit, return as STATUS_ACCESS_VIOLATION. 00363 // 00364 00365 status = STATUS_ACCESS_VIOLATION; 00366 00367 goto return_status; 00368 00369 } 00370 00371 // 00372 // check to see if the faulting page is split to 4k pages 00373 // 00374 00375 PageIsSplit = MiIsSplitPage(VirtualAddress); 00376 00377 // 00378 // get a real protection for the native PTE 00379 // 00380 00381 NewPteProtection = MiFindProtectionForNativePte (VirtualAddress); 00382 00383 Check_Pte: 00384 00385 // 00386 // Block APCs and acquire the working set lock. 00387 // 00388 00389 LOCK_WS (CurrentProcess); 00390 00391 // 00392 // make PPE and PDE exist and valid 00393 // 00394 00395 PointerPde = MiGetPdeAddress(VirtualAddress); 00396 PointerPpe = MiGetPpeAddress(VirtualAddress); 00397 00398 if (MiDoesPpeExistAndMakeValid (PointerPpe, 00399 CurrentProcess, 00400 FALSE, 00401 &Waited) == FALSE) { 00402 PteContents.u.Long = 0; 00403 00404 } else if (MiDoesPdeExistAndMakeValid (PointerPde, 00405 CurrentProcess, 00406 FALSE, 00407 &Waited) == FALSE) { 00408 00409 PteContents.u.Long = 0; 00410 00411 } else { 00412 00413 // 00414 // if it is safe to read PointerPte 00415 // 00416 00417 PteContents = *PointerPte; 00418 00419 } 00420 00421 // 00422 // Check to see if the protection for the native page should be set 00423 // and if the access-bit of the PTE should be set. 00424 // 00425 00426 if (PteContents.u.Hard.Valid != 0) { 00427 00428 TempPte = PteContents; 00429 00430 // 00431 // perfom PTE protection mask corrections 00432 // 00433 00434 TempPte.u.Long |= NewPteProtection; 00435 00436 if (PteContents.u.Hard.Accessed == 0) { 00437 00438 TempPte.u.Hard.Accessed = 1; 00439 00440 if (PageIsSplit == TRUE) { 00441 00442 TempPte.u.Hard.Cache = MM_PTE_CACHE_RESERVED; 00443 00444 } 00445 } 00446 00447 // 00448 // if the private page has been assigned to COW, remove the COW bit 00449 // 00450 00451 if ((TempPte.u.Hard.CopyOnWrite != 0) && (PteContents.u.Hard.Write != 0)) { 00452 00453 TempPte.u.Hard.CopyOnWrite = 0; 00454 00455 } 00456 00457 MI_WRITE_VALID_PTE_NEW_PROTECTION(PointerPte, TempPte); 00458 } 00459 00460 UNLOCK_WS (CurrentProcess); 00461 00462 // 00463 // faulting 4kb page must be a valid page, but we need to resolve it 00464 // case by case. 00465 // 00466 00467 ASSERT (AltPteContents.u.Long != 0); 00468 ASSERT (AltPteContents.u.Alt.Commit != 0); 00469 00470 if (AltPteContents.u.Alt.Accessed == 0) { 00471 00472 // 00473 // When PointerAte->u.Hard.Accessed is zero, there are the following 4 cases: 00474 // 00475 // 1. Lowest Protection 00476 // 2. 4kb Demand Zero 00477 // 3. GUARD page fault 00478 // 4. this 4kb page is no access, but the other 4K page(s) within a native page 00479 // has accessible permission. 00480 // 00481 00482 if (AltPteContents.u.Alt.FillZero != 0) { 00483 00484 // 00485 // schedule it later 00486 // 00487 00488 FillZero = TRUE; 00489 00490 } 00491 00492 if ((AltPteContents.u.Alt.Protection & MM_GUARD_PAGE) != 0) { 00493 00494 MiCheckPoint(5); 00495 00496 // 00497 // if 4k page is guard page then call MmAccessFault() to handle the faults 00498 // 00499 00500 if (PteContents.u.Hard.Valid == 0) { 00501 00502 UNLOCK_ALTERNATE_TABLE (Wow64Process); 00503 00504 // 00505 // Let MmAccessFault() perform a page-in, dirty-bit setting, etc. 00506 // 00507 00508 status = MmAccessFault (StoreInstruction, 00509 VirtualAddress, 00510 PreviousMode, 00511 TrapInformation); 00512 00513 LOCK_ALTERNATE_TABLE (Wow64Process); 00514 00515 if (status == STATUS_PAGE_FAULT_GUARD_PAGE) { 00516 00517 PointerAltPte = MiGetAltPteAddress(PAGE_ALIGN(VirtualAddress)); 00518 00519 for (i = 0; i < SPLITS_PER_PAGE; i += 1) { 00520 00521 AltPteContents.u.Long = PointerAltPte->u.Long; 00522 00523 if ((AltPteContents.u.Alt.Protection & MM_GUARD_PAGE) != 0) { 00524 00525 AltPteContents.u.Alt.Protection &= ~MM_GUARD_PAGE; 00526 AltPteContents.u.Alt.Accessed = 1; 00527 PointerAltPte->u.Long = AltPteContents.u.Long; 00528 00529 } 00530 00531 PointerAltPte += 1; 00532 00533 } 00534 00535 goto return_status; 00536 } 00537 00538 } 00539 00540 AltPteContents.u.Alt.Protection &= ~MM_GUARD_PAGE; 00541 AltPteContents.u.Alt.Accessed = 1; 00542 00543 PointerAltPte->u.Long = AltPteContents.u.Long; 00544 00545 status = STATUS_GUARD_PAGE_VIOLATION; 00546 00547 goto return_status; 00548 00549 } else if (FillZero == FALSE) { 00550 00551 // 00552 // this 4kb page has no access permission 00553 // 00554 00555 status = STATUS_ACCESS_VIOLATION; 00556 00557 goto return_status; 00558 00559 } 00560 } 00561 00562 if (ExecutionFault == TRUE) { 00563 00564 // 00565 // As execute permission is already given to IA32 by setting it in 00566 // MI_MAKE_VALID_PTE(). 00567 // 00568 00569 } else if (StoreInstruction == TRUE) { 00570 00571 // 00572 // Check to see if this is the copy-on-write page. 00573 // 00574 00575 if (AltPteContents.u.Alt.CopyOnWrite != 0) { 00576 00577 #if 0 00578 MiCheckDemandZeroCopyOnWriteFor4kPage(VirtualAddress, CurrentProcess); 00579 #endif 00580 // 00581 // let MmAccessFault() perform a copy-on-write 00582 // 00583 00584 status = MmAccessFault (StoreInstruction, 00585 VirtualAddress, 00586 PreviousMode, 00587 TrapInformation); 00588 00589 #if 0 00590 if (PteContents.u.Hard.Valid != 0) { 00591 DbgPrint("copyonwrite original page = %p, %p\n", VirtualAddress, PteContents.u.Long); 00592 } 00593 #endif 00594 00595 if (!NT_SUCCESS(status)) { 00596 00597 MiCheckPointBreak(); 00598 goto return_status; 00599 00600 } 00601 00602 if (status == STATUS_PAGE_FAULT_COPY_ON_WRITE) { 00603 MiCopyOnWriteFor4kPage(VirtualAddress, CurrentProcess); 00604 } else { 00605 MiCheckPointBreak(); 00606 } 00607 00608 // 00609 // write debug code to check the consistency 00610 // 00611 00612 status = STATUS_SUCCESS; 00613 00614 goto return_status; 00615 } 00616 00617 if (AltPteContents.u.Hard.Write == 0) { 00618 00619 status = STATUS_ACCESS_VIOLATION; 00620 00621 goto return_status; 00622 } 00623 00624 } 00625 00626 // 00627 // Let MmAccessFault() perform a page-in, dirty-bit setting, etc. 00628 // 00629 00630 UNLOCK_ALTERNATE_TABLE (Wow64Process); 00631 00632 status = MmAccessFault (StoreInstruction, 00633 VirtualAddress, 00634 PreviousMode, 00635 TrapInformation); 00636 00637 if ((status == STATUS_PAGE_FAULT_GUARD_PAGE) || 00638 (status == STATUS_GUARD_PAGE_VIOLATION)) { 00639 00640 LOCK_ALTERNATE_TABLE (Wow64Process); 00641 00642 AltPteContents = *PointerAltPte; 00643 00644 if ((AltPteContents.u.Alt.Protection & MM_GUARD_PAGE) != 0) { 00645 00646 AltPteContents = *PointerAltPte; 00647 AltPteContents.u.Alt.Protection &= ~MM_GUARD_PAGE; 00648 AltPteContents.u.Alt.Accessed = 1; 00649 00650 PointerAltPte->u.Long = AltPteContents.u.Long; 00651 00652 } 00653 00654 UNLOCK_ALTERNATE_TABLE (Wow64Process); 00655 00656 if (status == STATUS_GUARD_PAGE_VIOLATION) { 00657 00658 status = STATUS_SUCCESS; 00659 00660 } 00661 00662 } 00663 00664 KiFlushSingleTb(TRUE, VirtualAddress); 00665 00666 if (FillZero == TRUE) { 00667 00668 MiFillZeroFor4kPage (VirtualAddress, CurrentProcess); 00669 00670 } 00671 00672 if (!NT_SUCCESS(status)) { 00673 00674 MiCheckPointBreak(); 00675 00676 } 00677 00678 return status; 00679 00680 return_status: 00681 00682 KiFlushSingleTb(TRUE, VirtualAddress); 00683 00684 UNLOCK_ALTERNATE_TABLE (Wow64Process); 00685 00686 if (FillZero == TRUE) { 00687 00688 MiFillZeroFor4kPage (VirtualAddress, CurrentProcess); 00689 00690 } 00691 00692 if (!NT_SUCCESS(status)) { 00693 00694 MiCheckPointBreak(); 00695 00696 } 00697 00698 return status; 00699 } 00700 00701 ULONG 00702 MiFindProtectionForNativePte( 00703 PVOID VirtualAddress 00704 ) 00705 00706 /*++ 00707 00708 Routine Description: 00709 00710 This function finds the protection for the native PTE 00711 00712 Arguments: 00713 00714 VirtualAddress - Supplies a virtual address to be examined for the protection 00715 of the PTE. 00716 00717 Return Value: 00718 00719 none 00720 00721 Environment: 00722 00723 00724 --*/ 00725 00726 { 00727 PMMPTE PointerAltPte; 00728 ULONG i; 00729 ULONG ProtectionCode = 0; 00730 00731 PointerAltPte = MiGetAltPteAddress(PAGE_ALIGN(VirtualAddress)); 00732 00733 for (i = 0; i < SPLITS_PER_PAGE; i++) { 00734 00735 ProtectionCode |= (PointerAltPte->u.Long & ALT_PROTECTION_MASK); 00736 00737 if (PointerAltPte->u.Alt.CopyOnWrite != 0) { 00738 ProtectionCode |= MM_PTE_COPY_ON_WRITE_MASK; 00739 } 00740 00741 PointerAltPte += 1; 00742 } 00743 00744 return ProtectionCode; 00745 00746 } 00747 00748 00749 // 00750 // Define and initialize the protection convertion table for 00751 // Alternate Permision Table Entries. 00752 // 00753 00754 ULONGLONG MmProtectToAteMask[32] = { 00755 MM_PTE_NOACCESS | MM_ATE_NOACCESS, 00756 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00757 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00758 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00759 MM_PTE_EXECUTE_READWRITE | MM_PTE_ACCESS_MASK, 00760 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK | MM_ATE_COPY_ON_WRITE, 00761 MM_PTE_EXECUTE_READWRITE | MM_PTE_ACCESS_MASK, 00762 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK | MM_ATE_COPY_ON_WRITE, 00763 MM_PTE_NOACCESS | MM_ATE_NOACCESS, 00764 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00765 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00766 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK, 00767 MM_PTE_EXECUTE_READWRITE | MM_PTE_ACCESS_MASK, 00768 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK | MM_ATE_COPY_ON_WRITE, 00769 MM_PTE_EXECUTE_READWRITE | MM_PTE_ACCESS_MASK, 00770 MM_PTE_EXECUTE_READ | MM_PTE_ACCESS_MASK | MM_ATE_COPY_ON_WRITE, 00771 MM_PTE_NOACCESS | MM_ATE_NOACCESS, 00772 MM_PTE_EXECUTE_READ, 00773 MM_PTE_EXECUTE_READ, 00774 MM_PTE_EXECUTE_READ, 00775 MM_PTE_EXECUTE_READWRITE, 00776 MM_PTE_EXECUTE_READ | MM_ATE_COPY_ON_WRITE, 00777 MM_PTE_EXECUTE_READWRITE, 00778 MM_PTE_EXECUTE_READ | MM_ATE_COPY_ON_WRITE, 00779 MM_PTE_NOACCESS | MM_ATE_NOACCESS, 00780 MM_PTE_EXECUTE_READ, 00781 MM_PTE_EXECUTE_READ, 00782 MM_PTE_EXECUTE_READ, 00783 MM_PTE_EXECUTE_READWRITE, 00784 MM_PTE_EXECUTE_READ | MM_ATE_COPY_ON_WRITE, 00785 MM_PTE_EXECUTE_READWRITE, 00786 MM_PTE_EXECUTE_READ | MM_ATE_COPY_ON_WRITE 00787 }; 00788 00789 #define MiMakeProtectionAteMask(NewProtect) MmProtectToAteMask[NewProtect] 00790 00791 VOID 00792 MiProtectFor4kPage( 00793 IN PVOID Base, 00794 IN SIZE_T Size, 00795 IN ULONG NewProtect, 00796 IN ULONG Flags, 00797 IN PEPROCESS Process 00798 ) 00799 /*++ 00800 00801 Routine Description: 00802 00803 This routine sets the permissions on the alternate bitmap (based on 00804 4K page sizes). The base and size are assumed to be aligned for 00805 4K pages already. 00806 00807 Arguments: 00808 00809 Base - The base address (assumed to be 4K aligned already) 00810 00811 Size - The size to be protected (assumed to be 4K aligned already) 00812 00813 NewProtect - The protection for the new pages 00814 00815 Flags - The alternate table entry request flags 00816 00817 Process - Supplies a pointer to the process in which to create the 00818 protections on the alternate table 00819 00820 ChangeProtection - if the protection on the existing entries to be 00821 changed. FALSE if new alternate entries are allocated. 00822 00823 Return Value: 00824 00825 None 00826 00827 Environment: 00828 00829 Kernel mode. All arguments are assumed to be in kernel space. 00830 00831 --*/ 00832 00833 { 00834 PVOID Starting4KAddress; 00835 PVOID Ending4KAddress; 00836 PVOID VirtualAddress; 00837 ULONG NewProtectNotCopy; 00838 ULONGLONG ProtectionMask; 00839 ULONGLONG ProtectionMaskNotCopy; 00840 ULONGLONG HardwareProtectionMask; 00841 PMMPTE StartAltPte, EndAltPte; 00842 PMMPTE StartAltPte0, EndAltPte0; 00843 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 00844 PVOID Virtual[MM_MAXIMUM_FLUSH_COUNT]; 00845 ULONG FlushCount; 00846 MMPTE AltPteContents; 00847 MMPTE TempAltPte; 00848 00849 00850 Starting4KAddress = Base; 00851 Ending4KAddress = (PCHAR)Base + Size - 1; 00852 00853 // 00854 // Make sure we don't over run the table 00855 // 00856 ASSERT( ((ULONG_PTR) Starting4KAddress) < _MAX_WOW64_ADDRESS); 00857 ASSERT( ((ULONG_PTR) Ending4KAddress) < _MAX_WOW64_ADDRESS); 00858 00859 // 00860 // for free builds, until this is more tested 00861 // 00862 if ((((UINT_PTR) Starting4KAddress) >= _MAX_WOW64_ADDRESS) 00863 || (((UINT_PTR) Ending4KAddress) >= _MAX_WOW64_ADDRESS)) { 00864 return; 00865 } 00866 00867 // 00868 // Set up the protection to be used for this range of addresses 00869 // 00870 00871 if ((NewProtect & MM_COPY_ON_WRITE_MASK) == MM_COPY_ON_WRITE_MASK) { 00872 NewProtectNotCopy = NewProtect & ~MM_PROTECTION_COPY_MASK; 00873 } else { 00874 NewProtectNotCopy = NewProtect; 00875 } 00876 00877 ProtectionMask = MiMakeProtectionAteMask (NewProtect); 00878 ProtectionMaskNotCopy = MiMakeProtectionAteMask (NewProtectNotCopy); 00879 00880 if (Flags & ALT_COMMIT) { 00881 00882 ProtectionMask |= MM_ATE_COMMIT; 00883 ProtectionMaskNotCopy |= MM_ATE_COMMIT; 00884 00885 } 00886 00887 // 00888 // Get the entry in the table for each of these addresses 00889 // 00890 00891 StartAltPte = MiGetAltPteAddress (Starting4KAddress); 00892 EndAltPte = MiGetAltPteAddress (Ending4KAddress); 00893 00894 StartAltPte0 = MiGetAltPteAddress(PAGE_ALIGN(Starting4KAddress) ); 00895 EndAltPte0 = MiGetAltPteAddress((ULONG_PTR)PAGE_ALIGN(Ending4KAddress)+PAGE_SIZE-1); 00896 00897 // 00898 // lock the alternate page table 00899 // 00900 00901 LOCK_ALTERNATE_TABLE (Wow64Process); 00902 00903 if (!(Flags & ALT_ALLOCATE) && 00904 (MI_CHECK_BIT(Wow64Process->AltPermBitmap, MI_VA_TO_VPN(Starting4KAddress)) == 0)) { 00905 00906 UNLOCK_ALTERNATE_TABLE (Wow64Process); 00907 return; 00908 00909 } 00910 00911 // 00912 // And then change all of the protections 00913 // 00914 00915 VirtualAddress = Starting4KAddress; 00916 00917 while (StartAltPte <= EndAltPte) { 00918 00919 AltPteContents.u.Long = StartAltPte->u.Long; 00920 00921 if (!(Flags & ALT_ALLOCATE) && (AltPteContents.u.Alt.Private != 0)) { 00922 00923 00924 // 00925 // if it is already private, don't make it writecopy 00926 // 00927 00928 TempAltPte.u.Long = ProtectionMaskNotCopy; 00929 TempAltPte.u.Alt.Protection = NewProtectNotCopy; 00930 00931 // 00932 // Private is sticky bit 00933 // 00934 00935 TempAltPte.u.Alt.Private = 1; 00936 00937 } else { 00938 00939 TempAltPte.u.Long = ProtectionMask; 00940 TempAltPte.u.Alt.Protection = NewProtect; 00941 00942 } 00943 00944 if (Flags & ALT_CHANGE) { 00945 00946 // 00947 // if it is a change request, make Commit sticky 00948 // 00949 00950 TempAltPte.u.Alt.Commit = AltPteContents.u.Alt.Commit; 00951 00952 } 00953 00954 if (!(Flags & ALT_ALLOCATE) && (AltPteContents.u.Alt.FillZero != 0)) { 00955 00956 TempAltPte.u.Alt.Accessed = 0; 00957 TempAltPte.u.Alt.FillZero = 1; 00958 00959 } 00960 00961 // 00962 // atomic PTE update 00963 // 00964 00965 StartAltPte->u.Long = TempAltPte.u.Long; 00966 00967 StartAltPte++; 00968 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_4K); 00969 00970 } 00971 00972 if (Flags & ALT_ALLOCATE) { 00973 00974 // 00975 // fill the empty Alt Pte as NoAccess ATE at the end 00976 // 00977 00978 while (EndAltPte <= EndAltPte0) { 00979 00980 if (EndAltPte->u.Long == 0) { 00981 00982 TempAltPte.u.Long = EndAltPte->u.Long; 00983 TempAltPte.u.Alt.NoAccess = 1; 00984 00985 // 00986 // atomic PTE update 00987 // 00988 00989 EndAltPte->u.Long = TempAltPte.u.Long; 00990 00991 } 00992 00993 EndAltPte++; 00994 } 00995 00996 // 00997 // update the permission bitmap 00998 // 00999 01000 MiMarkSplitPages(Base, 01001 (PVOID)((ULONG_PTR)Base + Size - 1), 01002 Wow64Process->AltPermBitmap, 01003 TRUE); 01004 } 01005 01006 // 01007 // As OS always perform MI_MAKE_VLID_PTE to change a valid PTE 01008 // and the macro always reset the access-bit, we don't need to 01009 // call MiResetAccessBitForNativePtes. 01010 // 01011 // MiResetAccessBitForNativePtes(Starting4KAddress, 01012 // Ending4KAddress, 01013 // Process); 01014 01015 01016 01017 // 01018 // flush the TB since the page protections has been changed. 01019 // 01020 01021 VirtualAddress = PAGE_ALIGN(Starting4KAddress); 01022 01023 FlushCount = 0; 01024 while (VirtualAddress <= Ending4KAddress) { 01025 if (FlushCount != MM_MAXIMUM_FLUSH_COUNT) { 01026 Virtual[FlushCount] = VirtualAddress; 01027 FlushCount += 1; 01028 } 01029 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE); 01030 } 01031 01032 if (FlushCount != 0) { 01033 01034 if (FlushCount <= MM_MAXIMUM_FLUSH_COUNT) { 01035 01036 KeFlushMultipleTb(FlushCount, 01037 &Virtual[0], 01038 TRUE, 01039 TRUE, 01040 NULL, 01041 ZeroPte.u.Flush); 01042 } else { 01043 01044 KeFlushEntireTb(TRUE, TRUE); 01045 01046 } 01047 } 01048 01049 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01050 } 01051 01052 VOID 01053 MiProtectMapFileFor4kPage( 01054 IN PVOID Base, 01055 IN SIZE_T Size, 01056 IN ULONG NewProtect, 01057 IN PMMPTE PointerPte, 01058 IN PEPROCESS Process 01059 ) 01060 /*++ 01061 01062 Routine Description: 01063 01064 This routine sets the permissions on the alternate bitmap (based on 01065 4K page sizes). The base and size are assumed to be aligned for 01066 4K pages already. 01067 01068 Arguments: 01069 01070 Base - The base address (assumed to be 4K aligned already) 01071 01072 Size - The size to be protected (assumed to be 4K aligned already) 01073 01074 NewProtect - The protection for the new pages 01075 01076 Commit - True if the page is commited, false otherwise 01077 01078 Process - Supplies a pointer to the process in which to create the 01079 protections on the alternate table 01080 01081 Return Value: 01082 01083 None 01084 01085 Environment: 01086 01087 Kernel mode. All arguments are assumed to be in kernel space. 01088 01089 --*/ 01090 01091 { 01092 PVOID Starting4KAddress; 01093 PVOID Ending4KAddress; 01094 ULONGLONG ProtectionMask; 01095 ULONGLONG HardwareProtectionMask; 01096 PMMPTE StartAltPte, EndAltPte; 01097 PMMPTE StartAltPte0, EndAltPte0; 01098 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01099 MMPTE TempAltPte; 01100 01101 Starting4KAddress = Base; 01102 Ending4KAddress = (PCHAR)Base + Size - 1; 01103 01104 // 01105 // Make sure we don't over run the table 01106 // 01107 ASSERT( ((ULONG_PTR) Starting4KAddress) < _MAX_WOW64_ADDRESS); 01108 ASSERT( ((ULONG_PTR) Ending4KAddress) < _MAX_WOW64_ADDRESS); 01109 01110 // 01111 // for free builds, until this is more tested 01112 // 01113 if ((((UINT_PTR) Starting4KAddress) >= _MAX_WOW64_ADDRESS) 01114 || (((UINT_PTR) Ending4KAddress) >= _MAX_WOW64_ADDRESS)) { 01115 return; 01116 } 01117 01118 // 01119 // Set up the protection to be used for this range of addresses 01120 // 01121 01122 ProtectionMask = MiMakeProtectionAteMask (NewProtect); 01123 01124 // 01125 // Get the entry in the table for each of these addresses 01126 // 01127 01128 StartAltPte = MiGetAltPteAddress (Starting4KAddress); 01129 EndAltPte = MiGetAltPteAddress (Ending4KAddress); 01130 EndAltPte0 = MiGetAltPteAddress((ULONG_PTR)PAGE_ALIGN(Ending4KAddress)+PAGE_SIZE-1); 01131 01132 LOCK_ALTERNATE_TABLE (Wow64Process); 01133 01134 ExAcquireFastMutexUnsafe (&MmSectionCommitMutex); 01135 01136 // 01137 // And then change all of the protections 01138 // 01139 01140 while (StartAltPte <= EndAltPte) { 01141 01142 TempAltPte.u.Long = ProtectionMask; 01143 TempAltPte.u.Alt.Protection = NewProtect; 01144 01145 if (PointerPte->u.Long != 0) { 01146 01147 TempAltPte.u.Alt.Commit = 1; 01148 01149 } else { 01150 01151 TempAltPte.u.Alt.Commit = 0; 01152 01153 } 01154 01155 // 01156 // atomic PTE update 01157 // 01158 01159 StartAltPte->u.Long = TempAltPte.u.Long; 01160 01161 StartAltPte++; 01162 01163 if (((ULONG_PTR)StartAltPte & ((SPLITS_PER_PAGE * sizeof(MMPTE))-1)) == 0) { 01164 01165 PointerPte++; 01166 01167 } 01168 } 01169 01170 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01171 01172 // 01173 // fill the empty Alt Pte as NoAccess ATE at the end 01174 // 01175 01176 while (EndAltPte <= EndAltPte0) { 01177 01178 if (EndAltPte->u.Long == 0) { 01179 01180 TempAltPte.u.Long = EndAltPte->u.Long; 01181 TempAltPte.u.Alt.NoAccess = 1; 01182 01183 // 01184 // atomic PTE size update 01185 // 01186 01187 EndAltPte->u.Long = TempAltPte.u.Long; 01188 01189 } 01190 01191 EndAltPte++; 01192 } 01193 01194 MiMarkSplitPages(Base, 01195 (PVOID)((ULONG_PTR)Base + Size - 1), 01196 Wow64Process->AltPermBitmap, 01197 TRUE); 01198 01199 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01200 } 01201 01202 VOID 01203 MiProtectImageFileFor4kPage( 01204 IN PVOID Base, 01205 IN SIZE_T Size, 01206 IN PMMPTE PointerPte, 01207 IN PEPROCESS Process 01208 ) 01209 { 01210 PVOID Starting4KAddress; 01211 PVOID Ending4KAddress; 01212 ULONGLONG ProtectionMask; 01213 ULONGLONG HardwareProtectionMask; 01214 PMMPTE StartAltPte; 01215 PMMPTE EndAltPte; 01216 PMMPTE EndAltPte0; 01217 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01218 MMPTE TempAltPte; 01219 MMPTE TempPte; 01220 ULONG NewProtect; 01221 KIRQL OldIrql; 01222 ULONG i; 01223 01224 Starting4KAddress = Base; 01225 Ending4KAddress = (PCHAR)Base + Size - 1; 01226 01227 // 01228 // Make sure we don't over run the table 01229 // 01230 ASSERT( ((ULONG_PTR) Starting4KAddress) < _MAX_WOW64_ADDRESS); 01231 ASSERT( ((ULONG_PTR) Ending4KAddress) < _MAX_WOW64_ADDRESS); 01232 01233 // 01234 // for free builds, until this is more tested 01235 // 01236 if ((((UINT_PTR) Starting4KAddress) >= _MAX_WOW64_ADDRESS) 01237 || (((UINT_PTR) Ending4KAddress) >= _MAX_WOW64_ADDRESS)) { 01238 return; 01239 } 01240 01241 // 01242 // Get the entry in the table for each of these addresses 01243 // 01244 01245 StartAltPte = MiGetAltPteAddress (Starting4KAddress); 01246 EndAltPte = MiGetAltPteAddress (Ending4KAddress); 01247 EndAltPte0 = MiGetAltPteAddress((ULONG_PTR)PAGE_ALIGN(Ending4KAddress)+PAGE_SIZE-1); 01248 01249 LOCK_ALTERNATE_TABLE (Wow64Process); 01250 01251 // 01252 // And then change all of the protections 01253 // 01254 01255 while (StartAltPte <= EndAltPte) { 01256 01257 // 01258 // Get the original protection information from the prototype PTEs 01259 // 01260 01261 LOCK_WS_UNSAFE (Process); 01262 01263 LOCK_PFN (OldIrql); 01264 MiMakeSystemAddressValidPfnWs (PointerPte, Process); 01265 TempPte = *PointerPte; 01266 UNLOCK_PFN (OldIrql); 01267 01268 NewProtect = 01269 MiMakeProtectionMask(MiGetPageProtection(&TempPte, Process)); 01270 01271 UNLOCK_WS_UNSAFE (Process); 01272 01273 // 01274 // if demand-zero and copy-on-write, remove copy-on-write 01275 // 01276 01277 if ((!IS_PTE_NOT_DEMAND_ZERO(TempPte)) && 01278 (TempPte.u.Soft.Protection & MM_COPY_ON_WRITE_MASK)) { 01279 NewProtect = NewProtect & ~MM_PROTECTION_COPY_MASK; 01280 } 01281 01282 ProtectionMask = MiMakeProtectionAteMask (NewProtect); 01283 ProtectionMask |= MM_ATE_COMMIT; 01284 01285 TempAltPte.u.Long = ProtectionMask; 01286 TempAltPte.u.Alt.Protection = NewProtect; 01287 01288 if ((NewProtect & MM_PROTECTION_COPY_MASK) == 0) { 01289 01290 // 01291 // if the copy-on-write is removed, make it private 01292 // 01293 01294 TempAltPte.u.Alt.Private = 1; 01295 01296 } 01297 01298 // 01299 // atomic PTE update 01300 // 01301 01302 for (i = 0; i < SPLITS_PER_PAGE; i += 1) { 01303 01304 StartAltPte->u.Long = TempAltPte.u.Long; 01305 StartAltPte++; 01306 01307 } 01308 01309 PointerPte++; 01310 } 01311 01312 // 01313 // fill the empty Alt Pte as NoAccess ATE at the end 01314 // 01315 01316 while (EndAltPte <= EndAltPte0) { 01317 01318 if (EndAltPte->u.Long == 0) { 01319 01320 TempAltPte.u.Long = EndAltPte->u.Long; 01321 TempAltPte.u.Alt.NoAccess = 1; 01322 01323 // 01324 // atomic PTE size update 01325 // 01326 01327 EndAltPte->u.Long = TempAltPte.u.Long; 01328 01329 } 01330 01331 EndAltPte++; 01332 } 01333 01334 MiMarkSplitPages(Base, 01335 (PVOID)((ULONG_PTR)Base + Size - 1), 01336 Wow64Process->AltPermBitmap, 01337 TRUE); 01338 01339 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01340 } 01341 01342 VOID 01343 MiReleaseFor4kPage( 01344 IN PVOID StartVirtual, 01345 IN PVOID EndVirtual, 01346 IN PEPROCESS Process 01347 ) 01348 /*++ 01349 01350 Routine Description: 01351 01352 This function releases a region of pages within the virtual address 01353 space of a subject process. 01354 01355 Arguments: 01356 01357 01358 StartVirtual - the start address of the region of pages 01359 to be released. 01360 01361 EndVirtual - the end address of the region of pages 01362 to be released. 01363 01364 Process - Supplies a pointer to the process in which to release a 01365 region of pages. 01366 01367 Return Value: 01368 01369 None 01370 01371 01372 --*/ 01373 01374 { 01375 PMMPTE StartAltPte; 01376 PMMPTE EndAltPte; 01377 MMPTE TempAltPte; 01378 ULONG_PTR VirtualAddress; 01379 ULONG i; 01380 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01381 PVOID Virtual[MM_MAXIMUM_FLUSH_COUNT]; 01382 ULONG FlushCount = 0; 01383 01384 ASSERT(StartVirtual <= EndVirtual); 01385 01386 StartAltPte = MiGetAltPteAddress (StartVirtual); 01387 EndAltPte = MiGetAltPteAddress (EndVirtual); 01388 01389 LOCK_ALTERNATE_TABLE (Wow64Process); 01390 01391 VirtualAddress = (ULONG_PTR)StartVirtual; 01392 01393 while (StartAltPte <= EndAltPte) { 01394 01395 StartAltPte->u.Long = 0; 01396 StartAltPte->u.Alt.NoAccess = 1; 01397 StartAltPte->u.Alt.FillZero = 1; 01398 StartAltPte++; 01399 01400 } 01401 01402 StartVirtual = PAGE_ALIGN(StartVirtual); 01403 01404 VirtualAddress = (ULONG_PTR)StartVirtual; 01405 01406 while (VirtualAddress <= (ULONG_PTR)EndVirtual) { 01407 01408 StartAltPte = MiGetAltPteAddress(VirtualAddress); 01409 TempAltPte = *StartAltPte; 01410 01411 i = 0; 01412 01413 while (TempAltPte.u.Long == StartAltPte->u.Long) { 01414 i += 1; 01415 StartAltPte++; 01416 } 01417 01418 if (i == SPLITS_PER_PAGE) { 01419 01420 StartAltPte = MiGetAltPteAddress(VirtualAddress); 01421 01422 for (i = 0; i < SPLITS_PER_PAGE; i += 1) { 01423 StartAltPte->u.Long = 0; 01424 StartAltPte++; 01425 } 01426 01427 } 01428 01429 VirtualAddress += PAGE_SIZE; 01430 01431 if (FlushCount != MM_MAXIMUM_FLUSH_COUNT) { 01432 Virtual[FlushCount] = (PVOID)VirtualAddress; 01433 FlushCount += 1; 01434 } 01435 } 01436 01437 MiResetAccessBitForNativePtes(StartVirtual, EndVirtual, Process); 01438 01439 if (FlushCount != 0) { 01440 01441 if (FlushCount <= MM_MAXIMUM_FLUSH_COUNT) { 01442 01443 KeFlushMultipleTb(FlushCount, 01444 &Virtual[0], 01445 TRUE, 01446 TRUE, 01447 NULL, 01448 ZeroPte.u.Flush); 01449 } else { 01450 01451 KeFlushEntireTb(TRUE, TRUE); 01452 01453 } 01454 } 01455 01456 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01457 } 01458 01459 VOID 01460 MiDecommitFor4kPage( 01461 IN PVOID StartVirtual, 01462 IN PVOID EndVirtual, 01463 IN PEPROCESS Process 01464 ) 01465 /*++ 01466 01467 Routine Description: 01468 01469 This function decommits a region of pages within the virtual address 01470 space of a subject process. 01471 01472 Arguments: 01473 01474 01475 StartVirtual - the start address of the region of pages 01476 to be decommitted. 01477 01478 EndVirtual - the end address of the region of the pages 01479 to be decommitted. 01480 01481 Process - Supplies a pointer to the process in which to decommit a 01482 a region of pages. 01483 01484 Return Value: 01485 01486 None 01487 01488 01489 --*/ 01490 01491 { 01492 PMMPTE StartAltPte; 01493 PMMPTE EndAltPte; 01494 MMPTE TempAltPte; 01495 ULONG_PTR VirtualAddress; 01496 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01497 PVOID Virtual[MM_MAXIMUM_FLUSH_COUNT]; 01498 ULONG FlushCount = 0; 01499 01500 ASSERT(StartVirtual <= EndVirtual); 01501 01502 StartAltPte = MiGetAltPteAddress (StartVirtual); 01503 EndAltPte = MiGetAltPteAddress (EndVirtual); 01504 01505 LOCK_ALTERNATE_TABLE (Wow64Process); 01506 01507 while (StartAltPte <= EndAltPte) { 01508 01509 TempAltPte.u.Long = StartAltPte->u.Long; 01510 TempAltPte.u.Alt.Commit = 0; 01511 TempAltPte.u.Alt.FillZero = 1; 01512 01513 // 01514 // atomic PTE update 01515 // 01516 01517 StartAltPte->u.Long = TempAltPte.u.Long; 01518 01519 StartAltPte++; 01520 } 01521 01522 // 01523 // Flush the tb for virtual addreses 01524 // 01525 01526 VirtualAddress = (ULONG_PTR)StartVirtual; 01527 01528 while ((PVOID)VirtualAddress <= EndVirtual) { 01529 01530 if (FlushCount != MM_MAXIMUM_FLUSH_COUNT) { 01531 Virtual[FlushCount] = (PVOID)VirtualAddress; 01532 FlushCount += 1; 01533 } 01534 VirtualAddress += PAGE_SIZE; 01535 01536 } 01537 01538 MiResetAccessBitForNativePtes(StartVirtual, EndVirtual, Process); 01539 01540 if (FlushCount != 0) { 01541 01542 if (FlushCount <= MM_MAXIMUM_FLUSH_COUNT) { 01543 01544 KeFlushMultipleTb(FlushCount, 01545 &Virtual[0], 01546 TRUE, 01547 TRUE, 01548 NULL, 01549 ZeroPte.u.Flush); 01550 } else { 01551 01552 KeFlushEntireTb(TRUE, TRUE); 01553 01554 } 01555 } 01556 01557 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01558 } 01559 01560 01561 VOID 01562 MiDeleteFor4kPage( 01563 IN PVOID StartVirtual, 01564 IN PVOID EndVirtual, 01565 IN PEPROCESS Process 01566 ) 01567 /*++ 01568 01569 Routine Description: 01570 01571 This function deletes a region of pages within the virtual address 01572 space of a subject process. 01573 01574 Arguments: 01575 01576 01577 StartVirtual - the start address of the region of pages 01578 to be deleted 01579 01580 EndVirtual - the end address of the region of the pages 01581 to be deleted. 01582 01583 Process - Supplies a pointer to the process in which to delete a 01584 a region of pages. 01585 01586 Return Value: 01587 01588 None 01589 01590 01591 --*/ 01592 01593 { 01594 PMMPTE StartAltPte; 01595 PMMPTE EndAltPte; 01596 ULONG_PTR VirtualAddress; 01597 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01598 PVOID Virtual[MM_MAXIMUM_FLUSH_COUNT]; 01599 ULONG FlushCount = 0; 01600 01601 ASSERT(StartVirtual <= EndVirtual); 01602 01603 StartAltPte = MiGetAltPteAddress (StartVirtual); 01604 EndAltPte = MiGetAltPteAddress (EndVirtual); 01605 01606 LOCK_ALTERNATE_TABLE (Wow64Process); 01607 01608 VirtualAddress = (ULONG_PTR)StartVirtual; 01609 01610 while (StartAltPte <= EndAltPte) { 01611 01612 StartAltPte->u.Long= 0; 01613 StartAltPte++; 01614 } 01615 01616 01617 // 01618 // Flush the tb for virtual addreses 01619 // 01620 01621 VirtualAddress = (ULONG_PTR)StartVirtual; 01622 01623 while ((PVOID)VirtualAddress <= EndVirtual) { 01624 01625 if (FlushCount != MM_MAXIMUM_FLUSH_COUNT) { 01626 Virtual[FlushCount] = (PVOID)VirtualAddress; 01627 FlushCount += 1; 01628 } 01629 VirtualAddress += PAGE_SIZE; 01630 01631 } 01632 01633 MiMarkSplitPages(StartVirtual, 01634 EndVirtual, 01635 Wow64Process->AltPermBitmap, 01636 TRUE); 01637 01638 MiResetAccessBitForNativePtes(StartVirtual, EndVirtual, Process); 01639 01640 if (FlushCount != 0) { 01641 01642 if (FlushCount <= MM_MAXIMUM_FLUSH_COUNT) { 01643 01644 KeFlushMultipleTb(FlushCount, 01645 &Virtual[0], 01646 TRUE, 01647 TRUE, 01648 NULL, 01649 ZeroPte.u.Flush); 01650 } else { 01651 01652 KeFlushEntireTb(TRUE, TRUE); 01653 01654 } 01655 } 01656 01657 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01658 } 01659 01660 BOOLEAN 01661 MiIsSplitPage( 01662 IN PVOID Virtual 01663 ) 01664 { 01665 PMMPTE AltPte; 01666 MMPTE PteContents; 01667 BOOLEAN IsSplit; 01668 ULONG i; 01669 01670 Virtual = PAGE_ALIGN(Virtual); 01671 AltPte = MiGetAltPteAddress(Virtual); 01672 PteContents = *AltPte; 01673 01674 for (i = 0; i < SPLITS_PER_PAGE; i++) { 01675 01676 if ((AltPte->u.Long != 0) && 01677 ((AltPte->u.Alt.Commit == 0) || 01678 (AltPte->u.Alt.Accessed == 0) || 01679 (AltPte->u.Alt.CopyOnWrite != 0) || 01680 (AltPte->u.Alt.FillZero != 0))) { 01681 01682 // 01683 // if it is a NoAccess, FillZero or Guard page, CopyONWrite, 01684 // mark it as a split page 01685 // 01686 01687 return TRUE; 01688 01689 } else if (PteContents.u.Long != AltPte->u.Long) { 01690 01691 // 01692 // if the next 4kb page is different from the 1st 4k page 01693 // the page is split 01694 // 01695 01696 return TRUE; 01697 01698 } 01699 01700 AltPte++; 01701 01702 } 01703 01704 return FALSE; 01705 } 01706 01707 01708 VOID 01709 MiMarkSplitPages( 01710 IN PVOID StartVirtual, 01711 IN PVOID EndVirtual, 01712 IN PULONG Bitmap, 01713 IN BOOLEAN SetBit 01714 ) 01715 /*++ 01716 01717 Routine Description: 01718 01719 This function sets the corresponding bit on the bitmap table if a split 01720 page condition within a native page is detected. 01721 01722 Arguments: 01723 01724 01725 StartVirtual - the start address of the region of pages 01726 to be inspected. 01727 01728 EndVirtual - the end address of the region of the pages 01729 to be inspected. 01730 01731 Bitmap - Supplies a pointer to the alternate bitmap table. 01732 01733 SetBit - if TRUE, set the bit on the bitmap table. Otherwise, the bit 01734 is set when only when a split contidition is found. 01735 01736 Return Value: 01737 01738 None 01739 01740 --*/ 01741 01742 { 01743 ULONG i; 01744 01745 ASSERT(StartVirtual <= EndVirtual); 01746 ASSERT((ULONG_PTR)StartVirtual < _MAX_WOW64_ADDRESS); 01747 ASSERT((ULONG_PTR)EndVirtual < _MAX_WOW64_ADDRESS); 01748 01749 StartVirtual = PAGE_ALIGN(StartVirtual); 01750 01751 while (StartVirtual <= EndVirtual) { 01752 01753 if (SetBit == TRUE) { 01754 01755 // 01756 // set the bit, marking it as a split page 01757 // 01758 01759 MI_SET_BIT(Bitmap, MI_VA_TO_VPN(StartVirtual)); 01760 01761 } else { 01762 01763 // 01764 // clear the bit, marking it as a non split page 01765 // 01766 01767 MI_CLEAR_BIT(Bitmap, MI_VA_TO_VPN(StartVirtual)); 01768 01769 } 01770 01771 StartVirtual = (PVOID)((ULONG_PTR)StartVirtual + PAGE_SIZE); 01772 } 01773 } 01774 01775 VOID 01776 MiResetAccessBitForNativePtes( 01777 IN PVOID StartVirtual, 01778 IN PVOID EndVirtual, 01779 IN PEPROCESS Process 01780 ) 01781 /*++ 01782 01783 Routine Description: 01784 01785 This function resets the access bit of the native PTEs if the bitmap 01786 indicates it is a split page. 01787 01788 Arguments: 01789 01790 01791 StartVirtual - the start address of the region of pages 01792 to be inspected. 01793 01794 EndVirtual - the end address of the region of the pages 01795 to be inspected. 01796 01797 Bitmap - Supplies a pointer to the process. 01798 01799 Return Value: 01800 01801 None 01802 01803 --*/ 01804 { 01805 PMMPTE PointerPte; 01806 PMMPTE PointerPde; 01807 PMMPTE PointerPpe; 01808 BOOLEAN FirstTime; 01809 ULONG Waited; 01810 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01811 01812 PointerPte = MiGetPteAddress (StartVirtual); 01813 01814 LOCK_WS_UNSAFE (Process); 01815 01816 FirstTime = TRUE; 01817 01818 while (StartVirtual <= EndVirtual) { 01819 01820 if ((FirstTime == TRUE) || MiIsPteOnPdeBoundary (PointerPte)) { 01821 01822 PointerPde = MiGetPteAddress (PointerPte); 01823 PointerPpe = MiGetPdeAddress (PointerPte); 01824 01825 if (MiDoesPpeExistAndMakeValid (PointerPpe, 01826 Process, 01827 FALSE, 01828 &Waited) == FALSE) { 01829 01830 // 01831 // This page directory parent entry is empty, 01832 // go to the next one. 01833 // 01834 01835 PointerPpe += 1; 01836 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 01837 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 01838 StartVirtual = MiGetVirtualAddressMappedByPte (PointerPte); 01839 continue; 01840 } 01841 01842 if (MiDoesPdeExistAndMakeValid (PointerPde, 01843 Process, 01844 FALSE, 01845 &Waited) == FALSE) { 01846 01847 01848 // 01849 // This page directory entry is empty, 01850 // go to the next one. 01851 // 01852 01853 PointerPde++; 01854 PointerPte = MiGetVirtualAddressMappedByPte(PointerPde); 01855 StartVirtual = MiGetVirtualAddressMappedByPte(PointerPte); 01856 continue; 01857 } 01858 01859 FirstTime = FALSE; 01860 01861 } 01862 01863 if ((MI_CHECK_BIT(Wow64Process->AltPermBitmap, MI_VA_TO_VPN(StartVirtual))) && 01864 ((PointerPte->u.Hard.Valid != 0) && (PointerPte->u.Hard.Accessed != 0))) { 01865 01866 PointerPte->u.Hard.Accessed = 0; 01867 01868 } 01869 01870 PointerPte += 1; 01871 StartVirtual = (PVOID)((ULONG_PTR)StartVirtual + PAGE_SIZE); 01872 01873 } 01874 01875 UNLOCK_WS_UNSAFE (Process); 01876 } 01877 01878 VOID 01879 MiQueryRegionFor4kPage( 01880 IN PVOID BaseAddress, 01881 IN PVOID EndAddress, 01882 IN OUT PSIZE_T RegionSize, 01883 IN OUT PULONG RegionState, 01884 IN OUT PULONG RegionProtect, 01885 IN PEPROCESS Process 01886 ) 01887 01888 /*++ 01889 01890 Routine Description: 01891 01892 This function checks the size of region which has the same memory 01893 state. 01894 01895 Arguments: 01896 01897 BaseAddress - The base address of the region of pages to be 01898 queried. 01899 01900 EndAddress - The end of address of the region of pages to be queried. 01901 01902 RegionSize - Original region size. Returns a region size for 4k pages 01903 if different. 01904 01905 RegionState - Original region state. Returns a region state for 4k pages 01906 if different. 01907 01908 RegionProtect - Original protection. Returns a protection for 4k pages 01909 if different. 01910 01911 Process - Supplies a pointer to the process to be queried. 01912 01913 Return Value: 01914 01915 Returns the size of the region 01916 01917 Environment: 01918 01919 01920 --*/ 01921 01922 { 01923 PMMPTE AltPte; 01924 MMPTE AltContents; 01925 PVOID Va; 01926 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 01927 01928 AltPte = MiGetAltPteAddress(BaseAddress); 01929 01930 LOCK_ALTERNATE_TABLE (Wow64Process); 01931 01932 if (MI_CHECK_BIT(Wow64Process->AltPermBitmap, 01933 MI_VA_TO_VPN(BaseAddress)) == 0) { 01934 01935 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01936 return; 01937 01938 } 01939 01940 01941 AltContents.u.Long = AltPte->u.Long; 01942 01943 if (AltContents.u.Long == 0) { 01944 01945 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01946 01947 return; 01948 01949 } 01950 01951 if (AltContents.u.Alt.Commit != 0) { 01952 01953 *RegionState = MEM_COMMIT; 01954 01955 *RegionProtect = 01956 MI_CONVERT_FROM_PTE_PROTECTION(AltContents.u.Alt.Protection); 01957 01958 } else { 01959 01960 *RegionState = MEM_RESERVE; 01961 01962 *RegionProtect = 0; 01963 01964 } 01965 01966 Va = BaseAddress; 01967 01968 while ((ULONG_PTR)Va < (ULONG_PTR)EndAddress) { 01969 01970 Va = (PVOID)((ULONG_PTR)Va + PAGE_4K); 01971 AltPte++; 01972 01973 if ((AltPte->u.Alt.Protection != AltContents.u.Alt.Protection) || 01974 (AltPte->u.Alt.Commit != AltContents.u.Alt.Commit)) { 01975 01976 // 01977 // The state for this address does not match, calculate 01978 // size and return. 01979 // 01980 01981 break; 01982 } 01983 01984 } // end while 01985 01986 UNLOCK_ALTERNATE_TABLE (Wow64Process); 01987 01988 *RegionSize = (SIZE_T)((ULONG_PTR)Va - (ULONG_PTR)BaseAddress); 01989 } 01990 01991 ULONG 01992 MiQueryProtectionFor4kPage ( 01993 IN PVOID BaseAddress, 01994 IN PEPROCESS Process 01995 ) 01996 01997 /*++ 01998 01999 Routine Description: 02000 02001 This function queries the protection for a specified 4k page. 02002 02003 Arguments: 02004 02005 BaseAddress - Supplies a base address of the 4k page. 02006 02007 Process - Supplies a pointer to the process to query the 4k page. 02008 02009 Return Value: 02010 02011 Returns the protection of the 4k page. 02012 02013 Environment: 02014 02015 02016 --*/ 02017 02018 { 02019 02020 ULONG Protection; 02021 PMMPTE PointerAltPte; 02022 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02023 02024 PointerAltPte = MiGetAltPteAddress(BaseAddress); 02025 02026 LOCK_ALTERNATE_TABLE (Process->Wow64Process); 02027 02028 if (MI_CHECK_BIT(Wow64Process->AltPermBitmap, 02029 MI_VA_TO_VPN(BaseAddress)) == 0) { 02030 02031 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02032 return 0; 02033 02034 } 02035 02036 Protection = (ULONG)PointerAltPte->u.Alt.Protection; 02037 02038 UNLOCK_ALTERNATE_TABLE (Process->Wow64Process); 02039 02040 return Protection; 02041 02042 } 02043 02044 VOID 02045 MiCheckPointBreak(VOID) 02046 { 02047 } 02048 02049 VOID 02050 MiCheckPoint( 02051 ULONG Number 02052 ) 02053 { 02054 if (Number == MmCheckPointNumber) { 02055 02056 MiCheckPointBreak(); 02057 02058 } 02059 } 02060 02061 02062 MiCheckPointBreakVirtualAddress ( 02063 PVOID VirtualAddress 02064 ) 02065 { 02066 ULONG Value; 02067 02068 if (PAGE_4K_ALIGN(VirtualAddress) == MmAddressBreak) { 02069 02070 MiCheckPointBreak(); 02071 02072 } 02073 } 02074 02075 02076 NTSTATUS 02077 MiInitializeAlternateTable( 02078 PEPROCESS Process 02079 ) 02080 /*++ 02081 02082 Routine Description: 02083 02084 This function initializes the alternate table for the specified process. 02085 02086 Arguments: 02087 02088 Process - Supplies a pointer to the process to initialize the alternate 02089 table. 02090 02091 Return Value: 02092 02093 STATUS_SUCCESS is returned if the alternate table was successfully initialized. 02094 02095 STATUS_NO_MEMORY is returned if there was not enough physical memory in the 02096 system. 02097 02098 Environment: 02099 02100 02101 --*/ 02102 { 02103 PULONG AltTablePointer; 02104 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02105 02106 AltTablePointer = (PULONG)ExAllocatePoolWithTag (NonPagedPool, 02107 (_MAX_WOW64_ADDRESS >> PTI_SHIFT)/8, 02108 'AlmM'); 02109 02110 if (AltTablePointer == (PULONG) NULL) { 02111 return STATUS_NO_MEMORY; 02112 } 02113 02114 Wow64Process->AltPermBitmap = AltTablePointer; 02115 02116 RtlZeroMemory(AltTablePointer, (_MAX_WOW64_ADDRESS >> PTI_SHIFT)/8); 02117 02118 ExInitializeFastMutex(&Wow64Process->AlternateTableLock); 02119 02120 return STATUS_SUCCESS; 02121 } 02122 02123 02124 VOID 02125 MiDeleteAlternateTable( 02126 PEPROCESS Process 02127 ) 02128 /*++ 02129 02130 Routine Description: 02131 02132 This function deletes the alternate table for the specified process. 02133 02134 Arguments: 02135 02136 Process - Supplies a pointer to the process to delete the alternate 02137 table. 02138 02139 Return Value: 02140 02141 none 02142 02143 Environment: 02144 02145 Kernel mode, APCs disabled, working set mutex held. 02146 02147 --*/ 02148 02149 { 02150 02151 PMMPTE PointerPte; 02152 PMMPTE PointerPde; 02153 PMMPTE PointerPpe; 02154 ULONG_PTR Va; 02155 ULONG_PTR TempVa; 02156 ULONG i; 02157 ULONG Waited; 02158 MMPTE_FLUSH_LIST PteFlushList; 02159 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02160 KIRQL OldIrql; 02161 02162 ASSERT (Wow64Process->AltPermBitmap != NULL); 02163 02164 // 02165 // Since Ppe for Alternate Table is shared with the hyper space, 02166 // we can assume it is always present without performing 02167 // MiDoesPpeExistAndMakeValid(). 02168 // 02169 02170 PointerPpe = MiGetPpeAddress (ALT4KB_PERMISSION_TABLE_START); 02171 PointerPde = MiGetPdeAddress (ALT4KB_PERMISSION_TABLE_START); 02172 PointerPte = MiGetPteAddress (ALT4KB_PERMISSION_TABLE_START); 02173 02174 Va = ALT4KB_PERMISSION_TABLE_START; 02175 02176 LOCK_PFN(OldIrql); 02177 02178 while (Va < ALT4KB_PERMISSION_TABLE_END) { 02179 02180 while (MiDoesPdeExistAndMakeValid (PointerPde, 02181 Process, 02182 TRUE, 02183 &Waited) == FALSE) { 02184 02185 // 02186 // this page directory entry is empty, go to the next one. 02187 // 02188 02189 PointerPde += 1; 02190 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 02191 Va = (ULONG_PTR)MiGetVirtualAddressMappedByPte (PointerPte); 02192 02193 if (Va > ALT4KB_PERMISSION_TABLE_START) { 02194 02195 goto delete_end; 02196 02197 } 02198 02199 } 02200 02201 // 02202 // delete PTE entries for Altnerate Table 02203 // 02204 02205 TempVa = Va; 02206 for (i = 0; i < PTE_PER_PAGE; i++) { 02207 02208 if (PointerPte->u.Long != 0) { 02209 02210 if (IS_PTE_NOT_DEMAND_ZERO (*PointerPte)) { 02211 02212 MiDeletePte (PointerPte, 02213 (PVOID)TempVa, 02214 TRUE, 02215 Process, 02216 NULL, 02217 &PteFlushList); 02218 } else { 02219 02220 *PointerPte = ZeroPte; 02221 } 02222 02223 } 02224 02225 TempVa = PAGE_4K; 02226 PointerPte += 1; 02227 } 02228 02229 // 02230 // delete PDE entries for Alternate Table 02231 // 02232 02233 TempVa = (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPde); 02234 MiDeletePte (PointerPde, 02235 (PVOID)TempVa, 02236 TRUE, 02237 Process, 02238 NULL, 02239 &PteFlushList); 02240 02241 02242 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02243 02244 PointerPde += 1; 02245 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 02246 Va = (ULONG_PTR)MiGetVirtualAddressMappedByPte (PointerPte); 02247 02248 } 02249 02250 delete_end: 02251 02252 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02253 02254 UNLOCK_PFN(OldIrql); 02255 02256 ExFreePool (Wow64Process->AltPermBitmap); 02257 02258 Wow64Process->AltPermBitmap = NULL; 02259 } 02260 02261 VOID 02262 MiFillZeroFor4kPage ( 02263 IN PVOID VirtualAddress, 02264 IN PEPROCESS Process 02265 ) 02266 02267 /*++ 02268 02269 Routine Description: 02270 02271 This function performs bzero for a specified 4k page. 02272 02273 Arguments: 02274 02275 BaseAddress - Supplies a base address of the 4k page. 02276 02277 Process - Supplies a pointer to the process to perform bzero. 02278 02279 Return Value: 02280 02281 None. 02282 02283 Environment: 02284 02285 02286 --*/ 02287 02288 { 02289 SIZE_T RegionSize = PAGE_4K; 02290 PVOID BaseAddress; 02291 ULONG OldProtect; 02292 NTSTATUS Status; 02293 PMMPTE PointerAltPte; 02294 PMMPTE PointerPde; 02295 PMMPTE PointerPpe; 02296 PMMPTE PointerPte; 02297 MMPTE TempAltContents; 02298 MMPTE PteContents; 02299 ULONG Waited; 02300 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02301 02302 PointerAltPte = MiGetAltPteAddress (VirtualAddress); 02303 02304 LOCK_ALTERNATE_TABLE (Wow64Process); 02305 02306 if (PointerAltPte->u.Alt.FillZero == 0) { 02307 02308 // 02309 // Some one has already completed the bzero operations. 02310 // 02311 02312 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02313 02314 return; 02315 02316 } 02317 02318 // 02319 // make PPE and PDE exist and valid 02320 // 02321 02322 PointerPte = MiGetPteAddress(VirtualAddress); 02323 PointerPde = MiGetPdeAddress(VirtualAddress); 02324 PointerPpe = MiGetPpeAddress(VirtualAddress); 02325 02326 // 02327 // make the page table for the original PTE exit to satisfy 02328 // the TLB forward progress for the TLB indirect fault 02329 // 02330 02331 LOCK_WS (Process); 02332 02333 if (MiDoesPpeExistAndMakeValid (PointerPpe, 02334 Process, 02335 FALSE, 02336 &Waited) == FALSE) { 02337 PteContents.u.Long = 0; 02338 02339 } else if (MiDoesPdeExistAndMakeValid (PointerPde, 02340 Process, 02341 FALSE, 02342 &Waited) == FALSE) { 02343 02344 PteContents.u.Long = 0; 02345 02346 } else { 02347 02348 // 02349 // if it is safe to read PointerPte 02350 // 02351 02352 PteContents = *PointerPte; 02353 02354 } 02355 02356 TempAltContents.u.Long = PointerAltPte->u.Long; 02357 02358 if (PteContents.u.Hard.Valid != 0) { 02359 02360 BaseAddress = KSEG_ADDRESS(PteContents.u.Hard.PageFrameNumber); 02361 02362 BaseAddress = 02363 (PVOID)((ULONG_PTR)BaseAddress + 02364 ((ULONG_PTR)PAGE_4K_ALIGN(VirtualAddress) & (PAGE_SIZE-1))); 02365 02366 RtlZeroMemory(BaseAddress, PAGE_4K); 02367 02368 UNLOCK_WS (Process); 02369 02370 TempAltContents.u.Alt.FillZero = 0; 02371 TempAltContents.u.Alt.Accessed = 1; 02372 02373 } else { 02374 02375 UNLOCK_WS (Process); 02376 02377 TempAltContents.u.Alt.Accessed = 0; 02378 02379 } 02380 02381 PointerAltPte->u.Long = TempAltContents.u.Long; 02382 02383 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02384 } 02385 02386 #define USE_MAPVIEW 1 02387 02388 #if !USE_MAPVIEW 02389 NTSTATUS 02390 MiCreateAliasOfDataSection( 02391 IN PCONTROL_AREA ControlArea, 02392 IN PEPROCESS Process, 02393 IN PVOID *CapturedBase, 02394 IN PLARGE_INTEGER SectionOffset, 02395 IN PSIZE_T CapturedViewSize, 02396 IN ULONG ProtectionMask, 02397 OUT PMMVAD *Vad 02398 ) 02399 /*++ 02400 02401 Routine Description: 02402 02403 This is a simplified version of MiMapViewOfSection and creates an alias 02404 map view for the exsiting map view space. 02405 02406 Arguments: 02407 02408 See MmMapViewOfSection. 02409 02410 ControlArea - Supplies the control area for the section. 02411 02412 Process - Supplies the process pointer which is receiving the section. 02413 02414 ProtectionMask - Supplies the initial page protection-mask. 02415 02416 Vad - Returns a pointer to the pointer to the VAD containing the new alias 02417 map view. 02418 02419 Return Value: 02420 02421 Returns a NT status code. 02422 02423 Environment: 02424 02425 Kernel mode, address creating mutex held. 02426 APCs disabled. 02427 02428 --*/ 02429 02430 { 02431 ULONG_PTR Alignment; 02432 KIRQL OldIrql; 02433 PSUBSECTION Subsection; 02434 ULONG PteOffset; 02435 PVOID NewStartingAddress; 02436 PVOID NewEndingAddress; 02437 PMMVAD NewVad; 02438 PMMPTE TheFirstPrototypePte; 02439 02440 // 02441 // Calculate the first prototype PTE field in the Vad. 02442 // 02443 02444 Subsection = (PSUBSECTION)(ControlArea + 1); 02445 02446 Alignment = X64K; 02447 02448 SectionOffset->LowPart = SectionOffset->LowPart & ~((ULONG)Alignment - 1); 02449 PteOffset = (ULONG)(SectionOffset->QuadPart >> PAGE_SHIFT); 02450 02451 // 02452 // Make sure the PTEs are not in the extended part of the 02453 // segment. 02454 // 02455 02456 if (PteOffset >= ControlArea->Segment->TotalNumberOfPtes) { 02457 LOCK_PFN (OldIrql); 02458 ControlArea->NumberOfMappedViews -= 1; 02459 ControlArea->NumberOfUserReferences -= 1; 02460 UNLOCK_PFN (OldIrql); 02461 return STATUS_INVALID_VIEW_SIZE; 02462 } 02463 02464 while (PteOffset >= Subsection->PtesInSubsection) { 02465 PteOffset -= Subsection->PtesInSubsection; 02466 Subsection = Subsection->NextSubsection; 02467 ASSERT (Subsection != NULL); 02468 } 02469 02470 TheFirstPrototypePte = &Subsection->SubsectionBase[PteOffset]; 02471 02472 LOCK_WS_UNSAFE (Process); 02473 02474 try { 02475 02476 // 02477 // Find a starting address on a 64k boundary. 02478 // 02479 02480 NewStartingAddress = MiFindEmptyAddressRange (*CapturedViewSize, 02481 X64K, 02482 (ULONG)0); 02483 } except (EXCEPTION_EXECUTE_HANDLER) { 02484 02485 LOCK_PFN (OldIrql); 02486 ControlArea->NumberOfMappedViews -= 1; 02487 ControlArea->NumberOfUserReferences -= 1; 02488 UNLOCK_PFN (OldIrql); 02489 02490 UNLOCK_WS_UNSAFE(Process); 02491 02492 return GetExceptionCode(); 02493 } 02494 02495 NewEndingAddress = (PVOID)(((ULONG_PTR)NewStartingAddress + 02496 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L)); 02497 02498 // 02499 // An unoccupied address range has been found, build the virtual 02500 // address descriptor to describe this range. 02501 // 02502 02503 try { 02504 02505 NewVad = ExAllocatePoolWithTag (NonPagedPool, 02506 sizeof(MMVAD), 02507 MMVADKEY); 02508 if (NewVad == NULL) { 02509 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); 02510 } 02511 RtlZeroMemory (NewVad, sizeof(MMVAD)); 02512 02513 NewVad->StartingVpn = MI_VA_TO_VPN (NewStartingAddress); 02514 NewVad->EndingVpn = MI_VA_TO_VPN (NewEndingAddress); 02515 NewVad->FirstPrototypePte = TheFirstPrototypePte; 02516 02517 // 02518 // Set the protection in the PTE template field of the VAD. 02519 // 02520 02521 NewVad->ControlArea = ControlArea; 02522 02523 NewVad->u2.VadFlags2.Inherit = 1; 02524 NewVad->u.VadFlags.Protection = ProtectionMask; 02525 NewVad->u2.VadFlags2.CopyOnWrite = 0; 02526 02527 // 02528 // Note that for MEM_DOS_LIM significance is lost here, but those 02529 // files are not mapped MEM_RESERVE. 02530 // 02531 02532 NewVad->u2.VadFlags2.FileOffset = (ULONG)(SectionOffset->QuadPart >> 16); 02533 02534 // 02535 // If this is a page file backed section, charge the process's page 02536 // file quota as if all the pages have been committed. This solves 02537 // the problem when other processes commit all the pages and leave 02538 // only one process around who may not have been charged the proper 02539 // quota. This is solved by charging everyone the maximum quota. 02540 // 02541 02542 PteOffset += (ULONG)(NewVad->EndingVpn - NewVad->StartingVpn); 02543 02544 if (PteOffset < Subsection->PtesInSubsection ) { 02545 NewVad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset]; 02546 02547 } else { 02548 NewVad->LastContiguousPte = &Subsection->SubsectionBase[ 02549 (Subsection->PtesInSubsection - 1) + 02550 Subsection->UnusedPtes]; 02551 } 02552 02553 ASSERT (NewVad->FirstPrototypePte <= NewVad->LastContiguousPte); 02554 MiInsertVad (NewVad); 02555 02556 } except (EXCEPTION_EXECUTE_HANDLER) { 02557 02558 LOCK_PFN (OldIrql); 02559 ControlArea->NumberOfMappedViews -= 1; 02560 ControlArea->NumberOfUserReferences -= 1; 02561 UNLOCK_PFN (OldIrql); 02562 02563 if (NewVad != (PMMVAD)NULL) { 02564 02565 // 02566 // The pool allocation succeeded, but the quota charge 02567 // in InsertVad failed, deallocate the pool and return 02568 // an error. 02569 // 02570 02571 ExFreePool (NewVad); 02572 02573 UNLOCK_WS_UNSAFE (Process); 02574 02575 return GetExceptionCode(); 02576 } 02577 02578 UNLOCK_WS_UNSAFE (Process); 02579 02580 return STATUS_INSUFFICIENT_RESOURCES; 02581 } 02582 02583 UNLOCK_WS_UNSAFE (Process); 02584 02585 // 02586 // Update the current virtual size in the process header. 02587 // 02588 02589 *CapturedViewSize = (PCHAR)NewEndingAddress - (PCHAR)NewStartingAddress + 1L; 02590 02591 Process->VirtualSize += *CapturedViewSize; 02592 02593 if (Process->VirtualSize > Process->PeakVirtualSize) { 02594 Process->PeakVirtualSize = Process->VirtualSize; 02595 } 02596 02597 *CapturedBase = NewStartingAddress; 02598 02599 *Vad = NewVad; 02600 02601 return STATUS_SUCCESS; 02602 } 02603 #endif 02604 02605 NTSTATUS 02606 MiSetCopyPagesFor4kPage( 02607 IN PEPROCESS Process, 02608 IN OUT PMMVAD *Vad, 02609 IN OUT PVOID *StartingAddress, 02610 IN OUT PVOID *EndingAddress, 02611 IN ULONG NewProtection 02612 ) 02613 /*++ 02614 02615 Routine Description: 02616 02617 This function creates another map for the existing mapped view space then give 02618 copy-on-write protection. This function is called when SetProtectionOnSection() 02619 tries to change the protection from non copy-on-write to copy-on-write. Since a 02620 large native page cannot be broken to shared and copy-on-written 4kb pages, 02621 references to the copy-on-written page(s) needs to fixed to reference to 02622 the new mapped view space and this should be done through the smart tlb handler 02623 and the alternate page table entries. 02624 02625 Arguments: 02626 02627 Process - Supplies a EPROCESS pointer of the current process. 02628 02629 Vad - Supplies a pointer to the pointer to the VAD containing the range to 02630 protect. 02631 02632 StartingAddress - Supplies a pointer to the starting address to protect. 02633 02634 EndingAddress - Supplies a pointer to the ending address to the protect. 02635 02636 NewProtect - Supplies the new protection to set. 02637 02638 Return Value: 02639 02640 Returns a NT status code. 02641 02642 Environment: 02643 02644 Kernel mode, working set mutex held, address creating mutex held 02645 APCs disabled. 02646 02647 --*/ 02648 { 02649 LARGE_INTEGER SectionOffset; 02650 SIZE_T CapturedViewSize; 02651 PVOID CapturedBase; 02652 PVOID Va; 02653 PVOID VaEnd; 02654 PVOID Alias; 02655 PMMVAD NewVad; 02656 PMMPTE PointerPte; 02657 PMMPTE AltPte; 02658 #if USE_MAPVIEW 02659 BOOLEAN ReleasedWsMutex; 02660 SECTION Section; 02661 PCONTROL_AREA ControlArea; 02662 #endif 02663 NTSTATUS status; 02664 02665 SectionOffset.QuadPart = (ULONG_PTR)*StartingAddress - 02666 (ULONG_PTR)((*Vad)->StartingVpn << PAGE_SHIFT); 02667 02668 CapturedBase = (PVOID)NULL; 02669 CapturedViewSize = (ULONG_PTR)*EndingAddress - (ULONG_PTR)*StartingAddress + 1; 02670 02671 #if USE_MAPVIEW 02672 02673 ControlArea = (*Vad)->ControlArea; 02674 02675 RtlZeroMemory((PVOID)&Section, sizeof(Section)); 02676 02677 ReleasedWsMutex = FALSE; 02678 02679 UNLOCK_WS_UNSAFE (Process); 02680 02681 status = MiMapViewOfDataSection (ControlArea, 02682 Process, 02683 &CapturedBase, 02684 &SectionOffset, 02685 &CapturedViewSize, 02686 &Section, 02687 ViewShare, 02688 (ULONG)(*Vad)->u.VadFlags.Protection, 02689 0, 02690 0, 02691 0, 02692 &ReleasedWsMutex); 02693 02694 if (!ReleasedWsMutex) { 02695 UNLOCK_WS_UNSAFE (Process); 02696 } 02697 02698 if (status != STATUS_SUCCESS) { 02699 02700 return status; 02701 } 02702 02703 NewVad = MiLocateAddress(CapturedBase); 02704 02705 ASSERT(NewVad != (PMMVAD)NULL); 02706 02707 #else 02708 02709 UNLOCK_WS_UNSAFE (Process); 02710 02711 status = MiCreateAliasOfDataSection((*Vad)->ControlArea, 02712 Process, 02713 &CapturedBase, 02714 &SectionOffset, 02715 &CapturedViewSize, 02716 (ULONG)(*Vad)->u.VadFlags.Protection, 02717 &NewVad); 02718 if (status != STATUS_SUCCESS) { 02719 02720 LOCK_WS_UNSAFE (Process); 02721 return status; 02722 } 02723 02724 02725 #endif 02726 02727 LOCK_ALTERNATE_TABLE (Process->Wow64Process); 02728 02729 Va = *StartingAddress; 02730 VaEnd = *EndingAddress; 02731 Alias = CapturedBase; 02732 02733 while (Va <= VaEnd) { 02734 02735 AltPte = MiGetAltPteAddress (Va); 02736 PointerPte = MiGetPteAddress (Alias); 02737 if (AltPte->u.Alt.CopyOnWrite == 1) { 02738 AltPte->u.Alt.PteOffset = (ULONG_PTR)PointerPte - PTE_UBASE; 02739 AltPte->u.Alt.PteIndirect = 1; 02740 } 02741 02742 Va = (PVOID)((ULONG_PTR)Va + PAGE_4K); 02743 Alias = (PVOID)((ULONG_PTR)Alias + PAGE_4K); 02744 } 02745 02746 MiMarkSplitPages(*StartingAddress, 02747 *EndingAddress, 02748 Process->Wow64Process->AltPermBitmap, 02749 TRUE); 02750 02751 UNLOCK_ALTERNATE_TABLE (Process->Wow64Process); 02752 02753 LOCK_WS_UNSAFE (Process); 02754 02755 Process->Wow64Process->AltFlags |= MI_ALTFLG_FLUSH2G; 02756 02757 *Vad = NewVad; 02758 *StartingAddress = CapturedBase; 02759 *EndingAddress = (PVOID)((ULONG_PTR)CapturedBase + CapturedViewSize - 1L); 02760 02761 return STATUS_SUCCESS; 02762 } 02763 02764 VOID 02765 MiLockFor4kPage( 02766 PVOID CapturedBase, 02767 SIZE_T CapturedRegionSize, 02768 PEPROCESS Process 02769 ) 02770 /*++ 02771 02772 Routine Description: 02773 02774 This function adds the page locked attributes to the alternate table entries. 02775 02776 Arguments: 02777 02778 CapturedBase - Supplies the base address to be locked. 02779 02780 CapturedREgionSize - Supplies the size of the region to be locked. 02781 02782 Process - Supplies a pointer to the process object. 02783 02784 02785 Return Value: 02786 02787 None. 02788 02789 Environment: 02790 02791 Kernel mode, the address creation mutex is held. 02792 02793 --*/ 02794 { 02795 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02796 PVOID EndingAddress; 02797 PMMPTE StartAltPte; 02798 PMMPTE EndAltPte; 02799 02800 EndingAddress = (PVOID)((ULONG_PTR)CapturedBase + CapturedRegionSize - 1); 02801 02802 StartAltPte = MiGetAltPteAddress(CapturedBase); 02803 EndAltPte = MiGetAltPteAddress(EndingAddress); 02804 02805 LOCK_ALTERNATE_TABLE (Wow64Process); 02806 02807 while (StartAltPte <= EndAltPte) { 02808 02809 StartAltPte->u.Alt.Lock = 1; 02810 StartAltPte++; 02811 02812 } 02813 02814 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02815 02816 } 02817 02818 NTSTATUS 02819 MiUnlockFor4kPage( 02820 PVOID CapturedBase, 02821 SIZE_T CapturedRegionSize, 02822 PEPROCESS Process 02823 ) 02824 /*++ 02825 02826 Routine Description: 02827 02828 This function removes the page locked attributes from the alternate table entries. 02829 02830 Arguments: 02831 02832 CapturedBase - Supplies the base address to be unlocked. 02833 02834 CapturedREgionSize - Supplies the size of the region to be unlocked. 02835 02836 Process - Supplies a pointer to the process object. 02837 02838 02839 Return Value: 02840 02841 None. 02842 02843 Environment: 02844 02845 Kernel mode, the address creation mutex is held. 02846 02847 --*/ 02848 { 02849 PMMPTE StartAltPte; 02850 PMMPTE EndAltPte; 02851 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02852 PVOID EndingAddress; 02853 NTSTATUS Status = STATUS_SUCCESS; 02854 02855 EndingAddress = (PVOID)((ULONG_PTR)CapturedBase + CapturedRegionSize - 1); 02856 02857 StartAltPte = MiGetAltPteAddress(CapturedBase); 02858 EndAltPte = MiGetAltPteAddress(EndingAddress); 02859 02860 // 02861 // unlock the working set mutex 02862 // 02863 02864 UNLOCK_WS_UNSAFE (Process); 02865 02866 LOCK_ALTERNATE_TABLE (Wow64Process); 02867 02868 while (StartAltPte <= EndAltPte) { 02869 02870 if (StartAltPte->u.Alt.Lock == 0) { 02871 02872 Status = STATUS_NOT_LOCKED; 02873 goto StatusReturn; 02874 02875 } 02876 02877 StartAltPte++; 02878 } 02879 02880 StartAltPte = MiGetAltPteAddress(CapturedBase); 02881 02882 while (StartAltPte <= EndAltPte) { 02883 02884 StartAltPte->u.Alt.Lock = 0; 02885 02886 StartAltPte++; 02887 } 02888 02889 StatusReturn: 02890 02891 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02892 02893 LOCK_WS_UNSAFE (Process); 02894 02895 return (Status); 02896 } 02897 02898 BOOLEAN 02899 MiShouldBeUnlockedFor4kPage( 02900 PVOID VirtualAddress, 02901 PEPROCESS Process 02902 ) 02903 /*++ 02904 02905 Routine Description: 02906 02907 This function examines whether the pape should be unlocked. 02908 02909 Arguments: 02910 02911 VirtualAddress - Supplies the virtual address to be examined. 02912 02913 Process - Supplies a pointer to the process object. 02914 02915 02916 Return Value: 02917 02918 None. 02919 02920 Environment: 02921 02922 Kernel mode, the working set mutex is held and the address 02923 creation mutex is held. 02924 02925 --*/ 02926 { 02927 PMMPTE PointerAltPte; 02928 PMMPTE StartAltPte; 02929 PMMPTE EndAltPte; 02930 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 02931 PVOID VirtualAligned; 02932 PVOID EndingAddress; 02933 BOOLEAN PageUnlocked = TRUE; 02934 02935 VirtualAligned = PAGE_ALIGN(VirtualAddress); 02936 EndingAddress = (PVOID)((ULONG_PTR)VirtualAligned + PAGE_SIZE - 1); 02937 02938 StartAltPte = MiGetAltPteAddress(VirtualAligned); 02939 EndAltPte = MiGetAltPteAddress(EndingAddress); 02940 02941 // 02942 // unlock the working set mutex 02943 // 02944 02945 UNLOCK_WS_UNSAFE (Process); 02946 02947 LOCK_ALTERNATE_TABLE (Wow64Process); 02948 02949 while (StartAltPte <= EndAltPte) { 02950 02951 if (StartAltPte->u.Alt.Lock != 0) { 02952 PageUnlocked = FALSE; 02953 } 02954 02955 StartAltPte++; 02956 } 02957 02958 UNLOCK_ALTERNATE_TABLE (Wow64Process); 02959 02960 LOCK_WS_UNSAFE (Process); 02961 02962 return (PageUnlocked); 02963 } 02964 02965 VOID 02966 MiCopyOnWriteFor4kPage( 02967 PVOID VirtualAddress, 02968 PEPROCESS Process 02969 ) 02970 /*++ 02971 02972 Routine Description: 02973 02974 This function changes the protection of the alt pages for a copy on 02975 written native page. 02976 02977 Arguments: 02978 02979 VirtualAddress - Supplies the virtual address which caused the 02980 copy-on-written. 02981 02982 Process - Supplies a pointer to the process object. 02983 02984 Return Value: 02985 02986 None. 02987 02988 Environment: 02989 02990 Kernel mode, alternate table lock is held. 02991 02992 --**/ 02993 { 02994 PMMPTE PointerAltPte; 02995 MMPTE TempAltPte; 02996 ULONG i; 02997 02998 PointerAltPte = MiGetAltPteAddress(PAGE_ALIGN(VirtualAddress)); 02999 03000 for (i = 0; i < SPLITS_PER_PAGE; i++) { 03001 03002 TempAltPte.u.Long = PointerAltPte->u.Long; 03003 03004 if ((TempAltPte.u.Alt.Commit != 0) && 03005 (TempAltPte.u.Alt.CopyOnWrite != 0)) { 03006 03007 TempAltPte.u.Alt.CopyOnWrite = 0; 03008 TempAltPte.u.Alt.Private = 1; 03009 TempAltPte.u.Hard.Write = 1; 03010 03011 TempAltPte.u.Alt.Protection = 03012 MI_MAKE_PROTECT_NOT_WRITE_COPY(PointerAltPte->u.Alt.Protection); 03013 03014 } else { 03015 03016 // 03017 // make IA64 binary work 03018 // 03019 03020 TempAltPte.u.Alt.Private = 1; 03021 03022 MiCheckPointBreak(); 03023 03024 } 03025 03026 // 03027 // atomic PTE update 03028 // 03029 03030 PointerAltPte->u.Long = TempAltPte.u.Long; 03031 PointerAltPte++; 03032 } 03033 } 03034 03035 VOID 03036 MiCheckDemandZeroCopyOnWriteFor4kPage( 03037 PVOID VirtualAddress, 03038 PEPROCESS Process 03039 ) 03040 /*++ 03041 03042 Routine Description: 03043 03044 This function changes the protection of the alt pages for a copy on 03045 written native page. 03046 03047 Arguments: 03048 03049 VirtualAddress - Supplies the virtual address which caused the 03050 copy-on-written. 03051 03052 Process - Supplies a pointer to the process object. 03053 03054 Return Value: 03055 03056 None. 03057 03058 Environment: 03059 03060 Kernel mode, alternate table lock is held. 03061 03062 --**/ 03063 { 03064 PMMPTE PointerPpe; 03065 PMMPTE PointerPde; 03066 PMMPTE PointerPte; 03067 MMPTE PteContents; 03068 PMMPTE ProtoPte; 03069 PMMPFN Pfn1; 03070 KIRQL OldIrql; 03071 ULONG OriginalProtection; 03072 ULONGLONG ProtectionMaskOriginal; 03073 ULONG Waited; 03074 03075 // 03076 // get the original protection from the OS 03077 // 03078 03079 LOCK_WS (Process); 03080 03081 ProtoPte = MiCheckVirtualAddress (VirtualAddress, &OriginalProtection); 03082 03083 if (OriginalProtection == MM_UNKNOWN_PROTECTION) { 03084 03085 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 03086 PointerPde = MiGetPteAddress (ProtoPte); 03087 LOCK_PFN (OldIrql); 03088 if (PointerPde->u.Hard.Valid == 0) { 03089 MiMakeSystemAddressValidPfn (ProtoPte); 03090 } 03091 Pfn1 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 03092 Pfn1->u3.e2.ReferenceCount += 1; 03093 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 03094 UNLOCK_PFN (OldIrql); 03095 } 03096 03097 if (!IS_PTE_NOT_DEMAND_ZERO(*ProtoPte)) { 03098 03099 PointerPde = MiGetPdeAddress(VirtualAddress); 03100 PointerPpe = MiGetPpeAddress(VirtualAddress); 03101 PointerPte = MiGetPteAddress(VirtualAddress); 03102 03103 if (MiDoesPpeExistAndMakeValid (PointerPpe, 03104 Process, 03105 FALSE, 03106 &Waited) == FALSE) { 03107 PteContents.u.Long = 0; 03108 03109 } else if (MiDoesPdeExistAndMakeValid (PointerPde, 03110 Process, 03111 FALSE, 03112 &Waited) == FALSE) { 03113 03114 PteContents.u.Long = 0; 03115 03116 } else { 03117 03118 // 03119 // if it is safe to read PointerPte 03120 // 03121 03122 PteContents = *PointerPte; 03123 03124 } 03125 03126 if (PteContents.u.Hard.Valid != 0) { 03127 03128 PteContents.u.Hard.CopyOnWrite = 0; 03129 PteContents.u.Hard.Write = 1; 03130 PointerPte->u.Long = PteContents.u.Long; 03131 03132 } 03133 } 03134 03135 // 03136 // Unlock page containing prototype PTEs. 03137 // 03138 03139 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 03140 LOCK_PFN (OldIrql); 03141 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 03142 Pfn1->u3.e2.ReferenceCount -= 1; 03143 UNLOCK_PFN (OldIrql); 03144 } 03145 } 03146 03147 UNLOCK_WS (Process); 03148 } 03149 03150 ULONG 03151 MiMakeProtectForNativePage( 03152 IN PVOID VirtualAddress, 03153 IN ULONG NewProtect, 03154 IN PEPROCESS Process 03155 ) 03156 /*++ 03157 03158 Routine Description: 03159 03160 This function makes a PAGE protection mask for native pages. 03161 03162 Arguments: 03163 03164 VirtualAddress - Supplies the virtual address to make the PAGE 03165 protection mask. 03166 03167 NewProtect - Supplies the protection originally given. 03168 03169 Process - Supplies a pointer to the process object. 03170 03171 Return Value: 03172 03173 None. 03174 03175 Environment: 03176 03177 Kernel mode. 03178 03179 --**/ 03180 { 03181 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 03182 03183 #if 0 03184 LOCK_ALTERNATE_TABLE (Wow64Process); 03185 #endif 03186 03187 if (MI_CHECK_BIT(Wow64Process->AltPermBitmap, 03188 MI_VA_TO_VPN(VirtualAddress)) != 0) { 03189 03190 if (NewProtect & PAGE_NOACCESS) { 03191 NewProtect &= ~PAGE_NOACCESS; 03192 NewProtect |= PAGE_EXECUTE_READWRITE; 03193 } 03194 03195 if (NewProtect & PAGE_READONLY) { 03196 NewProtect &= ~PAGE_READONLY; 03197 NewProtect |= PAGE_EXECUTE_READWRITE; 03198 } 03199 03200 if (NewProtect & PAGE_EXECUTE) { 03201 NewProtect &= ~PAGE_EXECUTE; 03202 NewProtect |= PAGE_EXECUTE_READWRITE; 03203 } 03204 03205 if (NewProtect & PAGE_EXECUTE_READ) { 03206 NewProtect &= ~PAGE_EXECUTE_READ; 03207 NewProtect |= PAGE_EXECUTE_READWRITE; 03208 } 03209 03210 #if 0 03211 // 03212 // Remove PAGE_GUARD as it is emulated by Altenate Table. 03213 // 03214 03215 if (NewProtect & PAGE_GUARD) { 03216 NewProtect &= ~PAGE_GUARD; 03217 } 03218 #endif 03219 } 03220 03221 #if 0 03222 UNLOCK_ALTERNATE_TABLE (Wow64Process); 03223 #endif 03224 03225 return NewProtect; 03226 } 03227 03228 VOID 03229 MiCheckVirtualAddressFor4kPage( 03230 PVOID VirtualAddress, 03231 PEPROCESS Process 03232 ) 03233 { 03234 PMMPTE ProtoPte; 03235 PMMPTE PointerAltPte; 03236 PMMPTE PointerPde; 03237 MMPTE AltPteContents; 03238 MMPTE TempPte; 03239 ULONG OriginalProtection; 03240 ULONGLONG ProtectionMaskOriginal; 03241 PWOW64_PROCESS Wow64Process; 03242 KIRQL OldIrql; 03243 PMMPFN Pfn1; 03244 ULONG i; 03245 03246 Wow64Process = Process->Wow64Process; 03247 03248 LOCK_WS (Process); 03249 03250 ProtoPte = MiCheckVirtualAddress (VirtualAddress, &OriginalProtection); 03251 03252 if (OriginalProtection == MM_UNKNOWN_PROTECTION) { 03253 03254 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 03255 PointerPde = MiGetPteAddress (ProtoPte); 03256 LOCK_PFN (OldIrql); 03257 if (PointerPde->u.Hard.Valid == 0) { 03258 MiMakeSystemAddressValidPfn (ProtoPte); 03259 } 03260 Pfn1 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 03261 Pfn1->u3.e2.ReferenceCount += 1; 03262 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 03263 UNLOCK_PFN (OldIrql); 03264 } 03265 03266 OriginalProtection = 03267 MiMakeProtectionMask(MiGetPageProtection(ProtoPte, Process)); 03268 03269 // 03270 // Unlock page containing prototype PTEs. 03271 // 03272 03273 if (!MI_IS_PHYSICAL_ADDRESS(ProtoPte)) { 03274 LOCK_PFN (OldIrql); 03275 ASSERT (Pfn1->u3.e2.ReferenceCount > 1); 03276 Pfn1->u3.e2.ReferenceCount -= 1; 03277 UNLOCK_PFN (OldIrql); 03278 } 03279 03280 } 03281 03282 UNLOCK_WS (Process); 03283 03284 ProtectionMaskOriginal = MiMakeProtectionAteMask (OriginalProtection); 03285 ProtectionMaskOriginal |= MM_ATE_COMMIT; 03286 03287 PointerAltPte = MiGetAltPteAddress(PAGE_ALIGN(VirtualAddress)); 03288 03289 AltPteContents.u.Long = ProtectionMaskOriginal; 03290 AltPteContents.u.Alt.Protection = OriginalProtection; 03291 03292 for (i = 0; i < SPLITS_PER_PAGE; i += 1) { 03293 03294 // 03295 // atomic PTE update 03296 // 03297 03298 PointerAltPte->u.Long = AltPteContents.u.Long; 03299 PointerAltPte += 1; 03300 } 03301 03302 // 03303 // Update the bitmap 03304 // 03305 03306 MiMarkSplitPages( 03307 VirtualAddress, 03308 VirtualAddress, 03309 Wow64Process->AltPermBitmap, 03310 TRUE); 03311 } 03312 03313 MiIsEntireRangeCommittedFor4kPage( 03314 IN PVOID StartVirtual, 03315 IN PVOID EndVirtual, 03316 IN PEPROCESS Process 03317 ) 03318 { 03319 PWOW64_PROCESS Wow64Process = Process->Wow64Process; 03320 03321 LOCK_ALTERNATE_TABLE (Wow64Process); 03322 03323 UNLOCK_ALTERNATE_TABLE (Wow64Process); 03324 } 03325 03326 #endif 03327 03328

Generated on Sat May 15 19:39:15 2004 for test by doxygen 1.3.7