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

freevm.c File Reference

#include "mi.h"

Go to the source code of this file.

Defines

#define MEM_CHECK_COMMIT_STATE   0x400000
#define MM_VALID_PTE_SIZE   (256)

Functions

VOID MiProcessValidPteList (IN PMMPTE *PteList, IN ULONG Count)
ULONG MiDecommitPages (IN PVOID StartingAddress, IN PMMPTE EndingPte, IN PEPROCESS Process, IN PMMVAD_SHORT Vad)
VOID MiDeleteFreeVm (IN PVOID StartingAddress, IN PVOID EndingAddress)
NTSTATUS NtFreeVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG FreeType)
ULONG MiIsEntireRangeCommitted (IN PVOID StartingAddress, IN PVOID EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)

Variables

MMPTE MmDecommittedPte = {MM_DECOMMIT << MM_PROTECT_FIELD_SHIFT}


Define Documentation

#define MEM_CHECK_COMMIT_STATE   0x400000
 

Definition at line 25 of file freevm.c.

Referenced by NtAllocateVirtualMemory(), and NtFreeVirtualMemory().

#define MM_VALID_PTE_SIZE   (256)
 

Definition at line 27 of file freevm.c.

Referenced by MiDecommitPages().


Function Documentation

ULONG MiDecommitPages IN PVOID  StartingAddress,
IN PMMPTE  EndingPte,
IN PEPROCESS  Process,
IN PMMVAD_SHORT  Vad
 

Definition at line 1161 of file freevm.c.

References ASSERT, FALSE, _MMWSL::FirstDynamic, FreePageList, LOCK_PFN, _MMWSLENTRY::LockedInMemory, _MMWSLENTRY::LockedInWs, _MMWSLE::Long, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_GET_USED_PTES_HANDLE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MI_SET_PTE_IN_WORKING_SET, MI_VPN_TO_VA, MI_WRITE_INVALID_PTE, MiDecrementShareCount(), MiDeletePte(), MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiInsertPageInList(), MiIsPteOnPdeBoundary, MiLocateWsle(), MiMakePdeExistAndMakeValid(), MiMakePpeExistAndMakeValid, MiProcessValidPteList(), MiReleasePageFileSpace(), MiReleaseWsle(), MiRemoveWsle(), MiSwapWslEntries(), MiUnlinkPageFromList(), MM_VALID_PTE_SIZE, MmDecommittedPte, MmPageLocationList, MmWorkingSetList, MmWsle, NULL, _MMPFN::OriginalPte, PAGE_ALIGN, PAGE_SIZE, _MMPFN::PteFrame, _MMPTE::u, _MMWSLE::u1, _MMPFN::u1, _MMPFN::u3, and UNLOCK_PFN.

Referenced by NtFreeVirtualMemory().

01170 : 01171 01172 This routine decommits the specified range of pages. 01173 01174 Arguments: 01175 01176 StartingAddress - Supplies the starting address of the range. 01177 01178 EndingPte - Supplies the ending PTE of the range. 01179 01180 Process - Supplies the current process. 01181 01182 Vad - Supplies the virtual address descriptor which describes the range. 01183 01184 Return Value: 01185 01186 Value to reduce commitment by for the VAD. 01187 01188 Environment: 01189 01190 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 01191 held. 01192 01193 --*/ 01194 01195 { 01196 PMMPTE PointerPpe; 01197 PMMPTE PointerPde; 01198 PMMPTE PointerPte; 01199 PVOID Va; 01200 ULONG CommitReduction; 01201 PMMPTE CommitLimitPte; 01202 KIRQL OldIrql; 01203 PMMPTE ValidPteList[MM_VALID_PTE_SIZE]; 01204 ULONG count; 01205 ULONG WorkingSetIndex; 01206 PMMPFN Pfn1; 01207 PMMPFN Pfn2; 01208 PVOID SwapVa; 01209 ULONG Entry; 01210 MMWSLENTRY Locked; 01211 MMPTE PteContents; 01212 PVOID UsedPageTableHandle; 01213 PVOID UsedPageDirectoryHandle; 01214 01215 count = 0; 01216 CommitReduction = 0; 01217 01218 if (Vad->u.VadFlags.MemCommit) { 01219 CommitLimitPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->EndingVpn)); 01220 } else { 01221 CommitLimitPte = NULL; 01222 } 01223 01224 // 01225 // Decommit each page by setting the PTE to be explicitly 01226 // decommitted. The PTEs cannot be deleted all at once as 01227 // this would set the PTEs to zero which would auto-evaluate 01228 // as committed if referenced by another thread when a page 01229 // table page is being in-paged. 01230 // 01231 01232 PointerPpe = MiGetPpeAddress (StartingAddress); 01233 PointerPde = MiGetPdeAddress (StartingAddress); 01234 PointerPte = MiGetPteAddress (StartingAddress); 01235 Va = StartingAddress; 01236 01237 // 01238 // Loop through all the PDEs which map this region and ensure that 01239 // they exist. If they don't exist create them by touching a 01240 // PTE mapped by the PDE. 01241 // 01242 01243 #if defined (_WIN64) 01244 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01245 if (PointerPde->u.Long == 0) { 01246 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01247 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01248 } 01249 #endif 01250 01251 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 01252 01253 while (PointerPte <= EndingPte) { 01254 01255 if (MiIsPteOnPdeBoundary (PointerPte)) { 01256 01257 PointerPde = MiGetPdeAddress (Va); 01258 PointerPpe = MiGetPpeAddress (Va); 01259 if (count != 0) { 01260 MiProcessValidPteList (&ValidPteList[0], count); 01261 count = 0; 01262 } 01263 01264 #if defined (_WIN64) 01265 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01266 if (PointerPde->u.Long == 0) { 01267 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01268 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01269 } 01270 #endif 01271 01272 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 01273 } 01274 01275 // 01276 // The working set lock is held. No PTEs can go from 01277 // invalid to valid or valid to invalid. Transition 01278 // PTEs can go from transition to pagefile. 01279 // 01280 01281 PteContents = *PointerPte; 01282 01283 if (PteContents.u.Long != 0) { 01284 01285 if (PointerPte->u.Long == MmDecommittedPte.u.Long) { 01286 01287 // 01288 // This PTE is already decommitted. 01289 // 01290 01291 CommitReduction += 1; 01292 01293 } else { 01294 01295 Process->NumberOfPrivatePages -= 1; 01296 01297 if (PteContents.u.Hard.Valid == 1) { 01298 01299 // 01300 // Make sure this is not a forked PTE. 01301 // 01302 01303 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01304 01305 if (Pfn1->u3.e1.PrototypePte) { 01306 01307 LOCK_PFN (OldIrql); 01308 MiDeletePte (PointerPte, 01309 Va, 01310 FALSE, 01311 Process, 01312 NULL, 01313 NULL); 01314 UNLOCK_PFN (OldIrql); 01315 Process->NumberOfPrivatePages += 1; 01316 MI_WRITE_INVALID_PTE (PointerPte, MmDecommittedPte); 01317 } else { 01318 01319 // 01320 // Pte is valid, process later when PFN lock is held. 01321 // 01322 01323 if (count == MM_VALID_PTE_SIZE) { 01324 MiProcessValidPteList (&ValidPteList[0], count); 01325 count = 0; 01326 } 01327 ValidPteList[count] = PointerPte; 01328 count += 1; 01329 01330 // 01331 // Remove address from working set list. 01332 // 01333 01334 01335 WorkingSetIndex = Pfn1->u1.WsIndex; 01336 01337 ASSERT (PAGE_ALIGN(MmWsle[WorkingSetIndex].u1.Long) == 01338 Va); 01339 // 01340 // Check to see if this entry is locked in the working set 01341 // or locked in memory. 01342 // 01343 01344 Locked = MmWsle[WorkingSetIndex].u1.e1; 01345 01346 MiRemoveWsle (WorkingSetIndex, MmWorkingSetList); 01347 01348 // 01349 // Add this entry to the list of free working set entries 01350 // and adjust the working set count. 01351 // 01352 01353 MiReleaseWsle (WorkingSetIndex, &Process->Vm); 01354 01355 if ((Locked.LockedInWs == 1) || (Locked.LockedInMemory == 1)) { 01356 01357 // 01358 // This entry is locked. 01359 // 01360 01361 MmWorkingSetList->FirstDynamic -= 1; 01362 01363 if (WorkingSetIndex != MmWorkingSetList->FirstDynamic) { 01364 01365 SwapVa = MmWsle[MmWorkingSetList->FirstDynamic].u1.VirtualAddress; 01366 SwapVa = PAGE_ALIGN (SwapVa); 01367 Pfn2 = MI_PFN_ELEMENT ( 01368 MiGetPteAddress (SwapVa)->u.Hard.PageFrameNumber); 01369 01370 Entry = MiLocateWsle (SwapVa, 01371 MmWorkingSetList, 01372 Pfn2->u1.WsIndex); 01373 01374 MiSwapWslEntries (Entry, 01375 WorkingSetIndex, 01376 &Process->Vm); 01377 } 01378 } 01379 MI_SET_PTE_IN_WORKING_SET (PointerPte, 0); 01380 } 01381 } else if (PteContents.u.Soft.Prototype) { 01382 01383 // 01384 // This is a forked PTE, just delete it. 01385 // 01386 01387 LOCK_PFN (OldIrql); 01388 MiDeletePte (PointerPte, 01389 Va, 01390 FALSE, 01391 Process, 01392 NULL, 01393 NULL); 01394 UNLOCK_PFN (OldIrql); 01395 Process->NumberOfPrivatePages += 1; 01396 MI_WRITE_INVALID_PTE (PointerPte, MmDecommittedPte); 01397 01398 } else if (PteContents.u.Soft.Transition == 1) { 01399 01400 // 01401 // Transition PTE, get the PFN database lock 01402 // and reprocess this one. 01403 // 01404 01405 LOCK_PFN (OldIrql); 01406 PteContents = *PointerPte; 01407 01408 if (PteContents.u.Soft.Transition == 1) { 01409 01410 // 01411 // PTE is still in transition, delete it. 01412 // 01413 01414 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 01415 01416 MI_SET_PFN_DELETED (Pfn1); 01417 01418 MiDecrementShareCount (Pfn1->PteFrame); 01419 01420 // 01421 // Check the reference count for the page, if the 01422 // reference count is zero, move the page to the 01423 // free list, if the reference count is not zero, 01424 // ignore this page. When the reference count 01425 // goes to zero, it will be placed on the free list. 01426 // 01427 01428 if (Pfn1->u3.e2.ReferenceCount == 0) { 01429 MiUnlinkPageFromList (Pfn1); 01430 MiReleasePageFileSpace (Pfn1->OriginalPte); 01431 MiInsertPageInList (MmPageLocationList[FreePageList], 01432 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents)); 01433 } 01434 01435 } else { 01436 01437 // 01438 // Page MUST be in page file format! 01439 // 01440 01441 ASSERT (PteContents.u.Soft.Valid == 0); 01442 ASSERT (PteContents.u.Soft.Prototype == 0); 01443 ASSERT (PteContents.u.Soft.PageFileHigh != 0); 01444 MiReleasePageFileSpace (PteContents); 01445 } 01446 MI_WRITE_INVALID_PTE (PointerPte, MmDecommittedPte); 01447 UNLOCK_PFN (OldIrql); 01448 } else { 01449 01450 // 01451 // Must be demand zero or paging file format. 01452 // 01453 01454 if (PteContents.u.Soft.PageFileHigh != 0) { 01455 LOCK_PFN (OldIrql); 01456 MiReleasePageFileSpace (PteContents); 01457 UNLOCK_PFN (OldIrql); 01458 } else { 01459 01460 // 01461 // Don't subtract out the private page count for 01462 // a demand zero page. 01463 // 01464 01465 Process->NumberOfPrivatePages += 1; 01466 } 01467 01468 MI_WRITE_INVALID_PTE (PointerPte, MmDecommittedPte); 01469 } 01470 } 01471 01472 } else { 01473 01474 // 01475 // The PTE is already zero. 01476 // 01477 01478 // 01479 // Increment the count of non-zero page table entries for this 01480 // page table and the number of private pages for the process. 01481 // 01482 01483 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va); 01484 01485 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 01486 01487 if (PointerPte > CommitLimitPte) { 01488 01489 // 01490 // Pte is not committed. 01491 // 01492 01493 CommitReduction += 1; 01494 } 01495 MI_WRITE_INVALID_PTE (PointerPte, MmDecommittedPte); 01496 } 01497 01498 PointerPte += 1; 01499 Va = (PVOID)((PCHAR)Va + PAGE_SIZE); 01500 } 01501 if (count != 0) { 01502 MiProcessValidPteList (&ValidPteList[0], count); 01503 } 01504 01505 return CommitReduction; 01506 }

VOID MiDeleteFreeVm IN PVOID  StartingAddress,
IN PVOID  EndingAddress
 

Definition at line 1586 of file freevm.c.

References FALSE, LOCK_PFN, MiDeleteVirtualAddresses(), NULL, and UNLOCK_PFN.

01593 : 01594 01595 Nonpagable routine to call acquire PFN lock and call 01596 MiDeleteVirtualAddresses. 01597 01598 Arguments: 01599 01600 01601 Return Value: 01602 01603 none. 01604 01605 Environment: 01606 01607 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 01608 held. 01609 01610 --*/ 01611 01612 { 01613 KIRQL OldIrql; 01614 01615 LOCK_PFN (OldIrql); 01616 01617 // 01618 // Delete the address range. 01619 // 01620 01621 MiDeleteVirtualAddresses (StartingAddress, 01622 EndingAddress, 01623 FALSE, 01624 (PMMVAD)NULL); 01625 01626 UNLOCK_PFN (OldIrql); 01627 01628 }

ULONG MiIsEntireRangeCommitted IN PVOID  StartingAddress,
IN PVOID  EndingAddress,
IN PMMVAD  Vad,
IN PEPROCESS  Process
 

Definition at line 937 of file freevm.c.

References FALSE, MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiGetPdeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteDecommittedPage(), MiIsPteOnPdeBoundary, PAGE_SIZE, PAGED_CODE, TRUE, and _MMPTE::u.

Referenced by MiProtectVirtualMemory(), and NtFreeVirtualMemory().

00946 : 00947 00948 This routine examines the range of pages from the starting address 00949 up to and including the ending address and returns TRUE if every 00950 page in the range is committed, FALSE otherwise. 00951 00952 Arguments: 00953 00954 StartingAddress - Supplies the starting address of the range. 00955 00956 EndingAddress - Supplies the ending address of the range. 00957 00958 Vad - Supplies the virtual address descriptor which describes the range. 00959 00960 Process - Supplies the current process. 00961 00962 Return Value: 00963 00964 TRUE if the entire range is committed. 00965 FALSE if any page within the range is not committed. 00966 00967 Environment: 00968 00969 Kernel mode, APCs disable, WorkingSetMutex and AddressCreation mutexes 00970 held. 00971 00972 --*/ 00973 00974 { 00975 PMMPTE PointerPte; 00976 PMMPTE LastPte; 00977 PMMPTE PointerPde; 00978 PMMPTE PointerPpe; 00979 ULONG FirstTime; 00980 ULONG Waited; 00981 PVOID Va; 00982 00983 PAGED_CODE(); 00984 00985 FirstTime = TRUE; 00986 00987 PointerPde = MiGetPdeAddress (StartingAddress); 00988 PointerPte = MiGetPteAddress (StartingAddress); 00989 LastPte = MiGetPteAddress (EndingAddress); 00990 00991 // 00992 // Set the Va to the starting address + 8, this solves problems 00993 // associated with address 0 (NULL) being used as a valid virtual 00994 // address and NULL in the VAD commitment field indicating no pages 00995 // are committed. 00996 // 00997 00998 Va = (PVOID)((PCHAR)StartingAddress + 8); 00999 01000 while (PointerPte <= LastPte) { 01001 01002 if (MiIsPteOnPdeBoundary(PointerPte) || (FirstTime)) { 01003 01004 // 01005 // This may be a PPE/PDE boundary, check to see if both 01006 // PPE/PDE pages exist. 01007 // 01008 01009 FirstTime = FALSE; 01010 PointerPde = MiGetPteAddress (PointerPte); 01011 PointerPpe = MiGetPteAddress (PointerPde); 01012 01013 do { 01014 01015 while (!MiDoesPpeExistAndMakeValid(PointerPpe, Process, FALSE, &Waited)) { 01016 01017 // 01018 // No PDE exists for the starting address, check the VAD 01019 // to see if the pages are committed. 01020 // 01021 01022 PointerPpe += 1; 01023 01024 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 01025 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 01026 Va = MiGetVirtualAddressMappedByPte (PointerPte); 01027 01028 if (PointerPte > LastPte) { 01029 01030 // 01031 // Make sure the entire range is committed. 01032 // 01033 01034 if (Vad->u.VadFlags.MemCommit == 0) { 01035 01036 // 01037 // The entire range to be decommitted is not committed, 01038 // return an error. 01039 // 01040 01041 return FALSE; 01042 } else { 01043 return TRUE; 01044 } 01045 } 01046 01047 // 01048 // Make sure the range thus far is committed. 01049 // 01050 01051 if (Vad->u.VadFlags.MemCommit == 0) { 01052 01053 // 01054 // The entire range to be decommitted is not committed, 01055 // return an error. 01056 // 01057 01058 return FALSE; 01059 } 01060 } 01061 01062 Waited = 0; 01063 01064 while (!MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE, &Waited)) { 01065 01066 // 01067 // No PDE exists for the starting address, check the VAD 01068 // to see if the pages are committed. 01069 // 01070 01071 PointerPde += 1; 01072 01073 PointerPpe = MiGetPteAddress (PointerPde); 01074 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 01075 Va = MiGetVirtualAddressMappedByPte (PointerPte); 01076 01077 if (PointerPte > LastPte) { 01078 01079 // 01080 // Make sure the entire range is committed. 01081 // 01082 01083 if (Vad->u.VadFlags.MemCommit == 0) { 01084 01085 // 01086 // The entire range to be decommitted is not committed, 01087 // return an error. 01088 // 01089 01090 return FALSE; 01091 } else { 01092 return TRUE; 01093 } 01094 } 01095 01096 // 01097 // Make sure the range thus far is committed. 01098 // 01099 01100 if (Vad->u.VadFlags.MemCommit == 0) { 01101 01102 // 01103 // The entire range to be decommitted is not committed, 01104 // return an error. 01105 // 01106 01107 return FALSE; 01108 } 01109 #if defined (_WIN64) 01110 if (MiIsPteOnPdeBoundary (PointerPde)) { 01111 PointerPpe = MiGetPteAddress (PointerPde); 01112 Waited = 1; 01113 break; 01114 } 01115 #endif 01116 } 01117 } while (Waited != 0); 01118 } 01119 01120 // 01121 // The page table page exists, check each PTE for commitment. 01122 // 01123 01124 if (PointerPte->u.Long == 0) { 01125 01126 // 01127 // This page has not been committed, check the VAD. 01128 // 01129 01130 if (Vad->u.VadFlags.MemCommit == 0) { 01131 01132 // 01133 // The entire range to be decommitted is not committed, 01134 // return an error. 01135 // 01136 01137 return FALSE; 01138 } 01139 } else { 01140 01141 // 01142 // Has this page been explicitly decommitted? 01143 // 01144 01145 if (MiIsPteDecommittedPage (PointerPte)) { 01146 01147 // 01148 // This page has been explicitly decommitted, return an error. 01149 // 01150 01151 return FALSE; 01152 } 01153 } 01154 PointerPte += 1; 01155 Va = (PVOID)((PCHAR)(Va) + PAGE_SIZE); 01156 } 01157 return TRUE; 01158 }

VOID MiProcessValidPteList IN PMMPTE PteList,
IN ULONG  Count
 

Definition at line 1510 of file freevm.c.

References ASSERT, Count, _MMPTE_FLUSH_LIST::Count, FALSE, _MMPTE_FLUSH_LIST::FlushPte, _MMPTE_FLUSH_LIST::FlushVa, LOCK_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiDecrementShareAndValidCount, MiDecrementShareCountOnly, MiFlushPteList(), MiGetVirtualAddressMappedByPte, MM_MAXIMUM_FLUSH_COUNT, MmDecommittedPte, _MMPFN::PteFrame, _MMPTE::u, and UNLOCK_PFN.

Referenced by MiDecommitPages().

01517 : 01518 01519 This routine flushes the specified range of valid PTEs. 01520 01521 Arguments: 01522 01523 ValidPteList - Supplies a pointer to an array of PTEs to flush. 01524 01525 Count - Supplies the count of the number of elements in the array. 01526 01527 Return Value: 01528 01529 none. 01530 01531 Environment: 01532 01533 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 01534 held. 01535 01536 --*/ 01537 01538 { 01539 ULONG i = 0; 01540 MMPTE_FLUSH_LIST PteFlushList; 01541 MMPTE PteContents; 01542 PMMPFN Pfn1; 01543 KIRQL OldIrql; 01544 01545 PteFlushList.Count = Count; 01546 01547 LOCK_PFN (OldIrql); 01548 01549 do { 01550 PteContents = *ValidPteList[i]; 01551 ASSERT (PteContents.u.Hard.Valid == 1); 01552 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01553 01554 // 01555 // Decrement the share and valid counts of the page table 01556 // page which maps this PTE. 01557 // 01558 01559 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01560 01561 MI_SET_PFN_DELETED (Pfn1); 01562 01563 // 01564 // Decrement the share count for the physical page. As the page 01565 // is private it will be put on the free list. 01566 // 01567 01568 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 01569 01570 if (Count < MM_MAXIMUM_FLUSH_COUNT) { 01571 PteFlushList.FlushPte[i] = ValidPteList[i]; 01572 PteFlushList.FlushVa[i] = 01573 MiGetVirtualAddressMappedByPte (ValidPteList[i]); 01574 } 01575 *ValidPteList[i] = MmDecommittedPte; 01576 i += 1; 01577 } while (i != Count); 01578 01579 MiFlushPteList (&PteFlushList, FALSE, MmDecommittedPte); 01580 UNLOCK_PFN (OldIrql); 01581 return; 01582 }

NTSTATUS NtFreeVirtualMemory IN HANDLE  ProcessHandle,
IN OUT PVOID *  BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  FreeType
 

Definition at line 66 of file freevm.c.

References _EPROCESS::AddressSpaceDeleted, ASSERT, _EPROCESS::CommitCharge, DbgPrint, _MMVAD::EndingVpn, _MMVAD_SHORT::EndingVpn, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), ExSystemExceptionFilter(), FALSE, _EPROCESS::JobStatus, KeAttachProcess(), KeDetachProcess(), KernelMode, KPROCESSOR_MODE, LOCK_WS_AND_ADDRESS_SPACE, MEM_CHECK_COMMIT_STATE, MI_VA_TO_VPN, MI_VPN_TO_VA, MI_VPN_TO_VA_ENDING, MiCalculatePageCommitment(), MiCheckSecuredVad(), MiDecommitFor4kPage(), MiDecommitPages(), MiDeleteFreeVm(), MiDeletePageTablesForPhysicalRange(), MiGetNextVad, MiGetPreviousVad, MiGetPteAddress, MiInsertVad(), MiIsEntireRangeCommitted(), MiLocateAddress(), MiPhysicalViewRemover(), MiReleaseFor4kPage(), MiRemoveUserPhysicalPagesVad(), MiRemoveVad(), MiReturnCommitment(), MiReturnPageFileQuota(), MiReturnPageTablePageCommitment(), MM_DBG_COMMIT_RETURN_NTFREEVM1, MM_DBG_COMMIT_RETURN_NTFREEVM2, MM_DBG_COMMIT_RETURN_NTFREEVM3, MM_DBG_COMMIT_RETURN_NTFREEVM4, MM_DBG_SHOW_NT_CALLS, MM_SECURE_DELETE_CHECK, MM_TRACK_COMMIT, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGE_4K, PAGE_4K_ALIGN, PAGE_ALIGN, PAGE_NEXT_ALIGN, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, _EPROCESS::Pcb, ProbeForWritePointer, ProbeForWriteUlong_ptr, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, PsChangeJobMemoryUsage(), PsGetCurrentProcess, PsProcessType, _MMVAD_SHORT::StartingVpn, _MMVAD::StartingVpn, Status, TRUE, _MMVAD::u, _MMVAD_SHORT::u, UNLOCK_ADDRESS_SPACE, UNLOCK_WS_AND_ADDRESS_SPACE, UNLOCK_WS_UNSAFE, _EPROCESS::VirtualSize, and _EPROCESS::Wow64Process.

Referenced by ExFreePool(), LdrpInitializeProcess(), RegLoadAsciiFileAsUnicode(), RtlDebugDestroyHeap(), RtlDestroyHandleTable(), RtlDestroyQueryDebugBuffer(), RtlFreeUserThreadStack(), RtlpDestroyTags(), RtlpValidateHeap(), RtlQueryProcessDebugInformation(), RtlUsageHeap(), and UnlockConsole().

00075 : 00076 00077 This function deletes a region of pages within the virtual address 00078 space of a subject process. 00079 00080 Arguments: 00081 00082 ProcessHandle - An open handle to a process object. 00083 00084 BaseAddress - The base address of the region of pages 00085 to be freed. This value is rounded down to the 00086 next host page address boundary. 00087 00088 RegionSize - A pointer to a variable that will receive 00089 the actual size in bytes of the freed region of 00090 pages. The initial value of this argument is 00091 rounded up to the next host page size boundary. 00092 00093 FreeType - A set of flags that describe the type of 00094 free that is to be performed for the specified 00095 region of pages. 00096 00097 00098 FreeType Flags 00099 00100 00101 MEM_DECOMMIT - The specified region of pages is to 00102 be decommitted. 00103 00104 MEM_RELEASE - The specified region of pages is to 00105 be released. 00106 00107 00108 Return Value: 00109 00110 Returns the status 00111 00112 --*/ 00113 00114 { 00115 PMMVAD_SHORT Vad; 00116 PMMVAD_SHORT NewVad; 00117 PMMVAD PreviousVad; 00118 PMMVAD NextVad; 00119 PEPROCESS Process; 00120 KPROCESSOR_MODE PreviousMode; 00121 PVOID StartingAddress; 00122 PVOID EndingAddress; 00123 NTSTATUS Status; 00124 ULONG Attached = FALSE; 00125 SIZE_T CapturedRegionSize; 00126 PVOID CapturedBase; 00127 PMMPTE StartingPte; 00128 PMMPTE EndingPte; 00129 SIZE_T OldQuota; 00130 SIZE_T QuotaCharge; 00131 SIZE_T CommitReduction; 00132 ULONG_PTR OldEnd; 00133 LOGICAL UserPhysicalPages; 00134 #if defined(_MIALT4K_) 00135 PVOID OriginalStartingAddress; 00136 PVOID OriginalEndingAddress; 00137 BOOLEAN EmulationFor4kPage = FALSE; 00138 #endif 00139 00140 PAGED_CODE(); 00141 00142 // 00143 // Check to make sure FreeType is good. 00144 // 00145 00146 if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) { 00147 return STATUS_INVALID_PARAMETER_4; 00148 } 00149 00150 // 00151 // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both. 00152 // 00153 00154 if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) || 00155 ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 00156 (MEM_DECOMMIT | MEM_RELEASE))) { 00157 return STATUS_INVALID_PARAMETER_4; 00158 } 00159 00160 PreviousMode = KeGetPreviousMode(); 00161 00162 // 00163 // Establish an exception handler, probe the specified addresses 00164 // for write access and capture the initial values. 00165 // 00166 00167 try { 00168 00169 if (PreviousMode != KernelMode) { 00170 00171 ProbeForWritePointer (BaseAddress); 00172 ProbeForWriteUlong_ptr (RegionSize); 00173 } 00174 00175 // 00176 // Capture the base address. 00177 // 00178 00179 CapturedBase = *BaseAddress; 00180 00181 // 00182 // Capture the region size. 00183 // 00184 00185 CapturedRegionSize = *RegionSize; 00186 00187 } except (ExSystemExceptionFilter()) { 00188 00189 // 00190 // If an exception occurs during the probe or capture 00191 // of the initial values, then handle the exception and 00192 // return the exception code as the status value. 00193 // 00194 00195 return GetExceptionCode(); 00196 } 00197 00198 #if DBG 00199 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00200 if ( !MmWatchProcess ) { 00201 DbgPrint("freevm processhandle %lx base %lx size %lx type %lx\n", 00202 ProcessHandle, CapturedBase, CapturedRegionSize, FreeType); 00203 } 00204 } 00205 #endif 00206 00207 // 00208 // Make sure the specified starting and ending addresses are 00209 // within the user part of the virtual address space. 00210 // 00211 00212 if (CapturedBase > MM_HIGHEST_USER_ADDRESS) { 00213 00214 // 00215 // Invalid base address. 00216 // 00217 00218 return STATUS_INVALID_PARAMETER_2; 00219 } 00220 00221 if ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)CapturedBase < 00222 CapturedRegionSize) { 00223 00224 // 00225 // Invalid region size; 00226 // 00227 00228 return STATUS_INVALID_PARAMETER_3; 00229 00230 } 00231 00232 EndingAddress = (PVOID)(((LONG_PTR)CapturedBase + CapturedRegionSize - 1) | 00233 (PAGE_SIZE - 1)); 00234 00235 StartingAddress = (PVOID)PAGE_ALIGN(CapturedBase); 00236 00237 if ( ProcessHandle == NtCurrentProcess() ) { 00238 Process = PsGetCurrentProcess(); 00239 } else { 00240 // 00241 // Reference the specified process handle for VM_OPERATION access. 00242 // 00243 00244 Status = ObReferenceObjectByHandle ( ProcessHandle, 00245 PROCESS_VM_OPERATION, 00246 PsProcessType, 00247 PreviousMode, 00248 (PVOID *)&Process, 00249 NULL ); 00250 00251 if (!NT_SUCCESS(Status)) { 00252 return Status; 00253 } 00254 } 00255 00256 // 00257 // If the specified process is not the current process, attach 00258 // to the specified process. 00259 // 00260 00261 if (PsGetCurrentProcess() != Process) { 00262 KeAttachProcess (&Process->Pcb); 00263 Attached = TRUE; 00264 } 00265 00266 // 00267 // Get the address creation mutex to block multiple threads from 00268 // creating or deleting address space at the same time and 00269 // get the working set mutex so virtual address descriptors can 00270 // be inserted and walked. Block APCs to prevent page faults while 00271 // we own the working set mutex. 00272 // 00273 00274 LOCK_WS_AND_ADDRESS_SPACE (Process); 00275 00276 // 00277 // Make sure the address space was not deleted. 00278 // 00279 00280 if (Process->AddressSpaceDeleted != 0) { 00281 Status = STATUS_PROCESS_IS_TERMINATING; 00282 goto ErrorReturn; 00283 } 00284 00285 #if defined(_MIALT4K_) 00286 00287 if (CapturedRegionSize != 0) { 00288 00289 OriginalStartingAddress = (PVOID)PAGE_4K_ALIGN (CapturedBase); 00290 00291 OriginalEndingAddress = (PVOID)(((LONG_PTR)CapturedBase + CapturedRegionSize - 1) | 00292 (PAGE_4K - 1)); 00293 00294 if (Process->Wow64Process != NULL) { 00295 00296 EmulationFor4kPage = TRUE; 00297 00298 // 00299 // adjust Starting/EndingAddress for the native page size 00300 // 00301 00302 StartingAddress = PAGE_NEXT_ALIGN(OriginalStartingAddress); 00303 00304 EndingAddress = 00305 (PVOID)((ULONG_PTR)PAGE_ALIGN ((ULONG_PTR)OriginalEndingAddress + PAGE_4K) - 1); 00306 00307 if (StartingAddress > EndingAddress) { 00308 00309 // 00310 // There is no need to free native pages 00311 // 00312 00313 UNLOCK_WS_UNSAFE (Process); 00314 00315 goto perform_free4kpages; 00316 00317 } 00318 } 00319 } 00320 00321 #endif 00322 00323 Vad = (PMMVAD_SHORT)MiLocateAddress (StartingAddress); 00324 00325 if (Vad == NULL) { 00326 00327 // 00328 // No Virtual Address Descriptor located for Base Address. 00329 // 00330 00331 Status = STATUS_MEMORY_NOT_ALLOCATED; 00332 goto ErrorReturn; 00333 } 00334 00335 // 00336 // Found the associated Virtual Address Descriptor. 00337 // 00338 00339 if (Vad->EndingVpn < MI_VA_TO_VPN (EndingAddress)) { 00340 00341 // 00342 // The entire range to delete is not contained within a single 00343 // virtual address descriptor. Return an error. 00344 // 00345 00346 Status = STATUS_UNABLE_TO_FREE_VM; 00347 goto ErrorReturn; 00348 } 00349 00350 // 00351 // Check to ensure this Vad is deletable. Delete is required 00352 // for both decommit and release. 00353 // 00354 00355 if ((Vad->u.VadFlags.PrivateMemory == 0) || 00356 (Vad->u.VadFlags.PhysicalMapping == 1)) { 00357 Status = STATUS_UNABLE_TO_DELETE_SECTION; 00358 goto ErrorReturn; 00359 } 00360 00361 if (Vad->u.VadFlags.NoChange == 1) { 00362 00363 // 00364 // An attempt is being made to delete a secured VAD, check 00365 // to see if this deletion is allowed. 00366 // 00367 00368 if (FreeType & MEM_RELEASE) { 00369 00370 // 00371 // Specify the whole range, this solves the problem with 00372 // splitting the VAD and trying to decide where the various 00373 // secure ranges need to go. 00374 // 00375 00376 Status = MiCheckSecuredVad ((PMMVAD)Vad, 00377 MI_VPN_TO_VA (Vad->StartingVpn), 00378 ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT) + 00379 (PAGE_SIZE - 1), 00380 MM_SECURE_DELETE_CHECK); 00381 00382 } else { 00383 Status = MiCheckSecuredVad ((PMMVAD)Vad, 00384 CapturedBase, 00385 CapturedRegionSize, 00386 MM_SECURE_DELETE_CHECK); 00387 } 00388 if (!NT_SUCCESS (Status)) { 00389 goto ErrorReturn; 00390 } 00391 } 00392 00393 UserPhysicalPages = FALSE; 00394 00395 PreviousVad = MiGetPreviousVad (Vad); 00396 NextVad = MiGetNextVad (Vad); 00397 if (FreeType & MEM_RELEASE) { 00398 00399 // 00400 // ***************************************************************** 00401 // MEM_RELEASE was specified. 00402 // ***************************************************************** 00403 // 00404 00405 // 00406 // The descriptor for the address range is deletable. Remove or split 00407 // the descriptor. 00408 // 00409 00410 // 00411 // If the region size is zero, remove the whole VAD. 00412 // 00413 00414 if (CapturedRegionSize == 0) { 00415 00416 // 00417 // If the region size is specified as 0, the base address 00418 // must be the starting address for the region. 00419 // 00420 00421 if (MI_VA_TO_VPN (CapturedBase) != Vad->StartingVpn) { 00422 Status = STATUS_FREE_VM_NOT_AT_BASE; 00423 goto ErrorReturn; 00424 } 00425 00426 // 00427 // This Virtual Address Descriptor has been deleted. 00428 // 00429 00430 StartingAddress = MI_VPN_TO_VA (Vad->StartingVpn); 00431 EndingAddress = MI_VPN_TO_VA_ENDING (Vad->EndingVpn); 00432 00433 // 00434 // Free all the physical pages that this VAD might be mapping. 00435 // Since only the AWE lock synchronizes the remap API, carefully 00436 // remove this VAD from the list first. 00437 // 00438 00439 if (Vad->u.VadFlags.UserPhysicalPages == 1) { 00440 MiPhysicalViewRemover (Process, (PMMVAD)Vad); 00441 MiRemoveUserPhysicalPagesVad (Vad); 00442 UserPhysicalPages = TRUE; 00443 } 00444 else if (Vad->u.VadFlags.WriteWatch == 1) { 00445 MiPhysicalViewRemover (Process, (PMMVAD)Vad); 00446 } 00447 00448 MiRemoveVad ((PMMVAD)Vad); 00449 ExFreePool (Vad); 00450 00451 #if defined(_MIALT4K_) 00452 00453 OriginalStartingAddress = StartingAddress; 00454 OriginalEndingAddress = EndingAddress; 00455 00456 if (Process->Wow64Process != NULL) { 00457 00458 EmulationFor4kPage = TRUE; 00459 00460 } else { 00461 00462 EmulationFor4kPage = FALSE; 00463 00464 } 00465 00466 #endif 00467 00468 } else { 00469 00470 // 00471 // Region's size was not specified as zero, delete the 00472 // whole VAD or split the VAD. 00473 // 00474 00475 if (MI_VA_TO_VPN (StartingAddress) == Vad->StartingVpn) { 00476 if (MI_VA_TO_VPN (EndingAddress) == Vad->EndingVpn) { 00477 00478 // 00479 // This Virtual Address Descriptor has been deleted. 00480 // 00481 00482 // 00483 // Free all the physical pages that this VAD might be 00484 // mapping. Since only the AWE lock synchronizes the 00485 // remap API, carefully remove this VAD from the list first. 00486 // 00487 00488 if (Vad->u.VadFlags.UserPhysicalPages == 1) { 00489 MiPhysicalViewRemover (Process, (PMMVAD)Vad); 00490 MiRemoveUserPhysicalPagesVad (Vad); 00491 UserPhysicalPages = TRUE; 00492 } 00493 else if (Vad->u.VadFlags.WriteWatch == 1) { 00494 MiPhysicalViewRemover (Process, (PMMVAD)Vad); 00495 } 00496 00497 MiRemoveVad ((PMMVAD)Vad); 00498 ExFreePool (Vad); 00499 00500 } else { 00501 00502 if ((Vad->u.VadFlags.UserPhysicalPages == 1) || 00503 (Vad->u.VadFlags.WriteWatch == 1)) { 00504 00505 // 00506 // Splitting or chopping a physical VAD or a write-watch 00507 // VAD is not allowed. 00508 // 00509 00510 Status = STATUS_FREE_VM_NOT_AT_BASE; 00511 goto ErrorReturn; 00512 } 00513 00514 // 00515 // This Virtual Address Descriptor has a new starting 00516 // address. 00517 // 00518 00519 CommitReduction = MiCalculatePageCommitment ( 00520 StartingAddress, 00521 EndingAddress, 00522 (PMMVAD)Vad, 00523 Process ); 00524 00525 Vad->StartingVpn = MI_VA_TO_VPN ((PCHAR)EndingAddress + 1); 00526 Vad->u.VadFlags.CommitCharge -= CommitReduction; 00527 ASSERT ((SSIZE_T)Vad->u.VadFlags.CommitCharge >= 0); 00528 MiReturnPageFileQuota (CommitReduction, Process); 00529 MiReturnCommitment (CommitReduction); 00530 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00531 PsChangeJobMemoryUsage (-(SSIZE_T)CommitReduction); 00532 } 00533 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_NTFREEVM1, 00534 CommitReduction); 00535 Process->CommitCharge -= CommitReduction; 00536 NextVad = (PMMVAD)Vad; 00537 } 00538 00539 } else { 00540 00541 if ((Vad->u.VadFlags.UserPhysicalPages == 1) || 00542 (Vad->u.VadFlags.WriteWatch == 1)) { 00543 00544 // 00545 // Splitting or chopping a physical VAD or a write-watch 00546 // VAD is not allowed. 00547 // 00548 00549 Status = STATUS_FREE_VM_NOT_AT_BASE; 00550 goto ErrorReturn; 00551 } 00552 00553 // 00554 // Starting address is greater than start of VAD. 00555 // 00556 00557 if (MI_VA_TO_VPN (EndingAddress) == Vad->EndingVpn) { 00558 00559 // 00560 // Change the ending address of the VAD. 00561 // 00562 00563 CommitReduction = MiCalculatePageCommitment ( 00564 StartingAddress, 00565 EndingAddress, 00566 (PMMVAD)Vad, 00567 Process ); 00568 00569 Vad->u.VadFlags.CommitCharge -= CommitReduction; 00570 MiReturnPageFileQuota (CommitReduction, Process); 00571 MiReturnCommitment (CommitReduction); 00572 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00573 PsChangeJobMemoryUsage (-(SSIZE_T)CommitReduction); 00574 } 00575 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_NTFREEVM2, 00576 CommitReduction); 00577 Process->CommitCharge -= CommitReduction; 00578 00579 Vad->EndingVpn = MI_VA_TO_VPN ((PCHAR)StartingAddress - 1); 00580 PreviousVad = (PMMVAD)Vad; 00581 00582 } else { 00583 00584 // 00585 // Split this VAD as the address range is within the VAD. 00586 // 00587 00588 // 00589 // Allocate an new VAD under an exception handler 00590 // as there may not be enough quota. 00591 // 00592 00593 NewVad = ExAllocatePoolWithTag (NonPagedPool, 00594 sizeof(MMVAD_SHORT), 00595 'SdaV'); 00596 if ( NewVad == NULL ) { 00597 Status = STATUS_INSUFFICIENT_RESOURCES; 00598 goto ErrorReturn; 00599 } 00600 00601 CommitReduction = MiCalculatePageCommitment ( 00602 StartingAddress, 00603 EndingAddress, 00604 (PMMVAD)Vad, 00605 Process ); 00606 00607 OldQuota = Vad->u.VadFlags.CommitCharge - CommitReduction; 00608 OldEnd = Vad->EndingVpn; 00609 00610 *NewVad = *Vad; 00611 00612 Vad->EndingVpn = MI_VA_TO_VPN ((PCHAR)StartingAddress - 1); 00613 NewVad->StartingVpn = MI_VA_TO_VPN ((PCHAR)EndingAddress + 1); 00614 00615 // 00616 // Set the commit charge to zero so MiInsertVad will 00617 // not charge commitment for splitting the VAD. 00618 // 00619 00620 NewVad->u.VadFlags.CommitCharge = 0; 00621 00622 try { 00623 00624 // 00625 // Insert the VAD, this could get an exception 00626 // on charging quota. 00627 // 00628 00629 MiInsertVad ((PMMVAD)NewVad); 00630 00631 } except (EXCEPTION_EXECUTE_HANDLER) { 00632 00633 // 00634 // Inserting the Vad failed, reset the original 00635 // VAD, free new vad and return an error. 00636 // 00637 00638 Vad->EndingVpn = OldEnd; 00639 00640 ExFreePool (NewVad); 00641 Status = GetExceptionCode(); 00642 goto ErrorReturn; 00643 } 00644 00645 Vad->u.VadFlags.CommitCharge -= CommitReduction; 00646 MiReturnPageFileQuota (CommitReduction, Process); 00647 MiReturnCommitment (CommitReduction); 00648 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00649 PsChangeJobMemoryUsage (-(SSIZE_T)CommitReduction); 00650 } 00651 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_NTFREEVM3, 00652 CommitReduction); 00653 Process->CommitCharge -= CommitReduction; 00654 00655 // 00656 // As we have split the original VAD into 2 separate VADs 00657 // there is know way of knowing what the commit charge 00658 // is for each VAD. Calculate the charge and reset 00659 // each VAD. Note that we also use the previous value 00660 // to make sure the books stay balanced. 00661 // 00662 00663 QuotaCharge = MiCalculatePageCommitment (MI_VPN_TO_VA (Vad->StartingVpn), 00664 (PCHAR)StartingAddress - 1, 00665 (PMMVAD)Vad, 00666 Process ); 00667 00668 Vad->u.VadFlags.CommitCharge = QuotaCharge; 00669 00670 // 00671 // Give the remaining charge to the new VAD. 00672 // 00673 00674 NewVad->u.VadFlags.CommitCharge = OldQuota - QuotaCharge; 00675 PreviousVad = (PMMVAD)Vad; 00676 NextVad = (PMMVAD)NewVad; 00677 } 00678 } 00679 } 00680 00681 // 00682 // Return commitment for page table pages if possible. 00683 // 00684 00685 MiReturnPageTablePageCommitment (StartingAddress, 00686 EndingAddress, 00687 Process, 00688 PreviousVad, 00689 NextVad); 00690 00691 if (UserPhysicalPages == TRUE) { 00692 MiDeletePageTablesForPhysicalRange (StartingAddress, EndingAddress); 00693 } 00694 else { 00695 00696 // 00697 // Get the PFN mutex so the MiDeleteVirtualAddresses can be called. 00698 // 00699 00700 MiDeleteFreeVm (StartingAddress, EndingAddress); 00701 } 00702 00703 UNLOCK_WS_UNSAFE (Process); 00704 00705 CapturedRegionSize = 1 + (PCHAR)EndingAddress - (PCHAR)StartingAddress; 00706 00707 // 00708 // Update the virtual size in the process header. 00709 // 00710 00711 Process->VirtualSize -= CapturedRegionSize; 00712 00713 #if defined(_MIALT4K_) 00714 if (EmulationFor4kPage == TRUE) { 00715 00716 goto perform_free4kpages; 00717 00718 } 00719 #endif 00720 00721 UNLOCK_ADDRESS_SPACE (Process); 00722 00723 if (Attached) { 00724 KeDetachProcess(); 00725 } 00726 00727 if ( ProcessHandle != NtCurrentProcess() ) { 00728 ObDereferenceObject (Process); 00729 } 00730 // 00731 // Establish an exception handler and write the size and base 00732 // address. 00733 // 00734 00735 try { 00736 00737 *RegionSize = CapturedRegionSize; 00738 *BaseAddress = StartingAddress; 00739 00740 } except (EXCEPTION_EXECUTE_HANDLER) { 00741 00742 // 00743 // An exception occurred, don't take any action (just handle 00744 // the exception and return success. 00745 00746 } 00747 00748 #if DBG 00749 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00750 if ( MmWatchProcess ) { 00751 if ( MmWatchProcess == PsGetCurrentProcess() ) { 00752 DbgPrint("\n--- FREE Type 0x%lx Base %lx Size %lx\n", 00753 FreeType, StartingAddress, CapturedRegionSize); 00754 MmFooBar(); 00755 } 00756 } 00757 } 00758 #endif 00759 00760 return STATUS_SUCCESS; 00761 } 00762 00763 if (Vad->u.VadFlags.UserPhysicalPages == 1) { 00764 00765 // 00766 // Pages from a physical VAD must be released via 00767 // NtFreeUserPhysicalPages, not this routine. 00768 // 00769 00770 Status = STATUS_MEMORY_NOT_ALLOCATED; 00771 goto ErrorReturn; 00772 } 00773 00774 // 00775 // ************************************************************** 00776 // 00777 // MEM_DECOMMIT was specified. 00778 // 00779 // ************************************************************** 00780 // 00781 00782 // 00783 // Check to ensure the complete range of pages is already committed. 00784 // 00785 00786 if (CapturedRegionSize == 0) { 00787 00788 if (MI_VA_TO_VPN (CapturedBase) != Vad->StartingVpn) { 00789 Status = STATUS_FREE_VM_NOT_AT_BASE; 00790 goto ErrorReturn; 00791 } 00792 EndingAddress = MI_VPN_TO_VA_ENDING (Vad->EndingVpn); 00793 } 00794 00795 #if defined(_MIALT4K_) 00796 00797 OriginalStartingAddress = StartingAddress; 00798 OriginalEndingAddress = EndingAddress; 00799 00800 if (Process->Wow64Process != NULL) { 00801 00802 EmulationFor4kPage = TRUE; 00803 00804 } else { 00805 00806 EmulationFor4kPage = FALSE; 00807 00808 } 00809 00810 #endif 00811 00812 #if 0 00813 if (FreeType & MEM_CHECK_COMMIT_STATE) { 00814 if ( !MiIsEntireRangeCommitted(StartingAddress, 00815 EndingAddress, 00816 Vad, 00817 Process)) { 00818 00819 // 00820 // The entire range to be decommitted is not committed, 00821 // return an error. 00822 // 00823 00824 Status = STATUS_UNABLE_TO_DECOMMIT_VM; 00825 goto ErrorReturn; 00826 } 00827 } 00828 #endif //0 00829 00830 // 00831 // The address range is entirely committed, decommit it now. 00832 // 00833 00834 // 00835 // Calculate the initial quotas and commit charges for this VAD. 00836 // 00837 00838 StartingPte = MiGetPteAddress (StartingAddress); 00839 EndingPte = MiGetPteAddress (EndingAddress); 00840 00841 CommitReduction = 1 + EndingPte - StartingPte; 00842 00843 // 00844 // Check to see if the entire range can be decommitted by 00845 // just updating the virtual address descriptor. 00846 // 00847 00848 CommitReduction -= MiDecommitPages (StartingAddress, 00849 EndingPte, 00850 Process, 00851 Vad); 00852 00853 // 00854 // Adjust the quota charges. 00855 // 00856 00857 ASSERT ((LONG)CommitReduction >= 0); 00858 MiReturnPageFileQuota (CommitReduction, Process); 00859 MiReturnCommitment (CommitReduction); 00860 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_NTFREEVM4, CommitReduction); 00861 Vad->u.VadFlags.CommitCharge -= CommitReduction; 00862 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00863 PsChangeJobMemoryUsage (-(SSIZE_T)CommitReduction); 00864 } 00865 Process->CommitCharge -= CommitReduction; 00866 ASSERT ((LONG)Vad->u.VadFlags.CommitCharge >= 0); 00867 00868 00869 #if !(defined(_MIALT4K_)) 00870 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 00871 #else 00872 UNLOCK_WS_UNSAFE(Process); 00873 00874 perform_free4kpages: 00875 00876 if (EmulationFor4kPage == TRUE) { 00877 00878 if (FreeType & MEM_RELEASE) { 00879 00880 MiReleaseFor4kPage(OriginalStartingAddress, 00881 OriginalEndingAddress, 00882 Process); 00883 00884 } else { 00885 00886 MiDecommitFor4kPage(OriginalStartingAddress, 00887 OriginalEndingAddress, 00888 Process); 00889 00890 } 00891 00892 StartingAddress = OriginalStartingAddress; 00893 EndingAddress = OriginalEndingAddress; 00894 } 00895 00896 UNLOCK_ADDRESS_SPACE (Process); 00897 00898 #endif 00899 00900 if (Attached) { 00901 KeDetachProcess(); 00902 } 00903 if ( ProcessHandle != NtCurrentProcess() ) { 00904 ObDereferenceObject (Process); 00905 } 00906 00907 // 00908 // Establish an exception handler and write the size and base 00909 // address. 00910 // 00911 00912 try { 00913 00914 *RegionSize = 1 + (PCHAR)EndingAddress - (PCHAR)StartingAddress; 00915 *BaseAddress = StartingAddress; 00916 00917 } except (EXCEPTION_EXECUTE_HANDLER) { 00918 NOTHING; 00919 } 00920 00921 return STATUS_SUCCESS; 00922 00923 ErrorReturn: 00924 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 00925 00926 if (Attached) { 00927 KeDetachProcess(); 00928 } 00929 00930 if ( ProcessHandle != NtCurrentProcess() ) { 00931 ObDereferenceObject (Process); 00932 } 00933 return Status; 00934 }


Variable Documentation

MMPTE MmDecommittedPte = {MM_DECOMMIT << MM_PROTECT_FIELD_SHIFT}
 

Definition at line 30 of file freevm.c.

Referenced by MiDecommitPages(), and MiProcessValidPteList().


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