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

vlm.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1996 Microsoft Corporation 00004 00005 Module Name: 00006 00007 VLM.C 00008 00009 Abstract: 00010 00011 This module contains the routines which implement the 64-bit Very Large 00012 Memory support. 00013 00014 Author: 00015 00016 Lou Perazzoli (loup) 3-Sep-1996 00017 00018 Revision History: 00019 00020 --*/ 00021 00022 #include "mi.h" 00023 00024 extern ULONG MMVADKEY; 00025 00026 #ifdef VLM_SUPPORT 00027 00028 #define ROUND_TO_PAGES64(Size) ((ULONGLONG)(Size) + (PAGE_SIZE - 1) & ~((LONGLONG)PAGE_SIZE - 1)) 00029 00030 #define MM_VALID_PTE_SIZE (256) 00031 00032 #define MM_LARGEST_VLM_RANGE \ 00033 ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)MM_LOWEST_USER_ADDRESS64) 00034 00035 #define DELETE_TYPE_PRIVATE 0 00036 #define DELETE_TYPE_SHARED 1 00037 00038 MMPTE 00039 MiCaptureSystemPte ( 00040 IN PMMPTE PointerProtoPte, 00041 IN PEPROCESS Process 00042 ); 00043 00044 LOGICAL 00045 MiCommitPages64 ( 00046 IN PMMPTE StartPte, 00047 IN PMMPTE LastPte, 00048 IN ULONG ProtectionMask, 00049 IN PEPROCESS Process, 00050 OUT PSIZE_T ValidPtes 00051 ); 00052 00053 ULONG 00054 MiDecommitOrDeletePages64 ( 00055 IN PMMPTE StartingPte, 00056 IN PMMPTE EndingPte, 00057 IN PEPROCESS Process, 00058 IN ULONG Type, 00059 IN LOGICAL FlushTb 00060 ); 00061 00062 VOID 00063 MiFlushPteList64 ( 00064 IN PMMPTE_FLUSH_LIST64 PteFlushList, 00065 IN ULONG AllProcessors, 00066 IN MMPTE FillPte 00067 ); 00068 00069 VOID 00070 MiReturnAvailablePages ( 00071 IN PFN_NUMBER Amount 00072 ); 00073 00074 LOGICAL 00075 MiCheckPdeForDeletion ( 00076 IN PMMPTE PointerPde, 00077 IN LOGICAL FlushTb 00078 ); 00079 00080 VOID 00081 MiProcessValidPteList64 ( 00082 IN PMMPTE *ValidPteList, 00083 IN ULONG Count, 00084 IN LOGICAL FlushTb 00085 ); 00086 00087 ULONG 00088 MiDoesPdeExist64 ( 00089 IN PMMPTE PointerPde 00090 ); 00091 00092 LOGICAL 00093 MiMakePdeExistAndMakeValid64 ( 00094 IN PMMPTE PointerPde, 00095 IN PEPROCESS TargetProcess, 00096 IN LOGICAL PfnLockHeld, 00097 IN LOGICAL MakePageTablePage 00098 ); 00099 00100 HARDWARE_PTE 00101 MiFlushTbAndCapture( 00102 IN PMMPTE PtePointer, 00103 IN HARDWARE_PTE TempPte, 00104 IN PMMPFN Pfn1 00105 ); 00106 00107 NTSTATUS 00108 MiMapViewOfVlmDataSection ( 00109 IN PCONTROL_AREA ControlArea, 00110 IN PEPROCESS Process, 00111 IN PVOID64 *CapturedBase, 00112 IN PULONGLONG SectionOffset, 00113 IN PULONGLONG CapturedViewSize, 00114 IN PSECTION Section, 00115 IN ULONG ProtectionMask, 00116 IN ULONG AllocationType, 00117 IN PULONG ReleasedWsMutex 00118 ); 00119 00120 ULONG 00121 MiIsEntireRangeCommitted64 ( 00122 IN PVOID64 StartingAddress, 00123 IN PVOID64 EndingAddress, 00124 IN PMMVAD Vad, 00125 IN PEPROCESS Process 00126 ); 00127 00128 VOID 00129 MiMakeValidPageNoAccess64 ( 00130 IN PMMPTE PointePte 00131 ); 00132 00133 VOID 00134 MiMakeNoAccessPageValid64 ( 00135 IN PMMPTE PointerPte, 00136 IN ULONG Protect 00137 ); 00138 00139 ULONG 00140 MiSetProtectionOnTransitionPte ( 00141 IN PMMPTE PointerPte, 00142 IN ULONG ProtectionMask 00143 ); 00144 00145 ULONG 00146 MiQueryAddressState64 ( 00147 IN PVOID64 Va, 00148 IN PMMVAD Vad, 00149 IN PEPROCESS TargetProcess, 00150 OUT PULONG ReturnedProtect 00151 ); 00152 00153 #define MI_NONPAGABLE_MEMORY_AVAILABLE(_SizeInPages) \ 00154 (MmResidentAvailablePages > ((SPFN_NUMBER)_SizeInPages + (SPFN_NUMBER)MmTotalFreeSystemPtes[NonPagedPoolExpansion] + ((SPFN_NUMBER)MiSpecialPagesNonPagedMaximum - (SPFN_NUMBER)MiSpecialPagesNonPaged) + (SPFN_NUMBER)MM_VLM_FLUID_PAGES)) 00155 00156 #define MI_GET_USED_PDE64_HANDLE(PDE64) \ 00157 (&(((PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long))->UsedPageTableEntries[PDE64 - MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64)])) 00158 00159 ULONG MmSharedCommitVlm; // Protected by the PFN lock. 00160 00161 KSPIN_LOCK MiVlmStatisticsLock; // Protects both fields below. 00162 00163 ULONG MiVlmCommitChargeInPages; 00164 ULONG MiVlmCommitChargeInPagesPeak; 00165 00166 00167 NTSTATUS 00168 NtAllocateVirtualMemory64 ( 00169 IN HANDLE ProcessHandle, 00170 IN OUT PVOID64 *BaseAddress, 00171 IN ULONG ZeroBits, 00172 IN OUT PULONGLONG RegionSize, 00173 IN ULONG AllocationType, 00174 IN ULONG Protect 00175 ) 00176 00177 /*++ 00178 00179 Routine Description: 00180 00181 This function creates a region of pages within the virtual address 00182 space of a subject process. 00183 00184 Arguments: 00185 00186 ProcessHandle - Supplies an open handle to a process object. 00187 00188 BaseAddress - Supplies a pointer to a variable that will receive 00189 the base address of the allocated region of pages. 00190 If the initial value of this argument is not null, 00191 then the region will be allocated starting at the 00192 specified virtual address rounded down to the next 00193 host page size address boundary. If the initial 00194 value of this argument is null, then the operating 00195 system will determine where to allocate the 00196 region. 00197 00198 ZeroBits - IGNORED 00199 00200 RegionSize - Supplies a pointer to a variable that will receive 00201 the actual size in bytes of the allocated region 00202 of pages. The initial value of this argument 00203 specifies the size in bytes of the region and is 00204 rounded up to the next host page size boundary. 00205 00206 AllocationType - Supplies a set of flags that describe the type 00207 of allocation that is to be performed for the 00208 specified region of pages. Flags are: 00209 00210 00211 MEM_COMMIT - The specified region of pages is to 00212 be committed. 00213 00214 MEM_RESERVE - The specified region of pages is to 00215 be reserved. 00216 00217 MEM_TOP_DOWN - NOT ALLOWED. 00218 00219 MEM_RESET - IGNORED. 00220 00221 Protect - Supplies the protection desired for the committed 00222 region of pages. 00223 00224 Protect Values: 00225 00226 00227 PAGE_NOACCESS - No access to the committed region 00228 of pages is allowed. An attempt to read, 00229 write, or execute the committed region 00230 results in an access violation (i.e. a GP 00231 fault). 00232 00233 PAGE_EXECUTE - Not allowed 00234 00235 PAGE_READONLY - Read only and execute access to the 00236 committed region of pages is allowed. An 00237 attempt to write the committed region results 00238 in an access violation. 00239 00240 PAGE_READWRITE - Read, write, and execute access to 00241 the committed region of pages is allowed. If 00242 write access to the underlying section is 00243 allowed, then a single copy of the pages are 00244 shared. Otherwise the pages are shared read 00245 only/copy on write. 00246 00247 PAGE_NOCACHE - not allowed. 00248 00249 Return Value: 00250 00251 Returns the status 00252 00253 TBS 00254 00255 00256 --*/ 00257 00258 { 00259 PMMVAD Vad; 00260 PMMVAD FoundVad; 00261 PEPROCESS Process; 00262 KPROCESSOR_MODE PreviousMode; 00263 PVOID64 StartingAddress; 00264 PVOID64 EndingAddress; 00265 NTSTATUS Status; 00266 PVOID64 CapturedBase; 00267 ULONGLONG CapturedRegionSize; 00268 PMMPTE CommitLimitPte; 00269 ULONG ProtectionMask; 00270 PMMPTE LastPte; 00271 PMMPTE PointerPde; 00272 PMMPTE StartingPte; 00273 PMMPTE PointerPte; 00274 MMPTE TempPte; 00275 ULONG OldProtect; 00276 SSIZE_T QuotaCharge; 00277 SIZE_T QuotaFree; 00278 ULONG CopyOnWriteCharge; 00279 BOOLEAN PageFileChargeSucceeded; 00280 LOGICAL Attached; 00281 KIRQL OldIrql; 00282 ULONG_PTR NewPages; 00283 LOGICAL ChargedExactQuota; 00284 LOGICAL CommitSucceeded; 00285 LOGICAL LargeVad; 00286 LOGICAL GotResidentAvail; 00287 PMI_PROCESS_VLM_INFO VlmInfo; 00288 ULONG CommitCharge; 00289 00290 Attached = FALSE; 00291 00292 if (MI_VLM_ENABLED() == FALSE) { 00293 return STATUS_NOT_IMPLEMENTED; 00294 } 00295 00296 // 00297 // Check the AllocationType for correctness. 00298 // 00299 00300 if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | 00301 MEM_RESET)) != 0) { 00302 return STATUS_INVALID_PARAMETER_5; 00303 } 00304 00305 // 00306 // One of MEM_COMMIT, MEM_RESET or MEM_RESERVE must be set. 00307 // 00308 00309 if ((AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) == 0) { 00310 return STATUS_INVALID_PARAMETER_5; 00311 } 00312 00313 if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET)) { 00314 00315 // 00316 // MEM_RESET may not be used with any other flag. 00317 // 00318 00319 return STATUS_INVALID_PARAMETER_5; 00320 } 00321 00322 // 00323 // Check the protection field. This could raise an exception. 00324 // 00325 00326 try { 00327 ProtectionMask = MiMakeProtectionMask (Protect); 00328 } except (EXCEPTION_EXECUTE_HANDLER) { 00329 return GetExceptionCode(); 00330 } 00331 00332 if ((ProtectionMask == MM_NOACCESS) && 00333 (AllocationType & MEM_COMMIT)) { 00334 00335 return STATUS_INVALID_PAGE_PROTECTION; 00336 } 00337 00338 PreviousMode = KeGetPreviousMode(); 00339 00340 // 00341 // Establish an exception handler, probe the specified addresses 00342 // for write access and capture the initial values. 00343 // 00344 00345 try { 00346 00347 if (PreviousMode != KernelMode) { 00348 00349 ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 00350 ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG)); 00351 } 00352 00353 // 00354 // Capture the base address. 00355 // 00356 00357 CapturedBase = *BaseAddress; 00358 00359 // 00360 // Capture the region size. 00361 // 00362 00363 CapturedRegionSize = *RegionSize; 00364 00365 } except (ExSystemExceptionFilter()) { 00366 00367 // 00368 // If an exception occurs during the probe or capture 00369 // of the initial values, then handle the exception and 00370 // return the exception code as the status value. 00371 // 00372 00373 return GetExceptionCode(); 00374 } 00375 00376 #if 0 00377 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00378 if ( MmWatchProcess ) { 00379 ; 00380 } else { 00381 DbgPrint("allocvm process handle %lx base address %p zero bits %lx\n", 00382 ProcessHandle, CapturedBase, ZeroBits); 00383 DbgPrint(" region size %p alloc type %lx protect %lx\n", 00384 CapturedRegionSize, AllocationType, Protect); 00385 } 00386 } 00387 #endif 00388 00389 // 00390 // Make sure the specified starting and ending addresses are 00391 // within the user part of the virtual address space. 00392 // 00393 00394 if ((CapturedBase != NULL ) && 00395 ((CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) || 00396 (CapturedBase < (PVOID64)MM_LOWEST_USER_ADDRESS64))) { 00397 00398 // 00399 // Invalid base address. 00400 // 00401 00402 return STATUS_INVALID_PARAMETER_2; 00403 } 00404 00405 if (CapturedBase != NULL) { 00406 00407 if ((ULONGLONG)CapturedBase + CapturedRegionSize < (ULONGLONG)CapturedBase) { 00408 00409 // 00410 // the requested region wraps 00411 // 00412 00413 return STATUS_INVALID_PARAMETER_4; 00414 } 00415 00416 00417 if ((ULONGLONG)CapturedBase + CapturedRegionSize > (ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - X64K) { 00418 00419 // 00420 // the requested region goes beyond the end of user memory - flag it 00421 // 00422 00423 return STATUS_INVALID_PARAMETER_4; 00424 } 00425 } 00426 else if (CapturedRegionSize > (ULONGLONG)MM_LARGEST_VLM_RANGE - X64K) { 00427 00428 // 00429 // Invalid region size; 00430 // 00431 00432 return STATUS_INVALID_PARAMETER_4; 00433 } 00434 00435 if (CapturedRegionSize == 0) { 00436 00437 // 00438 // Region size cannot be 0. 00439 // 00440 00441 return STATUS_INVALID_PARAMETER_4; 00442 } 00443 00444 // 00445 // Reference the specified process handle for VM_OPERATION access. 00446 // 00447 00448 if ( ProcessHandle == NtCurrentProcess() ) { 00449 Process = PsGetCurrentProcess(); 00450 } else { 00451 Status = ObReferenceObjectByHandle ( ProcessHandle, 00452 PROCESS_VM_OPERATION, 00453 PsProcessType, 00454 PreviousMode, 00455 (PVOID *)&Process, 00456 NULL ); 00457 00458 if (!NT_SUCCESS(Status)) { 00459 return Status; 00460 } 00461 } 00462 00463 // 00464 // If the specified process is not the current process, attach 00465 // to the specified process. 00466 // 00467 00468 if (PsGetCurrentProcess() != Process) { 00469 KeAttachProcess (&Process->Pcb); 00470 Attached = TRUE; 00471 } 00472 00473 // 00474 // Get the address creation mutex to block multiple threads from 00475 // creating or deleting address space at the same time and 00476 // get the working set mutex so virtual address descriptors can 00477 // be inserted and walked. Block APCs so an APC which takes a page 00478 // fault does not corrupt various structures. 00479 // 00480 00481 LOCK_WS_AND_ADDRESS_SPACE (Process); 00482 00483 // 00484 // Make sure the address space was not deleted, if so, return an error. 00485 // 00486 00487 if (Process->AddressSpaceDeleted != 0) { 00488 Status = STATUS_PROCESS_IS_TERMINATING; 00489 goto ErrorReturn; 00490 } 00491 00492 // 00493 // Don't allow POSIX apps to do VLM operations. 00494 // 00495 00496 if ((Process->CloneRoot != NULL) && 00497 (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) { 00498 Status = STATUS_INVALID_VLM_OPERATION; 00499 goto ErrorReturn; 00500 } 00501 Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED; 00502 00503 if ((CapturedBase == NULL) || (AllocationType & MEM_RESERVE)) { 00504 00505 // 00506 // PAGE_WRITECOPY is not valid for private pages. 00507 // 00508 00509 if ((Protect & PAGE_WRITECOPY) || 00510 (Protect & PAGE_EXECUTE_WRITECOPY)) { 00511 Status = STATUS_INVALID_PAGE_PROTECTION; 00512 goto ErrorReturn; 00513 } 00514 00515 // 00516 // Reserve the address space. 00517 // 00518 00519 if (CapturedBase == NULL) { 00520 00521 // 00522 // No base address was specified. This MUST be a reserve or 00523 // reserve and commit. 00524 // 00525 00526 CapturedRegionSize = ROUND_TO_PAGES64 (CapturedRegionSize); 00527 00528 // 00529 // Establish exception handler as MiFindEmptyAddressRange 00530 // will raise an exception if it fails. 00531 // 00532 00533 try { 00534 00535 00536 StartingAddress = MiFindEmptyAddressRangeInTree64 ( 00537 CapturedRegionSize, 00538 X64K, 00539 (PMMADDRESS_NODE)(Process->CloneRoot)); 00540 00541 } except (EXCEPTION_EXECUTE_HANDLER) { 00542 Status = GetExceptionCode(); 00543 goto ErrorReturn; 00544 } 00545 00546 // 00547 // Calculate the ending address based on the top address. 00548 // 00549 00550 EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress + 00551 CapturedRegionSize - 1L) | (PAGE_SIZE - 1L)); 00552 00553 } else { 00554 00555 // 00556 // A non-NULL base address was specified. Check to make sure 00557 // the specified base address to ending address is currently 00558 // unused. 00559 // 00560 00561 EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + 00562 CapturedRegionSize - 1L) | (PAGE_SIZE - 1L)); 00563 00564 // 00565 // Align the starting address on a 64k boundary. 00566 // 00567 00568 StartingAddress = MI_64K_ALIGN64(CapturedBase); 00569 00570 // 00571 // See if a VAD overlaps with this starting/ending address pair. 00572 // 00573 00574 if (MiCheckForConflictingVad64 (StartingAddress, EndingAddress) != 00575 (PMMVAD)NULL) { 00576 00577 Status = STATUS_CONFLICTING_ADDRESSES; 00578 goto ErrorReturn; 00579 } 00580 } 00581 00582 if (AllocationType & MEM_COMMIT) { 00583 StartingPte = MiGetPteAddress64 (StartingAddress); 00584 ASSERT (MiGetPdeAddress64(StartingAddress) == MiGetPteAddress (StartingPte)); 00585 LastPte = MiGetPteAddress64 (EndingAddress); 00586 QuotaCharge = 1 + LastPte - StartingPte; 00587 } 00588 else { 00589 QuotaCharge = 0; 00590 } 00591 00592 // 00593 // An unoccupied address range has been found, build the virtual 00594 // address descriptor to describe this range. 00595 // 00596 00597 // 00598 // Establish an exception handler and attempt to allocate 00599 // the pool and charge quota. Note that the InsertVad routine 00600 // will also charge quota which could raise an exception. 00601 // 00602 00603 try { 00604 00605 if ((AllocationType & MEM_COMMIT) && (QuotaCharge + QuotaCharge / PTE_PER_PAGE + 2 >= MM_MAX_COMMIT)) { 00606 LargeVad = TRUE; 00607 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool, 00608 sizeof(MMVAD), 00609 MMVADKEY); 00610 } 00611 else { 00612 LargeVad = FALSE; 00613 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool, 00614 sizeof(MMVAD_SHORT), 00615 'SdaV'); 00616 } 00617 00618 // 00619 // Faults are not allowed here since we are already holding the WS 00620 // lock. This means we must check pool allocations explicitly. 00621 // 00622 00623 if (Vad == (PMMVAD)0) { 00624 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); 00625 } 00626 00627 Vad->StartingVpn = MI_VA_TO_VPN64 (StartingAddress); 00628 Vad->EndingVpn = MI_VA_TO_VPN64 (EndingAddress); 00629 00630 Vad->u.LongFlags = 0; 00631 if (AllocationType & MEM_COMMIT) { 00632 Vad->u.VadFlags.MemCommit = 1; 00633 00634 if (LargeVad == TRUE) { 00635 Vad->u.VadFlags.ImageMap = 1; // Signify large commit 00636 Vad->u.VadFlags.CommitCharge = 0; 00637 Vad->u3.List.Flink = (PLIST_ENTRY)QuotaCharge; 00638 } 00639 else { 00640 Vad->u.VadFlags.CommitCharge = QuotaCharge; 00641 } 00642 } 00643 00644 Vad->u.VadFlags.Protection = ProtectionMask; 00645 Vad->u.VadFlags.PrivateMemory = 1; 00646 00647 MiInsertVad64 ((PVOID)Vad); 00648 00649 } except (EXCEPTION_EXECUTE_HANDLER) { 00650 00651 if (Vad != (PMMVAD)NULL) { 00652 00653 // 00654 // The pool allocation succeeded, but the quota charge 00655 // in InsertVad failed, deallocate the pool and return 00656 // an error. 00657 // 00658 00659 ExFreePool (Vad); 00660 Status = GetExceptionCode(); 00661 } else { 00662 Status = STATUS_INSUFFICIENT_RESOURCES; 00663 } 00664 00665 goto ErrorReturn; 00666 } 00667 00668 if (AllocationType & MEM_COMMIT) { 00669 00670 // 00671 // Check to ensure these pages can be committed. 00672 // Charge quota and commitment for the range. Establish an 00673 // exception handler as this could raise an exception. 00674 // 00675 00676 QuotaFree = 1; 00677 Status = STATUS_SUCCESS; 00678 00679 LOCK_PFN (OldIrql); 00680 00681 if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) { 00682 MmResidentAvailablePages -= (PFN_NUMBER)QuotaCharge; 00683 MM_BUMP_COUNTER(22, QuotaCharge); 00684 QuotaFree = 0; 00685 } 00686 UNLOCK_PFN (OldIrql); 00687 if (QuotaFree == 1) { 00688 MiRemoveVad64 ((PMMVAD)Vad); 00689 ExFreePool (Vad); 00690 Status = STATUS_COMMITMENT_LIMIT; 00691 goto ErrorReturn; 00692 } 00693 00694 CommitSucceeded = MiCommitPages64 (StartingPte, 00695 LastPte, 00696 ProtectionMask, 00697 Process, 00698 &QuotaFree); 00699 00700 if (CommitSucceeded == FALSE) { 00701 00702 // 00703 // Nothing has been committed so just adjust counts and bail. 00704 // 00705 00706 LOCK_PFN (OldIrql); 00707 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 00708 MM_BUMP_COUNTER(22, -QuotaCharge); 00709 UNLOCK_PFN (OldIrql); 00710 MiRemoveVad64 ((PMMVAD)Vad); 00711 ExFreePool (Vad); 00712 Status = STATUS_INSUFFICIENT_RESOURCES; 00713 goto ErrorReturn; 00714 } 00715 00716 if (QuotaFree != 0) { 00717 LOCK_PFN (OldIrql); 00718 MmResidentAvailablePages += (PFN_NUMBER) QuotaFree; 00719 MM_BUMP_COUNTER(23, QuotaFree); 00720 UNLOCK_PFN (OldIrql); 00721 } 00722 00723 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 00724 VlmInfo->CommitCharge += (QuotaCharge - QuotaFree); 00725 if (VlmInfo->CommitCharge > VlmInfo->CommitChargePeak) { 00726 VlmInfo->CommitChargePeak = VlmInfo->CommitCharge; 00727 } 00728 } 00729 else { 00730 00731 // 00732 // The top level PDE map page is allocated here (it it is not 00733 // already) even though this is only a reserve. Because data like 00734 // the virtual size is saved in a pool allocation whose pointer is 00735 // in the top level PDE map page. 00736 // 00737 00738 CommitSucceeded = MiMakePdeExistAndMakeValid64 ( 00739 MiGetPdeAddress64 (StartingAddress), 00740 Process, 00741 FALSE, 00742 FALSE); 00743 00744 if (CommitSucceeded == FALSE) { 00745 MiRemoveVad64 ((PMMVAD)Vad); 00746 ExFreePool (Vad); 00747 Status = STATUS_INSUFFICIENT_RESOURCES; 00748 goto ErrorReturn; 00749 } 00750 QuotaCharge = 0; 00751 } 00752 00753 // 00754 // Unlock the working set lock, page faults can now be taken. 00755 // 00756 00757 UNLOCK_WS (Process); 00758 00759 // 00760 // Update the current virtual size in the process header, the 00761 // address space lock protects this operation. 00762 // 00763 00764 CapturedRegionSize = (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress + 1; 00765 00766 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 00767 VlmInfo->VirtualSize += CapturedRegionSize; 00768 if (VlmInfo->VirtualSize > VlmInfo->VirtualSizePeak) { 00769 VlmInfo->VirtualSizePeak = VlmInfo->VirtualSize; 00770 } 00771 00772 ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql); 00773 00774 if (AllocationType & MEM_COMMIT) { 00775 MiVlmCommitChargeInPages += (QuotaCharge - QuotaFree); 00776 if (MiVlmCommitChargeInPages > MiVlmCommitChargeInPagesPeak) { 00777 MiVlmCommitChargeInPagesPeak = MiVlmCommitChargeInPages; 00778 } 00779 } 00780 00781 ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql); 00782 00783 // 00784 // Release the address space lock, lower IRQL, detach, and dereference 00785 // the process object. 00786 // 00787 00788 UNLOCK_ADDRESS_SPACE(Process); 00789 if (Attached) { 00790 KeDetachProcess(); 00791 } 00792 00793 if ( ProcessHandle != NtCurrentProcess() ) { 00794 ObDereferenceObject (Process); 00795 } 00796 00797 // 00798 // Establish an exception handler and write the size and base 00799 // address. 00800 // 00801 try { 00802 00803 *RegionSize = CapturedRegionSize; 00804 *BaseAddress = StartingAddress; 00805 00806 } except (EXCEPTION_EXECUTE_HANDLER) { 00807 00808 // 00809 // Return success at this point even if the results 00810 // cannot be written. 00811 // 00812 00813 NOTHING; 00814 } 00815 00816 #if 0 00817 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00818 if ( MmWatchProcess ) { 00819 if ( MmWatchProcess == PsGetCurrentProcess() ) { 00820 DbgPrint("\n+++ ALLOC Type %lx Base %p Size %p\n", 00821 AllocationType,StartingAddress, CapturedRegionSize); 00822 MmFooBar(); 00823 } 00824 } else { 00825 DbgPrint("return allocvm status %lx baseaddr %p size %p\n", 00826 Status, StartingAddress, CapturedRegionSize); 00827 } 00828 } 00829 #endif 00830 00831 return STATUS_SUCCESS; 00832 00833 } else { 00834 00835 // 00836 // Commit previously reserved pages. Note that these pages could 00837 // be either private or a section. 00838 // 00839 00840 if (AllocationType == MEM_RESET) { 00841 00842 // 00843 // Don't do anything for the mem reset case as the pages are 00844 // all valid. 00845 // 00846 00847 Status = STATUS_SUCCESS; 00848 goto ErrorReturn; 00849 00850 } else { 00851 EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + 00852 CapturedRegionSize - 1) | (PAGE_SIZE - 1)); 00853 StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase); 00854 } 00855 00856 CapturedRegionSize = (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress + 1; 00857 00858 FoundVad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress); 00859 00860 if (FoundVad == (PMMVAD)NULL) { 00861 00862 // 00863 // No virtual address is reserved at the specified base address, 00864 // return an error. 00865 // 00866 00867 Status = STATUS_CONFLICTING_ADDRESSES; 00868 goto ErrorReturn; 00869 } 00870 00871 // 00872 // Ensure that the starting and ending addresses are all within 00873 // the same virtual address descriptor. 00874 // 00875 00876 if ((MI_VA_TO_VPN64 (StartingAddress) < FoundVad->StartingVpn) || 00877 (MI_VA_TO_VPN64 (EndingAddress) > FoundVad->EndingVpn)) { 00878 00879 // 00880 // Not within the section virtual address descriptor, 00881 // return an error. 00882 // 00883 00884 Status = STATUS_CONFLICTING_ADDRESSES; 00885 goto ErrorReturn; 00886 } 00887 00888 00889 if (FoundVad->u.VadFlags.PrivateMemory == 1) { 00890 00891 // 00892 // PAGE_WRITECOPY is not valid for private pages. 00893 // 00894 00895 if ((Protect & PAGE_WRITECOPY) || 00896 (Protect & PAGE_EXECUTE_WRITECOPY)) { 00897 Status = STATUS_INVALID_PAGE_PROTECTION; 00898 goto ErrorReturn; 00899 } 00900 00901 // 00902 // Ensure none of the pages are already committed as described 00903 // in the virtual address descriptor. 00904 // 00905 #if 0 00906 if (AllocationType & MEM_CHECK_COMMIT_STATE) { 00907 if ( !MiIsEntireRangeDecommitted(StartingAddress, 00908 EndingAddress, 00909 FoundVad, 00910 Process)) { 00911 00912 // 00913 // Previously reserved pages have been committed, or 00914 // an error occurred, release mutex and return status. 00915 // 00916 00917 Status = STATUS_ALREADY_COMMITTED; 00918 goto ErrorReturn; 00919 } 00920 } 00921 #endif //0 00922 00923 // 00924 // The address range has not been committed, commit it now. 00925 // Note, that for private pages, commitment is handled by 00926 // explicitly updating PTEs to contain Demand Zero entries. 00927 // 00928 00929 StartingPte = MiGetPteAddress64 (StartingAddress); 00930 ASSERT (MiGetPdeAddress64(StartingAddress) == MiGetPteAddress (StartingPte)); 00931 LastPte = MiGetPteAddress64 (EndingAddress); 00932 00933 // 00934 // Check to ensure these pages can be committed. 00935 // 00936 00937 QuotaCharge = 1 + LastPte - StartingPte; 00938 00939 // 00940 // Charge quota and commitment for the range. Establish an 00941 // exception handler as this could raise an exception. 00942 // 00943 00944 QuotaFree = 1; 00945 Status = STATUS_SUCCESS; 00946 00947 LOCK_PFN (OldIrql); 00948 if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) { 00949 MmResidentAvailablePages -= (PFN_NUMBER) QuotaCharge; 00950 MM_BUMP_COUNTER(24, QuotaCharge); 00951 QuotaFree = 0; 00952 } 00953 UNLOCK_PFN (OldIrql); 00954 if (QuotaFree == 1) { 00955 Status = STATUS_COMMITMENT_LIMIT; 00956 goto ErrorReturn; 00957 } 00958 00959 if (Process->CommitChargeLimit) { 00960 if (Process->CommitCharge + QuotaCharge > Process->CommitChargeLimit) { 00961 Status = STATUS_COMMITMENT_LIMIT; 00962 LOCK_PFN (OldIrql); 00963 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 00964 MM_BUMP_COUNTER(24, -QuotaCharge); 00965 UNLOCK_PFN (OldIrql); 00966 if (Process->Job) { 00967 PsReportProcessMemoryLimitViolation (); 00968 } 00969 goto ErrorReturn; 00970 } 00971 } 00972 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00973 if (PsChangeJobMemoryUsage(QuotaCharge) == FALSE) { 00974 Status = STATUS_COMMITMENT_LIMIT; 00975 LOCK_PFN (OldIrql); 00976 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 00977 MM_BUMP_COUNTER(24, -QuotaCharge); 00978 UNLOCK_PFN (OldIrql); 00979 goto ErrorReturn; 00980 } 00981 } 00982 00983 try { 00984 MiChargeCommitment (QuotaCharge, Process); 00985 } except (EXCEPTION_EXECUTE_HANDLER) { 00986 00987 Status = GetExceptionCode(); 00988 LOCK_PFN (OldIrql); 00989 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 00990 MM_BUMP_COUNTER(24, -QuotaCharge); 00991 UNLOCK_PFN (OldIrql); 00992 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00993 00994 // 00995 // Temporarily up the process commit charge as the 00996 // job code will be referencing it as though everything 00997 // has succeeded. 00998 // 00999 01000 Process->CommitCharge += QuotaCharge; 01001 PsChangeJobMemoryUsage (-(SSIZE_T)QuotaCharge); 01002 Process->CommitCharge -= QuotaCharge; 01003 } 01004 goto ErrorReturn; 01005 } 01006 01007 MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM1_VLM, QuotaCharge); 01008 01009 CommitSucceeded = MiCommitPages64 (StartingPte, 01010 LastPte, 01011 ProtectionMask, 01012 Process, 01013 &QuotaFree); 01014 01015 if (CommitSucceeded == FALSE) { 01016 Status = STATUS_INSUFFICIENT_RESOURCES; 01017 LOCK_PFN (OldIrql); 01018 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 01019 MM_BUMP_COUNTER(24, -QuotaCharge); 01020 UNLOCK_PFN (OldIrql); 01021 MiReturnCommitment (QuotaCharge); 01022 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01023 01024 // 01025 // Temporarily up the process commit charge as the 01026 // job code will be referencing it as though everything 01027 // has succeeded. 01028 // 01029 01030 Process->CommitCharge += QuotaCharge; 01031 PsChangeJobMemoryUsage (-(SSIZE_T)QuotaCharge); 01032 Process->CommitCharge -= QuotaCharge; 01033 } 01034 goto ErrorReturn; 01035 } 01036 01037 NewPages = QuotaCharge - QuotaFree; 01038 01039 // 01040 // Excess charging of commit is returned below. 01041 // 01042 01043 if (FoundVad->u.VadFlags.ImageMap == 1) { 01044 ASSERT (FoundVad->u.VadFlags.CommitCharge == 0); 01045 CommitCharge = (ULONG)FoundVad->u3.List.Flink; 01046 } 01047 else { 01048 CommitCharge = FoundVad->u.VadFlags.CommitCharge; 01049 } 01050 01051 ASSERT (CommitCharge + NewPages >= CommitCharge); 01052 CommitCharge += NewPages; 01053 01054 if (QuotaFree) { 01055 MiReturnCommitment (QuotaFree); 01056 MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM1_VLM, -QuotaFree); 01057 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01058 01059 // 01060 // Temporarily up the process commit charge as the 01061 // job code will be referencing it as though everything 01062 // has succeeded. 01063 // 01064 01065 Process->CommitCharge += QuotaFree; 01066 PsChangeJobMemoryUsage (-(SSIZE_T)QuotaFree); 01067 Process->CommitCharge -= QuotaFree; 01068 } 01069 } 01070 01071 if (FoundVad->u.VadFlags.ImageMap == 1) { 01072 ASSERT (FoundVad->u.VadFlags.CommitCharge == 0); 01073 FoundVad->u3.List.Flink = (PLIST_ENTRY)CommitCharge; 01074 } 01075 else { 01076 FoundVad->u.VadFlags.CommitCharge = CommitCharge; 01077 } 01078 01079 Process->CommitCharge += NewPages; 01080 if (Process->CommitCharge > Process->CommitChargePeak) { 01081 Process->CommitChargePeak = Process->CommitCharge; 01082 } 01083 01084 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 01085 VlmInfo->CommitCharge += NewPages; 01086 if (VlmInfo->CommitCharge > VlmInfo->CommitChargePeak) { 01087 VlmInfo->CommitChargePeak = VlmInfo->CommitCharge; 01088 } 01089 01090 ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql); 01091 01092 MiVlmCommitChargeInPages += NewPages; 01093 if (MiVlmCommitChargeInPages > MiVlmCommitChargeInPagesPeak) { 01094 MiVlmCommitChargeInPagesPeak = MiVlmCommitChargeInPages; 01095 } 01096 01097 ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql); 01098 01099 } else { 01100 01101 // 01102 // The no cache option is not allowed for sections. 01103 // 01104 01105 if (Protect & PAGE_NOCACHE) { 01106 Status = STATUS_INVALID_PAGE_PROTECTION; 01107 goto ErrorReturn; 01108 } 01109 01110 ASSERT (FoundVad->u.VadFlags.NoChange == 0); 01111 01112 ASSERT (FoundVad->ControlArea->FilePointer == NULL); 01113 01114 StartingPte = MiGetProtoPteAddress (FoundVad, 01115 MI_VA_TO_VPN64 (StartingAddress)); 01116 PointerPte = StartingPte; 01117 LastPte = MiGetProtoPteAddress (FoundVad, 01118 MI_VA_TO_VPN64 (EndingAddress)); 01119 01120 UNLOCK_WS (Process); 01121 01122 ExAcquireFastMutex (&MmSectionCommitMutex); 01123 01124 PointerPte = StartingPte; 01125 01126 // 01127 // Check to ensure these pages can be committed if this 01128 // is a page file backed segment. Note that page file quota 01129 // has already been charged for this. 01130 // 01131 01132 QuotaCharge = 1 + LastPte - StartingPte; 01133 01134 // 01135 // Charge commitment for the range. Establish an 01136 // exception handler as this could raise an exception. 01137 // 01138 01139 QuotaFree = 0; 01140 01141 Status = STATUS_INVALID_VLM_OPERATION; 01142 ChargedExactQuota = FALSE; 01143 01144 for (; ; ) { 01145 GotResidentAvail = FALSE; 01146 LOCK_PFN (OldIrql); 01147 if (MI_NONPAGABLE_MEMORY_AVAILABLE (QuotaCharge)) { 01148 MmResidentAvailablePages -= (PFN_NUMBER) QuotaCharge; 01149 MM_BUMP_COUNTER(36, QuotaCharge); 01150 Status = STATUS_SUCCESS; 01151 GotResidentAvail = TRUE; 01152 } 01153 UNLOCK_PFN (OldIrql); 01154 01155 if (Status == STATUS_SUCCESS) { 01156 01157 try { 01158 MiChargeCommitment (QuotaCharge, NULL); 01159 } except (EXCEPTION_EXECUTE_HANDLER) { 01160 Status = GetExceptionCode(); 01161 } 01162 if (Status == STATUS_SUCCESS) { 01163 LOCK_PFN (OldIrql); 01164 MmSharedCommitVlm += QuotaCharge; 01165 UNLOCK_PFN (OldIrql); 01166 break; 01167 } 01168 } 01169 01170 // 01171 // Not enough resident pages or commmit for the commitment, 01172 // If we've already backed out the previously committed 01173 // pages from the charge, just return an error. 01174 // 01175 01176 if (GotResidentAvail == TRUE) { 01177 LOCK_PFN (OldIrql); 01178 MmResidentAvailablePages += (PFN_NUMBER) QuotaCharge; 01179 MM_BUMP_COUNTER(36, -QuotaCharge); 01180 UNLOCK_PFN (OldIrql); 01181 } 01182 01183 if (Status != STATUS_INVALID_VLM_OPERATION) { 01184 01185 // 01186 // We have already tried for the precise charge, 01187 // return an error. 01188 // 01189 01190 ExReleaseFastMutex (&MmSectionCommitMutex); 01191 goto ErrorReturn1; 01192 } 01193 01194 // 01195 // Quota charge failed, calculate the exact quota 01196 // taking into account pages that may already be 01197 // committed and retry the operation. 01198 // 01199 01200 while (PointerPte <= LastPte) { 01201 01202 // 01203 // Check to see if the prototype PTE is committed. 01204 // Note that prototype PTEs cannot be decommitted so 01205 // PTE only needs to be checked for zeroes. 01206 // 01207 // 01208 01209 if (PointerPte->u.Long != 0) { 01210 QuotaFree += 1; 01211 } 01212 PointerPte += 1; 01213 } 01214 01215 if (QuotaFree) { 01216 PointerPte = StartingPte; 01217 QuotaCharge -= QuotaFree; 01218 Status = STATUS_COMMITMENT_LIMIT; 01219 ChargedExactQuota = TRUE; 01220 } 01221 else { 01222 ExReleaseFastMutex (&MmSectionCommitMutex); 01223 goto ErrorReturn1; 01224 } 01225 } 01226 01227 // 01228 // Commit all the pages. 01229 // 01230 01231 QuotaFree = 0; 01232 TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate; 01233 01234 FoundVad->ControlArea->Segment->NumberOfCommittedPages += 01235 QuotaCharge; 01236 01237 while (PointerPte <= LastPte) { 01238 01239 if (PointerPte->u.Long != 0) { 01240 01241 // 01242 // Page is already committed, back out commitment. 01243 // 01244 01245 QuotaFree += 1; 01246 } else { 01247 *PointerPte = TempPte; 01248 } 01249 PointerPte += 1; 01250 } 01251 01252 if (ChargedExactQuota == TRUE) { 01253 QuotaFree = 0; 01254 } 01255 else { 01256 LOCK_PFN (OldIrql); 01257 MmSharedCommitVlm -= QuotaFree; 01258 UNLOCK_PFN (OldIrql); 01259 FoundVad->ControlArea->Segment->NumberOfCommittedPages -= 01260 QuotaFree; 01261 } 01262 01263 ExReleaseFastMutex (&MmSectionCommitMutex); 01264 ASSERT ((LONG)QuotaFree >= 0); 01265 01266 // 01267 // Change all the protections to be protected as specified. 01268 // 01269 01270 LOCK_WS (Process); 01271 01272 #if 0 //fixfix charge and update protection. 01273 MiSetProtectionOnSection (Process, 01274 FoundVad, 01275 StartingAddress, 01276 EndingAddress, 01277 Protect, 01278 &OldProtect, 01279 TRUE); 01280 01281 #endif //0 01282 } 01283 01284 UNLOCK_WS (Process); 01285 01286 if (QuotaFree != 0) { 01287 LOCK_PFN (OldIrql); 01288 MmResidentAvailablePages += (PFN_NUMBER) QuotaFree; 01289 MM_BUMP_COUNTER(25, QuotaFree); 01290 UNLOCK_PFN (OldIrql); 01291 } 01292 01293 // 01294 // Previously reserved pages have been committed, or an error occurred, 01295 // release working set lock, address creation lock, detach, 01296 // dereference process and return status. 01297 // 01298 01299 UNLOCK_ADDRESS_SPACE(Process); 01300 01301 if (Attached) { 01302 KeDetachProcess(); 01303 } 01304 if ( ProcessHandle != NtCurrentProcess() ) { 01305 ObDereferenceObject (Process); 01306 } 01307 01308 // 01309 // Establish an exception handler and write the size and base 01310 // address. 01311 // 01312 01313 try { 01314 01315 *RegionSize = CapturedRegionSize; 01316 *BaseAddress = StartingAddress; 01317 01318 } except (EXCEPTION_EXECUTE_HANDLER) { 01319 return GetExceptionCode(); 01320 } 01321 01322 #if 0 01323 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 01324 if ( MmWatchProcess ) { 01325 if ( MmWatchProcess == PsGetCurrentProcess() ) { 01326 DbgPrint("\n+++ ALLOC Type %lx Base %p Size %p\n", 01327 AllocationType,StartingAddress, CapturedRegionSize); 01328 MmFooBar(); 01329 } 01330 } else { 01331 DbgPrint("return allocvm status %lx baseaddr %p size %p\n", 01332 Status, CapturedRegionSize, StartingAddress); 01333 } 01334 } 01335 #endif 01336 01337 return STATUS_SUCCESS; 01338 } 01339 01340 ErrorReturn: 01341 UNLOCK_WS (Process); 01342 01343 ErrorReturn1: 01344 01345 UNLOCK_ADDRESS_SPACE (Process); 01346 if (Attached) { 01347 KeDetachProcess(); 01348 } 01349 if (ProcessHandle != NtCurrentProcess()) { 01350 ObDereferenceObject (Process); 01351 } 01352 return Status; 01353 } 01354 01355 NTSTATUS 01356 NtFreeVirtualMemory64( 01357 IN HANDLE ProcessHandle, 01358 IN OUT PVOID64 *BaseAddress, 01359 IN OUT PULONGLONG RegionSize, 01360 IN ULONG FreeType 01361 ) 01362 01363 /*++ 01364 01365 Routine Description: 01366 01367 This function deletes a region of pages within the virtual address 01368 space of a subject process. 01369 01370 Arguments: 01371 01372 ProcessHandle - An open handle to a process object. 01373 01374 BaseAddress - The base address of the region of pages 01375 to be freed. This value is rounded down to the 01376 next host page address boundary. 01377 01378 RegionSize - A pointer to a variable that will receive 01379 the actual size in bytes of the freed region of 01380 pages. The initial value of this argument is 01381 rounded up to the next host page size boundary. 01382 01383 FreeType - A set of flags that describe the type of free that is to 01384 be performed for the specified region of pages. 01385 01386 01387 FreeType Flags 01388 01389 01390 MEM_DECOMMIT - The specified region of pages is to 01391 be decommitted. 01392 01393 MEM_RELEASE - The specified region of pages is to 01394 be released. 01395 01396 01397 Return Value: 01398 01399 Returns the status 01400 01401 TBS 01402 01403 01404 --*/ 01405 01406 { 01407 PMMVAD_SHORT Vad; 01408 PMMVAD_SHORT NewVad; 01409 PMMVAD PreviousVad; 01410 PMMVAD NextVad; 01411 PEPROCESS Process; 01412 KPROCESSOR_MODE PreviousMode; 01413 PVOID64 StartingAddress; 01414 PVOID64 EndingAddress; 01415 NTSTATUS Status; 01416 LOGICAL Attached; 01417 ULONGLONG CapturedRegionSize; 01418 PVOID64 CapturedBase; 01419 PMMPTE StartingPte; 01420 PMMPTE EndingPte; 01421 SIZE_T OldQuota; 01422 SIZE_T QuotaCharge; 01423 SIZE_T CommitReduction; 01424 ULONG OldEnd; 01425 KIRQL OldIrql; 01426 PMI_PROCESS_VLM_INFO VlmInfo; 01427 01428 PAGED_CODE(); 01429 01430 Attached = FALSE; 01431 01432 if (MI_VLM_ENABLED() == FALSE) { 01433 return STATUS_NOT_IMPLEMENTED; 01434 } 01435 01436 // 01437 // Check to make sure FreeType is good. 01438 // 01439 01440 if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) { 01441 return STATUS_INVALID_PARAMETER_4; 01442 } 01443 01444 // 01445 // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both. 01446 // 01447 01448 if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) || 01449 ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 01450 (MEM_DECOMMIT | MEM_RELEASE))) { 01451 return STATUS_INVALID_PARAMETER_4; 01452 } 01453 01454 PreviousMode = KeGetPreviousMode(); 01455 01456 // 01457 // Establish an exception handler, probe the specified addresses 01458 // for write access and capture the initial values. 01459 // 01460 01461 try { 01462 01463 if (PreviousMode != KernelMode) { 01464 01465 ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 01466 ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG)); 01467 } 01468 01469 // 01470 // Capture the base address. 01471 // 01472 01473 CapturedBase = *BaseAddress; 01474 01475 // 01476 // Capture the region size. 01477 // 01478 01479 CapturedRegionSize = *RegionSize; 01480 01481 } except (ExSystemExceptionFilter()) { 01482 01483 // 01484 // If an exception occurs during the probe or capture 01485 // of the initial values, then handle the exception and 01486 // return the exception code as the status value. 01487 // 01488 01489 return GetExceptionCode(); 01490 } 01491 01492 #if 0 01493 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 01494 if ( !MmWatchProcess ) { 01495 DbgPrint("freevm processhandle %lx base %p size %p type %lx\n", 01496 ProcessHandle, CapturedBase, CapturedRegionSize, FreeType); 01497 } 01498 } 01499 #endif 01500 01501 if ((CapturedRegionSize != 0) && (FreeType & MEM_RELEASE)) { 01502 return STATUS_FREE_VM_NOT_AT_BASE; 01503 } 01504 01505 // 01506 // Make sure the specified starting and ending addresses are 01507 // within the user part of the virtual address space. 01508 // 01509 01510 if (CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) { 01511 01512 // 01513 // Invalid base address. 01514 // 01515 01516 return STATUS_INVALID_PARAMETER_2; 01517 } 01518 01519 if ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)CapturedBase < 01520 CapturedRegionSize) { 01521 01522 // 01523 // Invalid region size; 01524 // 01525 01526 return STATUS_INVALID_PARAMETER_3; 01527 01528 } 01529 01530 EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + CapturedRegionSize - 1) | 01531 (PAGE_SIZE - 1)); 01532 01533 StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase); 01534 01535 if ( ProcessHandle == NtCurrentProcess() ) { 01536 Process = PsGetCurrentProcess(); 01537 } else { 01538 01539 // 01540 // Reference the specified process handle for VM_OPERATION access. 01541 // 01542 01543 Status = ObReferenceObjectByHandle ( ProcessHandle, 01544 PROCESS_VM_OPERATION, 01545 PsProcessType, 01546 PreviousMode, 01547 (PVOID *)&Process, 01548 NULL ); 01549 if (!NT_SUCCESS(Status)) { 01550 return Status; 01551 } 01552 } 01553 01554 // 01555 // If the specified process is not the current process, attach 01556 // to the specified process. 01557 // 01558 01559 if (PsGetCurrentProcess() != Process) { 01560 KeAttachProcess (&Process->Pcb); 01561 Attached = TRUE; 01562 } 01563 01564 01565 // 01566 // Get the address creation mutex to block multiple threads from 01567 // creating or deleting address space at the same time and 01568 // get the working set mutex so virtual address descriptors can 01569 // be inserted and walked. Block APCs to prevent page faults while 01570 // we own the working set mutex. 01571 // 01572 01573 LOCK_WS_AND_ADDRESS_SPACE (Process); 01574 01575 // 01576 // Make sure the address space was not deleted. 01577 // 01578 01579 if (Process->AddressSpaceDeleted != 0) { 01580 Status = STATUS_PROCESS_IS_TERMINATING; 01581 goto ErrorReturn; 01582 } 01583 01584 if (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED) { 01585 Status = STATUS_MEMORY_NOT_ALLOCATED; 01586 goto ErrorReturn; 01587 } 01588 01589 Vad = (PMMVAD_SHORT)MiLocateAddress64 (MI_VA_TO_VPN64 (StartingAddress)); 01590 01591 if (Vad == NULL) { 01592 01593 // 01594 // No Virtual Address Descriptor located for Base Address. 01595 // 01596 01597 Status = STATUS_MEMORY_NOT_ALLOCATED; 01598 goto ErrorReturn; 01599 } 01600 01601 // 01602 // Found the associated Virtual Address Descriptor. 01603 // 01604 01605 if (Vad->EndingVpn < MI_VA_TO_VPN64 (EndingAddress)) { 01606 01607 // 01608 // The entire range to delete is not contained within a single 01609 // virtual address descriptor. Return an error. 01610 // 01611 01612 Status = STATUS_UNABLE_TO_FREE_VM; 01613 goto ErrorReturn; 01614 } 01615 01616 // 01617 // Check to ensure this Vad is deletable. Delete is required 01618 // for both decommit and release. 01619 // 01620 01621 if ((Vad->u.VadFlags.PrivateMemory == 0) || 01622 (Vad->u.VadFlags.PhysicalMapping == 1)) { 01623 Status = STATUS_UNABLE_TO_DELETE_SECTION; 01624 goto ErrorReturn; 01625 } 01626 01627 ASSERT (Vad->u.VadFlags.NoChange == 0); 01628 01629 if (FreeType & MEM_RELEASE) { 01630 01631 // 01632 // ***************************************************************** 01633 // MEM_RELEASE was specified. 01634 // ***************************************************************** 01635 // 01636 01637 // 01638 // The descriptor for the address range is deletable. Remove the 01639 // the descriptor. 01640 // 01641 01642 ASSERT (CapturedRegionSize == 0); 01643 01644 // 01645 // If the region size is specified as 0, the base address 01646 // must be the starting address for the region. 01647 // 01648 01649 if (MI_VA_TO_VPN64 (CapturedBase) != Vad->StartingVpn) { 01650 Status = STATUS_FREE_VM_NOT_AT_BASE; 01651 goto ErrorReturn; 01652 } 01653 01654 // 01655 // This Virtual Address Descriptor has been deleted. 01656 // 01657 01658 StartingAddress = MI_VPN_TO_VA64 (Vad->StartingVpn); 01659 StartingPte = MiGetPteAddress64 (StartingAddress); 01660 EndingAddress = MI_VPN_TO_VA64 (Vad->EndingVpn); 01661 EndingPte = MiGetPteAddress64 (EndingAddress); 01662 CapturedRegionSize = ((EndingPte - StartingPte + 1) << PAGE_SHIFT); 01663 MiRemoveVad64 ((PMMVAD)Vad); 01664 ExFreePool (Vad); 01665 01666 // 01667 // Get the PFN mutex so that MiDeleteVirtualAddresses can be called. 01668 // 01669 01670 CommitReduction = MiDecommitOrDeletePages64 (StartingPte, 01671 EndingPte, 01672 Process, 01673 DELETE_TYPE_PRIVATE, 01674 TRUE); 01675 UNLOCK_WS (Process); 01676 01677 // 01678 // Update the virtual size in the process header. 01679 // 01680 01681 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 01682 VlmInfo->VirtualSize -= CapturedRegionSize; 01683 VlmInfo->CommitCharge -= CommitReduction; 01684 01685 ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql); 01686 MiVlmCommitChargeInPages -= CommitReduction; 01687 ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql); 01688 01689 UNLOCK_ADDRESS_SPACE (Process); 01690 01691 if (Attached) { 01692 KeDetachProcess(); 01693 } 01694 01695 if ( ProcessHandle != NtCurrentProcess() ) { 01696 ObDereferenceObject (Process); 01697 } 01698 // 01699 // Establish an exception handler and write the size and base 01700 // address. 01701 // 01702 01703 try { 01704 01705 *RegionSize = CapturedRegionSize; 01706 *BaseAddress = StartingAddress; 01707 01708 } except (EXCEPTION_EXECUTE_HANDLER) { 01709 01710 // 01711 // An exception occurred, don't take any action (just handle 01712 // the exception and return success. 01713 01714 } 01715 01716 #if 0 01717 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 01718 if ( MmWatchProcess ) { 01719 if ( MmWatchProcess == PsGetCurrentProcess() ) { 01720 DbgPrint("\n--- FREE Type 0x%lx Base %p Size %p\n", 01721 FreeType, StartingAddress, CapturedRegionSize); 01722 MmFooBar(); 01723 } 01724 } 01725 } 01726 #endif 01727 01728 return STATUS_SUCCESS; 01729 } 01730 01731 // 01732 // ************************************************************** 01733 // 01734 // MEM_DECOMMIT was specified. 01735 // 01736 // ************************************************************** 01737 // 01738 01739 // 01740 // Check to ensure the complete range of pages is already committed. 01741 // 01742 01743 if (CapturedRegionSize == 0) { 01744 01745 if (MI_VA_TO_VPN64 (CapturedBase) != Vad->StartingVpn) { 01746 Status = STATUS_FREE_VM_NOT_AT_BASE; 01747 goto ErrorReturn; 01748 } 01749 EndingAddress = MI_VPN_TO_VA_ENDING64 (Vad->EndingVpn); 01750 } 01751 01752 // 01753 // Calculate the initial quotas and commit charges for this VAD. 01754 // 01755 01756 StartingPte = MiGetPteAddress64 (StartingAddress); 01757 EndingPte = MiGetPteAddress64 (EndingAddress); 01758 01759 CapturedRegionSize = 1 + (ULONGLONG)EndingAddress - (ULONGLONG)StartingAddress; 01760 01761 CommitReduction = MiDecommitOrDeletePages64 (StartingPte, 01762 EndingPte, 01763 Process, 01764 DELETE_TYPE_PRIVATE, 01765 TRUE); 01766 01767 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 01768 VlmInfo->CommitCharge -= CommitReduction; 01769 01770 ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql); 01771 MiVlmCommitChargeInPages -= CommitReduction; 01772 ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql); 01773 01774 UNLOCK_WS (Process); 01775 UNLOCK_ADDRESS_SPACE (Process); 01776 01777 if (Attached) { 01778 KeDetachProcess(); 01779 } 01780 if (ProcessHandle != NtCurrentProcess()) { 01781 ObDereferenceObject (Process); 01782 } 01783 01784 // 01785 // Establish an exception handler and write the size and base 01786 // address. 01787 // 01788 01789 try { 01790 01791 *RegionSize = CapturedRegionSize; 01792 *BaseAddress = StartingAddress; 01793 01794 } except (EXCEPTION_EXECUTE_HANDLER) { 01795 NOTHING; 01796 } 01797 01798 return STATUS_SUCCESS; 01799 01800 ErrorReturn: 01801 01802 UNLOCK_WS (Process); 01803 UNLOCK_ADDRESS_SPACE (Process); 01804 01805 if (Attached) { 01806 KeDetachProcess(); 01807 } 01808 01809 if (ProcessHandle != NtCurrentProcess()) { 01810 ObDereferenceObject (Process); 01811 } 01812 01813 return Status; 01814 } 01815 01816 01817 PVOID64 01818 MiFindEmptyAddressRangeInTree64 ( 01819 IN ULONGLONG SizeOfRange64, 01820 IN ULONG_PTR Alignment, 01821 IN PMMADDRESS_NODE Root 01822 ) 01823 01824 /*++ 01825 01826 Routine Description: 01827 01828 The function examines the virtual address descriptors to locate 01829 an unused range of the specified size and returns the starting 01830 address of the range. 01831 01832 Arguments: 01833 01834 SizeOfRange - Supplies the size in bytes of the range to locate. 01835 01836 Alignment - Supplies the alignment for the address. Must be 01837 a power of 2 and greater than the page_size. 01838 01839 Root - Supplies the root of the tree to search through. 01840 01841 01842 Return Value: 01843 01844 Returns the starting address of a suitable range. 01845 01846 --*/ 01847 01848 { 01849 PMMADDRESS_NODE Node; 01850 PMMADDRESS_NODE NextNode; 01851 ULONG_PTR AlignmentVpn; 01852 ULONG SizeOfRange; 01853 PVOID64 Start; 01854 01855 AlignmentVpn = Alignment >> PAGE_SHIFT; 01856 01857 // 01858 // Locate the Node with the lowest starting address. 01859 // 01860 01861 SizeOfRange = (ULONG)((SizeOfRange64 + (PAGE_SIZE - 1)) >> PAGE_SHIFT); 01862 ASSERT (SizeOfRange != 0); 01863 01864 Node = Root; 01865 01866 if (Node == (PMMADDRESS_NODE)NULL) { 01867 return (PVOID64)MM_LOWEST_USER_ADDRESS64; 01868 } 01869 while (Node->LeftChild != (PMMADDRESS_NODE)NULL) { 01870 Node = Node->LeftChild; 01871 } 01872 01873 // 01874 // Check to see if a range exists between the lowest address VAD 01875 // and lowest user address. 01876 // 01877 01878 if (Node->StartingVpn > MI_VA_TO_VPN64 (MM_LOWEST_USER_ADDRESS64)) { 01879 if ( SizeOfRange < 01880 (Node->StartingVpn - MI_VA_TO_VPN64 (MM_LOWEST_USER_ADDRESS64))) { 01881 01882 return (PVOID64)MM_LOWEST_USER_ADDRESS64; 01883 } 01884 } 01885 01886 for (;;) { 01887 01888 NextNode = MiGetNextNode (Node); 01889 01890 if (NextNode != (PMMADDRESS_NODE)NULL) { 01891 01892 if (SizeOfRange <= 01893 ((ULONG_PTR)NextNode->StartingVpn - 01894 MI_ROUND_TO_SIZE(1 + Node->EndingVpn, 01895 AlignmentVpn))) { 01896 01897 // 01898 // Check to ensure that the ending address aligned upwards 01899 // is not greater than the starting address. 01900 // 01901 01902 if ((ULONG_PTR)NextNode->StartingVpn > 01903 MI_ROUND_TO_SIZE(1 + Node->EndingVpn, 01904 AlignmentVpn)) { 01905 01906 return (PVOID64)MI_ROUND_TO_SIZE( 01907 (ULONGLONG)(MI_VPN_TO_VA_ENDING64(Node->EndingVpn)), 01908 (ULONGLONG)Alignment); 01909 } 01910 } 01911 01912 } else { 01913 01914 // 01915 // No more descriptors, check to see if this fits into the remainder 01916 // of the address space. 01917 // 01918 01919 if ((((ULONG_PTR)Node->EndingVpn + MI_VA_TO_VPN(X64K)) < 01920 MI_VA_TO_VPN64 (MM_HIGHEST_VAD_ADDRESS64)) 01921 && 01922 (SizeOfRange64 <= 01923 ((ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 - X64K - 01924 MI_ROUND_TO_SIZE( 01925 (ULONGLONG)(MI_VPN_TO_VA64(Node->EndingVpn)), 01926 (ULONGLONG)Alignment)))) { 01927 01928 Start = MI_VPN_TO_VA_ENDING64 (Node->EndingVpn); 01929 ASSERT (MI_VA_TO_VPN64 (Start) == Node->EndingVpn); 01930 01931 Start = (PVOID64)MI_ROUND_TO_SIZE((ULONGLONG)Start, 01932 (ULONGLONG)Alignment); 01933 ASSERT (MI_VA_TO_VPN64 (Start) > Node->EndingVpn); 01934 return Start; 01935 } else { 01936 ExRaiseStatus (STATUS_NO_MEMORY); 01937 } 01938 } 01939 Node = NextNode; 01940 } 01941 } 01942 01943 LOGICAL 01944 MiCommitPages64 ( 01945 IN PMMPTE StartPte, 01946 IN PMMPTE LastPte, 01947 IN ULONG ProtectionMask, 01948 IN PEPROCESS Process, 01949 OUT PSIZE_T PtesCommitted 01950 ) 01951 01952 /*++ 01953 01954 Routine Description: 01955 01956 This function commits by making each page valid in the specified range of 01957 PTEs. It also changes the protection of any existing valid PTEs in 01958 the specified range. 01959 01960 Arguments: 01961 01962 StartPte - First PTE in the range. 01963 01964 LastPte - Last PTE in the range. 01965 01966 ProtectionMask - Protection mask to set in the valid PTEs. 01967 01968 Process - Pointer to the process object of the subject process. 01969 01970 PtesCommitted - Supplies a pointer to receive the number of valid PTEs 01971 encountered in the range. 01972 01973 Return Value: 01974 01975 TRUE if the pages were committed, FALSE if not. 01976 01977 Environment: 01978 01979 Process Working Set Lock held. 01980 01981 --*/ 01982 01983 { 01984 PMMPTE PointerPte; 01985 PMMPTE PointerPde; 01986 MMPTE TempPte; 01987 PFN_NUMBER PageFrameIndex; 01988 PMMPFN Pfn1; 01989 ULONG PageColor; 01990 KIRQL OldIrql; 01991 ULONG BarrierStamp; 01992 LOGICAL TopPdeBuilt; 01993 LOGICAL PdeBuilt; 01994 PUSHORT UsedPde64Handle; 01995 01996 *PtesCommitted = 0; 01997 PointerPde = MiGetPteAddress (StartPte); 01998 01999 // 02000 // Fill in all the page table pages with the valid PTEs. 02001 // 02002 02003 TopPdeBuilt = MiMakePdeExistAndMakeValid64 (PointerPde, Process, FALSE, TRUE); 02004 if (TopPdeBuilt == FALSE) { 02005 return FALSE; 02006 } 02007 02008 UsedPde64Handle = MI_GET_USED_PDE64_HANDLE (PointerPde); 02009 02010 PointerPte = StartPte; 02011 while (PointerPte <= LastPte) { 02012 02013 if (MiIsPteOnPdeBoundary(PointerPte)) { 02014 02015 // 02016 // Pointing to the next page table page, make 02017 // a page table page exist and make it valid. 02018 // 02019 02020 PointerPde = MiGetPteAddress (PointerPte); 02021 UsedPde64Handle = MI_GET_USED_PDE64_HANDLE (PointerPde); 02022 02023 // 02024 // This call will always succeed since the top level PDE already 02025 // exists. 02026 // 02027 02028 PdeBuilt = MiMakePdeExistAndMakeValid64 (PointerPde, Process, FALSE, TRUE); 02029 ASSERT (PdeBuilt == TRUE); 02030 } 02031 02032 if (PointerPte->u.Long == 0) { 02033 02034 PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPte, 02035 &Process->NextPageColor); 02036 PointerPte->u.Soft.Protection = ProtectionMask; 02037 LOCK_PFN (OldIrql); 02038 02039 // 02040 // There can be no races on private PTEs (just PDEs) so even 02041 // if a wait state occurs, nothing needs to be rechecked. 02042 // 02043 02044 MiEnsureAvailablePageOrWait (Process, NULL); 02045 02046 PageFrameIndex = MiRemoveZeroPage (PageColor); 02047 02048 BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame; 02049 02050 MiInitializePfn (PageFrameIndex, PointerPte, 1); 02051 UNLOCK_PFN (OldIrql); 02052 02053 MI_MAKE_VALID_PTE (TempPte, 02054 PageFrameIndex, 02055 ProtectionMask, 02056 NULL); 02057 02058 if (TempPte.u.Hard.Write) { 02059 MI_SET_PTE_DIRTY (TempPte); 02060 } 02061 02062 MI_BARRIER_SYNCHRONIZE (BarrierStamp); 02063 02064 *PointerPte = TempPte; 02065 (*UsedPde64Handle) += 1; 02066 02067 } else { 02068 ASSERT (PointerPte->u.Hard.Valid == 1); 02069 (*PtesCommitted) += 1; 02070 02071 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 02072 02073 if (Pfn1->OriginalPte.u.Soft.Protection != ProtectionMask) { 02074 02075 // 02076 // Change protection to match specified protection. 02077 // 02078 02079 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 02080 MI_MAKE_VALID_PTE (TempPte, 02081 PointerPte->u.Hard.PageFrameNumber, 02082 ProtectionMask, 02083 NULL); 02084 if (TempPte.u.Hard.Write) { 02085 MI_SET_PTE_DIRTY (TempPte); 02086 } 02087 02088 // 02089 // Flush the TB as we have changed the protection 02090 // of a valid PTE. 02091 // 02092 02093 MiFlushTbAndCapture (PointerPte, 02094 TempPte.u.Flush, 02095 Pfn1); 02096 } 02097 } 02098 PointerPte += 1; 02099 } 02100 return TRUE; 02101 } 02102 02103 LOGICAL 02104 MiMakePdeExistAndMakeValid64 ( 02105 IN PMMPTE PointerPde, 02106 IN PEPROCESS TargetProcess, 02107 IN LOGICAL PfnLockHeld, 02108 IN LOGICAL MakePageTablePage 02109 ) 02110 02111 /*++ 02112 02113 Routine Description: 02114 02115 This routine examines the specified Page Directory Entry to determine 02116 if the page table page mapped by the PDE exists. 02117 02118 If the page table page exists and is not currently in memory, the 02119 working set mutex and, if held, the PFN mutex are released and the 02120 page table page is faulted into the working set. The mutexes are 02121 required. 02122 02123 If the PDE exists, the function returns TRUE. 02124 02125 If the PDE does not exist, a zero filled PTE is created and it 02126 too is brought into the working set. In this case the return 02127 value is FALSE. 02128 02129 Arguments: 02130 02131 PointerPde - Supplies a pointer to the PDE to examine and bring 02132 into the working set. 02133 02134 TargetProcess - Supplies a pointer to the current process. 02135 02136 PfnLockHeld - Supplies the value TRUE if the PFN mutex is held, FALSE 02137 otherwise. 02138 02139 MakePageTablePage - Supplies the value TRUE if the PDE is to be created. 02140 FALSE if not - meaning just the top level Base is 02141 to be created. 02142 02143 Return Value: 02144 02145 TRUE if the PDE exists, FALSE if the PDE was created. 02146 02147 Environment: 02148 02149 Kernel mode, APCs disabled, WorkingSetLock and AddressSpace locks held. 02150 02151 --*/ 02152 02153 { 02154 PMMPTE PointerPte; 02155 KIRQL OldIrql; 02156 MMPTE TempPte; 02157 ULONG PageColor; 02158 PFN_NUMBER PageFrameIndex; 02159 ULONG BarrierStamp; 02160 PMI_PROCESS_VLM_INFO VlmInfo; 02161 PMMPTE PdeBase; 02162 02163 VlmInfo = NULL; 02164 02165 // 02166 // Make sure the Page Directory Page for this 32GB region exists. 02167 // 02168 02169 PointerPte = MiGetPteAddress (PointerPde); 02170 02171 redo: 02172 02173 if (PointerPte->u.Long == 0) { 02174 02175 // 02176 // Make a page directory page. 02177 // 02178 02179 if (VlmInfo == NULL) { 02180 02181 if (PfnLockHeld) { 02182 UNLOCK_PFN (OldIrql); 02183 } 02184 02185 UNLOCK_WS (TargetProcess); 02186 02187 VlmInfo = (PMI_PROCESS_VLM_INFO) ExAllocatePoolWithTag ( 02188 NonPagedPool, 02189 sizeof (MI_PROCESS_VLM_INFO), 02190 'lVmM'); 02191 02192 if (VlmInfo) { 02193 RtlZeroMemory (VlmInfo, 02194 sizeof (MI_PROCESS_VLM_INFO)); 02195 } 02196 02197 LOCK_WS (TargetProcess); 02198 02199 if (PfnLockHeld) { 02200 LOCK_PFN (OldIrql); 02201 } 02202 02203 if (VlmInfo == NULL) { 02204 return FALSE; 02205 } 02206 02207 // 02208 // Since locks were released, everything must be rechecked. 02209 // Note the VAD cannot disappear as the address space lock was 02210 // held all the way through. 02211 // 02212 02213 goto redo; 02214 } 02215 02216 PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPte, 02217 &TargetProcess->NextPageColor); 02218 if (!PfnLockHeld) { 02219 LOCK_PFN (OldIrql); 02220 } 02221 02222 if (MiEnsureAvailablePageOrWait (TargetProcess, NULL) == TRUE) { 02223 02224 // 02225 // A wait state occurred, everything must be rechecked. 02226 // 02227 02228 goto redo; 02229 } 02230 02231 PageFrameIndex = MiRemoveZeroPage (PageColor); 02232 BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame; 02233 MiInitializePfn (PageFrameIndex, PointerPte, 1); 02234 02235 if (!PfnLockHeld) { 02236 UNLOCK_PFN (OldIrql); 02237 } 02238 02239 MI_MAKE_VALID_PTE (TempPte, 02240 PageFrameIndex, 02241 MM_READWRITE, 02242 NULL); 02243 02244 MI_SET_PTE_DIRTY (TempPte); 02245 02246 MI_BARRIER_SYNCHRONIZE (BarrierStamp); 02247 02248 *PointerPte = TempPte; 02249 02250 // 02251 // Stash the used page table page counts pointer in the PDE_BASE64. 02252 // 02253 02254 PdeBase = MiGetVirtualAddressMappedByPte (PointerPte); 02255 02256 // 02257 // This will always be true unless VLM is expanded past 32GB. 02258 // 02259 02260 ASSERT (PdeBase == (PMMPTE)PDE_BASE64); 02261 02262 PdeBase->u.Long = (ULONG)VlmInfo; 02263 } 02264 else { 02265 if (VlmInfo) { 02266 ExFreePool (VlmInfo); 02267 } 02268 } 02269 02270 ASSERT (PointerPte->u.Hard.Valid == 1); 02271 02272 if (MakePageTablePage == FALSE) { 02273 return TRUE; 02274 } 02275 02276 redo2: 02277 02278 if (PointerPde->u.Hard.Valid == 1) { 02279 02280 // 02281 // Already valid. 02282 // 02283 02284 return TRUE; 02285 } 02286 02287 // 02288 // Page directory entry not valid, make it valid. 02289 // 02290 02291 PageColor = MI_PAGE_COLOR_PTE_PROCESS (PointerPde, 02292 &TargetProcess->NextPageColor); 02293 if (!PfnLockHeld) { 02294 LOCK_PFN (OldIrql); 02295 } 02296 02297 if (MiEnsureAvailablePageOrWait (TargetProcess, NULL) == TRUE) { 02298 02299 // 02300 // A wait state occurred, everything from the PDE down must 02301 // be rechecked. 02302 // 02303 02304 if (!PfnLockHeld) { 02305 UNLOCK_PFN (OldIrql); 02306 } 02307 goto redo2; 02308 } 02309 02310 PageFrameIndex = MiRemoveZeroPage (PageColor); 02311 BarrierStamp = MI_PFN_ELEMENT(PageFrameIndex)->PteFrame; 02312 MiInitializePfn (PageFrameIndex, PointerPde, 1); 02313 02314 if (!PfnLockHeld) { 02315 UNLOCK_PFN (OldIrql); 02316 } 02317 02318 MI_MAKE_VALID_PTE (TempPte, 02319 PageFrameIndex, 02320 MM_READWRITE, 02321 NULL); 02322 02323 MI_SET_PTE_DIRTY (TempPte); 02324 02325 MI_BARRIER_SYNCHRONIZE (BarrierStamp); 02326 02327 *PointerPde = TempPte; 02328 02329 return TRUE; 02330 } 02331 02332 ULONG 02333 MiDoesPdeExist64 ( 02334 IN PMMPTE PointerPde 02335 ) 02336 02337 /*++ 02338 02339 Routine Description: 02340 02341 This routine examines the specified Page Directory Entry to determine 02342 if the page table page mapped by the PDE exists. 02343 02344 If the page table page exists and is not currently in memory, the 02345 working set mutex and, if held, the PFN mutex are released and the 02346 page table page is faulted into the working set. The mutexes are 02347 required. 02348 02349 If the PDE exists, the function returns true. 02350 02351 Arguments: 02352 02353 PointerPde - Supplies a pointer to the PDE to examine and potentially 02354 bring into the working set. 02355 02356 TargetProcess - Supplies a pointer to the current process. 02357 02358 PfnMutexHeld - Supplies the value TRUE if the PFN mutex is held, FALSE 02359 otherwise. 02360 02361 Return Value: 02362 02363 TRUE if the PDE exists, FALSE if the PDE is zero. 02364 02365 Environment: 02366 02367 Kernel mode, APCs disabled, WorkingSetLock held. 02368 02369 --*/ 02370 02371 { 02372 PMMPTE PointerPte; 02373 PMI_PROCESS_VLM_INFO VlmInfo; 02374 02375 PointerPte = MiGetPteAddress(PointerPde); 02376 if (PointerPte->u.Long == 0) { 02377 02378 // 02379 // This page directory entry doesn't exist, return FALSE. 02380 // 02381 02382 return FALSE; 02383 } 02384 02385 if (PointerPde->u.Long == 0) { 02386 02387 // 02388 // This page directory entry doesn't exist, return FALSE. 02389 // 02390 02391 return FALSE; 02392 } 02393 02394 ASSERT (PointerPde->u.Hard.Valid == 1); 02395 02396 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 02397 ASSERT (VlmInfo != NULL); 02398 02399 return TRUE; 02400 } 02401 02402 ULONG 02403 MiDecommitOrDeletePages64 ( 02404 IN PMMPTE StartingPte, 02405 IN PMMPTE EndingPte, 02406 IN PEPROCESS Process, 02407 IN ULONG Type, 02408 IN LOGICAL FlushTb 02409 ) 02410 02411 /*++ 02412 02413 Routine Description: 02414 02415 This routine decommits the specified range of pages. 02416 02417 Arguments: 02418 02419 StartingAddress - Supplies the starting address of the range. 02420 02421 EndingPte - Supplies the ending PTE of the range. 02422 02423 Process - Supplies the current process. 02424 02425 Type - One of: DELETE_TYPE_PRIVATE for private memory or DELETE_TYPE_SHARED 02426 for shared memory. 02427 02428 FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not. 02429 02430 Return Value: 02431 02432 Value to reduce commitment by for the VAD. 02433 02434 Environment: 02435 02436 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02437 held. 02438 02439 --*/ 02440 02441 { 02442 PMMPTE PointerPde; 02443 PMMPTE PointerPte; 02444 ULONG PdeOffset; 02445 PFN_NUMBER CommitReduction; 02446 PMMPTE CommitLimitPte; 02447 KIRQL OldIrql; 02448 PMMPTE ValidPteList[MM_VALID_PTE_SIZE]; 02449 ULONG count; 02450 ULONG WorkingSetIndex; 02451 PMMPFN Pfn1; 02452 PMMPFN Pfn2; 02453 PVOID SwapVa; 02454 ULONG Entry; 02455 MMPTE PteContents; 02456 MMPTE NewPte; 02457 ULONG PfnLockHeld; 02458 PMMPTE LowestPde; 02459 PMI_PROCESS_VLM_INFO VlmInfo; 02460 02461 count = 0; 02462 PfnLockHeld = FALSE; 02463 CommitReduction = 0; 02464 02465 // 02466 // Decommit each page by setting the PTE to be explicitly 02467 // decommitted. The PTEs cannot be deleted all at once as 02468 // this would set the PTEs to zero which would auto-evaluate 02469 // as committed if referenced by another thread when a page 02470 // table page is being in-paged. 02471 // 02472 02473 PointerPte = StartingPte; 02474 PointerPde = MiGetPteAddress (StartingPte); 02475 02476 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 02477 LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64); 02478 02479 // 02480 // Loop through all the PDEs which map this region and ensure that 02481 // they exist. If they don't exist create them by touching a 02482 // PTE mapped by the PDE. 02483 // 02484 02485 if (!MiDoesPdeExist64 (PointerPde)) { 02486 PointerPte = (PMMPTE)PAGE_ALIGN (PointerPte); 02487 PointerPte += PTE_PER_PAGE; 02488 } 02489 02490 while (PointerPte <= EndingPte) { 02491 02492 if (MiIsPteOnPdeBoundary(PointerPte)) { 02493 02494 if (count != 0) { 02495 MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb); 02496 count = 0; 02497 } 02498 02499 if (PfnLockHeld) { 02500 UNLOCK_PFN (OldIrql); 02501 } 02502 02503 MiCheckPdeForDeletion (PointerPde, FlushTb); 02504 PointerPde = MiGetPteAddress (PointerPte); 02505 02506 if (!MiDoesPdeExist64 (PointerPde)) { 02507 PointerPte += PTE_PER_PAGE; 02508 continue; 02509 } 02510 if (PfnLockHeld) { 02511 LOCK_PFN (OldIrql); 02512 } 02513 } 02514 02515 // 02516 // The working set lock is held. No PTEs can go from 02517 // invalid to valid or valid to invalid. Transition 02518 // PTEs can go from transition to pagefile. 02519 // 02520 02521 PteContents = *PointerPte; 02522 02523 if (PteContents.u.Long != 0) { 02524 02525 VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] -= 1; 02526 02527 if (PteContents.u.Hard.Valid == 1) { 02528 if (Type == DELETE_TYPE_PRIVATE) { 02529 CommitReduction += 1; 02530 } 02531 02532 // 02533 // Pte is valid, process later when PFN lock is held. 02534 // 02535 02536 if (count == MM_VALID_PTE_SIZE) { 02537 MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb); 02538 count = 0; 02539 } 02540 ValidPteList[count] = PointerPte; 02541 count += 1; 02542 } else if (PteContents.u.Soft.Prototype == 1) { 02543 NOTHING; 02544 02545 } else if (PteContents.u.Soft.Transition == 1) { 02546 02547 // 02548 // This is a transition PTE. (Page is private) 02549 // 02550 // Get the PFN mutex so that MiDeletePte can be called. 02551 // 02552 02553 if (!PfnLockHeld) { 02554 LOCK_PFN (OldIrql); 02555 PfnLockHeld = TRUE; 02556 continue; 02557 } 02558 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 02559 02560 MI_SET_PFN_DELETED (Pfn1); 02561 02562 MiDecrementShareCount (Pfn1->PteFrame); 02563 02564 // 02565 // Check the reference count for the page, if the reference 02566 // count is zero, move the page to the free list, if the 02567 // reference count is not zero, ignore this page. When the 02568 // reference count goes to zero, it will be placed on the 02569 // free list. 02570 // 02571 02572 if (Pfn1->u3.e2.ReferenceCount == 0) { 02573 MiUnlinkPageFromList (Pfn1); 02574 MiReleasePageFileSpace (Pfn1->OriginalPte); 02575 MiInsertPageInList (MmPageLocationList[FreePageList], 02576 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents)); 02577 } 02578 } else { 02579 ASSERT (PteContents.u.Soft.PageFileHigh == 0); 02580 } 02581 } 02582 02583 if (PfnLockHeld) { 02584 UNLOCK_PFN (OldIrql); 02585 PfnLockHeld = FALSE; 02586 } 02587 PointerPte += 1; 02588 } 02589 if (count != 0) { 02590 MiProcessValidPteList64 (&ValidPteList[0], count, FlushTb); 02591 } 02592 02593 MiCheckPdeForDeletion (PointerPde, FlushTb); 02594 02595 MiReturnAvailablePages (CommitReduction); 02596 02597 return CommitReduction; 02598 } 02599 VOID 02600 MiProcessValidPteList64 ( 02601 IN PMMPTE *ValidPteList, 02602 IN ULONG Count, 02603 IN LOGICAL FlushTb 02604 ) 02605 02606 /*++ 02607 02608 Routine Description: 02609 02610 This routine flushes the specified range of valid PTEs. 02611 02612 Arguments: 02613 02614 ValidPteList - Supplies a pointer to an array of PTEs to flush. 02615 02616 Count - Supplies the count of the number of elements in the array. 02617 02618 FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not. 02619 02620 Return Value: 02621 02622 none. 02623 02624 Environment: 02625 02626 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02627 held. 02628 02629 --*/ 02630 02631 { 02632 ULONG i = 0; 02633 MMPTE_FLUSH_LIST64 PteFlushList; 02634 MMPTE PteContents; 02635 PMMPFN Pfn1; 02636 KIRQL OldIrql; 02637 PMMPTE PointerPde; 02638 02639 PteFlushList.Count = Count; 02640 02641 LOCK_PFN (OldIrql); 02642 02643 do { 02644 PteContents = *ValidPteList[i]; 02645 ASSERT (PteContents.u.Hard.Valid == 1); 02646 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02647 02648 if (Pfn1->u3.e1.PrototypePte == 1) { 02649 02650 // 02651 // Capture the state of the modified bit for this 02652 // pte. 02653 // 02654 02655 MI_CAPTURE_DIRTY_BIT_TO_PFN (&PteContents, Pfn1); 02656 02657 // 02658 // Decrement the share and valid counts of the page table 02659 // page which maps this PTE. 02660 // 02661 02662 PointerPde = MiGetPteAddress (ValidPteList[i]); 02663 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE(PointerPde)); 02664 02665 // 02666 // Decrement the share count for the physical page. 02667 // 02668 02669 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents)); 02670 02671 } else { 02672 02673 // 02674 // Decrement the share and valid counts of the page table 02675 // page which maps this PTE. 02676 // 02677 02678 MiDecrementShareAndValidCount (Pfn1->PteFrame); 02679 02680 MI_SET_PFN_DELETED (Pfn1); 02681 02682 // 02683 // Decrement the share count for the physical page. As the page 02684 // is private it will be put on the free list. 02685 // 02686 02687 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents)); 02688 } 02689 02690 if (Count < MM_MAXIMUM_FLUSH_COUNT) { 02691 PteFlushList.FlushPte[i] = ValidPteList[i]; 02692 PteFlushList.FlushVpn[i] = 02693 MiGetVirtualPageNumberMappedByPte64 (ValidPteList[i]) >> PAGE_SHIFT; 02694 } 02695 *ValidPteList[i] = ZeroPte; 02696 i += 1; 02697 } while (i != Count); 02698 02699 if (FlushTb) { 02700 MiFlushPteList64 (&PteFlushList, FALSE, ZeroPte); 02701 } 02702 02703 UNLOCK_PFN (OldIrql); 02704 return; 02705 } 02706 02707 VOID 02708 MiReturnAvailablePages ( 02709 IN PFN_NUMBER Amount 02710 ) 02711 02712 /*++ 02713 02714 Routine Description: 02715 02716 This routine returns the specified amount to the system resident pages list. 02717 02718 Arguments: 02719 02720 Amount - Supplies the amount to return. 02721 02722 Return Value: 02723 02724 none. 02725 02726 Environment: 02727 02728 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02729 held. 02730 02731 --*/ 02732 02733 { 02734 KIRQL OldIrql; 02735 02736 LOCK_PFN (OldIrql); 02737 MmResidentAvailablePages += Amount; 02738 MM_BUMP_COUNTER(26, Amount); 02739 UNLOCK_PFN (OldIrql); 02740 return; 02741 } 02742 02743 02744 LOGICAL 02745 MiCheckPdeForDeletion ( 02746 IN PMMPTE PointerPde, 02747 IN LOGICAL FlushTb 02748 ) 02749 02750 /*++ 02751 02752 Routine Description: 02753 02754 This routine checks to see if the share count of the specified PDE is 1, 02755 and if it is, the PDE is deleted. 02756 02757 Arguments: 02758 02759 PointerPde - Supplies the PDE to check. 02760 02761 FlushTb - Supplies TRUE if the TB needs to be flushed, FALSE if not. 02762 02763 Return Value: 02764 02765 TRUE if the PDE no longer exists upon return. 02766 FALSE if the PDE still exists on return. 02767 02768 Environment: 02769 02770 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02771 held. 02772 02773 --*/ 02774 02775 { 02776 LOGICAL Status; 02777 KIRQL OldIrql; 02778 PFN_NUMBER PageFrameIndex; 02779 PMMPFN Pfn1; 02780 PMMPTE PointerPte; 02781 PMI_PROCESS_VLM_INFO VlmInfo; 02782 PMMPTE LowestPde; 02783 02784 PointerPte = MiGetPteAddress (PointerPde); 02785 if (PointerPte->u.Hard.Valid == 0) { 02786 02787 // 02788 // Page Directory does not exist. 02789 // 02790 02791 return TRUE; 02792 } 02793 02794 if (PointerPde->u.Hard.Valid == 0) { 02795 02796 // 02797 // Page directory entry does not exist. 02798 // 02799 02800 return TRUE; 02801 } 02802 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE(PointerPde); 02803 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 02804 Status = FALSE; 02805 LOCK_PFN (OldIrql); 02806 02807 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 02808 LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64); 02809 02810 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 02811 02812 if (VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] == 0) { 02813 ASSERT (Pfn1->u2.ShareCount == 1); 02814 MiDecrementShareAndValidCount (Pfn1->PteFrame); 02815 MI_SET_PFN_DELETED (Pfn1); 02816 MiDecrementShareCountOnly (PageFrameIndex); 02817 if (FlushTb == TRUE) { 02818 KeFlushSingleTb (PointerPte, 02819 TRUE, 02820 FALSE, 02821 (PHARDWARE_PTE)PointerPde, 02822 ZeroPte.u.Flush); 02823 } 02824 else { 02825 *PointerPde = ZeroPte; 02826 } 02827 Status = TRUE; 02828 } 02829 #if DBG 02830 else { 02831 ULONG i; 02832 ULONG count; 02833 PULONG p; 02834 02835 count = 0; 02836 p = (PULONG)PointerPte; 02837 02838 for (i = 0; i < PAGE_SIZE; i += sizeof(p)) { 02839 p += 1; 02840 count += 1; 02841 } 02842 ASSERT (count != 0); 02843 } 02844 #endif 02845 02846 UNLOCK_PFN (OldIrql); 02847 return Status; 02848 } 02849 02850 VOID 02851 MiDeleteVlmAddressSpace ( 02852 IN PEPROCESS Process 02853 ) 02854 02855 /*++ 02856 02857 Routine Description: 02858 02859 This routine flushes the specified range of valid PTEs. 02860 02861 Arguments: 02862 02863 ValidPteList - Supplies a pointer to an array of PTEs to flush. 02864 02865 Count - Supplies the count of the number of elements in the array. 02866 02867 Return Value: 02868 02869 none. 02870 02871 Environment: 02872 02873 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02874 held. 02875 02876 --*/ 02877 02878 { 02879 PMMVAD Vad; 02880 PMMPTE PointerPde; 02881 PMMPTE PointerPte1; 02882 PMMPTE PointerPte2; 02883 PMMPFN Pfn1; 02884 MMPTE PteContents; 02885 KIRQL OldIrql; 02886 PCONTROL_AREA ControlArea; 02887 ULONG Type; 02888 PMI_PROCESS_VLM_INFO VlmInfo; 02889 SIZE_T CommitReduction; 02890 ULONGLONG RegionSize; 02891 02892 Vad = (PMMVAD)Process->CloneRoot; 02893 02894 if (Vad != (PMMVAD)NULL) { 02895 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 02896 02897 do { 02898 02899 MiRemoveVad64 (Vad); 02900 02901 Type = DELETE_TYPE_PRIVATE; 02902 if (Vad->u.VadFlags.PrivateMemory == 0) { 02903 Type = DELETE_TYPE_SHARED; 02904 } 02905 CommitReduction = MiDecommitOrDeletePages64 ( 02906 MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->StartingVpn)), 02907 MiGetPteAddress64 (MI_VPN_TO_VA_ENDING64 (Vad->EndingVpn)), 02908 Process, 02909 Type, 02910 FALSE); 02911 02912 02913 RegionSize = (((ULONGLONG)(Vad->EndingVpn - Vad->StartingVpn + 1)) << PAGE_SHIFT); 02914 VlmInfo->VirtualSize -= RegionSize; 02915 02916 ExAcquireFastLock (&MiVlmStatisticsLock, &OldIrql); 02917 if (Type != DELETE_TYPE_SHARED) { 02918 MiVlmCommitChargeInPages -= CommitReduction; 02919 } 02920 ExReleaseFastLock (&MiVlmStatisticsLock, OldIrql); 02921 02922 if (Type == DELETE_TYPE_SHARED) { 02923 02924 // 02925 // Decrement the count of the number of views for the 02926 // Segment object. This requires the PFN mutex to be held (it is already). 02927 // 02928 02929 ControlArea = Vad->ControlArea; 02930 02931 LOCK_PFN (OldIrql); 02932 ControlArea->NumberOfMappedViews -= 1; 02933 ControlArea->NumberOfUserReferences -= 1; 02934 02935 // 02936 // Check to see if the control area (segment) should be deleted. 02937 // This routine releases the PFN lock. 02938 // 02939 02940 MiCheckControlArea (ControlArea, Process, OldIrql); 02941 } 02942 else { 02943 VlmInfo->CommitCharge -= CommitReduction; 02944 } 02945 02946 ExFreePool (Vad); 02947 Vad = (PMMVAD)Process->CloneRoot; 02948 02949 } while (Vad != (PMMVAD)NULL); 02950 } 02951 02952 // 02953 // Delete any page directory pages. 02954 // 02955 02956 PointerPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64); 02957 PointerPte1 = MiGetPteAddress (PointerPde); 02958 PointerPde = MiGetPdeAddress64 (MM_HIGHEST_USER_ADDRESS64); 02959 PointerPte2 = MiGetPteAddress (PointerPde); 02960 02961 // 02962 // Free the use count allocation stashed in the PDE_BASE64. 02963 // 02964 02965 if (PointerPte1->u.Hard.Valid) { 02966 ASSERT (MiGetPteAddress (PDE_BASE64) == PointerPte1); 02967 ASSERT ((PMMPTE)PDE_BASE64 != PointerPde); 02968 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 02969 02970 #if DBG 02971 ASSERT (VlmInfo->CommitCharge == 0); 02972 ASSERT (VlmInfo->VirtualSize == 0); 02973 02974 { 02975 ULONG i; 02976 PUSHORT UsedPageTableEntries; 02977 02978 UsedPageTableEntries = VlmInfo->UsedPageTableEntries; 02979 02980 for (i = 0; i < MM_USER_PAGE_TABLE_PAGES64; i += 1) { 02981 ASSERT ((*UsedPageTableEntries) == 0); 02982 UsedPageTableEntries += 1; 02983 } 02984 } 02985 #endif 02986 02987 ExFreePool (VlmInfo); 02988 } 02989 02990 do { 02991 02992 PteContents = *PointerPte1; 02993 if (PteContents.u.Hard.Valid) { 02994 02995 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02996 02997 // 02998 // Decrement the share and valid counts of the page table 02999 // page which maps this PTE. 03000 // 03001 03002 LOCK_PFN (OldIrql); 03003 MiDecrementShareAndValidCount (Pfn1->PteFrame); 03004 03005 MI_SET_PFN_DELETED (Pfn1); 03006 03007 // 03008 // Decrement the share count for the physical page. As the page 03009 // is private it will be put on the free list. 03010 // 03011 03012 MiDecrementShareCountOnly(MI_GET_PAGE_FRAME_FROM_PTE(&PteContents)); 03013 ASSERT (Pfn1->u3.e2.ReferenceCount == 0); 03014 UNLOCK_PFN (OldIrql); 03015 } 03016 PointerPte1 += 1; 03017 03018 } while (PointerPte1 <= PointerPte2); 03019 03020 return; 03021 } 03022 03023 VOID 03024 MiFlushPteList64 ( 03025 IN PMMPTE_FLUSH_LIST64 PteFlushList, 03026 IN ULONG AllProcessors, 03027 IN MMPTE FillPte 03028 ) 03029 03030 /*++ 03031 03032 Routine Description: 03033 03034 This routine flushes all the PTEs in the pte flush list. 03035 Is the list has overflowed, the entire TB is flushed. 03036 03037 Arguments: 03038 03039 PteFlushList - Supplies an optional pointer to the list to be flushed. 03040 03041 AllProcessors - Supplies TRUE if the flush occurs on all processors. 03042 03043 FillPte - Supplies the PTE to fill with. 03044 03045 Return Value: 03046 03047 None. 03048 03049 Environment: 03050 03051 Kernel mode, PFN lock held. 03052 03053 --*/ 03054 03055 { 03056 ULONG count; 03057 ULONG i = 0; 03058 03059 ASSERT (ARGUMENT_PRESENT (PteFlushList)); 03060 MM_PFN_LOCK_ASSERT (); 03061 03062 count = PteFlushList->Count; 03063 03064 if (count != 0) { 03065 if (count != 1) { 03066 if (count < MM_MAXIMUM_FLUSH_COUNT) { 03067 KeFlushMultipleTb64 (count, 03068 &PteFlushList->FlushVpn[0], 03069 TRUE, 03070 (BOOLEAN)AllProcessors, 03071 &((PHARDWARE_PTE)PteFlushList->FlushPte[0]), 03072 FillPte.u.Flush); 03073 } else { 03074 03075 // 03076 // Array has overflowed, flush the entire TB. 03077 // 03078 03079 if (AllProcessors == TRUE) { 03080 MiLockSystemSpaceAtDpcLevel(); 03081 KeFlushEntireTb (TRUE, TRUE); 03082 MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK; 03083 MiUnlockSystemSpaceFromDpcLevel(); 03084 } else { 03085 KeFlushEntireTb (TRUE, FALSE); 03086 } 03087 } 03088 } else { 03089 KeFlushSingleTb64 (PteFlushList->FlushVpn[0], 03090 TRUE, 03091 (BOOLEAN)AllProcessors, 03092 (PHARDWARE_PTE)PteFlushList->FlushPte[0], 03093 FillPte.u.Flush); 03094 } 03095 PteFlushList->Count = 0; 03096 } 03097 return; 03098 } 03099 03100 BOOLEAN 03101 MmIsAddressValid64 ( 03102 IN PVOID64 VirtualAddress 03103 ) 03104 03105 /*++ 03106 03107 Routine Description: 03108 03109 For a given virtual address this function returns TRUE if no page fault 03110 will occur for a read operation on the address, FALSE otherwise. 03111 03112 Note that after this routine was called, if appropriate locks are not 03113 held, a non-faulting address could fault. 03114 03115 Arguments: 03116 03117 VirtualAddress - Supplies the virtual address to check. 03118 03119 Return Value: 03120 03121 TRUE if a no page fault would be generated reading the virtual address, 03122 FALSE otherwise. 03123 03124 Environment: 03125 03126 Kernel mode. 03127 03128 --*/ 03129 03130 { 03131 PMMPTE PointerPte; 03132 PMMPTE PointerPde; 03133 03134 PointerPde = MiGetPdeAddress64 (VirtualAddress); 03135 03136 // 03137 // Get Page Directory Page. 03138 // 03139 03140 PointerPte = MiGetPteAddress (PointerPde); 03141 if (PointerPte->u.Hard.Valid == 0) { 03142 return FALSE; 03143 } 03144 03145 if (PointerPde->u.Hard.Valid == 0) { 03146 return FALSE; 03147 } 03148 03149 PointerPte = MiGetPteAddress64 (VirtualAddress); 03150 if (PointerPte->u.Hard.Valid == 0) { 03151 return FALSE; 03152 } 03153 return TRUE; 03154 } 03155 03156 NTSTATUS 03157 NtMapViewOfVlmSection ( 03158 IN HANDLE SectionHandle, 03159 IN HANDLE ProcessHandle, 03160 IN OUT PVOID64 *BaseAddress, 03161 IN OUT PULONGLONG SectionOffset OPTIONAL, 03162 IN OUT PULONGLONG ViewSize, 03163 IN ULONG AllocationType, 03164 IN ULONG Protect 03165 ) 03166 03167 /*++ 03168 03169 Routine Description: 03170 03171 This function maps a view in the specified subject process to 03172 the section object. 03173 03174 Arguments: 03175 03176 SectionHandle - Supplies an open handle to a section object. 03177 03178 ProcessHandle - Supplies an open handle to a process object. 03179 03180 BaseAddress - Supplies a pointer to a variable that will receive 03181 the base address of the view. If the initial value 03182 of this argument is not null, then the view will 03183 be allocated starting at the specified virtual 03184 address rounded down to the next 64kb address 03185 boundary. If the initial value of this argument is 03186 null, then the operating system will determine 03187 where to allocate the view using the information 03188 specified by the ZeroBits argument value and the 03189 section allocation attributes (i.e. based and 03190 tiled). 03191 03192 SectionOffset - Supplies the offset from the beginning of the 03193 section to the view in bytes. This value is 03194 rounded down to the next host page size boundary. 03195 03196 ViewSize - Supplies a pointer to a variable that will receive 03197 the actual size in bytes of the view. If the value 03198 of this argument is zero, then a view of the 03199 section will be mapped starting at the specified 03200 section offset and continuing to the end of the 03201 section. Otherwise the initial value of this 03202 argument specifies the size of the view in bytes 03203 and is rounded up to the next host page size 03204 boundary. 03205 03206 AllocationType - Supplies the type of allocation. Only 0 is valid. 03207 03208 Protect - Supplies the protection desired for the region of 03209 initially committed pages. 03210 03211 Protect Values 03212 03213 PAGE_NOACCESS - No access to the committed region 03214 of pages is allowed. An attempt to read, 03215 write, or execute the committed region 03216 results in an access violation (i.e. a GP 03217 fault). 03218 03219 PAGE_READONLY - Read only and execute access to the 03220 committed region of pages is allowed. An 03221 attempt to write the committed region results 03222 in an access violation. 03223 03224 PAGE_READWRITE - Read, write, and execute access to 03225 the region of committed pages is allowed. If 03226 write access to the underlying section is 03227 allowed, then a single copy of the pages are 03228 shared. Otherwise the pages are shared read 03229 only/copy on write. 03230 03231 Return Value: 03232 03233 Returns the status. 03234 03235 --*/ 03236 03237 { 03238 PSECTION Section; 03239 PEPROCESS Process; 03240 KPROCESSOR_MODE PreviousMode; 03241 NTSTATUS Status; 03242 PVOID64 CapturedBase; 03243 ULONGLONG CapturedViewSize; 03244 ULONGLONG TempViewSize; 03245 ULONGLONG CapturedOffset; 03246 ACCESS_MASK DesiredSectionAccess; 03247 ULONG ProtectMaskForAccess; 03248 PCONTROL_AREA ControlArea; 03249 LOGICAL Attached; 03250 ULONG ReleasedWsMutex; 03251 03252 PAGED_CODE(); 03253 03254 Attached = FALSE; 03255 03256 if (MI_VLM_ENABLED() == FALSE) { 03257 return STATUS_NOT_IMPLEMENTED; 03258 } 03259 03260 // 03261 // Check the allocation type field. 03262 // 03263 03264 if (AllocationType != 0) { 03265 return STATUS_INVALID_PARAMETER_6; 03266 } 03267 03268 // 03269 // Check the protection field. This could raise an exception. 03270 // 03271 03272 try { 03273 ProtectMaskForAccess = MiMakeProtectionMask (Protect) & 0x7; 03274 } except (EXCEPTION_EXECUTE_HANDLER) { 03275 return GetExceptionCode(); 03276 } 03277 03278 DesiredSectionAccess = MmMakeSectionAccess[ProtectMaskForAccess]; 03279 03280 PreviousMode = KeGetPreviousMode(); 03281 03282 // 03283 // Establish an exception handler, probe the specified addresses 03284 // for write access and capture the initial values. 03285 // 03286 03287 CapturedOffset = 0; 03288 try { 03289 if (PreviousMode != KernelMode) { 03290 ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 03291 ProbeForWrite (ViewSize, sizeof(ULONGLONG), sizeof(ULONGLONG)); 03292 if (ARGUMENT_PRESENT (SectionOffset)) { 03293 if (PreviousMode != KernelMode) { 03294 ProbeForWrite (SectionOffset, 03295 sizeof(ULONGLONG), 03296 sizeof(ULONGLONG)); 03297 } 03298 } 03299 } 03300 03301 if (ARGUMENT_PRESENT (SectionOffset)) { 03302 CapturedOffset = *SectionOffset; 03303 } 03304 03305 // 03306 // Capture the base address. 03307 // 03308 03309 CapturedBase = *BaseAddress; 03310 03311 // 03312 // Capture the region size. 03313 // 03314 03315 CapturedViewSize = *ViewSize; 03316 03317 } except (ExSystemExceptionFilter()) { 03318 03319 // 03320 // If an exception occurs during the probe or capture 03321 // of the initial values, then handle the exception and 03322 // return the exception code as the status value. 03323 // 03324 03325 return GetExceptionCode(); 03326 } 03327 03328 if ((ARGUMENT_PRESENT (SectionOffset)) && 03329 ((CapturedOffset & (X64K - 1)) != 0)) { 03330 return STATUS_MAPPED_ALIGNMENT; 03331 } 03332 03333 if (((ULONGLONG)CapturedBase & (X64K - 1)) != 0) { 03334 return STATUS_MAPPED_ALIGNMENT; 03335 } 03336 03337 // 03338 // Make sure the specified starting and ending addresses are 03339 // within the user part of the virtual address space. 03340 // 03341 03342 if ((CapturedBase != NULL ) && 03343 ((CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) || 03344 (CapturedBase < (PVOID64)MM_LOWEST_USER_ADDRESS64))) { 03345 03346 // 03347 // Invalid base address. 03348 // 03349 03350 return STATUS_INVALID_PARAMETER_3; 03351 } 03352 03353 if (CapturedBase != NULL) { 03354 03355 if ((ULONGLONG)CapturedBase + CapturedViewSize < (ULONGLONG)CapturedBase) { 03356 03357 // 03358 // the requested region wraps 03359 // 03360 03361 return STATUS_INVALID_PARAMETER_5; 03362 } 03363 03364 03365 if ((ULONGLONG)CapturedBase + CapturedViewSize > (ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - X64K) { 03366 03367 // 03368 // the requested region goes beyond the end of user memory - flag it 03369 // 03370 03371 return STATUS_INVALID_PARAMETER_5; 03372 } 03373 } 03374 else if (CapturedViewSize > (ULONGLONG)MM_LARGEST_VLM_RANGE - X64K) { 03375 03376 // 03377 // Invalid view size; 03378 // 03379 03380 return STATUS_INVALID_PARAMETER_5; 03381 } 03382 03383 03384 Status = ObReferenceObjectByHandle ( ProcessHandle, 03385 PROCESS_VM_OPERATION, 03386 PsProcessType, 03387 PreviousMode, 03388 (PVOID *)&Process, 03389 NULL ); 03390 if (!NT_SUCCESS(Status)) { 03391 return Status; 03392 } 03393 03394 // 03395 // Reference the section object, if a view is mapped to the section 03396 // object, the object is not dereferenced as the virtual address 03397 // descriptor contains a pointer to the section object. 03398 // 03399 03400 Status = ObReferenceObjectByHandle ( SectionHandle, 03401 DesiredSectionAccess, 03402 MmSectionObjectType, 03403 PreviousMode, 03404 (PVOID *)&Section, 03405 NULL ); 03406 03407 if (!NT_SUCCESS(Status)) { 03408 goto ErrorReturn1; 03409 } 03410 03411 if (Section->Segment->ControlArea->u.Flags.Vlm == 0) { 03412 03413 // 03414 // This is not a VLM section. 03415 // 03416 03417 Status = STATUS_INVALID_VLM_OPERATION; 03418 goto ErrorReturn; 03419 } 03420 03421 // 03422 // Check to make sure the section offset is within the section. 03423 // 03424 03425 if ((CapturedOffset + CapturedViewSize) > 03426 (ULONGLONG)Section->SizeOfSection.QuadPart) { 03427 Status = STATUS_INVALID_VIEW_SIZE; 03428 goto ErrorReturn; 03429 } 03430 03431 if (CapturedViewSize == 0) { 03432 03433 // 03434 // Set the view size to be size of the section less the offset. 03435 // 03436 03437 TempViewSize = Section->SizeOfSection.QuadPart - 03438 CapturedOffset; 03439 03440 CapturedViewSize = TempViewSize; 03441 03442 if ((TempViewSize == 0) || 03443 (((ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 - (ULONGLONG)CapturedBase) < 03444 CapturedViewSize)) { 03445 03446 // 03447 // Invalid region size; 03448 // 03449 03450 Status = STATUS_INVALID_VIEW_SIZE; 03451 goto ErrorReturn; 03452 } 03453 03454 } else { 03455 03456 // 03457 // Check to make sure the view size plus the offset is less 03458 // than the size of the section. 03459 // 03460 03461 if ((CapturedViewSize + CapturedOffset) > 03462 (ULONGLONG)Section->SizeOfSection.QuadPart) { 03463 03464 Status = STATUS_INVALID_VIEW_SIZE; 03465 goto ErrorReturn; 03466 } 03467 } 03468 03469 ControlArea = Section->Segment->ControlArea; 03470 03471 if (PsGetCurrentProcess() != Process) { 03472 KeAttachProcess (&Process->Pcb); 03473 Attached = TRUE; 03474 } 03475 03476 // 03477 // Get the address creation mutex to block multiple threads 03478 // creating or deleting address space at the same time. 03479 // 03480 03481 LOCK_ADDRESS_SPACE (Process); 03482 03483 // 03484 // Make sure the address space was not deleted, if so, return an error. 03485 // 03486 03487 if (Process->AddressSpaceDeleted != 0) { 03488 UNLOCK_ADDRESS_SPACE (Process); 03489 Status = STATUS_PROCESS_IS_TERMINATING; 03490 goto ErrorReturn; 03491 } 03492 03493 // 03494 // Don't allow POSIX apps to do VLM operations. 03495 // 03496 03497 if ((Process->CloneRoot != NULL) && 03498 (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) { 03499 UNLOCK_ADDRESS_SPACE (Process); 03500 Status = STATUS_INVALID_VLM_OPERATION; 03501 goto ErrorReturn; 03502 } 03503 Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED; 03504 03505 ReleasedWsMutex = FALSE; 03506 03507 Status = MiMapViewOfVlmDataSection (ControlArea, 03508 Process, 03509 &CapturedBase, 03510 &CapturedOffset, 03511 &CapturedViewSize, 03512 Section, 03513 ProtectMaskForAccess, 03514 AllocationType, 03515 &ReleasedWsMutex); 03516 03517 if (!ReleasedWsMutex) { 03518 UNLOCK_WS (Process); 03519 } 03520 UNLOCK_ADDRESS_SPACE (Process); 03521 03522 if (Attached == TRUE) { 03523 KeDetachProcess(); 03524 Attached = FALSE; 03525 } 03526 03527 if (!NT_SUCCESS(Status) ) { 03528 goto ErrorReturn; 03529 } 03530 03531 // 03532 // Establish an exception handler and write the size and base 03533 // address. 03534 // 03535 03536 try { 03537 03538 *ViewSize = CapturedViewSize; 03539 *BaseAddress = CapturedBase; 03540 03541 if (ARGUMENT_PRESENT(SectionOffset)) { 03542 *SectionOffset = CapturedOffset; 03543 } 03544 03545 } except (EXCEPTION_EXECUTE_HANDLER) { 03546 NOTHING; 03547 } 03548 03549 ErrorReturn: 03550 if (Attached == TRUE) { 03551 KeDetachProcess(); 03552 Attached = FALSE; 03553 } 03554 03555 ObDereferenceObject (Section); 03556 ErrorReturn1: 03557 ObDereferenceObject (Process); 03558 return Status; 03559 } 03560 03561 NTSTATUS 03562 MiMapViewOfVlmDataSection ( 03563 IN PCONTROL_AREA ControlArea, 03564 IN PEPROCESS Process, 03565 IN PVOID64 *CapturedBase, 03566 IN PULONGLONG SectionOffset, 03567 IN PULONGLONG CapturedViewSize, 03568 IN PSECTION Section, 03569 IN ULONG ProtectionMask, 03570 IN ULONG AllocationType, 03571 IN PULONG ReleasedWsMutex 03572 ) 03573 03574 /*++ 03575 03576 Routine Description: 03577 03578 This routine maps the specified physical section into the 03579 specified process's address space. 03580 03581 Arguments: 03582 03583 See NtMapViewOfVlmSection above... 03584 03585 ControlArea - Supplies the control area for the section. 03586 03587 Process - Supplies the process pointer which is receiving the section. 03588 03589 ProtectionMask - Supplies the initial page protection-mask. 03590 03591 ReleasedWsMutex - Supplies FALSE. If the working set mutex is 03592 not held when returning this must be set to TRUE 03593 so the caller will release the mutex. 03594 03595 Return Value: 03596 03597 Status of the map view operation. 03598 03599 Environment: 03600 03601 Kernel Mode, working set mutex and address creation mutex held. 03602 03603 --*/ 03604 03605 { 03606 PMMVAD Vad; 03607 volatile PVOID64 Va; 03608 PVOID64 StartingAddress; 03609 PVOID64 EndingAddress; 03610 KIRQL OldIrql; 03611 PSUBSECTION Subsection; 03612 ULONG PteOffset; 03613 PMMPTE PointerPte; 03614 PMMPTE LastPte; 03615 MMPTE TempPte; 03616 ULONG QuotaCharge; 03617 PMMPTE TheFirstPrototypePte; 03618 PMMPTE Pde; 03619 PMMPTE LastPde; 03620 LOGICAL PdeBuilt; 03621 NTSTATUS ReturnStatus; 03622 PMI_PROCESS_VLM_INFO VlmInfo; 03623 03624 // 03625 // Check to see if a purge operation is in progress and if so, wait 03626 // for the purge to complete. In addition, up the count of mapped 03627 // views for this control area. 03628 // 03629 03630 if ((Process->CloneRoot != NULL) && 03631 (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED)) { 03632 *ReleasedWsMutex = TRUE; 03633 return STATUS_INVALID_VLM_OPERATION; 03634 } 03635 03636 QuotaCharge = 0; 03637 03638 Process->ForkWasSuccessful = MM_NO_FORK_ALLOWED; 03639 03640 MiCheckPurgeAndUpMapCount (ControlArea); 03641 03642 // 03643 // Calculate the first prototype PTE field in the Vad. 03644 // 03645 03646 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 03647 03648 Subsection = (PSUBSECTION)(ControlArea + 1); 03649 03650 *SectionOffset = (ULONGLONG)MI_ALIGN_TO_SIZE64 (*SectionOffset, X64K); 03651 PteOffset = (ULONG)(*SectionOffset >> PAGE_SHIFT); 03652 03653 // 03654 // Make sure the PTEs are not in the extended part of the 03655 // segment. 03656 // 03657 03658 while (PteOffset >= Subsection->PtesInSubsection) { 03659 PteOffset -= Subsection->PtesInSubsection; 03660 Subsection = Subsection->NextSubsection; 03661 ASSERT (Subsection != NULL); 03662 } 03663 03664 TheFirstPrototypePte = &Subsection->SubsectionBase[PteOffset]; 03665 03666 //fixfix - make copy on write invalid CapturedCopyOnWrite = Section->u.Flags.CopyOnWrite; 03667 03668 LOCK_WS (Process); 03669 03670 if (*CapturedBase == NULL) { 03671 03672 // 03673 // The section is not based, find an empty range. 03674 // This could raise an exception. 03675 03676 try { 03677 03678 // 03679 // Find a starting address on a 64k boundary. 03680 // 03681 03682 StartingAddress = MiFindEmptyAddressRangeInTree64 ( 03683 *CapturedViewSize, 03684 X64K, 03685 (PMMADDRESS_NODE)(Process->CloneRoot)); 03686 03687 } except (EXCEPTION_EXECUTE_HANDLER) { 03688 03689 LOCK_PFN (OldIrql); 03690 ControlArea->NumberOfMappedViews -= 1; 03691 ControlArea->NumberOfUserReferences -= 1; 03692 UNLOCK_PFN (OldIrql); 03693 return GetExceptionCode(); 03694 } 03695 03696 EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress + 03697 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L)); 03698 03699 } else { 03700 03701 StartingAddress = MI_ALIGN_TO_SIZE64 (*CapturedBase, X64K); 03702 03703 // 03704 // Check to make sure the specified base address to ending address 03705 // is currently unused. 03706 // 03707 03708 EndingAddress = (PVOID64)(((ULONGLONG)StartingAddress + 03709 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L)); 03710 03711 Vad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress); 03712 if (Vad != (PMMVAD)NULL) { 03713 LOCK_PFN (OldIrql); 03714 ControlArea->NumberOfMappedViews -= 1; 03715 ControlArea->NumberOfUserReferences -= 1; 03716 UNLOCK_PFN (OldIrql); 03717 return STATUS_CONFLICTING_ADDRESSES; 03718 } 03719 } 03720 03721 // 03722 // An unoccupied address range has been found, build the virtual 03723 // address descriptor to describe this range. 03724 // 03725 03726 try { 03727 03728 Vad = ExAllocatePoolWithTag (NonPagedPool, 03729 sizeof(MMVAD), 03730 MMVADKEY); 03731 if (Vad == NULL) { 03732 ExRaiseStatus (STATUS_INSUFFICIENT_RESOURCES); 03733 } 03734 RtlZeroMemory (Vad, sizeof(MMVAD)); 03735 03736 Vad->StartingVpn = MI_VA_TO_VPN64 (StartingAddress); 03737 Vad->EndingVpn = MI_VA_TO_VPN64 (EndingAddress); 03738 Vad->FirstPrototypePte = TheFirstPrototypePte; 03739 03740 // 03741 // The protection is in the PTE template field of the VAD. 03742 // 03743 03744 Vad->ControlArea = ControlArea; 03745 03746 Vad->u2.VadFlags2.Inherit = 0; 03747 Vad->u.VadFlags.Protection = ProtectionMask; 03748 Vad->u2.VadFlags2.CopyOnWrite = 0; //fixfix 03749 03750 Vad->u2.VadFlags2.FileOffset = (ULONG)(*SectionOffset >> 16); 03751 03752 PteOffset += (ULONG) (Vad->EndingVpn - Vad->StartingVpn); 03753 03754 if (PteOffset < Subsection->PtesInSubsection ) { 03755 Vad->LastContiguousPte = &Subsection->SubsectionBase[PteOffset]; 03756 03757 } else { 03758 Vad->LastContiguousPte = &Subsection->SubsectionBase[ 03759 (Subsection->PtesInSubsection - 1) + 03760 Subsection->UnusedPtes]; 03761 } 03762 03763 ASSERT (Vad->FirstPrototypePte <= Vad->LastContiguousPte); 03764 MiInsertVad64 (Vad); 03765 03766 } except (EXCEPTION_EXECUTE_HANDLER) { 03767 03768 LOCK_PFN (OldIrql); 03769 ControlArea->NumberOfMappedViews -= 1; 03770 ControlArea->NumberOfUserReferences -= 1; 03771 UNLOCK_PFN (OldIrql); 03772 03773 if (Vad != (PMMVAD)NULL) { 03774 03775 // 03776 // The pool allocation succeeded, but the quota charge 03777 // in InsertVad failed, deallocate the pool and return 03778 // an error. 03779 // 03780 03781 ExFreePool (Vad); 03782 return GetExceptionCode(); 03783 } 03784 return STATUS_INSUFFICIENT_RESOURCES; 03785 } 03786 03787 // 03788 // Build the top level page directory page to describe this range. 03789 // The individual page table pages are materialized when the process 03790 // faults. 03791 // 03792 03793 Pde = MiGetPdeAddress64 (StartingAddress); 03794 PdeBuilt = MiMakePdeExistAndMakeValid64 (Pde, Process, FALSE, FALSE); 03795 03796 if (PdeBuilt == FALSE) { 03797 ASSERT (Pde == MiGetPdeAddress64 (StartingAddress)); 03798 LOCK_PFN (OldIrql); 03799 ControlArea->NumberOfMappedViews -= 1; 03800 ControlArea->NumberOfUserReferences -= 1; 03801 UNLOCK_PFN (OldIrql); 03802 MiRemoveVad64 (Vad); 03803 ExFreePool (Vad); 03804 return STATUS_INSUFFICIENT_RESOURCES; 03805 } 03806 03807 *ReleasedWsMutex = TRUE; 03808 UNLOCK_WS (Process); 03809 03810 // 03811 // Update the current virtual size in the process header. 03812 // 03813 03814 *CapturedViewSize = (char * POINTER_64)EndingAddress - (char * POINTER_64)StartingAddress + 1L; 03815 03816 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 03817 VlmInfo->VirtualSize += *CapturedViewSize; 03818 if (VlmInfo->VirtualSize > VlmInfo->VirtualSizePeak) { 03819 VlmInfo->VirtualSizePeak = VlmInfo->VirtualSize; 03820 } 03821 03822 *CapturedBase = StartingAddress; 03823 03824 return STATUS_SUCCESS; 03825 } 03826 03827 NTSTATUS 03828 NtUnmapViewOfVlmSection( 03829 IN HANDLE ProcessHandle, 03830 IN OUT PVOID64 *BaseAddress 03831 ) 03832 03833 /*++ 03834 03835 Routine Description: 03836 03837 This function unmaps a previously created view to a section. 03838 03839 Arguments: 03840 03841 ProcessHandle - Supplies an open handle to a process object. 03842 03843 BaseAddress - Supplies the base address of the view. 03844 03845 Return Value: 03846 03847 Returns the status 03848 03849 TBS 03850 03851 03852 --*/ 03853 03854 { 03855 PEPROCESS Process; 03856 KPROCESSOR_MODE PreviousMode; 03857 PMMVAD Vad; 03858 ULONGLONG RegionSize; 03859 PVOID64 UnMapImageBase; 03860 PVOID64 CapturedBase; 03861 NTSTATUS status; 03862 PMMPTE StartingPte; 03863 PMMPTE EndingPte; 03864 PCONTROL_AREA ControlArea; 03865 KIRQL OldIrql; 03866 ULONG CommitReduction; 03867 PMI_PROCESS_VLM_INFO VlmInfo; 03868 03869 if (MI_VLM_ENABLED() == FALSE) { 03870 return STATUS_NOT_IMPLEMENTED; 03871 } 03872 03873 PreviousMode = KeGetPreviousMode(); 03874 03875 status = ObReferenceObjectByHandle ( ProcessHandle, 03876 PROCESS_VM_OPERATION, 03877 PsProcessType, 03878 PreviousMode, 03879 (PVOID *)&Process, 03880 NULL ); 03881 if (!NT_SUCCESS(status)) { 03882 return status; 03883 } 03884 03885 UnMapImageBase = NULL; 03886 03887 // 03888 // If the specified process is not the current process, attach 03889 // to the specified process. 03890 // 03891 03892 KeAttachProcess (&Process->Pcb); 03893 03894 // 03895 // Probe and capture the specified address 03896 // 03897 03898 PreviousMode = KeGetPreviousMode(); 03899 03900 if (PreviousMode != KernelMode) { 03901 try { 03902 ProbeForRead (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 03903 03904 // 03905 // Capture the base address. 03906 // 03907 03908 CapturedBase = *BaseAddress; 03909 } except (ExSystemExceptionFilter()) { 03910 03911 // 03912 // If an exception occurs during the probe or capture 03913 // of the initial value, then handle the exception and 03914 // return the exception code as the status value. 03915 // 03916 03917 KeDetachProcess(); 03918 ObDereferenceObject (Process); 03919 return GetExceptionCode(); 03920 } 03921 } 03922 else { 03923 CapturedBase = *BaseAddress; 03924 } 03925 03926 // 03927 // Get the address creation mutex to block multiple threads from 03928 // creating or deleting address space at the same time and 03929 // get the working set mutex so virtual address descriptors can 03930 // be inserted and walked. Raise IRQL to block APCs. 03931 // 03932 // Get the working set mutex, no page faults allowed for now until 03933 // working set mutex released. 03934 // 03935 03936 LOCK_WS_AND_ADDRESS_SPACE (Process); 03937 03938 // 03939 // Make sure the address space was not deleted, if so, return an error. 03940 // 03941 03942 if (Process->AddressSpaceDeleted != 0) { 03943 status = STATUS_PROCESS_IS_TERMINATING; 03944 goto ErrorReturn; 03945 } 03946 03947 if (Process->ForkWasSuccessful != MM_NO_FORK_ALLOWED) { 03948 status = STATUS_NOT_MAPPED_VIEW; 03949 goto ErrorReturn; 03950 } 03951 03952 // 03953 // Find the associated Vad. 03954 // 03955 03956 Vad = (PMMVAD)MiLocateAddress64 (MI_VA_TO_VPN64 (CapturedBase)); 03957 03958 if ((Vad == (PMMVAD)NULL) || (Vad->u.VadFlags.PrivateMemory)) { 03959 03960 // 03961 // No Virtual Address Descriptor located for Base Address. 03962 // 03963 03964 status = STATUS_NOT_MAPPED_VIEW; 03965 goto ErrorReturn; 03966 } 03967 03968 ASSERT (Vad->u.VadFlags.NoChange == 0); 03969 03970 RegionSize = PAGE_SIZE + (((ULONGLONG)(Vad->EndingVpn - Vad->StartingVpn)) << PAGE_SHIFT); 03971 03972 MiRemoveVad64 (Vad); 03973 03974 #if 0 03975 // 03976 // Return commitment for page table pages if possible. 03977 // 03978 03979 MiReturnPageTablePageCommitment (MI_VPN_TO_VA (Vad->StartingVpn), 03980 MI_VPN_TO_VA_ENDING (Vad->EndingVpn), 03981 Process, 03982 PreviousVad, 03983 NextVad); 03984 #endif //0 03985 03986 StartingPte = MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->StartingVpn)); 03987 EndingPte = MiGetPteAddress64 (MI_VPN_TO_VA64 (Vad->EndingVpn)); 03988 03989 CommitReduction = MiDecommitOrDeletePages64 (StartingPte, 03990 EndingPte, 03991 Process, 03992 DELETE_TYPE_SHARED, 03993 TRUE); 03994 03995 03996 // 03997 // Decrement the count of the number of views for the 03998 // Segment object. This requires the PFN mutex to be held (it is already). 03999 // 04000 04001 ControlArea = Vad->ControlArea; 04002 LOCK_PFN (OldIrql); 04003 ControlArea->NumberOfMappedViews -= 1; 04004 ControlArea->NumberOfUserReferences -= 1; 04005 04006 // 04007 // Check to see if the control area (segment) should be deleted. 04008 // This routine releases the PFN lock. 04009 // 04010 04011 MiCheckControlArea (ControlArea, Process, OldIrql); 04012 04013 ExFreePool (Vad); 04014 04015 // 04016 // Update the current virtual size in the process header. 04017 // 04018 04019 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 04020 VlmInfo->VirtualSize -= RegionSize; 04021 04022 status = STATUS_SUCCESS; 04023 04024 ErrorReturn: 04025 04026 UNLOCK_WS (Process); 04027 UNLOCK_ADDRESS_SPACE (Process); 04028 04029 KeDetachProcess(); 04030 ObDereferenceObject (Process); 04031 04032 return status; 04033 } 04034 04035 04036 NTSTATUS 04037 NtProtectVirtualMemory64( 04038 IN HANDLE ProcessHandle, 04039 IN OUT PVOID64 *BaseAddress, 04040 IN OUT PULONGLONG RegionSize, 04041 IN ULONG NewProtect, 04042 OUT PULONG OldProtect 04043 ) 04044 04045 { 04046 PEPROCESS Process; 04047 KPROCESSOR_MODE PreviousMode; 04048 NTSTATUS Status; 04049 LOGICAL Attached; 04050 PVOID64 CapturedBase; 04051 ULONGLONG CapturedRegionSize; 04052 ULONG ProtectionMask; 04053 PMMVAD FoundVad; 04054 PVOID64 StartingAddress; 04055 PVOID64 EndingAddress; 04056 PMMPTE PointerPte; 04057 PMMPTE LastPte; 04058 PMMPTE PointerPde; 04059 PMMPTE PointerProtoPte; 04060 PMMPTE LastProtoPte; 04061 PMMPFN Pfn1; 04062 ULONG CapturedOldProtect; 04063 MMPTE TempPte; 04064 MMPTE PteContents; 04065 PVOID64 Va; 04066 ULONG DoAgain; 04067 PMI_PROCESS_VLM_INFO VlmInfo; 04068 PMMPTE LowestPde; 04069 04070 PAGED_CODE(); 04071 04072 Attached = FALSE; 04073 04074 // 04075 // Check the protection field. This could raise an exception. 04076 // 04077 04078 if ((NewProtect & PAGE_GUARD) || 04079 (NewProtect & PAGE_NOCACHE)) { 04080 return STATUS_INVALID_PAGE_PROTECTION; 04081 } 04082 04083 try { 04084 ProtectionMask = MiMakeProtectionMask (NewProtect); 04085 } except (EXCEPTION_EXECUTE_HANDLER) { 04086 return GetExceptionCode(); 04087 } 04088 04089 PreviousMode = KeGetPreviousMode(); 04090 04091 if (PreviousMode != KernelMode) { 04092 04093 // 04094 // Capture the region size and base address under an exception handler. 04095 // 04096 04097 try { 04098 04099 ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 04100 ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG)); 04101 ProbeForWriteUlong (OldProtect); 04102 04103 // 04104 // Capture the region size and base address. 04105 // 04106 04107 CapturedBase = *BaseAddress; 04108 CapturedRegionSize = *RegionSize; 04109 04110 } except (EXCEPTION_EXECUTE_HANDLER) { 04111 04112 // 04113 // If an exception occurs during the probe or capture 04114 // of the initial values, then handle the exception and 04115 // return the exception code as the status value. 04116 // 04117 04118 return GetExceptionCode(); 04119 } 04120 04121 } else { 04122 04123 // 04124 // Capture the region size and base address. 04125 // 04126 04127 CapturedRegionSize = *RegionSize; 04128 CapturedBase = *BaseAddress; 04129 } 04130 04131 // 04132 // Make sure the specified starting and ending addresses are 04133 // within the user part of the virtual address space. 04134 // 04135 04136 if (CapturedBase > (PVOID64)MM_HIGHEST_USER_ADDRESS64) { 04137 04138 // 04139 // Invalid base address. 04140 // 04141 04142 return STATUS_INVALID_PARAMETER_2; 04143 } 04144 04145 if ((ULONGLONG)MM_HIGHEST_USER_ADDRESS64 - (ULONGLONG)CapturedBase < 04146 CapturedRegionSize) { 04147 04148 // 04149 // Invalid region size; 04150 // 04151 04152 return STATUS_INVALID_PARAMETER_3; 04153 } 04154 04155 if (CapturedRegionSize == 0) { 04156 return STATUS_INVALID_PARAMETER_3; 04157 } 04158 04159 Status = ObReferenceObjectByHandle ( ProcessHandle, 04160 PROCESS_VM_OPERATION, 04161 PsProcessType, 04162 PreviousMode, 04163 (PVOID *)&Process, 04164 NULL ); 04165 04166 if (!NT_SUCCESS(Status)) { 04167 return Status; 04168 } 04169 04170 // 04171 // If the specified process is not the current process, attach 04172 // to the specified process. 04173 // 04174 04175 if (PsGetCurrentProcess() != Process) { 04176 KeAttachProcess (&Process->Pcb); 04177 Attached = TRUE; 04178 } 04179 04180 04181 // 04182 // Get the address creation mutex to block multiple threads from 04183 // creating or deleting address space at the same time. 04184 // Get the working set mutex so PTEs can be modified. 04185 // Block APCs so an APC which takes a page 04186 // fault does not corrupt various structures. 04187 // 04188 04189 LOCK_WS_AND_ADDRESS_SPACE (Process); 04190 04191 // 04192 // Make sure the address space was not deleted, if so, return an error. 04193 // 04194 04195 if (Process->AddressSpaceDeleted != 0) { 04196 Status = STATUS_PROCESS_IS_TERMINATING; 04197 goto ErrorFound; 04198 } 04199 04200 EndingAddress = (PVOID64)(((ULONGLONG)CapturedBase + CapturedRegionSize - 1) | 04201 (PAGE_SIZE - 1)); 04202 StartingAddress = (PVOID64)PAGE_ALIGN64(CapturedBase); 04203 04204 FoundVad = MiCheckForConflictingVad64 (StartingAddress, EndingAddress); 04205 04206 if (FoundVad == NULL) { 04207 04208 // 04209 // No virtual address is reserved at the specified base address, 04210 // return an error. 04211 // 04212 04213 Status = STATUS_CONFLICTING_ADDRESSES; 04214 goto ErrorFound; 04215 } 04216 04217 // 04218 // Ensure that the starting and ending addresses are all within 04219 // the same virtual address descriptor. 04220 // 04221 04222 if ((MI_VA_TO_VPN64 (StartingAddress) < FoundVad->StartingVpn) || 04223 (MI_VA_TO_VPN64 (EndingAddress) > FoundVad->EndingVpn)) { 04224 04225 // 04226 // Not within the section virtual address descriptor, 04227 // return an error. 04228 // 04229 04230 Status = STATUS_CONFLICTING_ADDRESSES; 04231 goto ErrorFound; 04232 } 04233 04234 ASSERT (FoundVad->u.VadFlags.PhysicalMapping == 0); 04235 ASSERT (FoundVad->u.VadFlags.NoChange == 0); 04236 04237 if (FoundVad->u.VadFlags.PrivateMemory == 0) { 04238 04239 04240 // 04241 // For mapped sections, the NO_CACHE and the COPY_ON_WRITE attribute 04242 // are not allowed. 04243 // 04244 04245 if ((NewProtect & PAGE_NOCACHE) || 04246 (ProtectionMask & MM_COPY_ON_WRITE_MASK)) { 04247 04248 // 04249 // Not allowed. 04250 // 04251 04252 Status = STATUS_INVALID_PARAMETER_4; 04253 goto ErrorFound; 04254 } 04255 04256 // 04257 // If this is a file mapping, then all pages must be 04258 // committed as there can be no sparse file maps. Images 04259 // can have non-committed pages if the alignment is greater 04260 // than the page size. 04261 // 04262 04263 if ((FoundVad->ControlArea->u.Flags.File == 0) || 04264 (FoundVad->ControlArea->u.Flags.Image == 1)) { 04265 04266 PointerProtoPte = MiGetProtoPteAddress (FoundVad, 04267 MI_VA_TO_VPN64 (StartingAddress)); 04268 LastProtoPte = MiGetProtoPteAddress (FoundVad, 04269 MI_VA_TO_VPN64 (EndingAddress)); 04270 04271 // 04272 // Release the working set mutex and acquire the section 04273 // commit mutex. Check all the prototype PTEs described by 04274 // the virtual address range to ensure they are committed. 04275 // 04276 04277 UNLOCK_WS (Process); 04278 ExAcquireFastMutex (&MmSectionCommitMutex); 04279 04280 while (PointerProtoPte <= LastProtoPte) { 04281 04282 // 04283 // Check to see if the prototype PTE is committed, if 04284 // not return an error. 04285 // 04286 04287 if (PointerProtoPte->u.Long == 0) { 04288 04289 // 04290 // Error, this prototype PTE is not committed. 04291 // 04292 04293 ExReleaseFastMutex (&MmSectionCommitMutex); 04294 Status = STATUS_NOT_COMMITTED; 04295 goto ErrorFoundNoWs; 04296 } 04297 PointerProtoPte += 1; 04298 } 04299 04300 // 04301 // The range is committed, release the section commitment 04302 // mutex, acquire the working set mutex and update the local PTEs. 04303 // 04304 04305 ExReleaseFastMutex (&MmSectionCommitMutex); 04306 04307 // 04308 // Set the protection on the section pages. This could 04309 // get a quota exceeded exception. 04310 // 04311 04312 LOCK_WS (Process); 04313 } 04314 04315 // 04316 // Set the protection on the pages. 04317 // 04318 04319 // 04320 // The address range is committed, change the protection. 04321 // 04322 04323 PointerPde = MiGetPdeAddress64 (StartingAddress); 04324 PointerPte = MiGetPteAddress64 (StartingAddress); 04325 LastPte = MiGetPteAddress64 (EndingAddress); 04326 04327 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 04328 04329 // 04330 // Capture the protection for the first page. 04331 // 04332 04333 if (PointerPte->u.Long != 0) { 04334 04335 CapturedOldProtect = PAGE_READWRITE; 04336 if (PointerPte->u.Hard.Valid == 1) { 04337 if (PointerPte->u.Hard.Write == 0) { 04338 CapturedOldProtect = PAGE_READONLY; 04339 } 04340 } else { 04341 ASSERT (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED); 04342 ASSERT (PointerPte->u.Soft.Prototype == 1); 04343 CapturedOldProtect = 04344 MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection); 04345 } 04346 04347 } else { 04348 04349 // 04350 // Get the protection from the VAD. 04351 // 04352 04353 CapturedOldProtect = 04354 MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection); 04355 } 04356 04357 LowestPde = MiGetPdeAddress64 (MM_LOWEST_USER_ADDRESS64); 04358 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 04359 04360 // 04361 // For all the PTEs in the specified address range, set the 04362 // protection depending on the state of the PTE. 04363 // 04364 04365 while (PointerPte <= LastPte) { 04366 04367 if (MiIsPteOnPdeBoundary(PointerPte)) { 04368 04369 PointerPde = MiGetPteAddress (PointerPte); 04370 04371 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 04372 } 04373 04374 PteContents = *PointerPte; 04375 04376 if (PteContents.u.Hard.Valid == 1) { 04377 04378 if (ProtectionMask != MM_NOACCESS) { 04379 04380 // 04381 // Set the protection into both the PTE and the original PTE 04382 // in the PFN database. 04383 // 04384 04385 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 04386 04387 ASSERT (Pfn1->u3.e1.PrototypePte == 1); 04388 04389 // 04390 // The PTE is a private page which is valid, if the 04391 // specified protection is no-access or guard page 04392 // remove the PTE from the working set. 04393 // 04394 04395 MI_MAKE_VALID_PTE (TempPte, 04396 PointerPte->u.Hard.PageFrameNumber, 04397 ProtectionMask, 04398 NULL); 04399 if (TempPte.u.Hard.Write) { 04400 MI_SET_PTE_DIRTY (TempPte); 04401 } 04402 04403 // 04404 // Flush the TB as we have changed the protection 04405 // of a valid PTE. 04406 // 04407 04408 MiFlushTbAndCapture (PointerPte, 04409 TempPte.u.Flush, 04410 Pfn1); 04411 } else { 04412 04413 // 04414 // No access, remove page from memory. 04415 // 04416 04417 MiMakeValidPageNoAccess64 (PointerPte); 04418 } 04419 04420 } else { 04421 04422 if (PointerPte->u.Long == ZeroPte.u.Long) { 04423 *PointerPte = PrototypePte; 04424 PointerPte->u.Soft.Protection = ProtectionMask; 04425 04426 VlmInfo->UsedPageTableEntries[PointerPde - LowestPde] += 1; 04427 04428 } else { 04429 ASSERT (PointerPte->u.Soft.Prototype == 1); 04430 ASSERT (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED); 04431 PointerPte->u.Soft.Protection = ProtectionMask; 04432 } 04433 } 04434 PointerPte += 1; 04435 } //end while 04436 04437 } else { 04438 04439 // 04440 // Not a section, private. 04441 // For private pages, the WRITECOPY attribute is not allowed. 04442 // 04443 04444 if ((NewProtect & PAGE_WRITECOPY) || 04445 (NewProtect & PAGE_EXECUTE_WRITECOPY)) { 04446 04447 // 04448 // Not allowed. 04449 // 04450 04451 Status = STATUS_INVALID_PARAMETER_4; 04452 goto ErrorFound; 04453 } 04454 04455 // 04456 // Ensure all of the pages are already committed as described 04457 // in the virtual address descriptor. 04458 // 04459 04460 if ( !MiIsEntireRangeCommitted64 (StartingAddress, 04461 EndingAddress, 04462 FoundVad, 04463 Process)) { 04464 04465 // 04466 // Previously reserved pages have been decommitted, or an error 04467 // occurred, release mutex and return status. 04468 // 04469 04470 Status = STATUS_NOT_COMMITTED; 04471 goto ErrorFound; 04472 } 04473 04474 // 04475 // The address range is committed, change the protection. 04476 // 04477 04478 PointerPde = MiGetPdeAddress64 (StartingAddress); 04479 PointerPte = MiGetPteAddress64 (StartingAddress); 04480 LastPte = MiGetPteAddress64 (EndingAddress); 04481 04482 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 04483 04484 // 04485 // Capture the protection for the first page. 04486 // 04487 04488 if (PointerPte->u.Long != 0) { 04489 04490 CapturedOldProtect = MiGetPageProtection (PointerPte, Process); 04491 04492 } else { 04493 04494 // 04495 // Get the protection from the VAD. 04496 // 04497 04498 CapturedOldProtect = 04499 MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection); 04500 } 04501 04502 // 04503 // For all the PTEs in the specified address range, set the 04504 // protection depending on the state of the PTE. 04505 // 04506 04507 while (PointerPte <= LastPte) { 04508 04509 if (MiIsPteOnPdeBoundary(PointerPte)) { 04510 04511 PointerPde = MiGetPteAddress (PointerPte); 04512 04513 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 04514 } 04515 04516 PteContents = *PointerPte; 04517 04518 if (PteContents.u.Hard.Valid == 1) { 04519 04520 if (ProtectionMask != MM_NOACCESS) { 04521 04522 // 04523 // Set the protection into both the PTE and the original PTE 04524 // in the PFN database. 04525 // 04526 04527 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 04528 04529 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 04530 MI_MAKE_VALID_PTE (TempPte, 04531 PointerPte->u.Hard.PageFrameNumber, 04532 ProtectionMask, 04533 NULL); 04534 if (TempPte.u.Hard.Write) { 04535 MI_SET_PTE_DIRTY (TempPte); 04536 } 04537 04538 // 04539 // Flush the TB as we have changed the protection 04540 // of a valid PTE. 04541 // 04542 04543 MiFlushTbAndCapture (PointerPte, 04544 TempPte.u.Flush, 04545 Pfn1); 04546 } else { 04547 04548 // 04549 // No access, remove page from memory, make it transition. 04550 // 04551 04552 MiMakeValidPageNoAccess64 (PointerPte); 04553 } 04554 } else { 04555 04556 // 04557 // the page is not present. 04558 // 04559 04560 if (PteContents.u.Soft.Transition == 1) { 04561 04562 // 04563 // The only reason a PTE would be transition is if it has 04564 // been made no access. If the protection is not no access, 04565 // make it valid with the right protection. otherwise, it 04566 // is already in the desired state, so don't do anything. 04567 // 04568 04569 if (ProtectionMask != MM_NOACCESS) { 04570 MiMakeNoAccessPageValid64 (PointerPte, ProtectionMask); 04571 } 04572 04573 } else { 04574 04575 // 04576 // Must be page file space or demand zero. 04577 // 04578 04579 PointerPte->u.Soft.Protection = ProtectionMask; 04580 ASSERT (PointerPte->u.Long != 0); 04581 } 04582 } 04583 PointerPte += 1; 04584 } //end while 04585 } 04586 04587 // 04588 // Common completion code. 04589 // 04590 04591 CapturedRegionSize = (char * POINTER_64)EndingAddress - (char * POINTER_64)StartingAddress + 1L; 04592 04593 Status = STATUS_SUCCESS; 04594 04595 ErrorFound: 04596 04597 UNLOCK_WS (Process); 04598 ErrorFoundNoWs: 04599 04600 UNLOCK_ADDRESS_SPACE (Process); 04601 04602 if (Attached) { 04603 KeDetachProcess(); 04604 } 04605 04606 ObDereferenceObject (Process); 04607 04608 // 04609 // Establish an exception handler and write the size and base 04610 // address. 04611 // 04612 04613 try { 04614 04615 // 04616 // Reprobe the addresses as certain architectures (intel 386 for one) 04617 // do not trap kernel writes. This is the one service which allows 04618 // the protection of the page to change between the initial probe 04619 // and the final argument update. 04620 // 04621 04622 if (PreviousMode != KernelMode) { 04623 04624 ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64)); 04625 ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG)); 04626 ProbeForWriteUlong (OldProtect); 04627 } 04628 04629 *RegionSize = CapturedRegionSize; 04630 *BaseAddress = StartingAddress; 04631 *OldProtect = CapturedOldProtect; 04632 04633 } except (EXCEPTION_EXECUTE_HANDLER) { 04634 NOTHING; 04635 } 04636 04637 return Status; 04638 } 04639 04640 ULONG 04641 MiIsEntireRangeCommitted64 ( 04642 IN PVOID64 StartingAddress, 04643 IN PVOID64 EndingAddress, 04644 IN PMMVAD Vad, 04645 IN PEPROCESS Process 04646 ) 04647 04648 /*++ 04649 04650 Routine Description: 04651 04652 This routine examines the range of pages from the starting address 04653 up to and including the ending address and returns TRUE if every 04654 page in the range is committed, FALSE otherwise. 04655 04656 Arguments: 04657 04658 StartingAddress - Supplies the starting address of the range. 04659 04660 EndingAddress - Supplies the ending address of the range. 04661 04662 Vad - Supplies the virtual address descriptor which describes the range. 04663 04664 Process - Supplies the current process. 04665 04666 Return Value: 04667 04668 TRUE if the entire range is committed. 04669 FALSE if any page within the range is not committed. 04670 04671 Environment: 04672 04673 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 04674 held. 04675 04676 --*/ 04677 04678 { 04679 PMMPTE PointerPte; 04680 PMMPTE LastPte; 04681 PMMPTE PointerPde; 04682 LOGICAL FirstTime; 04683 PVOID64 Va; 04684 04685 PAGED_CODE(); 04686 04687 FirstTime = TRUE; 04688 04689 PointerPde = MiGetPdeAddress64 (StartingAddress); 04690 PointerPte = MiGetPteAddress64 (StartingAddress); 04691 LastPte = MiGetPteAddress64 (EndingAddress); 04692 04693 ASSERT (Vad->u.VadFlags.PrivateMemory == 1); 04694 04695 Va = StartingAddress; 04696 04697 while (PointerPte <= LastPte) { 04698 04699 if (MiIsPteOnPdeBoundary(PointerPte) || FirstTime) { 04700 04701 // 04702 // This is a PDE boundary, check to see if the entire 04703 // PDE page exists. 04704 // 04705 04706 FirstTime = FALSE; 04707 PointerPde = MiGetPteAddress (PointerPte); 04708 04709 if (PointerPde->u.Long == 0) { 04710 04711 // 04712 // No page directory entry for private memory means 04713 // we're not committed. 04714 // 04715 04716 ASSERT (Vad->u.VadFlags.PrivateMemory == 1); 04717 return FALSE; 04718 } 04719 #if 0 04720 while (!MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE)) { 04721 04722 // 04723 // No PDE exists for the starting address, check the VAD 04724 // to see if the pages are committed. 04725 // 04726 04727 PointerPde += 1; 04728 04729 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 04730 Va = MiGetVirtualAddressMappedByPte (PointerPte); 04731 04732 if (PointerPte > LastPte) { 04733 04734 // 04735 // Make sure the entire range is committed. 04736 // 04737 04738 if (Vad->u.VadFlags.MemCommit == 0) { 04739 04740 // 04741 // The entire range to be decommitted is not committed, 04742 // return an error. 04743 // 04744 04745 return FALSE; 04746 } else { 04747 return TRUE; 04748 } 04749 } 04750 04751 // 04752 // Make sure the range thus far is committed. 04753 // 04754 04755 if (Vad->u.VadFlags.MemCommit == 0) { 04756 04757 // 04758 // The entire range to be decommitted is not committed, 04759 // return an error. 04760 // 04761 04762 return FALSE; 04763 } 04764 } 04765 #endif //0 04766 } 04767 04768 // 04769 // The page table page exists, check each PTE for commitment. 04770 // 04771 04772 if (PointerPte->u.Long == 0) { 04773 04774 // 04775 // This page has not been committed, check the VAD. 04776 // 04777 04778 #if 0 04779 if (Vad->u.VadFlags.MemCommit == 0) { 04780 #endif 04781 04782 // 04783 // The entire range to be decommitted is not committed, 04784 // return an error. 04785 // 04786 04787 return FALSE; 04788 #if 0 04789 } 04790 #endif 04791 } else { 04792 04793 // 04794 // Has this page been explicitly decommitted? 04795 // 04796 04797 if (MiIsPteDecommittedPage (PointerPte)) { 04798 04799 // 04800 // This page has been explicitly decommitted, return an error. 04801 // 04802 04803 return FALSE; 04804 } 04805 } 04806 PointerPte += 1; 04807 Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE); 04808 } 04809 return TRUE; 04810 } 04811 04812 04813 VOID 04814 MiMakeValidPageNoAccess64 ( 04815 IN PMMPTE PointerPte 04816 ) 04817 { 04818 PMMPFN Pfn1; 04819 PMMPTE PointerPde; 04820 MMPTE PteContents; 04821 KIRQL OldIrql; 04822 MMPTE TempPte; 04823 ULONG_PTR Vpn; 04824 04825 Vpn = (ULONG_PTR)((ULONGLONG)MiGetVirtualAddressMappedByPte64(PointerPte) >> 04826 PAGE_SHIFT); 04827 04828 TempPte = PrototypePte; 04829 TempPte.u.Soft.Protection = MM_NOACCESS; 04830 04831 PointerPde = MiGetPteAddress (PointerPte); 04832 LOCK_PFN (OldIrql); 04833 04834 PteContents = *PointerPte; 04835 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 04836 04837 if (Pfn1->u3.e1.PrototypePte == 1) { 04838 04839 // 04840 // Capture the state of the modified bit for this pte. 04841 // 04842 04843 MI_CAPTURE_DIRTY_BIT_TO_PFN (&PteContents, Pfn1); 04844 04845 // 04846 // Decrement the share and valid counts of the page table 04847 // page which maps this PTE. 04848 // 04849 04850 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE(PointerPde)); 04851 04852 // 04853 // Decrement the share count for the physical page. 04854 // 04855 04856 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents)); 04857 04858 } else { 04859 04860 // 04861 // Make the PTE transition, but don't decrement the reference count 04862 // only the share count. 04863 // 04864 04865 ASSERT (Pfn1->u3.e2.ReferenceCount != 0); 04866 Pfn1->u3.e2.ReferenceCount += 1; 04867 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE(&PteContents)); 04868 TempPte = PteContents; 04869 MI_MAKE_VALID_PTE_TRANSITION (TempPte, MM_NOACCESS); 04870 } 04871 04872 KeFlushSingleTb64 (Vpn, 04873 TRUE, 04874 FALSE, 04875 (PHARDWARE_PTE)PointerPte, 04876 TempPte.u.Flush); 04877 UNLOCK_PFN (OldIrql); 04878 return; 04879 } 04880 04881 VOID 04882 MiMakeNoAccessPageValid64 ( 04883 IN PMMPTE PointerPte, 04884 IN ULONG Protect 04885 ) 04886 04887 { 04888 MMPTE PteContents; 04889 MMPTE TempPte; 04890 KIRQL OldIrql; 04891 PMMPFN Pfn1; 04892 PFN_NUMBER PageFrameIndex; 04893 04894 LOCK_PFN (OldIrql); 04895 PteContents = *PointerPte; 04896 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents); 04897 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 04898 MI_MAKE_VALID_PTE (TempPte, 04899 PageFrameIndex, 04900 Protect, 04901 NULL); 04902 if (TempPte.u.Hard.Write) { 04903 MI_SET_PTE_DIRTY (TempPte); 04904 } 04905 04906 // 04907 // Note that VLM no access pages are marked as transition pages and 04908 // are not in any page tables. Therefore their sharecount is zero. 04909 // 04910 // The subtlety is that the reference count on this VLM no access page 04911 // should never go to 0 because then the page will actually be freed 04912 // to the standby list - and we'd only want to do that if we were actually 04913 // getting rid of the page (as opposed to making it no-access). 04914 // 04915 // Thus, the ASSERT below cannot be turned on. 04916 // 04917 // ASSERT (Pfn1->u2.ShareCount == 1); 04918 // 04919 04920 ASSERT (Pfn1->u3.e2.ReferenceCount != 0); 04921 Pfn1->u2.ShareCount += 1; 04922 *PointerPte = TempPte; 04923 UNLOCK_PFN (OldIrql); 04924 return; 04925 } 04926 04927 NTSTATUS 04928 MiGetVlmInfo ( 04929 IN PMEMORY_VLM_COUNTERS VlmUserInfo 04930 ) 04931 04932 /*++ 04933 04934 Routine Description: 04935 04936 This function returns the various VLM information values. 04937 04938 Arguments: 04939 04940 VlmInfo - Supplies a VLM information structure to fill in. 04941 04942 Return Value: 04943 04944 Returns the status. 04945 04946 Environment: 04947 04948 Kernel mode. The caller is responsible for ensuring that VLM is enabled. 04949 04950 --*/ 04951 04952 { 04953 PMMPTE PointerPte; 04954 PEPROCESS TargetProcess; 04955 PMI_PROCESS_VLM_INFO VlmInfo; 04956 04957 RtlZeroMemory (VlmUserInfo, sizeof (*VlmUserInfo)); 04958 04959 VlmUserInfo->SystemCommitCharge = MiVlmCommitChargeInPages; 04960 VlmUserInfo->SystemPeakCommitCharge = MiVlmCommitChargeInPagesPeak; 04961 VlmUserInfo->SystemSharedCommitCharge = MmSharedCommitVlm; 04962 VlmUserInfo->VirtualSizeAvailable = 04963 MM_HIGHEST_USER_ADDRESS64 - MM_LOWEST_USER_ADDRESS64 + 1; 04964 04965 04966 TargetProcess = PsGetCurrentProcess(); 04967 04968 LOCK_WS (TargetProcess); 04969 04970 if (TargetProcess->AddressSpaceDeleted != 0) { 04971 UNLOCK_WS (TargetProcess); 04972 return STATUS_PROCESS_IS_TERMINATING; 04973 } 04974 04975 PointerPte = MiGetPteAddress (PDE_BASE64); 04976 04977 if (PointerPte->u.Long != 0) { 04978 04979 ASSERT (PointerPte->u.Hard.Valid == 1); 04980 04981 VlmInfo = (PMI_PROCESS_VLM_INFO) (((PMMPTE)PDE_BASE64)->u.Long); 04982 04983 VlmUserInfo->VirtualSize = VlmInfo->VirtualSize; 04984 VlmUserInfo->PeakVirtualSize = VlmInfo->VirtualSizePeak; 04985 04986 VlmUserInfo->VirtualSizeAvailable -= VlmInfo->VirtualSize; 04987 04988 VlmUserInfo->CommitCharge = VlmInfo->CommitCharge; 04989 VlmUserInfo->PeakCommitCharge = VlmInfo->CommitChargePeak; 04990 } 04991 04992 UNLOCK_WS (TargetProcess); 04993 04994 return STATUS_SUCCESS; 04995 } 04996 04997 NTSTATUS 04998 NtQueryVirtualMemory64( 04999 IN HANDLE ProcessHandle, 05000 IN PVOID64 *pBaseAddress, 05001 IN MEMORY_INFORMATION_CLASS MemoryInformationClass, 05002 OUT PVOID MemoryInformation, 05003 IN ULONG MemoryInformationLength, 05004 OUT PULONG ReturnLength OPTIONAL 05005 ) 05006 05007 /*++ 05008 05009 Routine Description: 05010 05011 This function provides the capability to determine the state, 05012 protection, and type of a region of pages within the virtual address 05013 space of the subject process. 05014 05015 The state of the first page within the region is determined and then 05016 subsequent entries in the process address map are scanned from the 05017 base address upward until either the entire range of pages has been 05018 scanned or until a page with a nonmatching set of attributes is 05019 encountered. The region attributes, the length of the region of pages 05020 with matching attributes, and an appropriate status value are 05021 returned. 05022 05023 If the entire region of pages does not have a matching set of 05024 attributes, then the returned length parameter value can be used to 05025 calculate the address and length of the region of pages that was not 05026 scanned. 05027 05028 Arguments: 05029 05030 05031 ProcessHandle - An open handle to a process object. 05032 05033 pBaseAddress - Pointer to the base address of the region of pages to be 05034 queried. This value is rounded down to the next host-page- 05035 address boundary. 05036 05037 Note this is a 32-bit pointer to a 64-bit pointer. This is 05038 necessary because all system service arguments are canonicalized 05039 to 32 bits. 05040 05041 MemoryInformationClass - The memory information class about which 05042 to retrieve information. 05043 05044 MemoryInformation - A pointer to a buffer that receives the 05045 specified information. The format and content of the buffer 05046 depend on the specified information class. 05047 05048 05049 MemoryBasicInformation - Data type is PMEMORY_BASIC_INFORMATION. 05050 05051 MEMORY_BASIC_INFORMATION Structure 05052 05053 05054 ULONG RegionSize - The size of the region in bytes 05055 beginning at the base address in which all pages have 05056 identical attributes. 05057 05058 ULONG State - The state of the pages within the region. 05059 05060 State Values State Values 05061 05062 MEM_COMMIT - The state of the pages within the region 05063 is committed. 05064 05065 MEM_FREE - The state of the pages within the region 05066 is free. 05067 05068 MEM_RESERVE - The state of the pages within the 05069 region is reserved. 05070 05071 ULONG Protect - The protection of the pages within the 05072 region. 05073 05074 05075 Protect Values Protect Values 05076 05077 PAGE_NOACCESS - No access to the region of pages is 05078 allowed. An attempt to read, write, or execute 05079 within the region results in an access violation 05080 (i.e., a GP fault). 05081 05082 PAGE_EXECUTE - Execute access to the region of pages 05083 is allowed. An attempt to read or write within 05084 the region results in an access violation. 05085 05086 PAGE_READONLY - Read-only and execute access to the 05087 region of pages is allowed. An attempt to write 05088 within the region results in an access violation. 05089 05090 PAGE_READWRITE - Read, write, and execute access to 05091 the region of pages is allowed. If write access 05092 to the underlying section is allowed, then a 05093 single copy of the pages are shared. Otherwise, 05094 the pages are shared read-only/copy-on-write. 05095 05096 PAGE_GUARD - Read, write, and execute access to the 05097 region of pages is allowed; however, access to 05098 the region causes a "guard region entered" 05099 condition to be raised in the subject process. 05100 05101 PAGE_NOCACHE - Disable the placement of committed 05102 pages into the data cache. 05103 05104 ULONG Type - The type of pages within the region. 05105 05106 05107 Type Values 05108 05109 MEM_PRIVATE - The pages within the region are 05110 private. 05111 05112 MEM_MAPPED - The pages within the region are mapped 05113 into the view of a section. 05114 05115 MEM_IMAGE - The pages within the region are mapped 05116 into the view of an image section. 05117 05118 MemoryInformationLength - Specifies the length in bytes of 05119 the memory information buffer. 05120 05121 ReturnLength - An optional pointer which, if specified, 05122 receives the number of bytes placed in the process 05123 information buffer. 05124 05125 05126 Return Value: 05127 05128 Returns the status 05129 05130 TBS 05131 05132 05133 Environment: 05134 05135 Kernel mode. 05136 05137 --*/ 05138 05139 { 05140 KPROCESSOR_MODE PreviousMode; 05141 PEPROCESS TargetProcess; 05142 NTSTATUS Status; 05143 PMMVAD Vad; 05144 PVOID64 Va; 05145 BOOLEAN Found = FALSE; 05146 ULONGLONG TheRegionSize; 05147 ULONG NewProtect; 05148 ULONG NewState; 05149 ULONG_PTR BaseVpn; 05150 PVOID64 BaseAddress; 05151 05152 MEMORY_BASIC_INFORMATION_VLM Info; 05153 05154 if (MI_VLM_ENABLED() == FALSE) { 05155 return STATUS_NOT_IMPLEMENTED; 05156 } 05157 05158 // 05159 // The only supported option is MEMORY_BASIC_INFORMATION_VLM, make 05160 // sure the user's buffer is large enough for this. 05161 // 05162 05163 // 05164 // Check argument validity. 05165 // 05166 switch (MemoryInformationClass) { 05167 case MemoryBasicInformation: 05168 if (MemoryInformationLength < sizeof(MEMORY_BASIC_INFORMATION_VLM)) { 05169 return STATUS_INFO_LENGTH_MISMATCH; 05170 } 05171 break; 05172 05173 default: 05174 return STATUS_INVALID_INFO_CLASS; 05175 } 05176 05177 PreviousMode = KeGetPreviousMode(); 05178 05179 if (PreviousMode != KernelMode) { 05180 05181 // 05182 // Check arguments. 05183 // 05184 05185 try { 05186 ProbeForRead(pBaseAddress, sizeof(PVOID64), sizeof(ULONG)); 05187 BaseAddress = *pBaseAddress; 05188 05189 ProbeForWrite(MemoryInformation, 05190 MemoryInformationLength, 05191 sizeof(ULONGLONG)); 05192 05193 if (ARGUMENT_PRESENT(ReturnLength)) { 05194 ProbeForWriteUlong(ReturnLength); 05195 } 05196 05197 } except (EXCEPTION_EXECUTE_HANDLER) { 05198 05199 // 05200 // If an exception occurs during the probe or capture 05201 // of the initial values, then handle the exception and 05202 // return the exception code as the status value. 05203 // 05204 05205 return GetExceptionCode(); 05206 } 05207 } else { 05208 BaseAddress = *pBaseAddress; 05209 } 05210 05211 if (BaseAddress == (PVOID64)NULL) { 05212 BaseAddress = (PVOID64)MM_LOWEST_USER_ADDRESS64; 05213 } 05214 05215 if ((BaseAddress > (PVOID64)MM_HIGHEST_USER_ADDRESS64) || 05216 (BaseAddress < (PVOID64)MM_LOWEST_USER_ADDRESS64)) { 05217 return STATUS_INVALID_PARAMETER; 05218 } 05219 05220 if ( ProcessHandle == NtCurrentProcess() ) { 05221 TargetProcess = PsGetCurrentProcess(); 05222 } else { 05223 Status = ObReferenceObjectByHandle ( ProcessHandle, 05224 PROCESS_QUERY_INFORMATION, 05225 PsProcessType, 05226 PreviousMode, 05227 (PVOID *)&TargetProcess, 05228 NULL ); 05229 05230 if (!NT_SUCCESS(Status)) { 05231 return Status; 05232 } 05233 } 05234 05235 // 05236 // If the specified process is not the current process, attach 05237 // to the specified process. 05238 // 05239 05240 KeAttachProcess (&TargetProcess->Pcb); 05241 05242 // 05243 // Get working set mutex and block APCs. 05244 // 05245 05246 LOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 05247 05248 // 05249 // Make sure the address space was not deleted, if so, return an error. 05250 // 05251 05252 if (TargetProcess->AddressSpaceDeleted != 0) { 05253 UNLOCK_WS (TargetProcess); 05254 UNLOCK_ADDRESS_SPACE (TargetProcess); 05255 KeDetachProcess(); 05256 if ( ProcessHandle != NtCurrentProcess() ) { 05257 ObDereferenceObject (TargetProcess); 05258 } 05259 return STATUS_PROCESS_IS_TERMINATING; 05260 } 05261 05262 if (TargetProcess->ForkWasSuccessful != MM_NO_FORK_ALLOWED) { 05263 Vad = NULL; 05264 } else { 05265 Vad = TargetProcess->CloneRoot; 05266 } 05267 05268 // 05269 // Locate the VAD that contains the base address or the VAD 05270 // which follows the base address. 05271 // 05272 05273 BaseVpn = MI_VA_TO_VPN64 (BaseAddress); 05274 05275 for (;;) { 05276 05277 if (Vad == (PMMVAD)NULL) { 05278 break; 05279 } 05280 05281 if ((BaseVpn >= Vad->StartingVpn) && 05282 (BaseVpn <= Vad->EndingVpn)) { 05283 Found = TRUE; 05284 break; 05285 } 05286 05287 if (BaseVpn < Vad->StartingVpn) { 05288 if (Vad->LeftChild == (PMMVAD)NULL) { 05289 break; 05290 } 05291 Vad = Vad->LeftChild; 05292 05293 } else { 05294 if (BaseVpn < Vad->EndingVpn) { 05295 break; 05296 } 05297 if (Vad->RightChild == (PMMVAD)NULL) { 05298 break; 05299 } 05300 Vad = Vad->RightChild; 05301 } 05302 } 05303 05304 if (!Found) { 05305 05306 // 05307 // There is no virtual address allocated at the base 05308 // address. Return the size of the hole starting at 05309 // the base address. 05310 // 05311 05312 if (Vad == NULL) { 05313 TheRegionSize = MM_LARGEST_VLM_RANGE + 1; 05314 } else { 05315 if (Vad->StartingVpn < BaseVpn) { 05316 05317 // 05318 // We are looking at the Vad which occupies the range 05319 // just before the desired range. Get the next Vad. 05320 // 05321 05322 Vad = MiGetNextVad (Vad); 05323 if (Vad == NULL) { 05324 TheRegionSize = (ULONGLONG)MM_HIGHEST_VAD_ADDRESS64 - 05325 (ULONGLONG)PAGE_ALIGN64(BaseAddress); 05326 } else { 05327 TheRegionSize = (ULONGLONG)MI_VPN_TO_VA64 (Vad->StartingVpn) - 05328 (ULONGLONG)PAGE_ALIGN64(BaseAddress); 05329 } 05330 } else { 05331 TheRegionSize = (ULONGLONG)MI_VPN_TO_VA64 (Vad->StartingVpn) - 05332 (ULONGLONG)PAGE_ALIGN64(BaseAddress); 05333 } 05334 } 05335 05336 UNLOCK_WS (TargetProcess); 05337 UNLOCK_ADDRESS_SPACE (TargetProcess); 05338 KeDetachProcess(); 05339 05340 if (ProcessHandle != NtCurrentProcess()) { 05341 ObDereferenceObject (TargetProcess); 05342 } 05343 05344 // 05345 // Establish an exception handler and write the information and 05346 // returned length. 05347 // 05348 05349 if (MemoryInformationClass == MemoryBasicInformation) { 05350 try { 05351 05352 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->AllocationBase = 05353 (PVOID64)MM_LOWEST_USER_ADDRESS64; 05354 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->AllocationProtect = 05355 0; 05356 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->BaseAddressAsUlongLong = 05357 (ULONGLONG)PAGE_ALIGN64(BaseAddress); 05358 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->RegionSize = 05359 TheRegionSize; 05360 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->State = MEM_FREE; 05361 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->Protect = PAGE_NOACCESS; 05362 ((PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation)->Type = 0; 05363 05364 if (ARGUMENT_PRESENT(ReturnLength)) { 05365 *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION_VLM); 05366 } 05367 05368 } except (EXCEPTION_EXECUTE_HANDLER) { 05369 05370 // 05371 // Just return success. 05372 // 05373 } 05374 05375 return STATUS_SUCCESS; 05376 } 05377 return STATUS_INVALID_ADDRESS; 05378 } 05379 05380 // 05381 // Found a vad. 05382 // 05383 05384 Va = PAGE_ALIGN64(BaseAddress); 05385 Info.BaseAddress = Va; 05386 05387 // 05388 // 05389 // There is a page mapped at the base address. 05390 // 05391 05392 if (Vad->u.VadFlags.PrivateMemory) { 05393 Info.Type = MEM_PRIVATE; 05394 } else { 05395 Info.Type = MEM_MAPPED; 05396 } 05397 05398 Info.State = MiQueryAddressState64 (Va, Vad, TargetProcess, &Info.Protect); 05399 05400 Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE); 05401 05402 while (MI_VA_TO_VPN64 (Va) <= Vad->EndingVpn) { 05403 05404 NewState = MiQueryAddressState64 (Va, 05405 Vad, 05406 TargetProcess, 05407 &NewProtect); 05408 05409 if ((NewState != Info.State) || (NewProtect != Info.Protect)) { 05410 05411 // 05412 // The state for this address does not match, calculate 05413 // size and return. 05414 // 05415 05416 break; 05417 } 05418 Va = (PVOID64)((ULONGLONG)Va + PAGE_SIZE); 05419 } // end while 05420 05421 Info.RegionSize = ((ULONGLONG)Va - (ULONGLONG)Info.BaseAddress); 05422 Info.AllocationBase = MI_VPN_TO_VA64 (Vad->StartingVpn); 05423 Info.AllocationProtect = MI_CONVERT_FROM_PTE_PROTECTION ( 05424 Vad->u.VadFlags.Protection); 05425 05426 // 05427 // A range has been found, release the mutexes, detach from the 05428 // target process and return the information. 05429 // 05430 05431 UNLOCK_WS (TargetProcess); 05432 UNLOCK_ADDRESS_SPACE (TargetProcess); 05433 KeDetachProcess(); 05434 05435 if ( ProcessHandle != NtCurrentProcess() ) { 05436 ObDereferenceObject (TargetProcess); 05437 } 05438 05439 05440 if ( MemoryInformationClass == MemoryBasicInformation ) { 05441 try { 05442 05443 *(PMEMORY_BASIC_INFORMATION_VLM)MemoryInformation = Info; 05444 05445 if (ARGUMENT_PRESENT(ReturnLength)) { 05446 *ReturnLength = sizeof(MEMORY_BASIC_INFORMATION_VLM); 05447 } 05448 05449 } except (EXCEPTION_EXECUTE_HANDLER) { 05450 NOTHING; 05451 } 05452 return STATUS_SUCCESS; 05453 } 05454 return Status; 05455 } 05456 05457 05458 05459 ULONG 05460 MiQueryAddressState64 ( 05461 IN PVOID64 Va, 05462 IN PMMVAD Vad, 05463 IN PEPROCESS TargetProcess, 05464 OUT PULONG ReturnedProtect 05465 ) 05466 05467 /*++ 05468 05469 Routine Description: 05470 05471 05472 Arguments: 05473 05474 Return Value: 05475 05476 Returns the state (MEM_COMMIT, MEM_RESERVE, MEM_PRIVATE). 05477 05478 Environment: 05479 05480 Kernel mode. Working set lock and address creation lock held. 05481 05482 --*/ 05483 05484 { 05485 PMMPTE PointerPte; 05486 PMMPTE PointerPde; 05487 MMPTE CapturedProtoPte; 05488 PMMPTE ProtoPte; 05489 LOGICAL PteIsZero; 05490 ULONG State; 05491 ULONG Protect; 05492 ULONG VadProtect; 05493 05494 VadProtect = MI_CONVERT_FROM_PTE_PROTECTION (Vad->u.VadFlags.Protection); 05495 #ifdef LARGE_PAGES 05496 if (Vad->u.VadFlags.LargePages) { 05497 *ReturnedProtect = VadProtect; 05498 return MEM_COMMIT; 05499 } 05500 #endif //LARGE_PAGES 05501 05502 PointerPde = MiGetPdeAddress64 (Va); 05503 PointerPte = MiGetPteAddress64 (Va); 05504 05505 ASSERT ((Vad->StartingVpn <= MI_VA_TO_VPN64 (Va)) && 05506 (Vad->EndingVpn >= MI_VA_TO_VPN64 (Va))); 05507 05508 PteIsZero = TRUE; 05509 05510 // 05511 // Note that if the PDE and PTE are not valid, then we must be 05512 // in a no-access guard page type VAD. 05513 // 05514 if (MmIsAddressValid (PointerPde) && MmIsAddressValid(PointerPte)) { 05515 05516 // 05517 // A PTE exists at this address, see if it is zero. 05518 // 05519 05520 if (PointerPte->u.Long != 0) { 05521 05522 PteIsZero = FALSE; 05523 05524 // 05525 // There is a non-zero PTE at this address, use 05526 // it to build the information block. 05527 // 05528 05529 if (MiIsPteDecommittedPage (PointerPte)) { 05530 Protect = 0; 05531 State = MEM_RESERVE; 05532 } else { 05533 05534 State = MEM_COMMIT; 05535 05536 Protect = PAGE_READWRITE; 05537 if (PointerPte->u.Hard.Valid == 1) { 05538 if (PointerPte->u.Hard.Write == 0) { 05539 Protect = PAGE_READONLY; 05540 } 05541 } else if (PointerPte->u.Soft.Prototype) { 05542 Protect = VadProtect; 05543 05544 if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED) { 05545 Protect = MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection); 05546 } 05547 05548 ProtoPte = MiGetProtoPteAddress(Vad, 05549 MI_VA_TO_VPN64 (Va)); 05550 CapturedProtoPte.u.Long = 0; 05551 if (ProtoPte) { 05552 CapturedProtoPte = MiCaptureSystemPte (ProtoPte, 05553 TargetProcess); 05554 } 05555 if (CapturedProtoPte.u.Long == 0) { 05556 State = MEM_RESERVE; 05557 Protect = 0; 05558 } 05559 05560 } else { 05561 Protect = MI_CONVERT_FROM_PTE_PROTECTION (PointerPte->u.Soft.Protection); 05562 } 05563 } 05564 } 05565 } 05566 05567 if (PteIsZero == TRUE) { 05568 05569 // 05570 // There is no PDE at this address, the template from 05571 // the VAD supplies the information unless the VAD is 05572 // for an image file. For image files the individual 05573 // protection is on the prototype PTE. 05574 // 05575 05576 // 05577 // Get the default protection information. 05578 // 05579 05580 State = MEM_RESERVE; 05581 Protect = 0; 05582 05583 if ((Vad->u.VadFlags.PrivateMemory == 0) && 05584 (Vad->ControlArea != (PCONTROL_AREA)NULL)) { 05585 05586 // 05587 // This VAD refers to a section. Even though the PTE is 05588 // zero, the actual page may be committed in the section. 05589 // 05590 05591 ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN64 (Va)); 05592 05593 CapturedProtoPte.u.Long = 0; 05594 if (ProtoPte) { 05595 CapturedProtoPte = MiCaptureSystemPte (ProtoPte, 05596 TargetProcess); 05597 } 05598 05599 if (CapturedProtoPte.u.Long != 0) { 05600 State = MEM_COMMIT; 05601 Protect = VadProtect; 05602 } 05603 05604 } else { 05605 05606 // 05607 // Get the protection from the corresponding VAD. 05608 // 05609 05610 if (Vad->u.VadFlags.MemCommit) { 05611 State = MEM_COMMIT; 05612 Protect = VadProtect; 05613 } 05614 } 05615 } 05616 05617 *ReturnedProtect = Protect; 05618 return State; 05619 } 05620 05621 05622 #else 05623 05624 NTSTATUS 05625 NtAllocateVirtualMemory64 ( 05626 IN HANDLE ProcessHandle, 05627 IN OUT PVOID64 *BaseAddress, 05628 IN ULONG ZeroBits, 05629 IN OUT PULONGLONG RegionSize, 05630 IN ULONG AllocationType, 05631 IN ULONG Protect 05632 ) 05633 { 05634 return STATUS_NOT_IMPLEMENTED; 05635 } 05636 05637 NTSTATUS 05638 NtFreeVirtualMemory64( 05639 IN HANDLE ProcessHandle, 05640 IN OUT PVOID64 *BaseAddress, 05641 IN OUT PULONGLONG RegionSize, 05642 IN ULONG FreeType 05643 ) 05644 { 05645 return STATUS_NOT_IMPLEMENTED; 05646 } 05647 05648 NTSTATUS 05649 NtMapViewOfVlmSection ( 05650 IN HANDLE SectionHandle, 05651 IN HANDLE ProcessHandle, 05652 IN OUT PVOID64 *BaseAddress, 05653 IN OUT PULONGLONG SectionOffset OPTIONAL, 05654 IN OUT PULONGLONG ViewSize, 05655 IN ULONG AllocationType, 05656 IN ULONG Protect 05657 ) 05658 { 05659 return STATUS_NOT_IMPLEMENTED; 05660 } 05661 05662 NTSTATUS 05663 NtUnmapViewOfVlmSection( 05664 IN HANDLE ProcessHandle, 05665 IN OUT PVOID64 *BaseAddress 05666 ) 05667 { 05668 return STATUS_NOT_IMPLEMENTED; 05669 } 05670 05671 NTSTATUS 05672 NtQueryVirtualMemory64( 05673 IN HANDLE ProcessHandle, 05674 IN PVOID64 *pBaseAddress, 05675 IN MEMORY_INFORMATION_CLASS MemoryInformationClass, 05676 OUT PVOID MemoryInformation, 05677 IN ULONG MemoryInformationLength, 05678 OUT PULONG ReturnLength OPTIONAL 05679 ) 05680 { 05681 return STATUS_NOT_IMPLEMENTED; 05682 } 05683 05684 NTSTATUS 05685 NtProtectVirtualMemory64( 05686 IN HANDLE ProcessHandle, 05687 IN OUT PVOID64 *BaseAddress, 05688 IN OUT PULONGLONG RegionSize, 05689 IN ULONG NewProtect, 05690 OUT PULONG OldProtect 05691 ) 05692 05693 { 05694 return STATUS_NOT_IMPLEMENTED; 05695 } 05696 05697 #endif //VLM_SUPPORT

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