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

allocvm.c File Reference

#include "mi.h"

Go to the source code of this file.

Functions

NTSTATUS MiResetVirtualMemory (IN PVOID StartingAddress, IN PVOID EndingAddress, IN PMMVAD Vad, IN PEPROCESS Process)
LOGICAL MiCreatePageTablesForPhysicalRange (IN PEPROCESS Process, IN PVOID StartingAddress, IN PVOID EndingAddress)
VOID MiPhysicalViewInserter (IN PEPROCESS Process, IN PMI_PHYSICAL_VIEW PhysicalView)
VOID MiFlushAcquire (IN PCONTROL_AREA ControlArea)
VOID MiFlushRelease (IN PCONTROL_AREA ControlArea)
NTSTATUS NtAllocateVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG_PTR ZeroBits, IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect)
VOID MiDeletePageTablesForPhysicalRange (IN PVOID StartingAddress, IN PVOID EndingAddress)

Variables

ULONG MMVADKEY = ' daV'
LOGICAL MmSupportWriteWatch = FALSE


Function Documentation

LOGICAL MiCreatePageTablesForPhysicalRange IN PEPROCESS  Process,
IN PVOID  StartingAddress,
IN PVOID  EndingAddress
 

Definition at line 2188 of file allocvm.c.

References ADDRESS_AND_SIZE_TO_SPAN_PAGES, ASSERT, FALSE, LOCK_PFN, MI_GET_USED_PTES_HANDLE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_NONPAGABLE_MEMORY_AVAILABLE, MI_PFN_ELEMENT, MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteOnPdeBoundary, MiIsPteOnPpeBoundary, MiMakePdeExistAndMakeValid(), MiMakePpeExistAndMakeValid, MM_BUMP_COUNTER, MMPTE, MmResidentAvailablePages, TRUE, _MMPTE::u, _MMPFN::u2, and UNLOCK_PFN.

Referenced by NtAllocateVirtualMemory().

02196 : 02197 02198 This routine initializes page directory and page table pages for a 02199 user-controlled physical range of pages. 02200 02201 Arguments: 02202 02203 Process - Supplies the current process. 02204 02205 StartingAddress - Supplies the starting address of the range. 02206 02207 EndingAddress - Supplies the ending address of the range. 02208 02209 Return Value: 02210 02211 TRUE if the page tables were created, FALSE if not. 02212 02213 Environment: 02214 02215 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02216 held. 02217 02218 --*/ 02219 02220 { 02221 MMPTE PteContents; 02222 PMMPTE LastPte; 02223 PMMPTE LastPde; 02224 PMMPTE PointerPte; 02225 PMMPTE PointerPde; 02226 PMMPTE PointerPpe; 02227 PUCHAR Va; 02228 PVOID UsedPageDirectoryHandle; 02229 PVOID UsedPageTableHandle; 02230 LOGICAL FirstTime; 02231 KIRQL OldIrql; 02232 PMMPFN Pfn1; 02233 ULONG PagesNeeded; 02234 02235 FirstTime = TRUE; 02236 PointerPpe = MiGetPpeAddress (StartingAddress); 02237 PointerPde = MiGetPdeAddress (StartingAddress); 02238 PointerPte = MiGetPteAddress (StartingAddress); 02239 LastPde = MiGetPdeAddress (EndingAddress); 02240 LastPte = MiGetPteAddress (EndingAddress); 02241 02242 // 02243 // Charge resident available pages for all of the page directory and table 02244 // pages as they will not be paged until the VAD is freed. 02245 // 02246 02247 if (LastPte != PointerPte) { 02248 PagesNeeded = ADDRESS_AND_SIZE_TO_SPAN_PAGES (PointerPte, 02249 (ULONG)(LastPte - PointerPte) * sizeof (MMPTE)); 02250 02251 #if defined (_WIN64) 02252 if (LastPde != PointerPde) { 02253 PagesNeeded += ADDRESS_AND_SIZE_TO_SPAN_PAGES (PointerPde, 02254 (ULONG)(LastPde - PointerPde) * sizeof (MMPTE)); 02255 } 02256 #endif 02257 } 02258 else { 02259 PagesNeeded = 1; 02260 #if defined (_WIN64) 02261 PagesNeeded += 1; 02262 #endif 02263 } 02264 02265 LOCK_PFN (OldIrql); 02266 02267 if ((SPFN_NUMBER)PagesNeeded > MI_NONPAGABLE_MEMORY_AVAILABLE() - 20) { 02268 UNLOCK_PFN (OldIrql); 02269 return FALSE; 02270 } 02271 02272 MmResidentAvailablePages -= PagesNeeded; 02273 MM_BUMP_COUNTER(58, PagesNeeded); 02274 UNLOCK_PFN (OldIrql); 02275 02276 // 02277 // Fill in all the page directory and page table pages with the zero PTE. 02278 // 02279 02280 #if defined (_WIN64) 02281 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 02282 if (PointerPde->u.Long == 0) { 02283 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 02284 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 02285 } 02286 #endif 02287 02288 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 02289 02290 while (PointerPte <= LastPte) { 02291 02292 if (MiIsPteOnPdeBoundary (PointerPte) || FirstTime == TRUE) { 02293 02294 PointerPde = MiGetPteAddress (PointerPte); 02295 PointerPpe = MiGetPteAddress (PointerPde); 02296 02297 #if defined (_WIN64) 02298 if (MiIsPteOnPpeBoundary (PointerPte) || FirstTime == TRUE) { 02299 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 02300 02301 // 02302 // Up the sharecount so the page directory page will not get 02303 // trimmed even if it has no currently valid entries. 02304 // 02305 02306 PteContents = *PointerPpe; 02307 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02308 LOCK_PFN (OldIrql); 02309 Pfn1->u2.ShareCount += 1; 02310 UNLOCK_PFN (OldIrql); 02311 } 02312 #endif 02313 02314 FirstTime = FALSE; 02315 02316 #if defined (_WIN64) 02317 if (PointerPde->u.Long == 0) { 02318 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 02319 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 02320 } 02321 #endif 02322 02323 // 02324 // Pointing to the next page table page, make 02325 // a page table page exist and make it valid. 02326 // 02327 02328 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 02329 02330 // 02331 // Up the sharecount so the page table page will not get 02332 // trimmed even if it has no currently valid entries. 02333 // 02334 02335 PteContents = *PointerPde; 02336 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02337 LOCK_PFN (OldIrql); 02338 Pfn1->u2.ShareCount += 1; 02339 UNLOCK_PFN (OldIrql); 02340 } 02341 02342 ASSERT (PointerPte->u.Long == 0); 02343 02344 // 02345 // Increment the count of non-zero page table entries 02346 // for this page table - even though this entry is still zero, 02347 // this is a special case. 02348 // 02349 02350 Va = MiGetVirtualAddressMappedByPte (PointerPte); 02351 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va); 02352 02353 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 02354 02355 PointerPte += 1; 02356 } 02357 return TRUE; 02358 }

VOID MiDeletePageTablesForPhysicalRange IN PVOID  StartingAddress,
IN PVOID  EndingAddress
 

Definition at line 2361 of file allocvm.c.

References ADDRESS_AND_SIZE_TO_SPAN_PAGES, ASSERT, FALSE, LOCK_PFN, MI_DECREMENT_USED_PTES_BY_HANDLE, MI_GET_USED_PTES_FROM_HANDLE, MI_GET_USED_PTES_HANDLE, MI_PFN_ELEMENT, MiDeletePte(), MiGetPdeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteOnPdeBoundary, MiIsPteOnPpeBoundary, MM_BUMP_COUNTER, MMPTE, MmResidentAvailablePages, NULL, PAGE_SIZE, PsGetCurrentProcess, _MMPTE::u, _MMPFN::u2, and UNLOCK_PFN.

Referenced by MmCleanProcessAddressSpace(), and NtFreeVirtualMemory().

02368 : 02369 02370 This routine deletes page directory and page table pages for a 02371 user-controlled physical range of pages. 02372 02373 Even though PTEs may be zero in this range, UsedPageTable counts were 02374 incremented for these special ranges and must be decremented now. 02375 02376 Arguments: 02377 02378 StartingAddress - Supplies the starting address of the range. 02379 02380 EndingAddress - Supplies the ending address of the range. 02381 02382 Return Value: 02383 02384 None. 02385 02386 Environment: 02387 02388 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 02389 held. 02390 02391 --*/ 02392 02393 { 02394 PVOID TempVa; 02395 MMPTE PteContents; 02396 PMMPTE LastPte; 02397 PMMPTE LastPde; 02398 PMMPTE PointerPte; 02399 PMMPTE PointerPde; 02400 PMMPTE PointerPpe; 02401 ULONG PagesNeeded; 02402 PEPROCESS CurrentProcess; 02403 PVOID UsedPageTableHandle; 02404 PVOID UsedPageDirectoryHandle; 02405 KIRQL OldIrql; 02406 PMMPFN Pfn1; 02407 02408 CurrentProcess = PsGetCurrentProcess(); 02409 02410 PointerPde = MiGetPdeAddress (StartingAddress); 02411 PointerPte = MiGetPteAddress (StartingAddress); 02412 LastPde = MiGetPdeAddress (EndingAddress); 02413 LastPte = MiGetPteAddress (EndingAddress); 02414 02415 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (StartingAddress); 02416 02417 // 02418 // Each PTE is already zeroed - just delete the containing pages. 02419 // 02420 02421 // 02422 // Restore resident available pages for all of the page directory and table 02423 // pages as they can now be paged again. 02424 // 02425 02426 if (LastPte != PointerPte) { 02427 PagesNeeded = ADDRESS_AND_SIZE_TO_SPAN_PAGES (PointerPte, 02428 (ULONG)(LastPte - PointerPte) * sizeof (MMPTE)); 02429 02430 #if defined (_WIN64) 02431 if (LastPde != PointerPde) { 02432 PagesNeeded += ADDRESS_AND_SIZE_TO_SPAN_PAGES (PointerPde, 02433 (ULONG)(LastPde - PointerPde) * sizeof (MMPTE)); 02434 } 02435 #endif 02436 } 02437 else { 02438 PagesNeeded = 1; 02439 #if defined (_WIN64) 02440 PagesNeeded += 1; 02441 #endif 02442 } 02443 02444 LOCK_PFN (OldIrql); 02445 02446 MmResidentAvailablePages += PagesNeeded; 02447 MM_BUMP_COUNTER(59, PagesNeeded); 02448 02449 while (StartingAddress <= EndingAddress) { 02450 02451 ASSERT (PointerPte->u.Long == 0); 02452 02453 PointerPte += 1; 02454 02455 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 02456 02457 if ((MiIsPteOnPdeBoundary(PointerPte)) || (PointerPte > LastPte)) { 02458 02459 // 02460 // The virtual address is on a page directory boundary or it is 02461 // the last address in the entire range. 02462 // 02463 // If all the entries have been eliminated from the previous 02464 // page table page, delete the page table page itself. 02465 // 02466 02467 PointerPde = MiGetPteAddress (PointerPte - 1); 02468 ASSERT (PointerPde->u.Hard.Valid == 1); 02469 02470 // 02471 // Down the sharecount on the finished page table page. 02472 // 02473 02474 PteContents = *PointerPde; 02475 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02476 ASSERT (Pfn1->u2.ShareCount > 1); 02477 Pfn1->u2.ShareCount -= 1; 02478 02479 // 02480 // If all the entries have been eliminated from the previous 02481 // page table page, delete the page table page itself. 02482 // 02483 02484 if (MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) { 02485 02486 TempVa = MiGetVirtualAddressMappedByPte(PointerPde); 02487 MiDeletePte (PointerPde, 02488 TempVa, 02489 FALSE, 02490 CurrentProcess, 02491 NULL, 02492 NULL); 02493 02494 #if defined (_WIN64) 02495 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1); 02496 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 02497 #endif 02498 } 02499 02500 #if defined (_WIN64) 02501 if ((MiIsPteOnPpeBoundary(PointerPte)) || (PointerPte > LastPte)) { 02502 02503 PointerPpe = MiGetPteAddress (PointerPde); 02504 ASSERT (PointerPpe->u.Hard.Valid == 1); 02505 02506 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1); 02507 // 02508 // Down the sharecount on the finished page directory page. 02509 // 02510 02511 PteContents = *PointerPpe; 02512 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02513 ASSERT (Pfn1->u2.ShareCount > 1); 02514 Pfn1->u2.ShareCount -= 1; 02515 02516 // 02517 // If all the entries have been eliminated from the previous 02518 // page directory page, delete the page directory page itself. 02519 // 02520 02521 if (MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) { 02522 TempVa = MiGetVirtualAddressMappedByPte(PointerPpe); 02523 MiDeletePte (PointerPpe, 02524 TempVa, 02525 FALSE, 02526 CurrentProcess, 02527 NULL, 02528 NULL); 02529 } 02530 } 02531 #endif 02532 02533 if (PointerPte > LastPte) { 02534 break; 02535 } 02536 02537 // 02538 // Release the PFN lock. This prevents a single thread 02539 // from forcing other high priority threads from being 02540 // blocked while a large address range is deleted. 02541 // 02542 02543 UNLOCK_PFN (OldIrql); 02544 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE ((PVOID)((PUCHAR)StartingAddress + PAGE_SIZE)); 02545 LOCK_PFN (OldIrql); 02546 } 02547 02548 StartingAddress = (PVOID)((PUCHAR)StartingAddress + PAGE_SIZE); 02549 } 02550 02551 UNLOCK_PFN (OldIrql); 02552 02553 // 02554 // All done, return. 02555 // 02556 02557 return; 02558 }

VOID MiFlushAcquire IN PCONTROL_AREA  ControlArea  ) 
 

Definition at line 223 of file flushsec.c.

References ASSERT, LOCK_PFN, and UNLOCK_PFN.

Referenced by MmFlushVirtualMemory(), and NtAllocateVirtualMemory().

00229 : 00230 00231 This is a helper routine to reference count the control area if needed 00232 during a flush section call to prevent the section object from being 00233 deleted while the flush is ongoing. 00234 00235 Arguments: 00236 00237 ControlArea - Supplies a pointer to the control area. 00238 00239 Return Value: 00240 00241 None. 00242 00243 --*/ 00244 00245 { 00246 KIRQL OldIrql; 00247 00248 LOCK_PFN (OldIrql); 00249 00250 ASSERT ((LONG)ControlArea->NumberOfMappedViews >= 1); 00251 ControlArea->NumberOfMappedViews += 1; 00252 00253 UNLOCK_PFN (OldIrql); 00254 }

VOID MiFlushRelease IN PCONTROL_AREA  ControlArea  ) 
 

Definition at line 258 of file flushsec.c.

References ASSERT, LOCK_PFN, MiCheckControlArea(), and NULL.

Referenced by MmFlushVirtualMemory(), and NtAllocateVirtualMemory().

00264 : 00265 00266 This is a helper routine to release the control area reference needed 00267 during a flush section call. 00268 00269 Arguments: 00270 00271 ControlArea - Supplies a pointer to the control area. 00272 00273 Return Value: 00274 00275 None. 00276 00277 --*/ 00278 00279 { 00280 KIRQL OldIrql; 00281 00282 LOCK_PFN (OldIrql); 00283 00284 ASSERT ((LONG)ControlArea->NumberOfMappedViews >= 1); 00285 ControlArea->NumberOfMappedViews -= 1; 00286 00287 // 00288 // Check to see if the control area should be deleted. This 00289 // will release the PFN lock. 00290 // 00291 00292 MiCheckControlArea (ControlArea, NULL, OldIrql); 00293 }

VOID MiPhysicalViewInserter IN PEPROCESS  Process,
IN PMI_PHYSICAL_VIEW  PhysicalView
 

Definition at line 2583 of file iosup.c.

References LOCK_AWE, LOCK_PFN2, MiActiveWriteWatch, MiMarkProcessAsWriteWatch(), UNLOCK_AWE, and UNLOCK_PFN2.

Referenced by MiMapLockedPagesInUserSpace(), and NtAllocateVirtualMemory().

02590 : 02591 02592 This function is a nonpaged wrapper which acquires the PFN lock to insert 02593 a physical VAD into the process chain. 02594 02595 Arguments: 02596 02597 Process - Supplies the process to add the physical VAD to. 02598 02599 PhysicalView - Supplies the physical view data to link in. 02600 02601 Return Value: 02602 02603 None. 02604 02605 Environment: 02606 02607 Kernel mode. APC_LEVEL, working set and address space mutexes held. 02608 02609 --*/ 02610 { 02611 KIRQL OldIrql; 02612 KIRQL OldIrql2; 02613 02614 LOCK_AWE (Process, OldIrql); 02615 02616 LOCK_PFN2 (OldIrql2); 02617 02618 InsertHeadList (&Process->PhysicalVadList, &PhysicalView->ListEntry); 02619 02620 if (PhysicalView->Vad->u.VadFlags.WriteWatch == 1) { 02621 MiActiveWriteWatch += 1; 02622 } 02623 02624 UNLOCK_PFN2 (OldIrql2); 02625 02626 UNLOCK_AWE (Process, OldIrql); 02627 02628 if (PhysicalView->Vad->u.VadFlags.WriteWatch == 1) { 02629 02630 // 02631 // Mark this process as forever containing write-watch 02632 // address space(s). 02633 02634 if (Process->Vm.u.Flags.WriteWatch == 0) { 02635 MiMarkProcessAsWriteWatch (Process); 02636 } 02637 } 02638 }

NTSTATUS MiResetVirtualMemory IN PVOID  StartingAddress,
IN PVOID  EndingAddress,
IN PMMVAD  Vad,
IN PEPROCESS  Process
 

Definition at line 1953 of file allocvm.c.

References FALSE, KeFlushSingleTb(), LOCK_PFN, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_IS_PTE_DIRTY, MI_PFN_ELEMENT, MI_SET_PTE_CLEAN, MI_VA_TO_VPN, MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiGetPdeAddress, MiGetProtoPteAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiInsertPageInList(), MiIsPteOnPdeBoundary, MiIsPteOnPpeBoundary, MiMakeSystemAddressValidPfnWs(), MiReleasePageFileSpace(), MiUnlinkPageFromList(), MmPageLocationList, ModifiedPageList, NULL, _MMPFN::OriginalPte, StandbyPageList, TRUE, _MMPTE::u, _MMPFN::u3, and UNLOCK_PFN.

Referenced by NtAllocateVirtualMemory().

01962 : 01963 01964 01965 Arguments: 01966 01967 StartingAddress - Supplies the starting address of the range. 01968 01969 RegionsSize - Supplies the size. 01970 01971 Process - Supplies the current process. 01972 01973 Return Value: 01974 01975 Environment: 01976 01977 Kernel mode, APCs disabled, WorkingSetMutex and AddressCreation mutexes 01978 held. 01979 01980 --*/ 01981 01982 { 01983 PMMPTE PointerPte; 01984 PMMPTE ProtoPte; 01985 PMMPTE PointerPde; 01986 PMMPTE PointerPpe; 01987 PMMPTE LastPte; 01988 MMPTE PteContents; 01989 ULONG Waited; 01990 ULONG PfnHeld; 01991 ULONG First; 01992 KIRQL OldIrql; 01993 PMMPFN Pfn1; 01994 01995 if (Vad->u.VadFlags.PrivateMemory == 0) { 01996 01997 if (Vad->ControlArea->FilePointer != NULL) { 01998 01999 // 02000 // Only page file backed sections can be committed. 02001 // 02002 02003 return STATUS_USER_MAPPED_FILE; 02004 } 02005 } 02006 02007 PfnHeld = FALSE; 02008 02009 First = TRUE; 02010 PointerPte = MiGetPteAddress (StartingAddress); 02011 LastPte = MiGetPteAddress (EndingAddress); 02012 02013 // 02014 // Examine all the PTEs in the range. 02015 // 02016 02017 while (PointerPte <= LastPte) { 02018 02019 if (MiIsPteOnPdeBoundary (PointerPte) || (First)) { 02020 02021 if (MiIsPteOnPpeBoundary (PointerPte)) { 02022 02023 PointerPpe = MiGetPdeAddress (PointerPte); 02024 02025 if (!MiDoesPpeExistAndMakeValid(PointerPpe, 02026 Process, 02027 (BOOLEAN)PfnHeld, 02028 &Waited)) { 02029 02030 // 02031 // This page directory parent entry is empty, 02032 // go to the next one. 02033 // 02034 02035 PointerPpe += 1; 02036 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 02037 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 02038 continue; 02039 } 02040 } 02041 02042 // 02043 // Pointing to the next page table page, make 02044 // a page table page exist and make it valid. 02045 // 02046 02047 First = FALSE; 02048 PointerPde = MiGetPteAddress (PointerPte); 02049 if (!MiDoesPdeExistAndMakeValid(PointerPde, 02050 Process, 02051 (BOOLEAN)PfnHeld, 02052 &Waited)) { 02053 02054 // 02055 // This page directory entry is empty, go to the next one. 02056 // 02057 02058 PointerPde += 1; 02059 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 02060 continue; 02061 } 02062 } 02063 02064 PteContents = *PointerPte; 02065 ProtoPte = NULL; 02066 02067 if ((PteContents.u.Hard.Valid == 0) && 02068 (PteContents.u.Soft.Prototype == 1)) { 02069 02070 // 02071 // This is a prototype PTE, evaluate the prototype PTE. 02072 // 02073 02074 ProtoPte = MiGetProtoPteAddress(Vad, 02075 MI_VA_TO_VPN ( 02076 MiGetVirtualAddressMappedByPte(PointerPte))); 02077 if (!PfnHeld) { 02078 PfnHeld = TRUE; 02079 LOCK_PFN (OldIrql); 02080 } 02081 02082 MiMakeSystemAddressValidPfnWs (ProtoPte, Process); 02083 02084 // 02085 // The working set mutex may be released in order to make the 02086 // prototype PTE which resides in paged pool resident. If this 02087 // occurs, the page directory and/or page table of the original 02088 // user address may get trimmed. Account for that here. 02089 // 02090 02091 if (MiMakeSystemAddressValidPfnWs (ProtoPte, Process) != 0) { 02092 02093 // 02094 // Working set mutex was released, restart from the top. 02095 // 02096 02097 First = TRUE; 02098 continue; 02099 } 02100 02101 PteContents = *ProtoPte; 02102 } 02103 if (PteContents.u.Hard.Valid == 1) { 02104 if (!PfnHeld) { 02105 LOCK_PFN (OldIrql); 02106 PfnHeld = TRUE; 02107 continue; 02108 } 02109 02110 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 02111 if (Pfn1->u3.e2.ReferenceCount == 1) { 02112 02113 // 02114 // Only this process has the page mapped. 02115 // 02116 02117 Pfn1->u3.e1.Modified = 0; 02118 MiReleasePageFileSpace (Pfn1->OriginalPte); 02119 Pfn1->OriginalPte.u.Soft.PageFileHigh = 0; 02120 } 02121 02122 if ((!ProtoPte) && (MI_IS_PTE_DIRTY (PteContents))) { 02123 02124 // 02125 // Clear the dirty bit and flush tb if it is NOT a prototype 02126 // PTE. 02127 // 02128 02129 MI_SET_PTE_CLEAN (PteContents); 02130 KeFlushSingleTb (MiGetVirtualAddressMappedByPte (PointerPte), 02131 TRUE, 02132 FALSE, 02133 (PHARDWARE_PTE)PointerPte, 02134 PteContents.u.Flush); 02135 } 02136 02137 } else if (PteContents.u.Soft.Transition == 1) { 02138 if (!PfnHeld) { 02139 LOCK_PFN (OldIrql); 02140 PfnHeld = TRUE; 02141 continue; 02142 } 02143 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 02144 if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) && 02145 (Pfn1->u3.e2.ReferenceCount == 0)) { 02146 02147 // 02148 // Remove from the modified list, release the page 02149 // file space and insert on the standby list. 02150 // 02151 02152 Pfn1->u3.e1.Modified = 0; 02153 MiUnlinkPageFromList (Pfn1); 02154 MiReleasePageFileSpace (Pfn1->OriginalPte); 02155 Pfn1->OriginalPte.u.Soft.PageFileHigh = 0; 02156 MiInsertPageInList (MmPageLocationList[StandbyPageList], 02157 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents)); 02158 } 02159 } else { 02160 if (PteContents.u.Soft.PageFileHigh != 0) { 02161 if (!PfnHeld) { 02162 LOCK_PFN (OldIrql); 02163 } 02164 PfnHeld = FALSE; 02165 MiReleasePageFileSpace (PteContents); 02166 UNLOCK_PFN (OldIrql); 02167 if (ProtoPte) { 02168 ProtoPte->u.Soft.PageFileHigh = 0; 02169 } else { 02170 PointerPte->u.Soft.PageFileHigh = 0; 02171 } 02172 } else { 02173 if (PfnHeld) { 02174 UNLOCK_PFN (OldIrql); 02175 } 02176 PfnHeld = FALSE; 02177 } 02178 } 02179 PointerPte += 1; 02180 } 02181 if (PfnHeld) { 02182 UNLOCK_PFN (OldIrql); 02183 } 02184 return STATUS_SUCCESS; 02185 }

NTSTATUS NtAllocateVirtualMemory IN HANDLE  ProcessHandle,
IN OUT PVOID *  BaseAddress,
IN ULONG_PTR  ZeroBits,
IN OUT PSIZE_T  RegionSize,
IN ULONG  AllocationType,
IN ULONG  Protect
 

Definition at line 75 of file allocvm.c.

References _EPROCESS::AddressSpaceDeleted, ALT_ALLOCATE, ALT_COMMIT, ASSERT, _MI_PHYSICAL_VIEW::BitMap, BitMap, BYTES_TO_PAGES, _EPROCESS::CommitCharge, _EPROCESS::CommitChargeLimit, _EPROCESS::CommitChargePeak, _MMVAD::ControlArea, DbgPrint, _MMVAD::EndingVpn, _MI_PHYSICAL_VIEW::EndVa, ExAcquireFastMutexUnsafe(), ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), ExRaiseStatus(), ExReleaseFastMutexUnsafe(), ExSystemExceptionFilter(), FALSE, _CONTROL_AREA::FilePointer, _SECTION::InitialPageProtection, _EPROCESS::Job, _EPROCESS::JobStatus, KeAttachProcess(), KeDetachProcess(), KernelMode, KPROCESSOR_MODE, L, LOCK_WS_AND_ADDRESS_SPACE, LOCK_WS_UNSAFE, MEM_CHECK_COMMIT_STATE, MI_64K_ALIGN, MI_GET_USED_PTES_HANDLE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_IS_PTE_PROTECTION_COPY_WRITE, MI_PHYSICAL_VIEW, MI_PHYSICAL_VIEW_KEY, MI_VA_TO_VPN, MI_VPN_TO_VA, MI_WRITE_INVALID_PTE, MI_WRITEWATCH_VIEW_KEY, MiCalculatePageCommitment(), MiChargeCommitment(), MiChargePageFileQuota(), MiCheckForConflictingVad, MiCheckSecuredVad(), MiCreatePageTablesForPhysicalRange(), MiFindEmptyAddressRange(), MiFindEmptyAddressRangeDown, MiFlushAcquire(), MiFlushRelease(), MiGetPageProtection(), MiGetPdeAddress, MiGetPpeAddress, MiGetProtoPteAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiInsertVad(), MiIsEntireRangeDecommitted(), MiIsPteOnPdeBoundary, MiIsPteOnPpeBoundary, MiMakePdeExistAndMakeValid(), MiMakePpeExistAndMakeValid, MiMakeProtectForNativePage(), MiMakeProtectionMask(), MiPhysicalViewInserter(), MiProtectFor4kPage(), MiProtectVirtualMemory(), MiRemoveVad(), MiResetVirtualMemory(), MiReturnCommitment(), MiReturnPageFileQuota(), MiSetProtectionOnSection(), MM_DBG_COMMIT_ALLOCVM1, MM_DBG_COMMIT_ALLOCVM2, MM_DBG_COMMIT_RETURN_ALLOCVM1, MM_DBG_COMMIT_RETURN_ALLOCVM2, MM_DBG_COMMIT_RETURN_ALLOCVM3, MM_DBG_SHOW_NT_CALLS, MM_DECOMMIT, MM_HIGHEST_VAD_ADDRESS, MM_MAX_COMMIT, MM_MAXIMUM_ZERO_BITS, MM_PROTECTION_COPY_MASK, MM_TRACK_COMMIT, MM_USER_ADDRESS_RANGE_LIMIT, MmExtendSection(), MmSectionCommitMutex, MmSharedCommit, MmSupportWriteWatch, MMVAD_SHORT, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, _SEGMENT::NumberOfCommittedPages, ObDereferenceObject, ObReferenceObjectByHandle(), PAGE_4K, PAGE_4K_ALIGN, PAGE_ALIGN, PAGE_SIZE, PAGED_CODE, _EPROCESS::Pcb, _EPROCESS::PeakVirtualSize, ProbeForWritePointer, ProbeForWriteUlong_ptr, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, PsChangeJobMemoryUsage(), PsChargePoolQuota(), PsGetCurrentProcess, PsProcessType, PsReportProcessMemoryLimitViolation(), PsReturnPoolQuota(), ROUND_TO_4K_PAGES, ROUND_TO_PAGES, RtlClearAllBits(), RtlFindMostSignificantBit(), RtlInitializeBitMap(), SECTION, _CONTROL_AREA::Segment, _SECTION::Segment, _SEGMENT::SegmentPteTemplate, Size, Start, _MMVAD::StartingVpn, _MI_PHYSICAL_VIEW::StartVa, Status, TRUE, _MMPTE::u, _CONTROL_AREA::u, _SECTION::u, _MMVAD::u, _MMVAD::u2, UNLOCK_ADDRESS_SPACE, UNLOCK_WS_AND_ADDRESS_SPACE, UNLOCK_WS_UNSAFE, _MI_PHYSICAL_VIEW::Vad, _EPROCESS::VirtualSize, _EPROCESS::Wow64Process, X64K, and ZeroPte.

Referenced by ExAllocatePool(), LdrpInitializeProcess(), main(), RegLoadAsciiFileAsUnicode(), RtlAllocateHandle(), RtlCreateQueryDebugBuffer(), RtlpAllocateHeapUsageEntry(), RtlpAllocateTags(), RtlpCommitQueryDebugInfo(), RtlpValidateHeap(), RtlpValidateHeapHeaders(), and RtlUsageHeap().

00086 : 00087 00088 This function creates a region of pages within the virtual address 00089 space of a subject process. 00090 00091 Arguments: 00092 00093 ProcessHandle - Supplies an open handle to a process object. 00094 00095 BaseAddress - Supplies a pointer to a variable that will receive 00096 the base address of the allocated region of pages. 00097 If the initial value of this argument is not null, 00098 then the region will be allocated starting at the 00099 specified virtual address rounded down to the next 00100 host page size address boundary. If the initial 00101 value of this argument is null, then the operating 00102 system will determine where to allocate the region. 00103 00104 ZeroBits - Supplies the number of high order address bits that 00105 must be zero in the base address of the section view. The 00106 value of this argument must be less than or equal to the 00107 maximum number of zero bits and is only used when memory 00108 management determines where to allocate the view (i.e. when 00109 BaseAddress is null). 00110 00111 If ZeroBits is zero, then no zero bit constraints are applied. 00112 00113 If ZeroBits is greater than 0 and less than 32, then it is 00114 the number of leading zero bits from bit 31. Bits 63:32 are 00115 also required to be zero. This retains compatibility 00116 with 32-bit systems. 00117 00118 If ZeroBits is greater than 32, then it is considered as 00119 a mask and then number of leading zero are counted out 00120 in the mask. This then becomes the zero bits argument. 00121 00122 RegionSize - Supplies a pointer to a variable that will receive 00123 the actual size in bytes of the allocated region 00124 of pages. The initial value of this argument 00125 specifies the size in bytes of the region and is 00126 rounded up to the next host page size boundary. 00127 00128 AllocationType - Supplies a set of flags that describe the type 00129 of allocation that is to be performed for the 00130 specified region of pages. Flags are: 00131 00132 00133 MEM_COMMIT - The specified region of pages is to 00134 be committed. 00135 00136 MEM_RESERVE - The specified region of pages is to 00137 be reserved. 00138 00139 MEM_TOP_DOWN - The specified region should be created at the 00140 highest virtual address possible based on ZeroBits. 00141 00142 MEM_RESET - Reset the state of the specified region so 00143 that if the pages are in page paging file, they 00144 are discarded and pages of zeroes are brought in. 00145 If the pages are in memory and modified, they are marked 00146 as not modified so they will not be written out to 00147 the paging file. The contents are NOT zeroed. 00148 00149 The Protect argument is ignored, but a valid protection 00150 must be specified. 00151 00152 Protect - Supplies the protection desired for the committed 00153 region of pages. 00154 00155 Protect Values: 00156 00157 00158 PAGE_NOACCESS - No access to the committed region 00159 of pages is allowed. An attempt to read, 00160 write, or execute the committed region 00161 results in an access violation (i.e. a GP 00162 fault). 00163 00164 PAGE_EXECUTE - Execute access to the committed 00165 region of pages is allowed. An attempt to 00166 read or write the committed region results in 00167 an access violation. 00168 00169 PAGE_READONLY - Read only and execute access to the 00170 committed region of pages is allowed. An 00171 attempt to write the committed region results 00172 in an access violation. 00173 00174 PAGE_READWRITE - Read, write, and execute access to 00175 the committed region of pages is allowed. If 00176 write access to the underlying section is 00177 allowed, then a single copy of the pages are 00178 shared. Otherwise the pages are shared read 00179 only/copy on write. 00180 00181 PAGE_NOCACHE - The region of pages should be allocated 00182 as non-cachable. 00183 00184 Return Value: 00185 00186 Various NTSTATUS codes. 00187 00188 --*/ 00189 00190 { 00191 PMMVAD Vad; 00192 PMMVAD FoundVad; 00193 PEPROCESS Process; 00194 KPROCESSOR_MODE PreviousMode; 00195 PVOID StartingAddress; 00196 PVOID EndingAddress; 00197 NTSTATUS Status; 00198 PVOID TopAddress; 00199 PVOID CapturedBase; 00200 SIZE_T CapturedRegionSize; 00201 PMMPTE PointerPte; 00202 PMMPTE CommitLimitPte; 00203 ULONG ProtectionMask; 00204 PMMPTE LastPte; 00205 PMMPTE PointerPde; 00206 PMMPTE PointerPpe; 00207 PMMPTE StartingPte; 00208 MMPTE TempPte; 00209 ULONG OldProtect; 00210 SSIZE_T QuotaCharge; 00211 SIZE_T QuotaFree; 00212 SIZE_T CopyOnWriteCharge; 00213 BOOLEAN PageFileChargeSucceeded; 00214 BOOLEAN Attached; 00215 LOGICAL ChargedExactQuota; 00216 MMPTE DecommittedPte; 00217 ULONG ChangeProtection; 00218 PVOID UsedPageDirectoryHandle; 00219 PVOID UsedPageTableHandle; 00220 PUCHAR Va; 00221 LOGICAL ChargedJobCommit; 00222 PMI_PHYSICAL_VIEW PhysicalView; 00223 PRTL_BITMAP BitMap; 00224 ULONG BitMapSize; 00225 ULONG BitMapBits; 00226 #if defined(_MIALT4K_) 00227 PVOID OriginalBase; 00228 SIZE_T OriginalRegionSize; 00229 BOOLEAN EmulationFor4kPage = FALSE; 00230 PVOID StartingAddressFor4k; 00231 PVOID EndingAddressFor4k; 00232 SIZE_T CapturedRegionSizeFor4k; 00233 ULONG CapturedOldProtectFor4k; 00234 ULONG OriginalProtectionMask; 00235 ULONG AltFlags; 00236 #endif 00237 00238 PAGED_CODE(); 00239 00240 Attached = FALSE; 00241 00242 // 00243 // Check the zero bits argument for correctness. 00244 // 00245 00246 #if defined (_WIN64) 00247 00248 if (ZeroBits >= 32) { 00249 00250 // 00251 // ZeroBits is a mask instead of a count. Translate it to a count now. 00252 // 00253 00254 ZeroBits = 64 - RtlFindMostSignificantBit (ZeroBits); 00255 } 00256 else if (ZeroBits) { 00257 ZeroBits += 32; 00258 } 00259 00260 #endif 00261 00262 if (ZeroBits > MM_MAXIMUM_ZERO_BITS) { 00263 return STATUS_INVALID_PARAMETER_3; 00264 } 00265 00266 // 00267 // Check the AllocationType for correctness. 00268 // 00269 00270 if ((AllocationType & ~(MEM_COMMIT | MEM_RESERVE | MEM_PHYSICAL | 00271 MEM_TOP_DOWN | MEM_RESET | MEM_WRITE_WATCH)) != 0) { 00272 return STATUS_INVALID_PARAMETER_5; 00273 } 00274 00275 // 00276 // One of MEM_COMMIT, MEM_RESET or MEM_RESERVE must be set. 00277 // 00278 00279 if ((AllocationType & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) == 0) { 00280 return STATUS_INVALID_PARAMETER_5; 00281 } 00282 00283 if ((AllocationType & MEM_RESET) && (AllocationType != MEM_RESET)) { 00284 00285 // 00286 // MEM_RESET may not be used with any other flag. 00287 // 00288 00289 return STATUS_INVALID_PARAMETER_5; 00290 } 00291 00292 if (AllocationType & MEM_WRITE_WATCH) { 00293 00294 // 00295 // Write watch address spaces can only be created with MEM_RESERVE. 00296 // 00297 00298 if ((AllocationType & MEM_RESERVE) == 0) { 00299 return STATUS_INVALID_PARAMETER_5; 00300 } 00301 00302 if (MmSupportWriteWatch == FALSE) { 00303 return STATUS_NOT_SUPPORTED; 00304 } 00305 } 00306 00307 if (AllocationType & MEM_PHYSICAL) { 00308 00309 // 00310 // MEM_PHYSICAL must be used with MEM_RESERVE and no other flags. 00311 // This memory is always read-write when allocated. 00312 // 00313 00314 if (AllocationType != (MEM_RESERVE | MEM_PHYSICAL)) { 00315 return STATUS_INVALID_PARAMETER_5; 00316 } 00317 00318 if (Protect != PAGE_READWRITE) { 00319 return STATUS_INVALID_PARAMETER_6; 00320 } 00321 } 00322 00323 // 00324 // Check the protection field. This could raise an exception. 00325 // 00326 00327 try { 00328 ProtectionMask = MiMakeProtectionMask (Protect); 00329 } except (EXCEPTION_EXECUTE_HANDLER) { 00330 return GetExceptionCode(); 00331 } 00332 00333 ChangeProtection = FALSE; 00334 00335 PreviousMode = KeGetPreviousMode(); 00336 00337 // 00338 // Establish an exception handler, probe the specified addresses 00339 // for write access and capture the initial values. 00340 // 00341 00342 try { 00343 00344 if (PreviousMode != KernelMode) { 00345 00346 ProbeForWritePointer (BaseAddress); 00347 ProbeForWriteUlong_ptr (RegionSize); 00348 } 00349 00350 // 00351 // Capture the base address. 00352 // 00353 00354 CapturedBase = *BaseAddress; 00355 00356 // 00357 // Capture the region size. 00358 // 00359 00360 CapturedRegionSize = *RegionSize; 00361 00362 } except (ExSystemExceptionFilter()) { 00363 00364 // 00365 // If an exception occurs during the probe or capture 00366 // of the initial values, then handle the exception and 00367 // return the exception code as the status value. 00368 // 00369 00370 return GetExceptionCode(); 00371 } 00372 00373 #if defined(_MIALT4K_) 00374 00375 OriginalBase = CapturedBase; 00376 OriginalRegionSize = CapturedRegionSize; 00377 00378 #endif 00379 00380 #if DBG 00381 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00382 if ( MmWatchProcess ) { 00383 ; 00384 } else { 00385 DbgPrint("allocvm process handle %lx base address %lx zero bits %lx\n", 00386 ProcessHandle, CapturedBase, ZeroBits); 00387 DbgPrint(" region size %lx alloc type %lx protect %lx\n", 00388 CapturedRegionSize, AllocationType, Protect); 00389 } 00390 } 00391 #endif 00392 00393 // 00394 // Make sure the specified starting and ending addresses are 00395 // within the user part of the virtual address space. 00396 // 00397 00398 if (CapturedBase > MM_HIGHEST_VAD_ADDRESS) { 00399 00400 // 00401 // Invalid base address. 00402 // 00403 00404 return STATUS_INVALID_PARAMETER_2; 00405 } 00406 00407 if ((((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) - (ULONG_PTR)CapturedBase) < 00408 CapturedRegionSize) { 00409 00410 // 00411 // Invalid region size; 00412 // 00413 00414 return STATUS_INVALID_PARAMETER_4; 00415 } 00416 00417 if (CapturedRegionSize == 0) { 00418 00419 // 00420 // Region size cannot be 0. 00421 // 00422 00423 return STATUS_INVALID_PARAMETER_4; 00424 } 00425 00426 // 00427 // Reference the specified process handle for VM_OPERATION access. 00428 // 00429 00430 if ( ProcessHandle == NtCurrentProcess() ) { 00431 Process = PsGetCurrentProcess(); 00432 } else { 00433 Status = ObReferenceObjectByHandle ( ProcessHandle, 00434 PROCESS_VM_OPERATION, 00435 PsProcessType, 00436 PreviousMode, 00437 (PVOID *)&Process, 00438 NULL ); 00439 00440 if (!NT_SUCCESS(Status)) { 00441 return Status; 00442 } 00443 } 00444 00445 // 00446 // If the specified process is not the current process, attach 00447 // to the specified process. 00448 // 00449 00450 if (PsGetCurrentProcess() != Process) { 00451 KeAttachProcess (&Process->Pcb); 00452 Attached = TRUE; 00453 } 00454 00455 // 00456 // Get the address creation mutex to block multiple threads from 00457 // creating or deleting address space at the same time and 00458 // get the working set mutex so virtual address descriptors can 00459 // be inserted and walked. Block APCs so an APC which takes a page 00460 // fault does not corrupt various structures. 00461 // 00462 00463 LOCK_WS_AND_ADDRESS_SPACE (Process); 00464 00465 // 00466 // Make sure the address space was not deleted, if so, return an error. 00467 // 00468 00469 if (Process->AddressSpaceDeleted != 0) { 00470 Status = STATUS_PROCESS_IS_TERMINATING; 00471 goto ErrorReturn; 00472 } 00473 00474 if ((CapturedBase == NULL) || (AllocationType & MEM_RESERVE)) { 00475 00476 // 00477 // PAGE_WRITECOPY is not valid for private pages. 00478 // 00479 00480 if ((Protect & PAGE_WRITECOPY) || 00481 (Protect & PAGE_EXECUTE_WRITECOPY)) { 00482 Status = STATUS_INVALID_PAGE_PROTECTION; 00483 goto ErrorReturn; 00484 } 00485 00486 // 00487 // Reserve the address space. 00488 // 00489 00490 if (CapturedBase == NULL) { 00491 00492 // 00493 // No base address was specified. This MUST be a reserve or 00494 // reserve and commit. 00495 // 00496 00497 CapturedRegionSize = ROUND_TO_PAGES (CapturedRegionSize); 00498 00499 // 00500 // If the number of zero bits is greater than zero, then calculate 00501 // the highest address. 00502 // 00503 00504 if (ZeroBits != 0) { 00505 TopAddress = (PVOID)(((ULONG_PTR)MM_USER_ADDRESS_RANGE_LIMIT) >> ZeroBits); 00506 00507 // 00508 // Keep the top address below the highest user vad address 00509 // regardless. 00510 // 00511 00512 if (TopAddress > MM_HIGHEST_VAD_ADDRESS) { 00513 Status = STATUS_INVALID_PARAMETER_3; 00514 goto ErrorReturn; 00515 } 00516 00517 } else { 00518 TopAddress = (PVOID)MM_HIGHEST_VAD_ADDRESS; 00519 } 00520 00521 #if defined (_WIN64) 00522 00523 // 00524 // BUGBUG: 00525 // For testing purposes, always set the MEM_TOP_DOWN flag to reduce 00526 // the number of low 4GB address allocations. This helps the 00527 // compiler people catch address truncation errors. 00528 // This must be removed before the final build. 00529 // 00530 00531 AllocationType |= MEM_TOP_DOWN; 00532 00533 #endif 00534 // 00535 // Establish exception handler as MiFindEmptyAddressRange 00536 // will raise an exception if it fails. 00537 // 00538 00539 try { 00540 00541 if (AllocationType & MEM_TOP_DOWN) { 00542 00543 // 00544 // Start from the top of memory downward. 00545 // 00546 00547 StartingAddress = MiFindEmptyAddressRangeDown ( 00548 CapturedRegionSize, 00549 TopAddress, 00550 X64K); 00551 00552 } else { 00553 00554 StartingAddress = MiFindEmptyAddressRange ( 00555 CapturedRegionSize, 00556 X64K, 00557 (ULONG)ZeroBits ); 00558 } 00559 00560 } except (EXCEPTION_EXECUTE_HANDLER) { 00561 Status = GetExceptionCode(); 00562 goto ErrorReturn; 00563 } 00564 00565 // 00566 // Calculate the ending address based on the top address. 00567 // 00568 00569 EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress + 00570 CapturedRegionSize - 1L) | (PAGE_SIZE - 1L)); 00571 00572 if (EndingAddress > TopAddress) { 00573 00574 // 00575 // The allocation does not honor the zero bits argument. 00576 // 00577 00578 Status = STATUS_NO_MEMORY; 00579 goto ErrorReturn; 00580 } 00581 00582 } else { 00583 00584 // 00585 // A non-NULL base address was specified. Check to make sure 00586 // the specified base address to ending address is currently 00587 // unused. 00588 // 00589 00590 EndingAddress = (PVOID)(((ULONG_PTR)CapturedBase + 00591 CapturedRegionSize - 1L) | (PAGE_SIZE - 1L)); 00592 00593 // 00594 // Align the starting address on a 64k boundary. 00595 // 00596 00597 StartingAddress = (PVOID)MI_64K_ALIGN(CapturedBase); 00598 00599 // 00600 // See if a VAD overlaps with this starting/ending address pair. 00601 // 00602 00603 if (MiCheckForConflictingVad (StartingAddress, EndingAddress) != 00604 (PMMVAD)NULL) { 00605 00606 Status = STATUS_CONFLICTING_ADDRESSES; 00607 goto ErrorReturn; 00608 } 00609 } 00610 00611 // 00612 // Calculate the page file quota for this address range. 00613 // 00614 00615 if (AllocationType & MEM_COMMIT) { 00616 QuotaCharge = BYTES_TO_PAGES ((PCHAR)EndingAddress - 00617 (PCHAR)StartingAddress); 00618 00619 } else { 00620 QuotaCharge = 0; 00621 } 00622 00623 // 00624 // An unoccupied address range has been found, build the virtual 00625 // address descriptor to describe this range. 00626 // 00627 // Allocate and initialize a VAD for the specified address range. 00628 // 00629 00630 BitMapSize = 0; 00631 00632 if (AllocationType & MEM_PHYSICAL) { 00633 00634 if (AllocationType & MEM_WRITE_WATCH) { 00635 Status = STATUS_INVALID_PARAMETER_5; 00636 goto ErrorReturn; 00637 } 00638 00639 PhysicalView = (PMI_PHYSICAL_VIEW) ExAllocatePoolWithTag ( 00640 NonPagedPool, 00641 sizeof(MI_PHYSICAL_VIEW), 00642 MI_PHYSICAL_VIEW_KEY); 00643 00644 if (PhysicalView == NULL) { 00645 Status = STATUS_INSUFFICIENT_RESOURCES; 00646 goto ErrorReturn; 00647 } 00648 } 00649 else if (AllocationType & MEM_WRITE_WATCH) { 00650 00651 ASSERT (AllocationType & MEM_RESERVE); 00652 00653 BitMapBits = BYTES_TO_PAGES ((PCHAR)EndingAddress - 00654 (PCHAR)StartingAddress); 00655 00656 BitMapSize = sizeof(RTL_BITMAP) + (ULONG)(((BitMapBits + 31) / 32) * 4); 00657 00658 BitMap = ExAllocatePoolWithTag (NonPagedPool, BitMapSize, 'wwmM'); 00659 00660 if (BitMap == NULL) { 00661 Status = STATUS_INSUFFICIENT_RESOURCES; 00662 goto ErrorReturn; 00663 } 00664 00665 try { 00666 00667 // 00668 // Charge quota for the nonpaged pool for the bitmap. This is 00669 // done here rather than by using ExAllocatePoolWithQuota 00670 // so the process object is not referenced by the quota charge. 00671 // 00672 00673 PsChargePoolQuota (Process, NonPagedPool, BitMapSize); 00674 00675 } except (EXCEPTION_EXECUTE_HANDLER) { 00676 Status = GetExceptionCode(); 00677 ExFreePool (BitMap); 00678 goto ErrorReturn; 00679 } 00680 00681 PhysicalView = (PMI_PHYSICAL_VIEW) ExAllocatePoolWithTag ( 00682 NonPagedPool, 00683 sizeof(MI_PHYSICAL_VIEW), 00684 MI_WRITEWATCH_VIEW_KEY); 00685 00686 if (PhysicalView == NULL) { 00687 ExFreePool (BitMap); 00688 PsReturnPoolQuota (Process, NonPagedPool, BitMapSize); 00689 Status = STATUS_INSUFFICIENT_RESOURCES; 00690 goto ErrorReturn; 00691 } 00692 00693 RtlInitializeBitMap (BitMap, 00694 (PULONG)(BitMap + 1), 00695 BitMapBits); 00696 00697 RtlClearAllBits (BitMap); 00698 } 00699 00700 Vad = ExAllocatePoolWithTag (NonPagedPool, 00701 sizeof(MMVAD_SHORT), 00702 'SdaV'); 00703 00704 try { 00705 00706 if (Vad == NULL) { 00707 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 00708 } 00709 00710 Vad->StartingVpn = MI_VA_TO_VPN (StartingAddress); 00711 Vad->EndingVpn = MI_VA_TO_VPN (EndingAddress); 00712 00713 Vad->u.LongFlags = 0; 00714 if (AllocationType & MEM_COMMIT) { 00715 Vad->u.VadFlags.MemCommit = 1; 00716 } 00717 00718 if (AllocationType & MEM_PHYSICAL) { 00719 Vad->u.VadFlags.UserPhysicalPages = 1; 00720 } 00721 00722 Vad->u.VadFlags.Protection = ProtectionMask; 00723 Vad->u.VadFlags.PrivateMemory = 1; 00724 00725 Vad->u.VadFlags.CommitCharge = QuotaCharge; 00726 00727 MiInsertVad (Vad); 00728 00729 } except (EXCEPTION_EXECUTE_HANDLER) { 00730 00731 if (Vad != (PMMVAD)NULL) { 00732 00733 // 00734 // The pool allocation succeeded, but the quota charge 00735 // in InsertVad failed, deallocate the pool and return 00736 // an error. 00737 // 00738 00739 ExFreePool (Vad); 00740 Status = GetExceptionCode(); 00741 00742 } else { 00743 Status = STATUS_INSUFFICIENT_RESOURCES; 00744 } 00745 00746 if (AllocationType & MEM_PHYSICAL) { 00747 ExFreePool (PhysicalView); 00748 } 00749 else if (BitMapSize != 0) { 00750 ExFreePool (PhysicalView); 00751 ExFreePool (BitMap); 00752 PsReturnPoolQuota (Process, NonPagedPool, BitMapSize); 00753 } 00754 00755 goto ErrorReturn; 00756 } 00757 00758 // 00759 // Initialize page directory and table pages for the physical range. 00760 // 00761 00762 if (AllocationType & MEM_PHYSICAL) { 00763 00764 if (MiCreatePageTablesForPhysicalRange (Process, 00765 StartingAddress, 00766 EndingAddress) == FALSE) { 00767 00768 MiRemoveVad (Vad); 00769 ExFreePool (Vad); 00770 ExFreePool (PhysicalView); 00771 Status = STATUS_INSUFFICIENT_RESOURCES; 00772 goto ErrorReturn; 00773 } 00774 00775 PhysicalView->Vad = Vad; 00776 PhysicalView->StartVa = StartingAddress; 00777 PhysicalView->EndVa = EndingAddress; 00778 00779 // 00780 // Insert the physical view into this process' list using a 00781 // nonpaged wrapper since the PFN lock is required. 00782 // 00783 00784 MiPhysicalViewInserter (Process, PhysicalView); 00785 } 00786 else if (BitMapSize != 0) { 00787 00788 Vad->u.VadFlags.WriteWatch = 1; 00789 00790 PhysicalView->Vad = Vad; 00791 PhysicalView->StartVa = StartingAddress; 00792 PhysicalView->EndVa = EndingAddress; 00793 PhysicalView->BitMap = BitMap; 00794 00795 MiPhysicalViewInserter (Process, PhysicalView); 00796 } 00797 00798 // 00799 // Unlock the working set lock, page faults can now be taken. 00800 // 00801 00802 UNLOCK_WS_UNSAFE (Process); 00803 00804 // 00805 // Update the current virtual size in the process header, the 00806 // address space lock protects this operation. 00807 // 00808 00809 CapturedRegionSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L; 00810 Process->VirtualSize += CapturedRegionSize; 00811 00812 if (Process->VirtualSize > Process->PeakVirtualSize) { 00813 Process->PeakVirtualSize = Process->VirtualSize; 00814 } 00815 00816 #if defined(_MIALT4K_) 00817 00818 if (Process->Wow64Process != NULL) { 00819 00820 if (OriginalBase == NULL) { 00821 00822 OriginalRegionSize = ROUND_TO_4K_PAGES(OriginalRegionSize); 00823 00824 EndingAddress = (PVOID)(((ULONG_PTR) StartingAddress + 00825 OriginalRegionSize - 1L) | (PAGE_4K - 1L)); 00826 00827 } else { 00828 00829 EndingAddress = (PVOID)(((ULONG_PTR)OriginalBase + 00830 OriginalRegionSize - 1L) | (PAGE_4K - 1L)); 00831 } 00832 00833 CapturedRegionSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L; 00834 00835 // 00836 // Set the alternate permission table 00837 // 00838 00839 AltFlags = (AllocationType & MEM_COMMIT) ? ALT_COMMIT : 0; 00840 00841 MiProtectFor4kPage (StartingAddress, 00842 CapturedRegionSize, 00843 ProtectionMask, 00844 ALT_ALLOCATE|AltFlags, 00845 Process); 00846 } 00847 00848 #endif 00849 00850 // 00851 // Release the address space lock, lower IRQL, detach, and dereference 00852 // the process object. 00853 // 00854 00855 UNLOCK_ADDRESS_SPACE(Process); 00856 if (Attached) { 00857 KeDetachProcess(); 00858 } 00859 00860 if (ProcessHandle != NtCurrentProcess()) { 00861 ObDereferenceObject (Process); 00862 } 00863 00864 // 00865 // Establish an exception handler and write the size and base 00866 // address. 00867 // 00868 00869 try { 00870 00871 *RegionSize = CapturedRegionSize; 00872 *BaseAddress = StartingAddress; 00873 00874 } except (EXCEPTION_EXECUTE_HANDLER) { 00875 00876 // 00877 // Return success at this point even if the results 00878 // cannot be written. 00879 // 00880 00881 NOTHING; 00882 } 00883 00884 #if DBG 00885 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00886 if ( MmWatchProcess ) { 00887 if ( MmWatchProcess == PsGetCurrentProcess() ) { 00888 DbgPrint("\n+++ ALLOC Type %lx Base %lx Size %lx\n", 00889 AllocationType,StartingAddress, CapturedRegionSize); 00890 MmFooBar(); 00891 } 00892 } else { 00893 DbgPrint("return allocvm status %lx baseaddr %lx size %lx\n", 00894 Status, StartingAddress, CapturedRegionSize); 00895 } 00896 } 00897 #endif 00898 00899 return STATUS_SUCCESS; 00900 00901 } else { 00902 00903 // 00904 // Commit previously reserved pages. Note that these pages could 00905 // be either private or a section. 00906 // 00907 00908 if (AllocationType == MEM_RESET) { 00909 00910 // 00911 // Round up to page boundaries so good data is not reset. 00912 // 00913 00914 EndingAddress = (PVOID)((ULONG_PTR)PAGE_ALIGN ((ULONG_PTR)CapturedBase + 00915 CapturedRegionSize) - 1); 00916 StartingAddress = (PVOID)PAGE_ALIGN((PUCHAR)CapturedBase + PAGE_SIZE - 1); 00917 if (StartingAddress > EndingAddress) { 00918 Status = STATUS_CONFLICTING_ADDRESSES; 00919 goto ErrorReturn; 00920 } 00921 } else { 00922 EndingAddress = (PVOID)(((ULONG_PTR)CapturedBase + 00923 CapturedRegionSize - 1) | (PAGE_SIZE - 1)); 00924 StartingAddress = (PVOID)PAGE_ALIGN(CapturedBase); 00925 } 00926 00927 CapturedRegionSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1; 00928 00929 FoundVad = MiCheckForConflictingVad (StartingAddress, EndingAddress); 00930 00931 #if defined(_MIALT4K_) 00932 00933 if (Process->Wow64Process != NULL) { 00934 00935 EmulationFor4kPage = TRUE; 00936 00937 OriginalProtectionMask = MiMakeProtectionMask(Protect); 00938 00939 // 00940 // if it is allowed to change the protection, relax the protection 00941 // 00942 00943 if (FoundVad->u.VadFlags.NoChange == 0) { 00944 00945 Protect = MiMakeProtectForNativePage(StartingAddress, 00946 Protect, 00947 Process); 00948 00949 ProtectionMask = MiMakeProtectionMask (Protect); 00950 } 00951 00952 } 00953 00954 #endif 00955 00956 if (FoundVad == (PMMVAD)NULL) { 00957 00958 // 00959 // No virtual address is reserved at the specified base address, 00960 // return an error. 00961 // 00962 00963 Status = STATUS_CONFLICTING_ADDRESSES; 00964 goto ErrorReturn; 00965 } 00966 00967 if (FoundVad->u.VadFlags.UserPhysicalPages == 1) { 00968 Status = STATUS_CONFLICTING_ADDRESSES; 00969 goto ErrorReturn; 00970 } 00971 00972 if (FoundVad->u.VadFlags.CommitCharge == MM_MAX_COMMIT) { 00973 00974 // 00975 // This is a special VAD, don't let any commits occur. 00976 // 00977 00978 Status = STATUS_CONFLICTING_ADDRESSES; 00979 goto ErrorReturn; 00980 } 00981 00982 // 00983 // Ensure that the starting and ending addresses are all within 00984 // the same virtual address descriptor. 00985 // 00986 00987 if ((MI_VA_TO_VPN (StartingAddress) < FoundVad->StartingVpn) || 00988 (MI_VA_TO_VPN (EndingAddress) > FoundVad->EndingVpn)) { 00989 00990 // 00991 // Not within the section virtual address descriptor, 00992 // return an error. 00993 // 00994 00995 Status = STATUS_CONFLICTING_ADDRESSES; 00996 goto ErrorReturn; 00997 } 00998 00999 if (AllocationType == MEM_RESET) { 01000 Status = MiResetVirtualMemory (StartingAddress, 01001 EndingAddress, 01002 FoundVad, 01003 Process); 01004 goto done; 01005 01006 } else if (FoundVad->u.VadFlags.PrivateMemory == 0) { 01007 01008 01009 // 01010 // The no cache option is not allowed for sections. 01011 // 01012 01013 if (Protect & PAGE_NOCACHE) { 01014 Status = STATUS_INVALID_PAGE_PROTECTION; 01015 goto ErrorReturn; 01016 } 01017 01018 if (FoundVad->u.VadFlags.NoChange == 1) { 01019 01020 // 01021 // An attempt is made at changing the protection 01022 // of a SEC_NO_CHANGE section. 01023 // 01024 01025 Status = MiCheckSecuredVad (FoundVad, 01026 CapturedBase, 01027 CapturedRegionSize, 01028 ProtectionMask); 01029 01030 if (!NT_SUCCESS (Status)) { 01031 goto ErrorReturn; 01032 } 01033 } 01034 01035 if (FoundVad->ControlArea->FilePointer != NULL) { 01036 if (FoundVad->u2.VadFlags2.ExtendableFile == 0) { 01037 01038 // 01039 // Only page file backed sections can be committed. 01040 // 01041 01042 Status = STATUS_ALREADY_COMMITTED; 01043 goto ErrorReturn; 01044 } else { 01045 01046 // 01047 // Commit the requested portions of the extendable file. 01048 // 01049 01050 SECTION Section; 01051 LARGE_INTEGER NewSize; 01052 PCONTROL_AREA ControlArea; 01053 01054 RtlZeroMemory (&Section, sizeof(SECTION)); 01055 ControlArea = FoundVad->ControlArea; 01056 Section.Segment = ControlArea->Segment; 01057 Section.u.LongFlags = ControlArea->u.LongFlags; 01058 Section.InitialPageProtection = PAGE_READWRITE; 01059 NewSize.QuadPart = FoundVad->u2.VadFlags2.FileOffset; 01060 NewSize.QuadPart = NewSize.QuadPart << 16; 01061 NewSize.QuadPart += 1 + 01062 ((PCHAR)EndingAddress - (PCHAR)MI_VPN_TO_VA (FoundVad->StartingVpn)); 01063 01064 // 01065 // The working set and address space mutexes must be 01066 // released prior to calling MmExtendSection otherwise 01067 // a deadlock with the filesystem can occur. 01068 // 01069 // Prevent the control area from being deleted while 01070 // the (potential) extension is ongoing. 01071 // 01072 01073 MiFlushAcquire (ControlArea); 01074 01075 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01076 01077 Status = MmExtendSection (&Section, 01078 &NewSize, 01079 FALSE); 01080 01081 MiFlushRelease (ControlArea); 01082 01083 if (NT_SUCCESS(Status)) { 01084 01085 LOCK_WS_AND_ADDRESS_SPACE (Process); 01086 01087 // 01088 // The Vad and/or the control area may have been changed 01089 // or deleted before the mutexes were regained above. 01090 // So everything must be revalidated. Note that 01091 // if anything has changed, success is silently 01092 // returned just as if the protection change had failed. 01093 // It is the caller's fault if any of these has gone 01094 // away and they will suffer. 01095 // 01096 01097 if (Process->AddressSpaceDeleted != 0) { 01098 // Status = STATUS_PROCESS_IS_TERMINATING; 01099 goto ErrorReturn; 01100 } 01101 01102 FoundVad = MiCheckForConflictingVad (StartingAddress, 01103 EndingAddress); 01104 01105 if (FoundVad == (PMMVAD)NULL) { 01106 01107 // 01108 // No virtual address is reserved at the specified 01109 // base address, return an error. 01110 // 01111 // Status = STATUS_CONFLICTING_ADDRESSES; 01112 01113 goto ErrorReturn; 01114 } 01115 01116 if (ControlArea != FoundVad->ControlArea) { 01117 goto ErrorReturn; 01118 } 01119 01120 if (FoundVad->u.VadFlags.UserPhysicalPages == 1) { 01121 // Status = STATUS_CONFLICTING_ADDRESSES; 01122 01123 goto ErrorReturn; 01124 } 01125 01126 if (FoundVad->u.VadFlags.CommitCharge == MM_MAX_COMMIT) { 01127 // 01128 // This is a special VAD, no commits are allowed. 01129 // 01130 // Status = STATUS_CONFLICTING_ADDRESSES; 01131 01132 goto ErrorReturn; 01133 } 01134 01135 // 01136 // Ensure that the starting and ending addresses are 01137 // all within the same virtual address descriptor. 01138 // 01139 01140 if ((MI_VA_TO_VPN (StartingAddress) < FoundVad->StartingVpn) || 01141 (MI_VA_TO_VPN (EndingAddress) > FoundVad->EndingVpn)) { 01142 01143 // 01144 // Not within the section virtual address 01145 // descriptor, return an error. 01146 // 01147 // Status = STATUS_CONFLICTING_ADDRESSES; 01148 01149 goto ErrorReturn; 01150 } 01151 01152 if (FoundVad->u.VadFlags.NoChange == 1) { 01153 01154 // 01155 // An attempt is made at changing the protection 01156 // of a SEC_NO_CHANGE section. 01157 // 01158 01159 NTSTATUS Status2; 01160 01161 Status2 = MiCheckSecuredVad (FoundVad, 01162 CapturedBase, 01163 CapturedRegionSize, 01164 ProtectionMask); 01165 01166 if (!NT_SUCCESS (Status2)) { 01167 goto ErrorReturn; 01168 } 01169 } 01170 01171 if (FoundVad->ControlArea->FilePointer == NULL) { 01172 goto ErrorReturn; 01173 } 01174 01175 if (FoundVad->u2.VadFlags2.ExtendableFile == 0) { 01176 goto ErrorReturn; 01177 } 01178 01179 #if defined(_MIALT4K_) 01180 01181 if (EmulationFor4kPage == TRUE) { 01182 01183 UNLOCK_WS_UNSAFE(Process); 01184 01185 StartingAddressFor4k = (PVOID)PAGE_4K_ALIGN(OriginalBase); 01186 01187 EndingAddressFor4k = (PVOID)(((ULONG_PTR)OriginalBase + 01188 OriginalRegionSize - 1) | (PAGE_4K - 1)); 01189 01190 CapturedRegionSizeFor4k = (ULONG_PTR)EndingAddressFor4k - 01191 (ULONG_PTR)StartingAddressFor4k + 1L; 01192 01193 if ((FoundVad->u.VadFlags.ImageMap == 1) || 01194 (FoundVad->u2.VadFlags2.CopyOnWrite == 1)) { 01195 01196 OriginalProtectionMask |= MM_PROTECTION_COPY_MASK; 01197 01198 } 01199 01200 MiProtectFor4kPage (StartingAddressFor4k, 01201 CapturedRegionSizeFor4k, 01202 OriginalProtectionMask, 01203 ALT_COMMIT, 01204 Process); 01205 01206 LOCK_WS_UNSAFE(Process); 01207 } 01208 01209 #endif 01210 01211 try { 01212 MiSetProtectionOnSection (Process, 01213 FoundVad, 01214 StartingAddress, 01215 EndingAddress, 01216 Protect, 01217 &OldProtect, 01218 TRUE); 01219 } except (EXCEPTION_EXECUTE_HANDLER) { 01220 NOTHING; 01221 } 01222 01223 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01224 } 01225 01226 goto ErrorReturn1; 01227 } 01228 } 01229 01230 StartingPte = MiGetProtoPteAddress (FoundVad, 01231 MI_VA_TO_VPN(StartingAddress)); 01232 PointerPte = StartingPte; 01233 LastPte = MiGetProtoPteAddress (FoundVad, 01234 MI_VA_TO_VPN(EndingAddress)); 01235 01236 UNLOCK_WS_UNSAFE (Process); 01237 01238 ExAcquireFastMutexUnsafe (&MmSectionCommitMutex); 01239 01240 #if 0 01241 if (AllocationType & MEM_CHECK_COMMIT_STATE) { 01242 01243 // 01244 // Make sure none of the pages are already committed. 01245 // 01246 01247 while (PointerPte <= LastPte) { 01248 01249 // 01250 // Check to see if the prototype PTE is committed. 01251 // Note that prototype PTEs cannot be decommitted so 01252 // the PTEs only need to be checked for zeroes. 01253 // 01254 // 01255 01256 if (PointerPte->u.Long != 0) { 01257 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01258 Status = STATUS_ALREADY_COMMITTED; 01259 UNLOCK_ADDRESS_SPACE (Process); 01260 goto ErrorReturn1; 01261 } 01262 PointerPte += 1; 01263 } 01264 } 01265 #endif //0 01266 01267 PointerPte = StartingPte; 01268 01269 // 01270 // Check to ensure these pages can be committed if this 01271 // is a page file backed segment. Note that page file quota 01272 // has already been charged for this. 01273 // 01274 01275 QuotaCharge = 1 + LastPte - StartingPte; 01276 01277 CopyOnWriteCharge = 0; 01278 01279 if (MI_IS_PTE_PROTECTION_COPY_WRITE(ProtectionMask)) { 01280 01281 // 01282 // If the protection is copy on write, charge for 01283 // the copy on writes. 01284 // 01285 01286 CopyOnWriteCharge = QuotaCharge; 01287 } 01288 01289 // 01290 // Charge commitment for the range. Establish an 01291 // exception handler as this could raise an exception. 01292 // 01293 01294 QuotaFree = 0; 01295 ChargedExactQuota = FALSE; 01296 Status = STATUS_SUCCESS; 01297 ChargedJobCommit = FALSE; 01298 01299 for (; ; ) { 01300 try { 01301 PageFileChargeSucceeded = FALSE; 01302 01303 if (CopyOnWriteCharge != 0) { 01304 MiChargePageFileQuota (CopyOnWriteCharge, Process); 01305 } 01306 01307 PageFileChargeSucceeded = TRUE; 01308 01309 // 01310 // Note this job charging is unusual because it is not 01311 // followed by an immediate process charge. 01312 // 01313 01314 if (Process->CommitChargeLimit) { 01315 if (Process->CommitCharge + CopyOnWriteCharge > Process->CommitChargeLimit) { 01316 if (Process->Job) { 01317 PsReportProcessMemoryLimitViolation (); 01318 } 01319 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01320 } 01321 } 01322 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01323 if (PsChangeJobMemoryUsage(CopyOnWriteCharge) == FALSE) { 01324 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01325 } 01326 ChargedJobCommit = TRUE; 01327 } 01328 01329 if (MiChargeCommitment (QuotaCharge + CopyOnWriteCharge, NULL) == FALSE) { 01330 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01331 } 01332 01333 MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM1, QuotaCharge + CopyOnWriteCharge); 01334 01335 break; 01336 01337 } except (EXCEPTION_EXECUTE_HANDLER) { 01338 01339 // 01340 // An exception has occurred during the charging 01341 // of commitment. Release the held mutexes and return 01342 // the exception status to the user. 01343 // 01344 01345 if (PageFileChargeSucceeded && CopyOnWriteCharge != 0) { 01346 MiReturnPageFileQuota (CopyOnWriteCharge, Process); 01347 } 01348 01349 if (ChargedJobCommit == TRUE) { 01350 01351 // 01352 // Temporarily up the process commit charge as the 01353 // job code will be referencing it as though everything 01354 // has succeeded. 01355 // 01356 01357 Process->CommitCharge += CopyOnWriteCharge; 01358 PsChangeJobMemoryUsage (-(SSIZE_T)CopyOnWriteCharge); 01359 Process->CommitCharge -= CopyOnWriteCharge; 01360 } 01361 01362 if (Status != STATUS_SUCCESS || PageFileChargeSucceeded == FALSE) { 01363 01364 // 01365 // We have already tried for the precise charge or the 01366 // attempt to charge pagefile quota failed, so just 01367 // return an error. 01368 // 01369 01370 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01371 UNLOCK_ADDRESS_SPACE (Process); 01372 goto ErrorReturn1; 01373 } 01374 01375 // 01376 // The commitment charging of quota failed, calculate the 01377 // exact quota taking into account pages that may already be 01378 // committed and retry the operation. 01379 // 01380 01381 while (PointerPte <= LastPte) { 01382 01383 // 01384 // Check to see if the prototype PTE is committed. 01385 // Note that prototype PTEs cannot be decommitted so 01386 // PTEs only need to be checked for zeroes. 01387 // 01388 01389 if (PointerPte->u.Long != 0) { 01390 QuotaFree -= 1; 01391 } 01392 PointerPte += 1; 01393 } 01394 01395 PointerPte = StartingPte; 01396 01397 QuotaCharge += QuotaFree; 01398 ChargedExactQuota = TRUE; 01399 Status = GetExceptionCode(); 01400 } 01401 } 01402 01403 FoundVad->ControlArea->Segment->NumberOfCommittedPages += 01404 QuotaCharge; 01405 01406 FoundVad->u.VadFlags.CommitCharge += CopyOnWriteCharge; 01407 Process->CommitCharge += CopyOnWriteCharge; 01408 if (Process->CommitCharge > Process->CommitChargePeak) { 01409 Process->CommitChargePeak = Process->CommitCharge; 01410 } 01411 MmSharedCommit += QuotaCharge; 01412 01413 // 01414 // Commit all the pages. 01415 // 01416 01417 TempPte = FoundVad->ControlArea->Segment->SegmentPteTemplate; 01418 01419 QuotaFree = 0; 01420 01421 while (PointerPte <= LastPte) { 01422 01423 if (PointerPte->u.Long != 0) { 01424 01425 // 01426 // Page is already committed, back out commitment. 01427 // 01428 01429 QuotaFree += 1; 01430 } else { 01431 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 01432 } 01433 PointerPte += 1; 01434 } 01435 01436 if (ChargedExactQuota == FALSE && QuotaFree != 0) { 01437 01438 FoundVad->ControlArea->Segment->NumberOfCommittedPages -= QuotaFree; 01439 MmSharedCommit -= QuotaFree; 01440 ASSERT ((LONG)FoundVad->ControlArea->Segment->NumberOfCommittedPages >= 0); 01441 01442 if (CopyOnWriteCharge != 0) { 01443 FoundVad->u.VadFlags.CommitCharge -= QuotaFree; 01444 if (ChargedJobCommit == TRUE) { 01445 PsChangeJobMemoryUsage (-(SSIZE_T)QuotaFree); 01446 } 01447 Process->CommitCharge -= QuotaFree; 01448 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01449 MiReturnPageFileQuota (QuotaFree, Process); 01450 } 01451 else { 01452 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01453 } 01454 01455 ASSERT ((SSIZE_T)FoundVad->u.VadFlags.CommitCharge >= 0); 01456 01457 MiReturnCommitment ( 01458 (CopyOnWriteCharge ? 2*QuotaFree : QuotaFree)); 01459 01460 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_ALLOCVM1, 01461 (CopyOnWriteCharge ? 2*QuotaFree : QuotaFree)); 01462 } 01463 else { 01464 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 01465 } 01466 01467 #if defined(_MIALT4K_) 01468 01469 // 01470 // We need to change the alternate table before PTEs are created 01471 // for the protection change. 01472 // 01473 01474 if (EmulationFor4kPage == TRUE) { 01475 01476 StartingAddressFor4k = (PVOID)PAGE_4K_ALIGN(OriginalBase); 01477 01478 EndingAddressFor4k = (PVOID)(((ULONG_PTR)OriginalBase + 01479 OriginalRegionSize - 1) | (PAGE_4K - 1)); 01480 01481 CapturedRegionSizeFor4k = (ULONG_PTR)EndingAddressFor4k - 01482 (ULONG_PTR)StartingAddressFor4k + 1L; 01483 01484 if ((FoundVad->u.VadFlags.ImageMap == 1) || 01485 (FoundVad->u2.VadFlags2.CopyOnWrite == 1)) { 01486 01487 OriginalProtectionMask |= MM_PROTECTION_COPY_MASK; 01488 01489 } 01490 01491 // 01492 // Set the alternate permission table 01493 // 01494 01495 MiProtectFor4kPage (StartingAddressFor4k, 01496 CapturedRegionSizeFor4k, 01497 OriginalProtectionMask, 01498 ALT_COMMIT, 01499 Process); 01500 } 01501 #endif 01502 01503 // 01504 // Change all the protection to be protected as specified. 01505 // 01506 01507 LOCK_WS_UNSAFE (Process); 01508 01509 try { 01510 MiSetProtectionOnSection (Process, 01511 FoundVad, 01512 StartingAddress, 01513 EndingAddress, 01514 Protect, 01515 &OldProtect, 01516 TRUE); 01517 } except (EXCEPTION_EXECUTE_HANDLER) { 01518 NOTHING; 01519 } 01520 01521 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01522 01523 if (Attached) { 01524 KeDetachProcess(); 01525 } 01526 if ( ProcessHandle != NtCurrentProcess() ) { 01527 ObDereferenceObject (Process); 01528 } 01529 01530 try { 01531 01532 *RegionSize = CapturedRegionSize; 01533 *BaseAddress = StartingAddress; 01534 01535 } except (EXCEPTION_EXECUTE_HANDLER) { 01536 01537 // 01538 // Return success at this point even if the results 01539 // cannot be written. 01540 // 01541 01542 NOTHING; 01543 } 01544 01545 #if defined(_MIALT4K_) 01546 if (EmulationFor4kPage == TRUE) { 01547 CapturedRegionSize = CapturedRegionSizeFor4k; 01548 StartingAddress = StartingAddressFor4k; 01549 } 01550 #endif 01551 01552 #if DBG 01553 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 01554 if ( MmWatchProcess ) { 01555 if ( MmWatchProcess == PsGetCurrentProcess() ) { 01556 DbgPrint("\n+++ ALLOC Type %lx Base %lx Size %lx\n", 01557 AllocationType,StartingAddress, CapturedRegionSize); 01558 MmFooBar(); 01559 } 01560 } else { 01561 DbgPrint("return allocvm status %lx baseaddr %lx size %lx\n", 01562 Status, CapturedRegionSize, StartingAddress); 01563 } 01564 } 01565 #endif 01566 01567 return STATUS_SUCCESS; 01568 01569 } else { 01570 01571 // 01572 // PAGE_WRITECOPY is not valid for private pages. 01573 // 01574 01575 if ((Protect & PAGE_WRITECOPY) || 01576 (Protect & PAGE_EXECUTE_WRITECOPY)) { 01577 Status = STATUS_INVALID_PAGE_PROTECTION; 01578 goto ErrorReturn; 01579 } 01580 01581 // 01582 // Ensure none of the pages are already committed as described 01583 // in the virtual address descriptor. 01584 // 01585 #if 0 01586 if (AllocationType & MEM_CHECK_COMMIT_STATE) { 01587 if ( !MiIsEntireRangeDecommitted(StartingAddress, 01588 EndingAddress, 01589 FoundVad, 01590 Process)) { 01591 01592 // 01593 // Previously reserved pages have been committed, or 01594 // an error occurred, release mutex and return status. 01595 // 01596 01597 Status = STATUS_ALREADY_COMMITTED; 01598 goto ErrorReturn; 01599 } 01600 } 01601 #endif //0 01602 01603 // 01604 // The address range has not been committed, commit it now. 01605 // Note, that for private pages, commitment is handled by 01606 // explicitly updating PTEs to contain Demand Zero entries. 01607 // 01608 01609 PointerPpe = MiGetPpeAddress (StartingAddress); 01610 PointerPde = MiGetPdeAddress (StartingAddress); 01611 PointerPte = MiGetPteAddress (StartingAddress); 01612 LastPte = MiGetPteAddress (EndingAddress); 01613 01614 // 01615 // Check to ensure these pages can be committed. 01616 // 01617 01618 QuotaCharge = 1 + LastPte - PointerPte; 01619 01620 // 01621 // Charge quota and commitment for the range. Establish an 01622 // exception handler as this could raise an exception. 01623 // 01624 01625 QuotaFree = 0; 01626 ChargedExactQuota = FALSE; 01627 Status = STATUS_SUCCESS; 01628 ChargedJobCommit = FALSE; 01629 01630 for (; ; ) { 01631 try { 01632 PageFileChargeSucceeded = FALSE; 01633 01634 if (Process->CommitChargeLimit) { 01635 if (Process->CommitCharge + QuotaCharge > Process->CommitChargeLimit) { 01636 if (Process->Job) { 01637 PsReportProcessMemoryLimitViolation (); 01638 } 01639 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01640 } 01641 } 01642 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01643 if (PsChangeJobMemoryUsage(QuotaCharge) == FALSE) { 01644 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01645 } 01646 ChargedJobCommit = TRUE; 01647 } 01648 01649 if (MiChargeCommitment (QuotaCharge, Process) == FALSE) { 01650 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01651 } 01652 01653 MM_TRACK_COMMIT (MM_DBG_COMMIT_ALLOCVM2, QuotaCharge); 01654 01655 PageFileChargeSucceeded = TRUE; 01656 MiChargePageFileQuota (QuotaCharge, Process); 01657 01658 FoundVad->u.VadFlags.CommitCharge += QuotaCharge; 01659 Process->CommitCharge += QuotaCharge; 01660 if (Process->CommitCharge > Process->CommitChargePeak) { 01661 Process->CommitChargePeak = Process->CommitCharge; 01662 } 01663 break; 01664 01665 } except (EXCEPTION_EXECUTE_HANDLER) { 01666 01667 // 01668 // An exception has occurred during the charging 01669 // of commitment. Release the held mutexes and return 01670 // the exception status to the user. 01671 // 01672 01673 if (ChargedJobCommit == TRUE) { 01674 01675 // 01676 // Temporarily up the process commit charge as the 01677 // job code will be referencing it as though everything 01678 // has succeeded. 01679 // 01680 01681 Process->CommitCharge += QuotaCharge; 01682 PsChangeJobMemoryUsage (-QuotaCharge); 01683 Process->CommitCharge -= QuotaCharge; 01684 } 01685 01686 if (PageFileChargeSucceeded) { 01687 MiReturnCommitment (QuotaCharge); 01688 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_ALLOCVM2, QuotaCharge); 01689 } 01690 01691 if (Status != STATUS_SUCCESS) { 01692 01693 // 01694 // We have already tried for the precise charge, 01695 // return an error. 01696 // 01697 01698 goto ErrorReturn; 01699 } 01700 01701 Status = GetExceptionCode(); 01702 01703 // 01704 // Quota charge failed, calculate the exact quota 01705 // taking into account pages that may already be 01706 // committed and retry the operation. 01707 // 01708 01709 QuotaFree = -(LONG)MiCalculatePageCommitment ( 01710 StartingAddress, 01711 EndingAddress, 01712 FoundVad, 01713 Process); 01714 01715 if (QuotaFree == 0) { 01716 goto ErrorReturn; 01717 } 01718 01719 ChargedExactQuota = TRUE; 01720 QuotaCharge += QuotaFree; 01721 ASSERT (QuotaCharge >= 0); 01722 } 01723 } 01724 01725 01726 // 01727 // Build a demand zero PTE with the proper protection. 01728 // 01729 01730 TempPte = ZeroPte; 01731 TempPte.u.Soft.Protection = ProtectionMask; 01732 01733 DecommittedPte = ZeroPte; 01734 DecommittedPte.u.Soft.Protection = MM_DECOMMIT; 01735 01736 // 01737 // Fill in all the page directory and page table pages with the 01738 // demand zero PTE. 01739 // 01740 01741 #if defined (_WIN64) 01742 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01743 if (PointerPde->u.Long == 0) { 01744 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01745 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01746 } 01747 #endif 01748 01749 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 01750 01751 if (FoundVad->u.VadFlags.MemCommit) { 01752 CommitLimitPte = MiGetPteAddress (MI_VPN_TO_VA (FoundVad->EndingVpn)); 01753 } else { 01754 CommitLimitPte = NULL; 01755 } 01756 01757 QuotaFree = 0; 01758 01759 while (PointerPte <= LastPte) { 01760 01761 if (MiIsPteOnPdeBoundary (PointerPte)) { 01762 01763 PointerPde = MiGetPteAddress (PointerPte); 01764 PointerPpe = MiGetPteAddress (PointerPde); 01765 01766 if (MiIsPteOnPpeBoundary (PointerPte)) { 01767 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01768 } 01769 01770 #if defined (_WIN64) 01771 if (PointerPde->u.Long == 0) { 01772 MI_WRITE_INVALID_PTE (PointerPde, TempPte); 01773 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01774 01775 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01776 } 01777 #endif 01778 01779 // 01780 // Pointing to the next page table page, make 01781 // a page table page exist and make it valid. 01782 // 01783 01784 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 01785 } 01786 01787 if (PointerPte->u.Long == 0) { 01788 01789 if (PointerPte <= CommitLimitPte) { 01790 01791 // 01792 // This page is implicitly committed. 01793 // 01794 01795 QuotaFree += 1; 01796 01797 } 01798 01799 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 01800 01801 // 01802 // Increment the count of non-zero page table entries 01803 // for this page table and the number of private pages 01804 // for the process. 01805 // 01806 01807 Va = MiGetVirtualAddressMappedByPte (PointerPte); 01808 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va); 01809 01810 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 01811 } else { 01812 if (PointerPte->u.Long == DecommittedPte.u.Long) { 01813 01814 // 01815 // Only commit the page if it is already decommitted. 01816 // 01817 01818 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 01819 } else { 01820 QuotaFree += 1; 01821 01822 // 01823 // Make sure the protection for the page is 01824 // right. 01825 // 01826 01827 if (!ChangeProtection && 01828 (Protect != MiGetPageProtection (PointerPte, 01829 Process))) { 01830 ChangeProtection = TRUE; 01831 } 01832 } 01833 } 01834 PointerPte += 1; 01835 } 01836 } 01837 01838 if (ChargedExactQuota == FALSE && QuotaFree != 0) { 01839 ASSERT (QuotaFree >= 0); 01840 MiReturnCommitment (QuotaFree); 01841 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_ALLOCVM3, QuotaFree); 01842 MiReturnPageFileQuota (QuotaFree, Process); 01843 FoundVad->u.VadFlags.CommitCharge -= QuotaFree; 01844 if (ChargedJobCommit) { 01845 PsChangeJobMemoryUsage (-(SSIZE_T)QuotaFree); 01846 } 01847 Process->CommitCharge -= QuotaFree; 01848 ASSERT (FoundVad->u.VadFlags.CommitCharge >= 0); 01849 } 01850 #if defined(_MIALT4K_) 01851 01852 if (EmulationFor4kPage == TRUE) { 01853 01854 UNLOCK_WS_UNSAFE (Process); 01855 01856 StartingAddress = (PVOID) PAGE_4K_ALIGN(OriginalBase); 01857 01858 EndingAddress = (PVOID)(((ULONG_PTR)OriginalBase + 01859 OriginalRegionSize - 1) | (PAGE_4K - 1)); 01860 01861 CapturedRegionSize = (ULONG_PTR)EndingAddress - 01862 (ULONG_PTR)StartingAddress + 1L; 01863 // 01864 // Set the alternate permission table 01865 // 01866 01867 MiProtectFor4kPage (StartingAddress, 01868 CapturedRegionSize, 01869 OriginalProtectionMask, 01870 ALT_COMMIT, 01871 Process); 01872 01873 LOCK_WS_UNSAFE (Process); 01874 } 01875 #endif 01876 01877 // 01878 // Previously reserved pages have been committed, or an error occurred, 01879 // release working set lock, address creation lock, detach, 01880 // dereference process and return status. 01881 // 01882 01883 done: 01884 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01885 01886 if (ChangeProtection) { 01887 PVOID Start; 01888 SIZE_T Size; 01889 ULONG LastProtect; 01890 01891 Start = StartingAddress; 01892 Size = CapturedRegionSize; 01893 MiProtectVirtualMemory (Process, 01894 &Start, 01895 &Size, 01896 Protect, 01897 &LastProtect); 01898 } 01899 01900 if (Attached) { 01901 KeDetachProcess(); 01902 } 01903 if ( ProcessHandle != NtCurrentProcess() ) { 01904 ObDereferenceObject (Process); 01905 } 01906 01907 // 01908 // Establish an exception handler and write the size and base 01909 // address. 01910 // 01911 01912 try { 01913 01914 *RegionSize = CapturedRegionSize; 01915 *BaseAddress = StartingAddress; 01916 01917 } except (EXCEPTION_EXECUTE_HANDLER) { 01918 return GetExceptionCode(); 01919 } 01920 01921 #if DBG 01922 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 01923 if ( MmWatchProcess ) { 01924 if ( MmWatchProcess == PsGetCurrentProcess() ) { 01925 DbgPrint("\n+++ ALLOC Type %lx Base %lx Size %lx\n", 01926 AllocationType,StartingAddress, CapturedRegionSize); 01927 MmFooBar(); 01928 } 01929 } else { 01930 DbgPrint("return allocvm status %lx baseaddr %lx size %lx\n", 01931 Status, CapturedRegionSize, StartingAddress); 01932 } 01933 } 01934 #endif 01935 01936 return STATUS_SUCCESS; 01937 } 01938 01939 ErrorReturn: 01940 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01941 01942 ErrorReturn1: 01943 if (Attached) { 01944 KeDetachProcess(); 01945 } 01946 if ( ProcessHandle != NtCurrentProcess() ) { 01947 ObDereferenceObject (Process); 01948 } 01949 return Status; 01950 }


Variable Documentation

LOGICAL MmSupportWriteWatch = FALSE
 

Definition at line 36 of file allocvm.c.

Referenced by NtAllocateVirtualMemory().

ULONG MMVADKEY = ' daV'
 

Definition at line 30 of file allocvm.c.

Referenced by MiMapViewOfDataSection(), MiMapViewOfImageSection(), MiMapViewOfPhysicalSection(), and MmSecureVirtualMemory().


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