test: lockvm.c Source File

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

# lockvm.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007    lockvm.c
    00008
    00009 Abstract:
    00010
    00011     This module contains the routines which implement the
    00012     NtLockVirtualMemory service.
    00013
    00014 Author:
    00015
    00016     Lou Perazzoli (loup) 20-August-1989
    00017
    00018 Revision History:
    00019
    00020     Landy Wang (landyw) 08-April-1998 : Modifications for 3-level 64-bit NT.
    00021
    00022 --*/
    00023
    00024 #include "mi.h"
    00025
    00026 #ifdef ALLOC_PRAGMA
    00027 #pragma alloc_text(PAGE,NtLockVirtualMemory)
    00028 #pragma alloc_text(PAGE,NtUnlockVirtualMemory)
    00029 #endif
    00030
    00031
    00032 NTSTATUS
    00033 NtLockVirtualMemory (
    00034     IN HANDLE ProcessHandle,
    00035     IN OUT PVOID *BaseAddress,
    00036     IN OUT PSIZE_T RegionSize,
    00037     IN ULONG MapType
    00038      )
    00039
    00040 /*++
    00041
    00042 Routine Description:
    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 }
    00603
    00604 NTSTATUS
    00605 NtUnlockVirtualMemory (
    00606     IN HANDLE ProcessHandle,
    00607     IN OUT PVOID *BaseAddress,
    00608     IN OUT PSIZE_T RegionSize,
    00609     IN ULONG MapType
    00610     )
    00611
    00612 /*++
    00613
    00614 Routine Description:
    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 }
    01044
    01045
    01046 //
    01047 // Nonpagable routines.
    01048 //
    01049
    01050 VOID
    01051 MiInsertConflictInList (
    01052     PMMLOCK_CONFLICT Conflict
    01053     )
    01054
    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 }
    01064
    01065
    01066 VOID
    01067 MiRemoveConflictFromList (
    01068     PMMLOCK_CONFLICT Conflict
    01069     )
    01070 {
    01071     KIRQL OldIrql;
    01072
    01073     ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql);
    01074     RemoveEntryList (&Conflict->List);
    01075     ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql);
    01076     return;
    01077 }