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

lockvm.c File Reference

#include "mi.h"

Go to the source code of this file.

Functions

NTSTATUS NtLockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
NTSTATUS NtUnlockVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG MapType)
VOID MiInsertConflictInList (PMMLOCK_CONFLICT Conflict)
VOID MiRemoveConflictFromList (PMMLOCK_CONFLICT Conflict)


Function Documentation

VOID MiInsertConflictInList PMMLOCK_CONFLICT  Conflict  ) 
 

Definition at line 1051 of file lockvm.c.

References _MMLOCK_CONFLICT::List, MmChargeCommitmentLock, MmLockConflictList, PMMLOCK_CONFLICT, PsGetCurrentThread, and _MMLOCK_CONFLICT::Thread.

01055 { 01056 KIRQL OldIrql; 01057 Conflict->Thread = PsGetCurrentThread(); 01058 ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); 01059 InsertHeadList ( &MmLockConflictList, 01060 &Conflict->List); 01061 ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); 01062 return; 01063 }

VOID MiRemoveConflictFromList PMMLOCK_CONFLICT  Conflict  ) 
 

Definition at line 1067 of file lockvm.c.

References _MMLOCK_CONFLICT::List, and MmChargeCommitmentLock.

01070 { 01071 KIRQL OldIrql; 01072 01073 ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); 01074 RemoveEntryList (&Conflict->List); 01075 ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); 01076 return; 01077 }

NTSTATUS NtLockVirtualMemory IN HANDLE  ProcessHandle,
IN OUT PVOID *  BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  MapType
 

Definition at line 33 of file lockvm.c.

References ASSERT, _MMVAD::EndingVpn, EXCEPTION_EXECUTE_HANDLER, ExSystemExceptionFilter(), FALSE, _MMWSL::FirstDynamic, KeAttachProcess(), KeDetachProcess(), KernelMode, KPROCESSOR_MODE, LOCK_WS_AND_ADDRESS_SPACE, LOCK_WS_UNSAFE, MI_PFN_ELEMENT, MI_VPN_TO_VA, MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiGetPdeAddress, MiGetPteAddress, MiInsertConflictInList(), MiLocateAddress(), MiLocateWsle(), MiLockFor4kPage(), MiRemoveConflictFromList(), MiSwapWslEntries(), MM_FLUID_WORKING_SET, MmIsAddressValid(), MMLOCK_CONFLICT, MmWorkingSetList, MmWsle, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGE_4K, PAGE_4K_ALIGN, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, ProbeForWritePointer, ProbeForWriteUlong_ptr, PsProcessType, SeLockMemoryPrivilege, SeSinglePrivilegeCheck(), Status, TRUE, _MMPTE::u, _MMVAD::u, _MMWSLE::u1, _MMPFN::u1, UNLOCK_ADDRESS_SPACE, UNLOCK_WS_AND_ADDRESS_SPACE, UNLOCK_WS_UNSAFE, VOID(), and WSLE_NULL_INDEX.

00042 : 00043 00044 This function locks a region of pages within the working set list 00045 of a subject process. 00046 00047 The caller of this function must have PROCESS_VM_OPERATION access 00048 to the target process. The caller must also have SeLockMemoryPrivilege. 00049 00050 Arguments: 00051 00052 ProcessHandle - Supplies an open handle to a process object. 00053 00054 BaseAddress - The base address of the region of pages 00055 to be locked. This value is rounded down to the 00056 next host page address boundary. 00057 00058 RegionSize - A pointer to a variable that will receive 00059 the actual size in bytes of the locked region of 00060 pages. The initial value of this argument is 00061 rounded up to the next host page size boundary. 00062 00063 MapType - A set of flags that describe the type of locking to 00064 perform. One of MAP_PROCESS or MAP_SYSTEM. 00065 00066 Return Value: 00067 00068 Returns the status 00069 00070 STATUS_PRIVILEGE_NOT_HELD - The caller did not have sufficient 00071 privilege to perform the requested operation. 00072 00073 TBS 00074 00075 00076 --*/ 00077 00078 { 00079 PVOID Va; 00080 PVOID EndingAddress; 00081 PMMPTE PointerPte; 00082 PMMPTE PointerPte1; 00083 PMMPFN Pfn1; 00084 PMMPTE PointerPde; 00085 PMMPTE PointerPpe; 00086 ULONG_PTR CapturedRegionSize; 00087 PVOID CapturedBase; 00088 PEPROCESS TargetProcess; 00089 NTSTATUS Status; 00090 BOOLEAN WasLocked; 00091 KPROCESSOR_MODE PreviousMode; 00092 ULONG Entry; 00093 ULONG SwapEntry; 00094 SIZE_T NumberOfAlreadyLocked; 00095 SIZE_T NumberToLock; 00096 ULONG WorkingSetIndex; 00097 PMMVAD Vad; 00098 PVOID LastVa; 00099 MMLOCK_CONFLICT Conflict; 00100 ULONG Waited; 00101 LOGICAL Attached; 00102 #if defined(_MIALT4K_) 00103 BOOLEAN IsWow64Process = FALSE; 00104 #endif 00105 00106 PAGED_CODE(); 00107 00108 WasLocked = FALSE; 00109 LastVa = NULL; 00110 00111 // 00112 // Validate the flags in MapType. 00113 // 00114 00115 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)) != 0) { 00116 return STATUS_INVALID_PARAMETER; 00117 } 00118 00119 if ((MapType & (MAP_PROCESS | MAP_SYSTEM)) == 0) { 00120 return STATUS_INVALID_PARAMETER; 00121 } 00122 00123 PreviousMode = KeGetPreviousMode(); 00124 00125 try { 00126 00127 if (PreviousMode != KernelMode) { 00128 00129 ProbeForWritePointer ((PULONG)BaseAddress); 00130 ProbeForWriteUlong_ptr (RegionSize); 00131 } 00132 00133 // 00134 // Capture the base address. 00135 // 00136 00137 CapturedBase = *BaseAddress; 00138 00139 // 00140 // Capture the region size. 00141 // 00142 00143 CapturedRegionSize = *RegionSize; 00144 00145 } except (ExSystemExceptionFilter()) { 00146 00147 // 00148 // If an exception occurs during the probe or capture 00149 // of the initial values, then handle the exception and 00150 // return the exception code as the status value. 00151 // 00152 00153 return GetExceptionCode(); 00154 } 00155 00156 // 00157 // Make sure the specified starting and ending addresses are 00158 // within the user part of the virtual address space. 00159 // 00160 00161 if (CapturedBase > MM_HIGHEST_USER_ADDRESS) { 00162 00163 // 00164 // Invalid base address. 00165 // 00166 00167 return STATUS_INVALID_PARAMETER; 00168 } 00169 00170 if ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)CapturedBase < 00171 CapturedRegionSize) { 00172 00173 // 00174 // Invalid region size; 00175 // 00176 00177 return STATUS_INVALID_PARAMETER; 00178 00179 } 00180 00181 if (CapturedRegionSize == 0) { 00182 return STATUS_INVALID_PARAMETER; 00183 } 00184 00185 // 00186 // Reference the specified process. 00187 // 00188 00189 Status = ObReferenceObjectByHandle ( ProcessHandle, 00190 PROCESS_VM_OPERATION, 00191 PsProcessType, 00192 PreviousMode, 00193 (PVOID *)&TargetProcess, 00194 NULL ); 00195 00196 if (!NT_SUCCESS(Status)) { 00197 return Status; 00198 } 00199 00200 if ((MapType & MAP_SYSTEM) != 0) { 00201 00202 // 00203 // In addition to PROCESS_VM_OPERATION access to the target 00204 // process, the caller must have SE_LOCK_MEMORY_PRIVILEGE. 00205 // 00206 00207 if (!SeSinglePrivilegeCheck( 00208 SeLockMemoryPrivilege, 00209 PreviousMode 00210 )) { 00211 00212 ObDereferenceObject( TargetProcess ); 00213 return( STATUS_PRIVILEGE_NOT_HELD ); 00214 } 00215 } 00216 00217 // 00218 // Attach to the specified process. 00219 // 00220 00221 if (ProcessHandle != NtCurrentProcess()) { 00222 KeAttachProcess (&TargetProcess->Pcb); 00223 Attached = TRUE; 00224 } 00225 else { 00226 Attached = FALSE; 00227 } 00228 00229 // 00230 // Get address creation mutex, this prevents the 00231 // address range from being modified while it is examined. Raise 00232 // to APC level to prevent an APC routine from acquiring the 00233 // address creation mutex. Get the working set mutex so the 00234 // number of already locked pages in the request can be determined. 00235 // 00236 00237 #if defined(_MIALT4K_) 00238 00239 // 00240 // changing to 4k aligned should not change the correctness. 00241 // 00242 00243 EndingAddress = PAGE_4K_ALIGN((PCHAR)CapturedBase + CapturedRegionSize - 1); 00244 #else 00245 EndingAddress = PAGE_ALIGN((PCHAR)CapturedBase + CapturedRegionSize - 1); 00246 #endif 00247 00248 Va = PAGE_ALIGN (CapturedBase); 00249 NumberOfAlreadyLocked = 0; 00250 NumberToLock = ((ULONG_PTR)EndingAddress - (ULONG_PTR)Va) >> PAGE_SHIFT; 00251 00252 LOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 00253 00254 // 00255 // Make sure the address space was not deleted, if so, return an error. 00256 // 00257 00258 if (TargetProcess->AddressSpaceDeleted != 0) { 00259 Status = STATUS_PROCESS_IS_TERMINATING; 00260 goto ErrorReturn; 00261 } 00262 00263 if (NumberToLock + MM_FLUID_WORKING_SET > 00264 TargetProcess->Vm.MinimumWorkingSetSize) { 00265 Status = STATUS_WORKING_SET_QUOTA; 00266 goto ErrorReturn; 00267 } 00268 00269 while (Va <= EndingAddress) { 00270 00271 if (Va > LastVa) { 00272 00273 // 00274 // Don't lock physically mapped views. 00275 // 00276 00277 Vad = MiLocateAddress (Va); 00278 if (Vad == NULL) { 00279 Status = STATUS_ACCESS_VIOLATION; 00280 goto ErrorReturn; 00281 } 00282 00283 if ((Vad->u.VadFlags.PhysicalMapping == 1) || 00284 (Vad->u.VadFlags.UserPhysicalPages == 1)) { 00285 Status = STATUS_INCOMPATIBLE_FILE_MAP; 00286 goto ErrorReturn; 00287 } 00288 LastVa = MI_VPN_TO_VA (Vad->EndingVpn); 00289 } 00290 00291 if (MmIsAddressValid (Va)) { 00292 00293 // 00294 // The page is valid, therefore it is in the working set. 00295 // Locate the WSLE for the page and see if it is locked. 00296 // 00297 00298 PointerPte1 = MiGetPteAddress (Va); 00299 Pfn1 = MI_PFN_ELEMENT (PointerPte1->u.Hard.PageFrameNumber); 00300 00301 WorkingSetIndex = MiLocateWsle (Va, 00302 MmWorkingSetList, 00303 Pfn1->u1.WsIndex); 00304 00305 ASSERT (WorkingSetIndex != WSLE_NULL_INDEX); 00306 00307 if (WorkingSetIndex < MmWorkingSetList->FirstDynamic) { 00308 00309 // 00310 // This page is locked in the working set. 00311 // 00312 00313 NumberOfAlreadyLocked += 1; 00314 00315 // 00316 // Check to see if the WAS_LOCKED status should be returned. 00317 // 00318 00319 if ((MapType & MAP_PROCESS) && 00320 (MmWsle[WorkingSetIndex].u1.e1.LockedInWs == 1)) { 00321 WasLocked = TRUE; 00322 } 00323 00324 if ((MapType & MAP_SYSTEM) && 00325 (MmWsle[WorkingSetIndex].u1.e1.LockedInMemory == 1)) { 00326 WasLocked = TRUE; 00327 } 00328 } 00329 } 00330 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00331 } 00332 00333 UNLOCK_WS_UNSAFE (TargetProcess); 00334 00335 // 00336 // Check to ensure the working set list is still fluid after 00337 // the requested number of pages are locked. 00338 // 00339 00340 if (TargetProcess->Vm.MinimumWorkingSetSize < 00341 ((MmWorkingSetList->FirstDynamic + NumberToLock + 00342 MM_FLUID_WORKING_SET) - NumberOfAlreadyLocked)) { 00343 00344 Status = STATUS_WORKING_SET_QUOTA; 00345 UNLOCK_ADDRESS_SPACE (TargetProcess); 00346 goto ErrorReturn1; 00347 } 00348 00349 Va = PAGE_ALIGN (CapturedBase); 00350 00351 #if defined(_MIALT4K_) 00352 00353 if (TargetProcess->Wow64Process != NULL) { 00354 00355 IsWow64Process = TRUE; 00356 Va = PAGE_4K_ALIGN (CapturedBase); 00357 00358 } 00359 00360 #endif 00361 00362 // 00363 // Set up an exception handler and touch each page in the specified 00364 // range. 00365 // 00366 00367 MiInsertConflictInList (&Conflict); 00368 00369 try { 00370 00371 while (Va <= EndingAddress) { 00372 *(volatile ULONG *)Va; 00373 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00374 } 00375 00376 } except (EXCEPTION_EXECUTE_HANDLER) { 00377 Status = GetExceptionCode(); 00378 MiRemoveConflictFromList (&Conflict); 00379 UNLOCK_ADDRESS_SPACE (TargetProcess); 00380 goto ErrorReturn1; 00381 } 00382 00383 MiRemoveConflictFromList (&Conflict); 00384 00385 // 00386 // The complete address range is accessible, lock the pages into 00387 // the working set. 00388 // 00389 00390 PointerPte = MiGetPteAddress (CapturedBase); 00391 Va = PAGE_ALIGN (CapturedBase); 00392 00393 #if defined(_MIALT4K_) 00394 00395 if (IsWow64Process) { 00396 00397 Va = PAGE_4K_ALIGN (CapturedBase); 00398 00399 } 00400 00401 #endif 00402 00403 // 00404 // Acquire the working set mutex, no page faults are allowed. 00405 // 00406 00407 LOCK_WS_UNSAFE (TargetProcess); 00408 00409 while (Va <= EndingAddress) { 00410 00411 // 00412 // Make sure the PDE is valid. 00413 // 00414 00415 PointerPde = MiGetPdeAddress (Va); 00416 PointerPpe = MiGetPteAddress (PointerPde); 00417 00418 do { 00419 00420 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, 00421 TargetProcess, 00422 FALSE, 00423 &Waited); 00424 00425 Waited = 0; 00426 00427 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 00428 TargetProcess, 00429 FALSE, 00430 &Waited); 00431 00432 } while (Waited != 0); 00433 00434 // 00435 // Make sure the page is in the working set. 00436 // 00437 00438 while (PointerPte->u.Hard.Valid == 0) { 00439 00440 // 00441 // Release the working set mutex and fault in the page. 00442 // 00443 00444 UNLOCK_WS_UNSAFE (TargetProcess); 00445 00446 // 00447 // Page in the PDE and make the PTE valid. 00448 // 00449 00450 *(volatile ULONG *)Va; 00451 00452 // 00453 // Reacquire the working set mutex. 00454 // 00455 00456 LOCK_WS_UNSAFE (TargetProcess); 00457 00458 // 00459 // Make sure the page directory & table pages are still valid. 00460 // Trimming could occur if either of the pages that were just 00461 // made valid were removed from the working set before the 00462 // working set lock was acquired. 00463 // 00464 00465 do { 00466 00467 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, 00468 TargetProcess, 00469 FALSE, 00470 &Waited); 00471 00472 Waited = 0; 00473 00474 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 00475 TargetProcess, 00476 FALSE, 00477 &Waited); 00478 } while (Waited != 0); 00479 } 00480 00481 // 00482 // The page is now in the working set, lock the page into 00483 // the working set. 00484 // 00485 00486 PointerPte1 = MiGetPteAddress (Va); 00487 Pfn1 = MI_PFN_ELEMENT (PointerPte1->u.Hard.PageFrameNumber); 00488 00489 Entry = MiLocateWsle (Va, MmWorkingSetList, Pfn1->u1.WsIndex); 00490 00491 if (Entry >= MmWorkingSetList->FirstDynamic) { 00492 00493 SwapEntry = MmWorkingSetList->FirstDynamic; 00494 00495 if (Entry != MmWorkingSetList->FirstDynamic) { 00496 00497 // 00498 // Swap this entry with the one at first dynamic. 00499 // 00500 00501 MiSwapWslEntries (Entry, SwapEntry, &TargetProcess->Vm); 00502 } 00503 00504 MmWorkingSetList->FirstDynamic += 1; 00505 } else { 00506 SwapEntry = Entry; 00507 } 00508 00509 // 00510 // Indicate that the page is locked. 00511 // 00512 00513 if (MapType & MAP_PROCESS) { 00514 MmWsle[SwapEntry].u1.e1.LockedInWs = 1; 00515 } 00516 00517 if (MapType & MAP_SYSTEM) { 00518 MmWsle[SwapEntry].u1.e1.LockedInMemory = 1; 00519 } 00520 00521 // 00522 // Increment to the next va and PTE. 00523 // 00524 00525 PointerPte += 1; 00526 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00527 } 00528 00529 #if !(defined(_MIALT4K_)) 00530 00531 UNLOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 00532 00533 #else 00534 00535 UNLOCK_WS_UNSAFE (TargetProcess); 00536 00537 if (IsWow64Process) { 00538 00539 MiLockFor4kPage(CapturedBase, CapturedRegionSize, TargetProcess); 00540 00541 } 00542 00543 UNLOCK_ADDRESS_SPACE (TargetProcess); 00544 00545 #endif 00546 00547 if (Attached == TRUE) { 00548 KeDetachProcess(); 00549 } 00550 ObDereferenceObject (TargetProcess); 00551 00552 // 00553 // Update return arguments. 00554 // 00555 00556 // 00557 // Establish an exception handler and write the size and base 00558 // address. 00559 // 00560 00561 try { 00562 00563 #if defined(_MIALT4K_) 00564 00565 if (IsWow64Process) { 00566 00567 *RegionSize = ((PCHAR)EndingAddress - 00568 (PCHAR)PAGE_4K_ALIGN(CapturedBase)) + PAGE_4K; 00569 00570 *BaseAddress = PAGE_4K_ALIGN(CapturedBase); 00571 00572 00573 } else { 00574 00575 #endif 00576 *RegionSize = ((PCHAR)EndingAddress - (PCHAR)PAGE_ALIGN(CapturedBase)) + 00577 PAGE_SIZE; 00578 *BaseAddress = PAGE_ALIGN(CapturedBase); 00579 00580 #if defined(_MIALT4K_) 00581 } 00582 #endif 00583 00584 } except (EXCEPTION_EXECUTE_HANDLER) { 00585 return GetExceptionCode(); 00586 } 00587 00588 if (WasLocked) { 00589 return STATUS_WAS_LOCKED; 00590 } 00591 00592 return STATUS_SUCCESS; 00593 00594 ErrorReturn: 00595 UNLOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 00596 ErrorReturn1: 00597 if (Attached == TRUE) { 00598 KeDetachProcess(); 00599 } 00600 ObDereferenceObject (TargetProcess); 00601 return Status; 00602 }

NTSTATUS NtUnlockVirtualMemory IN HANDLE  ProcessHandle,
IN OUT PVOID *  BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  MapType
 

Definition at line 605 of file lockvm.c.

References ASSERT, _MMVAD::EndingVpn, EXCEPTION_EXECUTE_HANDLER, ExSystemExceptionFilter(), FALSE, _MMWSL::FirstDynamic, KeAttachProcess(), KeDetachProcess(), KernelMode, KPROCESSOR_MODE, LOCK_WS_AND_ADDRESS_SPACE, MI_PFN_ELEMENT, MI_VPN_TO_VA, MiFreeWsle(), MiGetPteAddress, MiLocateAddress(), MiLocateWsle(), MiShouldBeUnlockedFor4kPage(), MiSwapWslEntries(), MiUnlockFor4kPage(), MmIsAddressValid(), MmWorkingSetList, MmWsle, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGE_4K, PAGE_4K_ALIGN, PAGE_ALIGN, PAGE_SIZE, PAGED_CODE, PERFINFO_GET_PAGE_INFO, PERFINFO_LOG_WS_REMOVAL, PERFINFO_PAGE_INFO_DECL, ProbeForWritePointer, ProbeForWriteUlong_ptr, PsProcessType, SeLockMemoryPrivilege, SeSinglePrivilegeCheck(), Status, TRUE, _MMPTE::u, _MMVAD::u, _MMWSLE::u1, _MMPFN::u1, UNLOCK_WS_AND_ADDRESS_SPACE, and WSLE_NULL_INDEX.

00614 : 00615 00616 This function unlocks a region of pages within the working set list 00617 of a subject process. 00618 00619 As a side effect, any pages which are not locked and are in the 00620 process's working set are removed from the process's working set. 00621 This allows NtUnlockVirtualMemory to remove a range of pages 00622 from the working set. 00623 00624 The caller of this function must have PROCESS_VM_OPERATION access 00625 to the target process. 00626 00627 The caller must also have SeLockMemoryPrivilege for MAP_SYSTEM. 00628 00629 Arguments: 00630 00631 ProcessHandle - Supplies an open handle to a process object. 00632 00633 BaseAddress - The base address of the region of pages 00634 to be unlocked. This value is rounded down to the 00635 next host page address boundary. 00636 00637 RegionSize - A pointer to a variable that will receive 00638 the actual size in bytes of the unlocked region of 00639 pages. The initial value of this argument is 00640 rounded up to the next host page size boundary. 00641 00642 MapType - A set of flags that describe the type of unlocking to 00643 perform. One of MAP_PROCESS or MAP_SYSTEM. 00644 00645 Return Value: 00646 00647 Returns the status 00648 00649 TBS 00650 00651 00652 --*/ 00653 00654 { 00655 PVOID Va; 00656 PVOID EndingAddress; 00657 SIZE_T CapturedRegionSize; 00658 PVOID CapturedBase; 00659 PEPROCESS TargetProcess; 00660 NTSTATUS Status; 00661 KPROCESSOR_MODE PreviousMode; 00662 ULONG Entry; 00663 PMMPTE PointerPte; 00664 PMMPFN Pfn1; 00665 PMMVAD Vad; 00666 PVOID LastVa; 00667 LOGICAL Attached; 00668 #if defined(_MIALT4K_) 00669 BOOLEAN IsWow64Process = FALSE; 00670 #endif 00671 00672 PAGED_CODE(); 00673 00674 LastVa = NULL; 00675 00676 // 00677 // Validate the flags in MapType. 00678 // 00679 00680 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)) != 0) { 00681 return STATUS_INVALID_PARAMETER; 00682 } 00683 00684 if ((MapType & (MAP_PROCESS | MAP_SYSTEM)) == 0) { 00685 return STATUS_INVALID_PARAMETER; 00686 } 00687 00688 PreviousMode = KeGetPreviousMode(); 00689 00690 try { 00691 00692 if (PreviousMode != KernelMode) { 00693 00694 ProbeForWritePointer (BaseAddress); 00695 ProbeForWriteUlong_ptr (RegionSize); 00696 } 00697 00698 // 00699 // Capture the base address. 00700 // 00701 00702 CapturedBase = *BaseAddress; 00703 00704 // 00705 // Capture the region size. 00706 // 00707 00708 CapturedRegionSize = *RegionSize; 00709 00710 } except (ExSystemExceptionFilter()) { 00711 00712 // 00713 // If an exception occurs during the probe or capture 00714 // of the initial values, then handle the exception and 00715 // return the exception code as the status value. 00716 // 00717 00718 return GetExceptionCode(); 00719 } 00720 00721 // 00722 // Make sure the specified starting and ending addresses are 00723 // within the user part of the virtual address space. 00724 // 00725 00726 if (CapturedBase > MM_HIGHEST_USER_ADDRESS) { 00727 00728 // 00729 // Invalid base address. 00730 // 00731 00732 return STATUS_INVALID_PARAMETER; 00733 } 00734 00735 if ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)CapturedBase < 00736 CapturedRegionSize) { 00737 00738 // 00739 // Invalid region size; 00740 // 00741 00742 return STATUS_INVALID_PARAMETER; 00743 00744 } 00745 00746 if (CapturedRegionSize == 0) { 00747 return STATUS_INVALID_PARAMETER; 00748 } 00749 00750 Status = ObReferenceObjectByHandle ( ProcessHandle, 00751 PROCESS_VM_OPERATION, 00752 PsProcessType, 00753 PreviousMode, 00754 (PVOID *)&TargetProcess, 00755 NULL ); 00756 00757 if (!NT_SUCCESS(Status)) { 00758 return Status; 00759 } 00760 00761 if ((MapType & MAP_SYSTEM) != 0) { 00762 00763 // 00764 // In addition to PROCESS_VM_OPERATION access to the target 00765 // process, the caller must have SE_LOCK_MEMORY_PRIVILEGE. 00766 // 00767 00768 if (!SeSinglePrivilegeCheck( 00769 SeLockMemoryPrivilege, 00770 PreviousMode 00771 )) { 00772 00773 ObDereferenceObject( TargetProcess ); 00774 return STATUS_PRIVILEGE_NOT_HELD; 00775 } 00776 } 00777 00778 // 00779 // Attach to the specified process. 00780 // 00781 00782 if (ProcessHandle != NtCurrentProcess()) { 00783 KeAttachProcess (&TargetProcess->Pcb); 00784 Attached = TRUE; 00785 } 00786 else { 00787 Attached = FALSE; 00788 } 00789 00790 // 00791 // Get address creation mutex, this prevents the 00792 // address range from being modified while it is examined. 00793 // Block APCs so an APC routine can't get a page fault and 00794 // corrupt the working set list, etc. 00795 // 00796 00797 LOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 00798 00799 // 00800 // Make sure the address space was not deleted, if so, return an error. 00801 // 00802 00803 if (TargetProcess->AddressSpaceDeleted != 0) { 00804 Status = STATUS_PROCESS_IS_TERMINATING; 00805 goto ErrorReturn; 00806 } 00807 00808 EndingAddress = PAGE_ALIGN((PCHAR)CapturedBase + CapturedRegionSize - 1); 00809 00810 Va = PAGE_ALIGN (CapturedBase); 00811 00812 while (Va <= EndingAddress) { 00813 00814 // 00815 // Check to ensure all the specified pages are locked. 00816 // 00817 00818 // 00819 // Don't unlock physically mapped views. 00820 // 00821 00822 if (Va > LastVa) { 00823 Vad = MiLocateAddress (Va); 00824 if (Vad == NULL) { 00825 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00826 Status = STATUS_NOT_LOCKED; 00827 break; 00828 } 00829 00830 if ((Vad->u.VadFlags.PhysicalMapping == 1) || 00831 (Vad->u.VadFlags.UserPhysicalPages == 1)) { 00832 Va = MI_VPN_TO_VA (Vad->EndingVpn); 00833 break; 00834 } 00835 LastVa = MI_VPN_TO_VA (Vad->EndingVpn); 00836 } 00837 00838 if (!MmIsAddressValid (Va)) { 00839 00840 // 00841 // This page is not valid, therefore not in working set. 00842 // 00843 00844 Status = STATUS_NOT_LOCKED; 00845 } else { 00846 00847 PointerPte = MiGetPteAddress (Va); 00848 ASSERT (PointerPte->u.Hard.Valid != 0); 00849 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 00850 Entry = MiLocateWsle (Va, MmWorkingSetList, Pfn1->u1.WsIndex); 00851 ASSERT (Entry != WSLE_NULL_INDEX); 00852 00853 if ((MmWsle[Entry].u1.e1.LockedInWs == 0) && 00854 (MmWsle[Entry].u1.e1.LockedInMemory == 0)) { 00855 00856 // 00857 // Not locked in memory or system, remove from working 00858 // set. 00859 // 00860 00861 PERFINFO_PAGE_INFO_DECL(); 00862 00863 PERFINFO_GET_PAGE_INFO(PointerPte); 00864 00865 if (MiFreeWsle (Entry, &TargetProcess->Vm, PointerPte)) { 00866 PERFINFO_LOG_WS_REMOVAL(PERFINFO_LOG_TYPE_OUTWS_EMPTYQ, &TargetProcess->Vm); 00867 } 00868 00869 Status = STATUS_NOT_LOCKED; 00870 00871 } else if (MapType & MAP_PROCESS) { 00872 if (MmWsle[Entry].u1.e1.LockedInWs == 0) { 00873 00874 // 00875 // This page is not locked. 00876 // 00877 00878 Status = STATUS_NOT_LOCKED; 00879 } 00880 } else { 00881 if (MmWsle[Entry].u1.e1.LockedInMemory == 0) { 00882 00883 // 00884 // This page is not locked. 00885 // 00886 00887 Status = STATUS_NOT_LOCKED; 00888 } 00889 } 00890 } 00891 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00892 } // end while 00893 00894 #if defined(_MIALT4K_) 00895 00896 if (TargetProcess->Wow64Process != NULL) { 00897 00898 IsWow64Process = TRUE; 00899 Status = MiUnlockFor4kPage(CapturedBase, CapturedRegionSize, TargetProcess); 00900 00901 } 00902 00903 #endif 00904 00905 if (Status == STATUS_NOT_LOCKED) { 00906 goto ErrorReturn; 00907 } 00908 00909 // 00910 // The complete address range is locked, unlock them. 00911 // 00912 00913 Va = PAGE_ALIGN (CapturedBase); 00914 LastVa = NULL; 00915 00916 00917 while (Va <= EndingAddress) { 00918 00919 #if defined(_MIALT4K_) 00920 00921 if (IsWow64Process) { 00922 00923 if (!MiShouldBeUnlockedFor4kPage(Va, TargetProcess)) { 00924 00925 // 00926 // The other 4k pages in the native page still hold the page lock. 00927 // Should skip unlocking. 00928 00929 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00930 continue; 00931 } 00932 } 00933 00934 #endif 00935 // 00936 // Don't unlock physically mapped views. 00937 // 00938 00939 if (Va > LastVa) { 00940 Vad = MiLocateAddress (Va); 00941 ASSERT (Vad != NULL); 00942 00943 if ((Vad->u.VadFlags.PhysicalMapping == 1) || 00944 (Vad->u.VadFlags.UserPhysicalPages == 1)) { 00945 Va = MI_VPN_TO_VA (Vad->EndingVpn); 00946 break; 00947 } 00948 LastVa = MI_VPN_TO_VA (Vad->EndingVpn); 00949 } 00950 00951 PointerPte = MiGetPteAddress (Va); 00952 ASSERT (PointerPte->u.Hard.Valid == 1); 00953 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 00954 Entry = MiLocateWsle (Va, MmWorkingSetList, Pfn1->u1.WsIndex); 00955 00956 if (MapType & MAP_PROCESS) { 00957 MmWsle[Entry].u1.e1.LockedInWs = 0; 00958 } 00959 00960 if (MapType & MAP_SYSTEM) { 00961 MmWsle[Entry].u1.e1.LockedInMemory = 0; 00962 } 00963 00964 if ((MmWsle[Entry].u1.e1.LockedInMemory == 0) && 00965 MmWsle[Entry].u1.e1.LockedInWs == 0) { 00966 00967 // 00968 // The page is no longer should be locked, move 00969 // it to the dynamic part of the working set. 00970 // 00971 00972 MmWorkingSetList->FirstDynamic -= 1; 00973 00974 if (Entry != MmWorkingSetList->FirstDynamic) { 00975 00976 // 00977 // Swap this element with the last locked page, making 00978 // this element the new first dynamic entry. 00979 // 00980 00981 MiSwapWslEntries (Entry, 00982 MmWorkingSetList->FirstDynamic, 00983 &TargetProcess->Vm); 00984 } 00985 } 00986 00987 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 00988 } 00989 00990 UNLOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 00991 if (Attached == TRUE) { 00992 KeDetachProcess(); 00993 } 00994 ObDereferenceObject (TargetProcess); 00995 00996 // 00997 // Update return arguments. 00998 // 00999 01000 // 01001 // Establish an exception handler and write the size and base 01002 // address. 01003 // 01004 01005 try { 01006 01007 #if defined(_MIALT4K_) 01008 01009 if (IsWow64Process) { 01010 01011 *RegionSize = ((PCHAR)EndingAddress - 01012 (PCHAR)PAGE_4K_ALIGN(CapturedBase)) + PAGE_4K; 01013 01014 *BaseAddress = PAGE_4K_ALIGN(CapturedBase); 01015 01016 01017 } else { 01018 01019 #endif 01020 *RegionSize = ((PCHAR)EndingAddress - 01021 (PCHAR)PAGE_ALIGN(CapturedBase)) + PAGE_SIZE; 01022 01023 *BaseAddress = PAGE_ALIGN(CapturedBase); 01024 01025 #if defined(_MIALT4K_) 01026 } 01027 #endif 01028 01029 } except (EXCEPTION_EXECUTE_HANDLER) { 01030 return GetExceptionCode(); 01031 } 01032 01033 return STATUS_SUCCESS; 01034 01035 ErrorReturn: 01036 01037 UNLOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 01038 if (Attached == TRUE) { 01039 KeDetachProcess(); 01040 } 01041 ObDereferenceObject (TargetProcess); 01042 return Status; 01043 }


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