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

procsup.c File Reference

#include "mi.h"

Go to the source code of this file.

Defines

#define MM_PROCESS_COMMIT_CHARGE   3
#define MM_PROCESS_CREATE_CHARGE   5
#define HEADER_FILE
#define MAX_STACK_PAGES   (KERNEL_LARGE_STACK_SIZE / PAGE_SIZE)
#define MI_INIT_PEB_FROM_IMAGE(Hdrs, ImgConfig)

Functions

ULONG MiGetSystemPteListCount (IN ULONG ListSize)
PFN_NUMBER MiMakeOutswappedPageResident (IN PMMPTE ActualPteAddress, IN PMMPTE PointerTempPte, IN ULONG Global, IN PFN_NUMBER ContainingPage)
PVOID MiCreatePebOrTeb (IN PEPROCESS TargetProcess, IN ULONG Size)
VOID MiDeleteAddressesInWorkingSet (IN PEPROCESS Process)
VOID MiDeleteValidAddress (IN PVOID Va, IN PEPROCESS CurrentProcess)
VOID MiDeleteFreeVm (IN PVOID StartingAddress, IN PVOID EndingAddress)
VOID VadTreeWalk (IN PMMVAD Start)
PMMVAD MiAllocateVad (IN ULONG_PTR StartingVirtualAddress, IN ULONG_PTR EndingVirtualAddress, IN LOGICAL Deletable)
PVOID MiPaeReplenishList (VOID)
PVOID MiAllocateLowMemory (IN SIZE_T NumberOfBytes, IN PFN_NUMBER LowestAcceptablePfn, IN PFN_NUMBER HighestAcceptablePfn, IN PFN_NUMBER BoundaryPfn, IN PVOID CallingAddress, IN ULONG Tag)
LOGICAL MiFreeLowMemory (IN PVOID BaseAddress, IN ULONG Tag)
BOOLEAN MmCreateProcessAddressSpace (IN ULONG MinimumWorkingSetSize, IN PEPROCESS NewProcess, OUT PULONG_PTR DirectoryTableBase)
NTSTATUS MmInitializeProcessAddressSpace (IN PEPROCESS ProcessToInitialize, IN PEPROCESS ProcessToClone OPTIONAL, IN PVOID SectionToMap OPTIONAL, OUT PUNICODE_STRING *AuditName OPTIONAL)
VOID MmDeleteProcessAddressSpace (IN PEPROCESS Process)
VOID MmCleanProcessAddressSpace ()
PVOID MmCreateKernelStack (IN BOOLEAN LargeStack)
VOID MmDeleteKernelStack (IN PVOID PointerKernelStack, IN BOOLEAN LargeStack)
NTSTATUS MmGrowKernelStack (IN PVOID CurrentStack)
VOID MmOutPageKernelStack (IN PKTHREAD Thread)
VOID MmInPageKernelStack (IN PKTHREAD Thread)
VOID MmOutSwapProcess (IN PKPROCESS Process)
VOID MmInSwapProcess (IN PKPROCESS Process)
PTEB MmCreateTeb (IN PEPROCESS TargetProcess, IN PINITIAL_TEB InitialTeb, IN PCLIENT_ID ClientId)
PPEB MmCreatePeb (IN PEPROCESS TargetProcess, IN PINITIAL_PEB InitialPeb)
VOID MmDeleteTeb (IN PEPROCESS TargetProcess, IN PVOID TebBase)
VOID MmAllowWorkingSetExpansion (VOID)
PFN_NUMBER MiMakeOutswappedPageResident (IN PMMPTE ActualPteAddress, IN OUT PMMPTE PointerTempPte, IN ULONG Global, IN PFN_NUMBER ContainingPage)
VOID MmSetMemoryPriorityProcess (IN PEPROCESS Process, IN UCHAR MemoryPriority)

Variables

ULONG MmProductType
ULONG MmWorkingSetReductionMax
MM_SYSTEMSIZE MmSystemSize
PVOID BBTBuffer
SIZE_T MmProcessCommit
ULONG MmKernelStackPages
PFN_NUMBER MmKernelStackResident
ULONG MmLargeStacks
ULONG MmSmallStacks
MMPTE KernelDemandZeroPte = {MM_KERNEL_DEMAND_ZERO_PTE}
CCHAR MmRotatingUniprocessorNumber
ULONG MiFaultRetries
LOGICAL MiNoLowMemory


Define Documentation

#define HEADER_FILE
 

Definition at line 84 of file procsup.c.

#define MAX_STACK_PAGES   (KERNEL_LARGE_STACK_SIZE / PAGE_SIZE)
 

Referenced by MmOutPageKernelStack().

#define MI_INIT_PEB_FROM_IMAGE Hdrs,
ImgConfig   ) 
 

Definition at line 4418 of file procsup.c.

Referenced by MmCreatePeb().

#define MM_PROCESS_COMMIT_CHARGE   3
 

Definition at line 42 of file procsup.c.

Referenced by MmCreateProcessAddressSpace(), MmDeleteProcessAddressSpace(), and MmOutSwapProcess().

#define MM_PROCESS_CREATE_CHARGE   5
 

Definition at line 43 of file procsup.c.

Referenced by MmCleanProcessAddressSpace(), and MmDeleteProcessAddressSpace().


Function Documentation

PVOID MiAllocateLowMemory IN SIZE_T  NumberOfBytes,
IN PFN_NUMBER  LowestAcceptablePfn,
IN PFN_NUMBER  HighestAcceptablePfn,
IN PFN_NUMBER  BoundaryPfn,
IN PVOID  CallingAddress,
IN ULONG  Tag
 

Referenced by MiAllocateContiguousMemory().

PMMVAD MiAllocateVad IN ULONG_PTR  StartingVirtualAddress,
IN ULONG_PTR  EndingVirtualAddress,
IN LOGICAL  Deletable
 

Definition at line 5659 of file procsup.c.

References ASSERT, _MMVAD::EndingVpn, ExAllocatePoolWithTag, MI_VA_TO_VPN, MM_MAX_COMMIT, MM_READONLY, NonPagedPool, NULL, _MMVAD::StartingVpn, TRUE, _MMVAD::u, _MMVAD::u2, and _MMVAD::u3.

Referenced by MmInitializeProcessAddressSpace().

05667 : 05668 05669 Reserve the specified range of address space. 05670 05671 Arguments: 05672 05673 StartingVirtualAddress - Supplies the starting virtual address. 05674 05675 EndingVirtualAddress - Supplies the ending virtual address. 05676 05677 Deletable - Supplies TRUE if the VAD is to be marked as deletable, FALSE 05678 if deletions of this VAD should be disallowed. 05679 05680 Return Value: 05681 05682 A VAD pointer on success, NULL on failure. 05683 05684 --*/ 05685 05686 { 05687 PMMVAD Vad; 05688 05689 ASSERT (StartingVirtualAddress <= EndingVirtualAddress); 05690 05691 Vad = (PMMVAD)ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD), ' daV'); 05692 05693 if (Vad == NULL) { 05694 return NULL; 05695 } 05696 05697 // 05698 // Set the starting and ending virtual page numbers of the VAD. 05699 // 05700 05701 Vad->StartingVpn = MI_VA_TO_VPN (StartingVirtualAddress); 05702 Vad->EndingVpn = MI_VA_TO_VPN (EndingVirtualAddress); 05703 05704 // 05705 // Mark VAD as no commitment, private, and readonly. 05706 // 05707 05708 Vad->u.LongFlags = 0; 05709 Vad->u.VadFlags.CommitCharge = MM_MAX_COMMIT; 05710 Vad->u.VadFlags.Protection = MM_READONLY; 05711 Vad->u.VadFlags.PrivateMemory = 1; 05712 05713 Vad->u2.LongFlags2 = 0; 05714 05715 if (Deletable == TRUE) { 05716 Vad->u.VadFlags.NoChange = 0; 05717 Vad->u2.VadFlags2.OneSecured = 0; 05718 Vad->u2.VadFlags2.StoredInVad = 0; 05719 Vad->u2.VadFlags2.ReadOnly = 0; 05720 Vad->u3.Secured.StartVpn = 0; 05721 Vad->u3.Secured.EndVpn = 0; 05722 } 05723 else { 05724 Vad->u.VadFlags.NoChange = 1; 05725 Vad->u2.VadFlags2.OneSecured = 1; 05726 Vad->u2.VadFlags2.StoredInVad = 1; 05727 Vad->u2.VadFlags2.ReadOnly = 1; 05728 Vad->u3.Secured.StartVpn = StartingVirtualAddress; 05729 Vad->u3.Secured.EndVpn = EndingVirtualAddress; 05730 } 05731 05732 return Vad; 05733 }

PVOID MiCreatePebOrTeb IN PEPROCESS  TargetProcess,
IN ULONG  Size
 

Referenced by MmCreatePeb(), and MmCreateTeb().

VOID MiDeleteAddressesInWorkingSet IN PEPROCESS  Process  ) 
 

Definition at line 5006 of file procsup.c.

References ASSERT, _MMWSL::FirstDynamic, _MMWSL::HashTable, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, LOCK_PFN, MI_PFN_ELEMENT, MiDeleteValidAddress(), MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiLocateWsle(), MiReleaseWsle(), MiSwapWslEntries(), MmWorkingSetList, MmWsle, NULL, PAGE_ALIGN, _MMPTE::u, _MMPFN::u1, _MMWSLE::u1, and UNLOCK_PFN.

Referenced by MmCleanProcessAddressSpace().

05012 : 05013 05014 This routine deletes all user mode addresses from the working set 05015 list. 05016 05017 Arguments: 05018 05019 Process = Pointer to the current process. 05020 05021 Return Value: 05022 05023 None. 05024 05025 Environment: 05026 05027 Kernel mode, Working Set Lock held. 05028 05029 --*/ 05030 05031 { 05032 PMMWSLE Wsle; 05033 ULONG index; 05034 ULONG Entry; 05035 PVOID Va; 05036 KIRQL OldIrql; 05037 #if DBG 05038 PVOID SwapVa; 05039 PMMPTE PointerPte; 05040 PMMPFN Pfn1; 05041 PMMWSLE LastWsle; 05042 #endif 05043 05044 // 05045 // Go through the working set and for any user-accessible page which is 05046 // in it, rip it out of the working set and free the page. 05047 // 05048 05049 index = 2; 05050 Wsle = &MmWsle[index]; 05051 05052 MmWorkingSetList->HashTable = NULL; 05053 05054 // 05055 // Go through the working set list and remove all pages for user 05056 // space addresses. 05057 // 05058 05059 while (index <= MmWorkingSetList->LastEntry) { 05060 if (Wsle->u1.e1.Valid == 1) { 05061 05062 #if defined (_WIN64) 05063 ASSERT(MiGetPpeAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05064 #endif 05065 ASSERT(MiGetPdeAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05066 ASSERT(MiGetPteAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05067 05068 if (Wsle->u1.VirtualAddress < (PVOID)MM_HIGHEST_USER_ADDRESS) { 05069 05070 // 05071 // This is a user mode address, for each one we remove we must 05072 // maintain the NonDirectCount. This is because we may fault 05073 // later for page tables and need to grow the hash table when 05074 // updating the working set. NonDirectCount needs to be correct 05075 // at that point. 05076 // 05077 05078 if (Wsle->u1.e1.Direct == 0) { 05079 Process->Vm.VmWorkingSetList->NonDirectCount -= 1; 05080 } 05081 05082 // 05083 // This entry is in the working set list. 05084 // 05085 05086 Va = Wsle->u1.VirtualAddress; 05087 05088 MiReleaseWsle (index, &Process->Vm); 05089 LOCK_PFN (OldIrql); 05090 MiDeleteValidAddress (Va, Process); 05091 UNLOCK_PFN (OldIrql); 05092 05093 if (index < MmWorkingSetList->FirstDynamic) { 05094 05095 // 05096 // This entry is locked. 05097 // 05098 05099 MmWorkingSetList->FirstDynamic -= 1; 05100 05101 if (index != MmWorkingSetList->FirstDynamic) { 05102 05103 Entry = MmWorkingSetList->FirstDynamic; 05104 #if DBG 05105 MiDeleteLocked += 1; 05106 SwapVa = MmWsle[MmWorkingSetList->FirstDynamic].u1.VirtualAddress; 05107 SwapVa = PAGE_ALIGN (SwapVa); 05108 05109 PointerPte = MiGetPteAddress (SwapVa); 05110 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 05111 05112 ASSERT (Entry == MiLocateWsle (SwapVa, MmWorkingSetList, Pfn1->u1.WsIndex)); 05113 #endif 05114 MiSwapWslEntries (Entry, index, &Process->Vm); 05115 } 05116 } 05117 } 05118 } 05119 index += 1; 05120 Wsle += 1; 05121 } 05122 05123 #if DBG 05124 Wsle = &MmWsle[2]; 05125 LastWsle = &MmWsle[MmWorkingSetList->LastInitializedWsle]; 05126 while (Wsle <= LastWsle) { 05127 if (Wsle->u1.e1.Valid == 1) { 05128 #if defined (_WIN64) 05129 ASSERT(MiGetPpeAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05130 #endif 05131 ASSERT(MiGetPdeAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05132 ASSERT(MiGetPteAddress(Wsle->u1.VirtualAddress)->u.Hard.Valid == 1); 05133 } 05134 Wsle += 1; 05135 } 05136 #endif 05137 05138 }

VOID MiDeleteFreeVm IN PVOID  StartingAddress,
IN PVOID  EndingAddress
 

Referenced by MmDeleteTeb(), and NtFreeVirtualMemory().

VOID MiDeleteValidAddress IN PVOID  Va,
IN PEPROCESS  CurrentProcess
 

Definition at line 5142 of file procsup.c.

References ASSERT, MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiDecrementCloneBlockReference(), MiDecrementShareAndValidCount, MiDecrementShareCount(), MiDecrementShareCountOnly, MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiLocateCloneAddress, MM_DEMAND_ZERO_WRITE_PTE, NULL, PMMCLONE_BLOCK, _MMPFN::PteAddress, _MMPFN::PteFrame, _MMPTE::u, and _MMPFN::u3.

Referenced by MiDeleteAddressesInWorkingSet().

05149 : 05150 05151 This routine deletes the specified virtual address. 05152 05153 Arguments: 05154 05155 Va - Supplies the virtual address to delete. 05156 05157 CurrentProcess - Supplies the current process. 05158 05159 Return Value: 05160 05161 None. 05162 05163 Environment: 05164 05165 Kernel mode. PFN LOCK HELD. 05166 05167 Note since this is only called during process teardown, the write watch 05168 bits are not updated. If this ever called from other places, code 05169 will need to be added here to update those bits. 05170 05171 --*/ 05172 05173 { 05174 PMMPTE PointerPde; 05175 PMMPTE PointerPte; 05176 PMMPFN Pfn1; 05177 PMMCLONE_BLOCK CloneBlock; 05178 PMMCLONE_DESCRIPTOR CloneDescriptor; 05179 PFN_NUMBER PageFrameIndex; 05180 05181 PointerPte = MiGetPteAddress (Va); 05182 05183 #if defined (_WIN64) 05184 ASSERT(MiGetPpeAddress(Va)->u.Hard.Valid == 1); 05185 #endif 05186 ASSERT(MiGetPdeAddress(Va)->u.Hard.Valid == 1); 05187 ASSERT (PointerPte->u.Hard.Valid == 1); 05188 05189 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 05190 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 05191 CloneDescriptor = NULL; 05192 05193 if (Pfn1->u3.e1.PrototypePte == 1) { 05194 05195 CloneBlock = (PMMCLONE_BLOCK)Pfn1->PteAddress; 05196 05197 // 05198 // Capture the state of the modified bit for this 05199 // pte. 05200 // 05201 05202 MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1); 05203 05204 // 05205 // Decrement the share and valid counts of the page table 05206 // page which maps this PTE. 05207 // 05208 05209 PointerPde = MiGetPteAddress (PointerPte); 05210 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 05211 05212 // 05213 // Decrement the share count for the physical page. 05214 // 05215 05216 MiDecrementShareCount (PageFrameIndex); 05217 05218 // 05219 // Check to see if this is a fork prototype PTE and if so 05220 // update the clone descriptor address. 05221 // 05222 05223 if (Va <= MM_HIGHEST_USER_ADDRESS) { 05224 05225 // 05226 // Locate the clone descriptor within the clone tree. 05227 // 05228 05229 CloneDescriptor = MiLocateCloneAddress ((PVOID)CloneBlock); 05230 } 05231 } else { 05232 05233 // 05234 // This PTE is a NOT a prototype PTE, delete the physical page. 05235 // 05236 05237 // 05238 // Decrement the share and valid counts of the page table 05239 // page which maps this PTE. 05240 // 05241 05242 MiDecrementShareAndValidCount (Pfn1->PteFrame); 05243 05244 MI_SET_PFN_DELETED (Pfn1); 05245 05246 // 05247 // Decrement the share count for the physical page. As the page 05248 // is private it will be put on the free list. 05249 // 05250 05251 MiDecrementShareCountOnly (PageFrameIndex); 05252 05253 // 05254 // Decrement the count for the number of private pages. 05255 // 05256 05257 CurrentProcess->NumberOfPrivatePages -= 1; 05258 } 05259 05260 // 05261 // Set the pointer to PTE to be a demand zero PTE. This allows 05262 // the page usage count to be kept properly and handles the case 05263 // when a page table page has only valid PTEs and needs to be 05264 // deleted later when the VADs are removed. 05265 // 05266 05267 PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE; 05268 05269 if (CloneDescriptor != NULL) { 05270 05271 // 05272 // Decrement the reference count for the clone block, 05273 // note that this could release and reacquire 05274 // the mutexes hence cannot be done until after the 05275 // working set index has been removed. 05276 // 05277 05278 if (MiDecrementCloneBlockReference ( CloneDescriptor, 05279 CloneBlock, 05280 CurrentProcess )) { 05281 05282 } 05283 } 05284 }

LOGICAL MiFreeLowMemory IN PVOID  BaseAddress,
IN ULONG  Tag
 

Referenced by MmFreeContiguousMemory(), and MmFreeContiguousMemorySpecifyCache().

ULONG MiGetSystemPteListCount IN ULONG  ListSize  ) 
 

Definition at line 1987 of file sysptes.c.

References ASSERT, Index, MM_PTE_TABLE_LIMIT, MmSysPteListBySizeCount, and MmSysPteTables.

01993 : 01994 01995 This routine returns the number of free entries of the list which 01996 covers the specified size. The size must be less than or equal to the 01997 largest list index. 01998 01999 Arguments: 02000 02001 ListSize - Supplies the number of PTEs needed. 02002 02003 Return Value: 02004 02005 Number of free entries on the list which contains ListSize PTEs. 02006 02007 Environment: 02008 02009 Kernel mode. 02010 02011 --*/ 02012 02013 { 02014 #ifdef _MI_GUARD_PTE_ 02015 UNREFERENCED_PARAMETER (ListSize); 02016 02017 return 8; 02018 #else 02019 ULONG Index; 02020 02021 ASSERT (ListSize <= MM_PTE_TABLE_LIMIT); 02022 02023 Index = MmSysPteTables [ListSize]; 02024 return MmSysPteListBySizeCount[Index]; 02025 #endif 02026 }

PFN_NUMBER MiMakeOutswappedPageResident IN PMMPTE  ActualPteAddress,
IN OUT PMMPTE  PointerTempPte,
IN ULONG  Global,
IN PFN_NUMBER  ContainingPage
 

Definition at line 5287 of file procsup.c.

References ActiveAndValid, APC_LEVEL, ASSERT, Event(), FALSE, File, GET_PAGING_FILE_NUMBER, GET_PAGING_FILE_OFFSET, IoPageRead(), KeBugCheckEx(), KeClearEvent, KeDelayExecutionThread(), KeInitializeEvent, KernelMode, KeWaitForSingleObject(), LOCK_PFN, _MDL::MappedSystemVa, MDL_MAPPED_TO_SYSTEM_VA, MDL_PAGES_LOCKED, _MDL::MdlFlags, MI_GET_PAGE_COLOR_FROM_PTE, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_MAKE_TRANSITION_PTE_VALID, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_SET_GLOBAL_STATE, MI_SET_PTE_DIRTY, MI_WRITE_VALID_PTE, MiEnsureAvailablePageOrWait(), MiGetVirtualAddressMappedByPte, MiInitializePfnForOtherProcess(), MiIoRetryLevel, MiMapPageInHyperSpace(), MiReleasePageFileSpace(), MiRemoveAnyPage(), MiUnlinkPageFromList(), MiUnmapPageInHyperSpace, MM_KERNEL_DEMAND_ZERO_PTE, MM_PFN_LOCK_ASSERT, MM_READWRITE, MmHalfSecond, MmInitializeMdl, MmIsRetryIoStatus, MmPagingFile, MmUnmapLockedPages(), NT_SUCCESS, NTSTATUS(), NULL, _MMPFN::OriginalPte, PAGE_SHIFT, PAGE_SIZE, Status, _MMPTE::u, _MMPFN::u2, _MMPFN::u3, UNLOCK_PFN, and WrPageIn.

Referenced by MmInPageKernelStack(), and MmInSwapProcess().

05296 : 05297 05298 This routine makes the specified PTE valid. 05299 05300 Arguments: 05301 05302 ActualPteAddress - Supplies the actual address that the PTE will 05303 reside at. This is used for page coloring. 05304 05305 PointerTempPte - Supplies the PTE to operate on, returns a valid 05306 PTE. 05307 05308 Global - Supplies 1 if the resulting PTE is global. 05309 05310 ContainingPage - Supplies the physical page number of the page which 05311 contains the resulting PTE. If this value is 0, no 05312 operations on the containing page are performed. 05313 05314 Return Value: 05315 05316 Returns the physical page number that was allocated for the PTE. 05317 05318 Environment: 05319 05320 Kernel mode, PFN LOCK HELD! 05321 05322 --*/ 05323 05324 { 05325 MMPTE TempPte; 05326 KIRQL OldIrql; 05327 PFN_NUMBER PageFrameIndex; 05328 PMMPFN Pfn1; 05329 PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + 2]; 05330 PMDL Mdl; 05331 LARGE_INTEGER StartingOffset; 05332 KEVENT Event; 05333 IO_STATUS_BLOCK IoStatus; 05334 PFN_NUMBER PageFileNumber; 05335 NTSTATUS Status; 05336 PPFN_NUMBER Page; 05337 ULONG RefaultCount; 05338 PVOID HyperVa; 05339 05340 MM_PFN_LOCK_ASSERT(); 05341 05342 OldIrql = APC_LEVEL; 05343 05344 ASSERT (PointerTempPte->u.Hard.Valid == 0); 05345 05346 if (PointerTempPte->u.Long == MM_KERNEL_DEMAND_ZERO_PTE) { 05347 05348 // 05349 // Any page will do. 05350 // 05351 05352 MiEnsureAvailablePageOrWait (NULL, NULL); 05353 PageFrameIndex = MiRemoveAnyPage ( 05354 MI_GET_PAGE_COLOR_FROM_PTE (ActualPteAddress)); 05355 05356 MI_MAKE_VALID_PTE (TempPte, 05357 PageFrameIndex, 05358 MM_READWRITE, 05359 ActualPteAddress ); 05360 MI_SET_PTE_DIRTY (TempPte); 05361 MI_SET_GLOBAL_STATE (TempPte, Global); 05362 05363 MI_WRITE_VALID_PTE (PointerTempPte, TempPte); 05364 MiInitializePfnForOtherProcess (PageFrameIndex, 05365 ActualPteAddress, 05366 ContainingPage); 05367 05368 } else if (PointerTempPte->u.Soft.Transition == 1) { 05369 05370 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerTempPte); 05371 PointerTempPte->u.Trans.Protection = MM_READWRITE; 05372 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 05373 05374 // 05375 // PTE refers to a transition PTE. 05376 // 05377 05378 if (Pfn1->u3.e1.PageLocation != ActiveAndValid) { 05379 MiUnlinkPageFromList (Pfn1); 05380 05381 // 05382 // Even though this routine is only used to bring in special 05383 // system pages that are separately charged, a modified write 05384 // may be in progress and if so, will have applied a systemwide 05385 // charge against the locked pages count. This all works out nicely 05386 // (with no code needed here) as the write completion will see 05387 // the nonzero ShareCount and remove the charge. 05388 // 05389 05390 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || 05391 (Pfn1->u3.e1.LockCharged == 1)); 05392 05393 Pfn1->u3.e2.ReferenceCount += 1; 05394 Pfn1->u3.e1.PageLocation = ActiveAndValid; 05395 } 05396 05397 // 05398 // Update the PFN database, the share count is now 1 and 05399 // the reference count is incremented as the share count 05400 // just went from zero to 1. 05401 // 05402 05403 Pfn1->u2.ShareCount += 1; 05404 Pfn1->u3.e1.Modified = 1; 05405 if (Pfn1->u3.e1.WriteInProgress == 0) { 05406 05407 // 05408 // Release the page file space for this page. 05409 // 05410 05411 MiReleasePageFileSpace (Pfn1->OriginalPte); 05412 Pfn1->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 05413 } 05414 05415 MI_MAKE_TRANSITION_PTE_VALID (TempPte, PointerTempPte); 05416 05417 MI_SET_PTE_DIRTY (TempPte); 05418 MI_SET_GLOBAL_STATE (TempPte, Global); 05419 MI_WRITE_VALID_PTE (PointerTempPte, TempPte); 05420 05421 } else { 05422 05423 // 05424 // Page resides in a paging file. 05425 // Any page will do. 05426 // 05427 05428 PointerTempPte->u.Soft.Protection = MM_READWRITE; 05429 MiEnsureAvailablePageOrWait (NULL, NULL); 05430 PageFrameIndex = MiRemoveAnyPage ( 05431 MI_GET_PAGE_COLOR_FROM_PTE (ActualPteAddress)); 05432 05433 // 05434 // Initialize the PFN database element, but don't 05435 // set read in progress as collided page faults cannot 05436 // occur here. 05437 // 05438 05439 MiInitializePfnForOtherProcess (PageFrameIndex, 05440 ActualPteAddress, 05441 ContainingPage); 05442 05443 KeInitializeEvent (&Event, NotificationEvent, FALSE); 05444 05445 // 05446 // Calculate the VPN for the in-page operation. 05447 // 05448 05449 TempPte = *PointerTempPte; 05450 PageFileNumber = GET_PAGING_FILE_NUMBER (TempPte); 05451 05452 StartingOffset.QuadPart = (LONGLONG)(GET_PAGING_FILE_OFFSET (TempPte)) << 05453 PAGE_SHIFT; 05454 05455 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 05456 05457 // 05458 // Build MDL for request. 05459 // 05460 05461 Mdl = (PMDL)&MdlHack[0]; 05462 MmInitializeMdl(Mdl, 05463 MiGetVirtualAddressMappedByPte (ActualPteAddress), 05464 PAGE_SIZE); 05465 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 05466 05467 Page = (PPFN_NUMBER)(Mdl + 1); 05468 *Page = PageFrameIndex; 05469 05470 UNLOCK_PFN (OldIrql); 05471 05472 #if DBG 05473 HyperVa = MiMapPageInHyperSpace (PageFrameIndex, &OldIrql); 05474 RtlFillMemoryUlong (HyperVa, 05475 PAGE_SIZE, 05476 0x34785690); 05477 MiUnmapPageInHyperSpace (OldIrql); 05478 #endif 05479 05480 // 05481 // Issue the read request. 05482 // 05483 05484 RefaultCount = MiIoRetryLevel; 05485 05486 Refault: 05487 Status = IoPageRead ( MmPagingFile[PageFileNumber]->File, 05488 Mdl, 05489 &StartingOffset, 05490 &Event, 05491 &IoStatus 05492 ); 05493 05494 if (Status == STATUS_PENDING) { 05495 KeWaitForSingleObject( &Event, 05496 WrPageIn, 05497 KernelMode, 05498 FALSE, 05499 (PLARGE_INTEGER)NULL); 05500 Status = IoStatus.Status; 05501 } 05502 05503 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) { 05504 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 05505 } 05506 05507 if (NT_SUCCESS(Status)) { 05508 if (IoStatus.Information != PAGE_SIZE) { 05509 KeBugCheckEx (KERNEL_STACK_INPAGE_ERROR, 05510 2, 05511 IoStatus.Status, 05512 PageFileNumber, 05513 StartingOffset.LowPart); 05514 } 05515 } 05516 05517 if ((!NT_SUCCESS(Status)) || (!NT_SUCCESS(IoStatus.Status))) { 05518 if (((MmIsRetryIoStatus(Status)) || 05519 (MmIsRetryIoStatus(IoStatus.Status))) && 05520 (RefaultCount != 0)) { 05521 05522 // 05523 // Insufficient resources, delay and reissue 05524 // the in page operation. 05525 // 05526 05527 KeDelayExecutionThread (KernelMode, 05528 FALSE, 05529 &MmHalfSecond); 05530 KeClearEvent (&Event); 05531 RefaultCount -= 1; 05532 goto Refault; 05533 } 05534 KdPrint(("MMINPAGE: status %lx io-status %lx\n", 05535 Status, IoStatus.Status)); 05536 KeBugCheckEx (KERNEL_STACK_INPAGE_ERROR, 05537 Status, 05538 IoStatus.Status, 05539 PageFileNumber, 05540 StartingOffset.LowPart); 05541 } 05542 05543 LOCK_PFN (OldIrql); 05544 05545 // 05546 // Release the page file space. 05547 // 05548 05549 MiReleasePageFileSpace (TempPte); 05550 Pfn1->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 05551 05552 MI_MAKE_VALID_PTE (TempPte, 05553 PageFrameIndex, 05554 MM_READWRITE, 05555 ActualPteAddress ); 05556 MI_SET_PTE_DIRTY (TempPte); 05557 Pfn1->u3.e1.Modified = 1; 05558 MI_SET_GLOBAL_STATE (TempPte, Global); 05559 05560 MI_WRITE_VALID_PTE (PointerTempPte, TempPte); 05561 } 05562 return PageFrameIndex; 05563 }

PFN_NUMBER MiMakeOutswappedPageResident IN PMMPTE  ActualPteAddress,
IN PMMPTE  PointerTempPte,
IN ULONG  Global,
IN PFN_NUMBER  ContainingPage
 

PVOID MiPaeReplenishList VOID   ) 
 

VOID MmAllowWorkingSetExpansion VOID   ) 
 

Definition at line 4948 of file procsup.c.

References _MMSUPPORT::AllowWorkingSetAdjustment, _MMWORKING_SET_EXPANSION_HEAD::ListHead, LOCK_EXPANSION, MmWorkingSetExpansionHead, PsGetCurrentProcess, TRUE, UNLOCK_EXPANSION, _EPROCESS::Vm, and _MMSUPPORT::WorkingSetExpansionLinks.

Referenced by MmAdjustWorkingSetSize(), PspSystemThreadStartup(), and PspUserThreadStartup().

04954 : 04955 04956 This routine updates the working set list head FLINK field to 04957 indicate that working set adjustment is allowed. 04958 04959 NOTE: This routine may be called more than once per process. 04960 04961 Arguments: 04962 04963 None. 04964 04965 Return Value: 04966 04967 None. 04968 04969 Environment: 04970 04971 Kernel mode. 04972 04973 --*/ 04974 04975 { 04976 04977 PEPROCESS CurrentProcess; 04978 KIRQL OldIrql; 04979 04980 // 04981 // Check the current state of the working set adjustment flag 04982 // in the process header. 04983 // 04984 04985 CurrentProcess = PsGetCurrentProcess(); 04986 04987 LOCK_EXPANSION (OldIrql); 04988 04989 if (!CurrentProcess->Vm.AllowWorkingSetAdjustment) { 04990 CurrentProcess->Vm.AllowWorkingSetAdjustment = TRUE; 04991 04992 InsertTailList (&MmWorkingSetExpansionHead.ListHead, 04993 &CurrentProcess->Vm.WorkingSetExpansionLinks); 04994 } 04995 04996 UNLOCK_EXPANSION (OldIrql); 04997 return; 04998 }

VOID MmCleanProcessAddressSpace  ) 
 

Definition at line 1695 of file procsup.c.

References _MMSUPPORT::AddressSpaceBeingDeleted, _EPROCESS::AddressSpaceDeleted, _EPROCESS::AddressSpaceInitialized, ASSERT, _LOCK_TRACKER::CallersCaller, _LOCK_TRACKER::CallingAddress, _EPROCESS::CloneRoot, _EPROCESS::CommitCharge, _MMVAD::ControlArea, _LOCK_HEADER::Count, _MMPTE_FLUSH_LIST::Count, DbgPrint, _MMVAD::EndingVpn, _MMVAD_SHORT::EndingVpn, Event(), ExFreePool(), FALSE, _MMWSL::HashTable, _MMWSL::HashTableSize, _MMWSL::HighestPermittedHashAddress, _EPROCESS::JobStatus, KeBugCheckEx(), KeEnterCriticalRegion, KeInitializeEvent, KeLeaveCriticalRegion, KernelMode, KeWaitForSingleObject(), _LOCK_HEADER::ListHead, LOCK_EXPANSION, LOCK_EXPANSION_IF_ALPHA, LOCK_PFN, LOCK_WS_AND_ADDRESS_SPACE, _EPROCESS::LockedPagesList, _LOCK_TRACKER::Mdl, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_VA_TO_VPN, MI_VPN_TO_VA, MI_VPN_TO_VA_ENDING, MiCleanPhysicalProcessPages(), MiDeleteAddressesInWorkingSet(), MiDeleteAlternateTable(), MiDeletePageTablesForPhysicalRange(), MiDeletePte(), MiDeleteVirtualAddresses(), MiFlushPteList(), MiGetPdeAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiHydra, MiIsPteOnPdeBoundary, MiIsPteOnPpeBoundary, MiLockSystemSpace, _MMSUPPORT::MinimumWorkingSetSize, MiPhysicalViewRemover(), MiRemoveMappedView(), MiRemoveUserPhysicalPagesVad(), MiRemoveVad(), MiReturnCommitment(), MiSessionRemoveProcess(), MiTrackingAborted, MiUnlockSystemSpace, MM_BUMP_COUNTER, MM_DBG_COMMIT_RETURN_PROCESS_CLEAN_PAGETABLES, MM_DBG_PRIVATE_PAGES, MM_MAXIMUM_WORKING_SET, MM_NO_WS_EXPANSION, MM_PROCESS_CREATE_CHARGE, MM_TRACK_COMMIT, MM_WS_EXPANSION_IN_PROGRESS, MmPagesAboveWsMinimum, MmResidentAvailablePages, MmTrackLockedPages, MmVirtualBias, MmWorkingSetList, MmWsle, NULL, _MMWSL::NumberOfCommittedPageTables, _EPROCESS::NumberOfLockedPages, _EPROCESS::NumberOfPrivatePages, _EPROCESS::PhysicalVadList, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, PsChangeJobMemoryUsage(), PsGetCurrentProcess, _MMVAD_SHORT::StartingVpn, _MMVAD::StartingVpn, TRUE, _MMVAD::u, _MMPTE::u, _MMSUPPORT::u, _MMPFN::u2, _MMPFN::u3, UNLOCK_EXPANSION, UNLOCK_EXPANSION_AND_THEN_WAIT, UNLOCK_EXPANSION_IF_ALPHA, UNLOCK_PFN, UNLOCK_WS_AND_ADDRESS_SPACE, _EPROCESS::VadRoot, _EPROCESS::Vm, _EPROCESS::VmOperation, _EPROCESS::VmOperationEvent, _MMSUPPORT::WorkingSetExpansionLinks, _MMSUPPORT::WorkingSetSize, _EPROCESS::Wow64Process, WrVirtualMemory, and ZeroPte.

Referenced by PspExitProcess(), and PspExitThread().

01700 : 01701 01702 This routine cleans an address space by deleting all the 01703 user and pagable portion of the address space. At the 01704 completion of this routine, no page faults may occur within 01705 the process. 01706 01707 Arguments: 01708 01709 None. 01710 01711 Return Value: 01712 01713 None. 01714 01715 Environment: 01716 01717 Kernel mode, APCs disabled. 01718 01719 --*/ 01720 01721 { 01722 PEPROCESS Process; 01723 PMMVAD Vad; 01724 KEVENT Event; 01725 KIRQL OldIrql; 01726 #if defined(_ALPHA_) && !defined(_AXP64_) 01727 KIRQL OldIrql2; 01728 #endif 01729 PMMPTE LastPte; 01730 PMMPTE PointerPte; 01731 PMMPTE PointerPde; 01732 PMMPTE PointerPpe; 01733 PMMPFN Pfn1; 01734 PVOID TempVa; 01735 LONG AboveWsMin; 01736 MMPTE_FLUSH_LIST PteFlushList; 01737 01738 PteFlushList.Count = 0; 01739 Process = PsGetCurrentProcess(); 01740 if ((Process->AddressSpaceDeleted != 0) || 01741 (Process->AddressSpaceInitialized == 0)) { 01742 01743 // 01744 // This process's address space has already been deleted. However, 01745 // this process can still have a session space. Get rid of it now. 01746 // 01747 01748 if (MiHydra == TRUE) { 01749 MiSessionRemoveProcess (); 01750 } 01751 01752 return; 01753 } 01754 01755 if (Process->AddressSpaceInitialized == 1) { 01756 01757 // 01758 // The process has been created but not fully initialized. 01759 // Return partial resources now. 01760 // 01761 01762 MmResidentAvailablePages += (Process->Vm.MinimumWorkingSetSize - 01763 MM_PROCESS_CREATE_CHARGE); 01764 01765 MM_BUMP_COUNTER(41, Process->Vm.MinimumWorkingSetSize - 01766 MM_PROCESS_CREATE_CHARGE); 01767 01768 // 01769 // This process's address space has already been deleted. However, 01770 // this process can still have a session space. Get rid of it now. 01771 // 01772 01773 if (MiHydra == TRUE) { 01774 MiSessionRemoveProcess (); 01775 } 01776 01777 return; 01778 } 01779 01780 // 01781 // If working set expansion for this process is allowed, disable 01782 // it and remove the process from expanded process list if it 01783 // is on it. 01784 // 01785 01786 LOCK_EXPANSION (OldIrql); 01787 01788 if (Process->Vm.u.Flags.BeingTrimmed) { 01789 01790 // 01791 // Initialize an event and put the event address 01792 // in the blink field. When the trimming is complete, 01793 // this event will be set. 01794 // 01795 01796 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01797 01798 Process->Vm.WorkingSetExpansionLinks.Blink = (PLIST_ENTRY)&Event; 01799 01800 // 01801 // Release the mutex and wait for the event. 01802 // 01803 01804 KeEnterCriticalRegion(); 01805 UNLOCK_EXPANSION_AND_THEN_WAIT (OldIrql); 01806 01807 KeWaitForSingleObject(&Event, 01808 WrVirtualMemory, 01809 KernelMode, 01810 FALSE, 01811 (PLARGE_INTEGER)NULL); 01812 KeLeaveCriticalRegion(); 01813 } 01814 else if (Process->Vm.WorkingSetExpansionLinks.Flink == MM_NO_WS_EXPANSION) { 01815 01816 // 01817 // No trimming is in progress and no expansion allowed, so this cannot 01818 // be on any lists. 01819 // 01820 01821 ASSERT (Process->Vm.WorkingSetExpansionLinks.Blink != MM_WS_EXPANSION_IN_PROGRESS); 01822 01823 UNLOCK_EXPANSION (OldIrql); 01824 } else { 01825 01826 RemoveEntryList (&Process->Vm.WorkingSetExpansionLinks); 01827 01828 // 01829 // Disable expansion. 01830 // 01831 01832 Process->Vm.WorkingSetExpansionLinks.Flink = MM_NO_WS_EXPANSION; 01833 01834 // 01835 // Release the pfn mutex. 01836 // 01837 01838 UNLOCK_EXPANSION (OldIrql); 01839 } 01840 01841 if (MiHydra == TRUE) { 01842 MiSessionRemoveProcess (); 01843 } 01844 01845 // 01846 // Delete all the user owned pagable virtual addresses in the process. 01847 // 01848 01849 LOCK_WS_AND_ADDRESS_SPACE (Process); 01850 01851 // 01852 // Synchronize address space delete with NtReadVirtualMemory and 01853 // NtWriteVirtualMemory. 01854 // 01855 01856 MiLockSystemSpace(OldIrql); 01857 Process->AddressSpaceDeleted = 1; 01858 if ( Process->VmOperation != 0) { 01859 01860 // 01861 // A Vm operation is in progress, set the event and 01862 // indicate this process is being deleted to stop other 01863 // Vm operations. 01864 // 01865 01866 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01867 Process->VmOperationEvent = &Event; 01868 01869 do { 01870 01871 MiUnlockSystemSpace(OldIrql); 01872 01873 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01874 KeWaitForSingleObject(&Event, 01875 WrVirtualMemory, 01876 KernelMode, 01877 FALSE, 01878 (PLARGE_INTEGER)NULL); 01879 01880 LOCK_WS_AND_ADDRESS_SPACE (Process); 01881 01882 // 01883 // Synchronize address space delete with NtReadVirtualMemory and 01884 // NtWriteVirtualMemory. 01885 // 01886 01887 MiLockSystemSpace(OldIrql); 01888 01889 } while (Process->VmOperation != 0); 01890 01891 MiUnlockSystemSpace(OldIrql); 01892 01893 } else { 01894 MiUnlockSystemSpace(OldIrql); 01895 } 01896 01897 // 01898 // Delete all the valid user mode addresses from the working set 01899 // list. At this point NO page faults are allowed on user space 01900 // addresses. Faults are allowed on page tables for user space, which 01901 // requires that we keep the working set structure consistent until we 01902 // finally take it all down. 01903 // 01904 01905 MiDeleteAddressesInWorkingSet (Process); 01906 01907 // 01908 // Remove hash table pages, if any. This is the first time we do this 01909 // during the deletion path, but we need to do it again before we finish 01910 // because we may fault in some page tables during the VAD clearing. We 01911 // could have maintained the hash table validity during the WorkingSet 01912 // deletion above in order to avoid freeing the hash table twice, but since 01913 // we're just deleting it all anyway, it's faster to do it this way. Note 01914 // that if we don't do this or maintain the validity, we can trap later 01915 // in MiGrowWsleHash. 01916 // 01917 01918 PointerPte = MiGetPteAddress (&MmWsle[MM_MAXIMUM_WORKING_SET]) + 1; 01919 LastPte = MiGetPteAddress (MmWorkingSetList->HighestPermittedHashAddress); 01920 01921 #if defined (_WIN64) 01922 PointerPpe = MiGetPdeAddress (PointerPte); 01923 PointerPde = MiGetPteAddress (PointerPte); 01924 01925 if ((PointerPpe->u.Hard.Valid == 1) && 01926 (PointerPde->u.Hard.Valid == 1) && 01927 (PointerPte->u.Hard.Valid == 1)) { 01928 01929 PteFlushList.Count = 0; 01930 LOCK_PFN (OldIrql); 01931 while (PointerPte->u.Hard.Valid) { 01932 TempVa = MiGetVirtualAddressMappedByPte(PointerPte); 01933 MiDeletePte (PointerPte, 01934 TempVa, 01935 FALSE, 01936 Process, 01937 NULL, 01938 &PteFlushList); 01939 01940 PointerPte += 1; 01941 Process->NumberOfPrivatePages += 1; 01942 01943 // 01944 // If all the entries have been removed from the previous page 01945 // table page, delete the page table page itself. Likewise with 01946 // the page directory page. 01947 // 01948 01949 if ((MiIsPteOnPdeBoundary(PointerPte)) || 01950 ((MiGetPdeAddress(PointerPte))->u.Hard.Valid == 0) || 01951 ((MiGetPteAddress(PointerPte))->u.Hard.Valid == 0) || 01952 (PointerPte->u.Hard.Valid == 0)) { 01953 01954 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 01955 01956 PointerPde = MiGetPteAddress (PointerPte - 1); 01957 01958 ASSERT (PointerPde->u.Hard.Valid == 1); 01959 01960 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 01961 01962 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 01963 { 01964 MiDeletePte (PointerPde, 01965 PointerPte - 1, 01966 FALSE, 01967 Process, 01968 NULL, 01969 NULL); 01970 Process->NumberOfPrivatePages += 1; 01971 } 01972 01973 if (MiIsPteOnPpeBoundary(PointerPte)) { 01974 01975 PointerPpe = MiGetPteAddress (PointerPde); 01976 01977 ASSERT (PointerPpe->u.Hard.Valid == 1); 01978 01979 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe)); 01980 01981 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 01982 { 01983 MiDeletePte (PointerPpe, 01984 PointerPde, 01985 FALSE, 01986 Process, 01987 NULL, 01988 NULL); 01989 Process->NumberOfPrivatePages += 1; 01990 } 01991 } 01992 PointerPde = MiGetPteAddress (PointerPte); 01993 PointerPpe = MiGetPdeAddress (PointerPte); 01994 if ((PointerPpe->u.Hard.Valid == 0) || 01995 (PointerPde->u.Hard.Valid == 0)) { 01996 break; 01997 } 01998 } 01999 } 02000 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02001 UNLOCK_PFN (OldIrql); 02002 } 02003 #else 02004 if (PointerPte->u.Hard.Valid) { 02005 PteFlushList.Count = 0; 02006 LOCK_PFN (OldIrql); 02007 while ((PointerPte < LastPte) && (PointerPte->u.Hard.Valid)) { 02008 TempVa = MiGetVirtualAddressMappedByPte(PointerPte); 02009 MiDeletePte (PointerPte, 02010 TempVa, 02011 FALSE, 02012 Process, 02013 NULL, 02014 &PteFlushList); 02015 02016 PointerPte += 1; 02017 Process->NumberOfPrivatePages += 1; 02018 } 02019 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02020 UNLOCK_PFN (OldIrql); 02021 } 02022 #endif 02023 02024 // 02025 // Clear the hash fields as a fault may occur below on the page table 02026 // pages during VAD clearing and resolution of the fault may result in 02027 // adding a hash table. Thus these fields must be consistent with the 02028 // clearing just done above. 02029 // 02030 02031 MmWorkingSetList->HashTableSize = 0; 02032 MmWorkingSetList->HashTable = NULL; 02033 02034 // 02035 // Delete the virtual address descriptors and dereference any 02036 // section objects. 02037 // 02038 02039 Vad = Process->VadRoot; 02040 02041 while (Vad != (PMMVAD)NULL) { 02042 02043 MiRemoveVad (Vad); 02044 02045 // 02046 // If the system has been biased to an alternate base address to 02047 // allow 3gb of user address space, then check if the current VAD 02048 // describes the shared memory page. 02049 // 02050 02051 #if defined(_X86_) && defined(MM_SHARED_USER_DATA_VA) 02052 02053 if (MmVirtualBias != 0) { 02054 02055 // 02056 // If the VAD describes the shared memory page, then free the 02057 // VAD and continue with the next entry. 02058 // 02059 02060 if (Vad->StartingVpn == MI_VA_TO_VPN (MM_SHARED_USER_DATA_VA)) { 02061 goto LoopEnd; 02062 } 02063 } 02064 #endif 02065 02066 if (((Vad->u.VadFlags.PrivateMemory == 0) && 02067 (Vad->ControlArea != NULL)) || 02068 (Vad->u.VadFlags.PhysicalMapping == 1)) { 02069 02070 // 02071 // This VAD represents a mapped view or a driver-mapped physical 02072 // view - delete the view and perform any section related cleanup 02073 // operations. 02074 // 02075 02076 MiRemoveMappedView (Process, Vad); 02077 02078 } else { 02079 02080 if (Vad->u.VadFlags.UserPhysicalPages == 1) { 02081 02082 // 02083 // Free all the physical pages that this VAD might be mapping. 02084 // Since only the AWE lock synchronizes the remap API, carefully 02085 // remove this VAD from the list first. 02086 // 02087 02088 MiPhysicalViewRemover (Process, Vad); 02089 02090 MiRemoveUserPhysicalPagesVad ((PMMVAD_SHORT)Vad); 02091 02092 MiDeletePageTablesForPhysicalRange ( 02093 MI_VPN_TO_VA (Vad->StartingVpn), 02094 MI_VPN_TO_VA_ENDING (Vad->EndingVpn)); 02095 } 02096 else { 02097 02098 if (Vad->u.VadFlags.WriteWatch == 1) { 02099 MiPhysicalViewRemover (Process, Vad); 02100 } 02101 02102 LOCK_PFN (OldIrql); 02103 02104 // 02105 // Don't specify address space deletion as TRUE as 02106 // the working set must be consistent as page faults may 02107 // be taken during clone removal, protoPTE lookup, etc. 02108 // 02109 02110 MiDeleteVirtualAddresses (MI_VPN_TO_VA (Vad->StartingVpn), 02111 MI_VPN_TO_VA_ENDING (Vad->EndingVpn), 02112 FALSE, 02113 Vad); 02114 02115 UNLOCK_PFN (OldIrql); 02116 } 02117 } 02118 02119 #if defined(_X86_) && defined(MM_SHARED_USER_DATA_VA) 02120 LoopEnd: 02121 #endif 02122 02123 ExFreePool (Vad); 02124 Vad = Process->VadRoot; 02125 } 02126 02127 ASSERT (IsListEmpty (&Process->PhysicalVadList) != 0); 02128 02129 MiCleanPhysicalProcessPages (Process); 02130 02131 // 02132 // Delete the shared data page, if any. 02133 // 02134 02135 LOCK_PFN (OldIrql); 02136 02137 #if defined(MM_SHARED_USER_DATA_VA) 02138 MiDeleteVirtualAddresses ((PVOID) MM_SHARED_USER_DATA_VA, 02139 (PVOID) MM_SHARED_USER_DATA_VA, 02140 FALSE, 02141 NULL); 02142 #endif 02143 02144 // 02145 // Delete the system portion of the address space. 02146 // Only now is it safe to specify TRUE to MiDelete because now that the 02147 // VADs have been deleted we can no longer fault on user space pages. 02148 // 02149 02150 #if defined(_ALPHA_) && !defined(_AXP64_) 02151 LOCK_EXPANSION_IF_ALPHA (OldIrql2); 02152 #endif 02153 Process->Vm.AddressSpaceBeingDeleted = 1; 02154 #if defined(_ALPHA_) && !defined(_AXP64_) 02155 UNLOCK_EXPANSION_IF_ALPHA (OldIrql2); 02156 #endif 02157 02158 // 02159 // Adjust the count of pages above working set maximum. This 02160 // must be done here because the working set list is not 02161 // updated during this deletion. 02162 // 02163 02164 AboveWsMin = (LONG)Process->Vm.WorkingSetSize - (LONG)Process->Vm.MinimumWorkingSetSize; 02165 if (AboveWsMin > 0) { 02166 MmPagesAboveWsMinimum -= AboveWsMin; 02167 } 02168 02169 UNLOCK_PFN (OldIrql); 02170 02171 // 02172 // Return commitment for page table pages. 02173 // 02174 02175 #ifdef _WIN64 02176 ASSERT (MmWorkingSetList->NumberOfCommittedPageTables == 0); 02177 #else 02178 MiReturnCommitment (MmWorkingSetList->NumberOfCommittedPageTables); 02179 02180 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PROCESS_CLEAN_PAGETABLES, 02181 MmWorkingSetList->NumberOfCommittedPageTables); 02182 02183 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 02184 PsChangeJobMemoryUsage(-(SSIZE_T)MmWorkingSetList->NumberOfCommittedPageTables); 02185 } 02186 Process->CommitCharge -= MmWorkingSetList->NumberOfCommittedPageTables; 02187 #endif 02188 02189 // 02190 // Check to make sure all the clone descriptors went away. 02191 // 02192 02193 ASSERT (Process->CloneRoot == (PMMCLONE_DESCRIPTOR)NULL); 02194 02195 if (Process->NumberOfLockedPages != 0) { 02196 if (Process->LockedPagesList) { 02197 02198 PLIST_ENTRY NextEntry; 02199 PLOCK_TRACKER Tracker; 02200 PLOCK_HEADER LockedPagesHeader; 02201 02202 LockedPagesHeader = (PLOCK_HEADER)Process->LockedPagesList; 02203 if ((LockedPagesHeader->Count != 0) && (MiTrackingAborted == FALSE)) { 02204 ASSERT (IsListEmpty (&LockedPagesHeader->ListHead) == 0); 02205 NextEntry = LockedPagesHeader->ListHead.Flink; 02206 02207 Tracker = CONTAINING_RECORD (NextEntry, 02208 LOCK_TRACKER, 02209 ListEntry); 02210 02211 KeBugCheckEx (DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS, 02212 (ULONG_PTR)Tracker->CallingAddress, 02213 (ULONG_PTR)Tracker->CallersCaller, 02214 (ULONG_PTR)Tracker->Mdl, 02215 Process->NumberOfLockedPages); 02216 } 02217 } 02218 02219 KeBugCheckEx (PROCESS_HAS_LOCKED_PAGES, 02220 0, 02221 (ULONG_PTR)Process, 02222 Process->NumberOfLockedPages, 02223 (ULONG_PTR)Process->LockedPagesList); 02224 return; 02225 } 02226 02227 if (Process->LockedPagesList) { 02228 ASSERT (MmTrackLockedPages == TRUE); 02229 ExFreePool (Process->LockedPagesList); 02230 Process->LockedPagesList = NULL; 02231 } 02232 02233 #if DBG 02234 if ((Process->NumberOfPrivatePages != 0) && (MmDebug & MM_DBG_PRIVATE_PAGES)) { 02235 DbgPrint("MM: Process contains private pages %ld\n", 02236 Process->NumberOfPrivatePages); 02237 DbgBreakPoint(); 02238 } 02239 #endif //DBG 02240 02241 02242 #if defined(_WIN64) 02243 // 02244 // Delete the WowProcess structure 02245 // 02246 02247 if (Process->Wow64Process != NULL) { 02248 #if defined(_MIALT4K_) 02249 MiDeleteAlternateTable(Process); 02250 #endif 02251 ExFreePool(Process->Wow64Process); 02252 Process->Wow64Process = NULL; 02253 } 02254 #endif 02255 02256 // 02257 // Remove the working set list pages (except for the first one). 02258 // These pages are not removed because DPCs could still occur within 02259 // the address space. In a DPC, nonpagedpool could be allocated 02260 // which could require removing a page from the standby list, requiring 02261 // hyperspace to map the previous PTE. 02262 // 02263 02264 PointerPte = MiGetPteAddress (MmWorkingSetList) + 1; 02265 02266 PteFlushList.Count = 0; 02267 02268 LOCK_PFN (OldIrql); 02269 while (PointerPte->u.Hard.Valid) { 02270 TempVa = MiGetVirtualAddressMappedByPte(PointerPte); 02271 MiDeletePte (PointerPte, 02272 TempVa, 02273 TRUE, 02274 Process, 02275 NULL, 02276 &PteFlushList); 02277 02278 PointerPte += 1; 02279 #if defined (_WIN64) 02280 // 02281 // If all the entries have been removed from the previous page 02282 // table page, delete the page table page itself. Likewise with 02283 // the page directory page. 02284 // 02285 02286 if ((MiIsPteOnPdeBoundary(PointerPte)) || 02287 ((MiGetPdeAddress(PointerPte))->u.Hard.Valid == 0) || 02288 ((MiGetPteAddress(PointerPte))->u.Hard.Valid == 0) || 02289 (PointerPte->u.Hard.Valid == 0)) { 02290 02291 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02292 02293 PointerPde = MiGetPteAddress (PointerPte - 1); 02294 02295 ASSERT (PointerPde->u.Hard.Valid == 1); 02296 02297 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 02298 02299 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 02300 { 02301 MiDeletePte (PointerPde, 02302 PointerPte - 1, 02303 TRUE, 02304 Process, 02305 NULL, 02306 NULL); 02307 } 02308 02309 if (MiIsPteOnPpeBoundary(PointerPte)) { 02310 02311 PointerPpe = MiGetPteAddress (PointerPde); 02312 02313 ASSERT (PointerPpe->u.Hard.Valid == 1); 02314 02315 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe)); 02316 02317 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 02318 { 02319 MiDeletePte (PointerPpe, 02320 PointerPde, 02321 TRUE, 02322 Process, 02323 NULL, 02324 NULL); 02325 } 02326 } 02327 } 02328 #endif 02329 } 02330 02331 // 02332 // Remove hash table pages, if any. Yes, we've already done this once 02333 // during the deletion path, but we need to do it again because we may 02334 // have faulted in some page tables during the VAD clearing. 02335 // 02336 02337 PointerPte = MiGetPteAddress (&MmWsle[MM_MAXIMUM_WORKING_SET]) + 1; 02338 02339 #if defined (_WIN64) 02340 PointerPpe = MiGetPdeAddress (PointerPte); 02341 PointerPde = MiGetPteAddress (PointerPte); 02342 02343 if ((PointerPpe->u.Hard.Valid == 1) && 02344 (PointerPde->u.Hard.Valid == 1) && 02345 (PointerPte->u.Hard.Valid == 1)) { 02346 02347 while (PointerPte->u.Hard.Valid) { 02348 TempVa = MiGetVirtualAddressMappedByPte(PointerPte); 02349 MiDeletePte (PointerPte, 02350 TempVa, 02351 TRUE, 02352 Process, 02353 NULL, 02354 &PteFlushList); 02355 02356 PointerPte += 1; 02357 02358 // 02359 // If all the entries have been removed from the previous page 02360 // table page, delete the page table page itself. Likewise with 02361 // the page directory page. 02362 // 02363 02364 if ((MiIsPteOnPdeBoundary(PointerPte)) || 02365 ((MiGetPdeAddress(PointerPte))->u.Hard.Valid == 0) || 02366 ((MiGetPteAddress(PointerPte))->u.Hard.Valid == 0) || 02367 (PointerPte->u.Hard.Valid == 0)) { 02368 02369 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02370 02371 PointerPde = MiGetPteAddress (PointerPte - 1); 02372 02373 ASSERT (PointerPde->u.Hard.Valid == 1); 02374 02375 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 02376 02377 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 02378 { 02379 MiDeletePte (PointerPde, 02380 PointerPte - 1, 02381 TRUE, 02382 Process, 02383 NULL, 02384 NULL); 02385 } 02386 02387 if (MiIsPteOnPpeBoundary(PointerPte)) { 02388 02389 PointerPpe = MiGetPteAddress (PointerPde); 02390 02391 ASSERT (PointerPpe->u.Hard.Valid == 1); 02392 02393 Pfn1 = MI_PFN_ELEMENT (MI_GET_PAGE_FRAME_FROM_PTE (PointerPpe)); 02394 02395 if (Pfn1->u2.ShareCount == 1 && Pfn1->u3.e2.ReferenceCount == 1) 02396 { 02397 MiDeletePte (PointerPpe, 02398 PointerPde, 02399 TRUE, 02400 Process, 02401 NULL, 02402 NULL); 02403 } 02404 } 02405 } 02406 } 02407 } 02408 #else 02409 while ((PointerPte < LastPte) && (PointerPte->u.Hard.Valid)) { 02410 TempVa = MiGetVirtualAddressMappedByPte(PointerPte); 02411 MiDeletePte (PointerPte, 02412 TempVa, 02413 TRUE, 02414 Process, 02415 NULL, 02416 &PteFlushList); 02417 02418 PointerPte += 1; 02419 } 02420 #endif 02421 02422 MiFlushPteList (&PteFlushList, FALSE, ZeroPte); 02423 02424 // 02425 // Update the count of available resident pages. 02426 // 02427 02428 ASSERT (Process->Vm.MinimumWorkingSetSize >= MM_PROCESS_CREATE_CHARGE); 02429 MmResidentAvailablePages += Process->Vm.MinimumWorkingSetSize - 02430 MM_PROCESS_CREATE_CHARGE; 02431 MM_BUMP_COUNTER(8, Process->Vm.MinimumWorkingSetSize - 02432 MM_PROCESS_CREATE_CHARGE); 02433 ASSERT (Process->Vm.WorkingSetExpansionLinks.Flink == MM_NO_WS_EXPANSION); 02434 UNLOCK_PFN (OldIrql); 02435 02436 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 02437 return; 02438 }

PVOID MmCreateKernelStack IN BOOLEAN  LargeStack  ) 
 

Definition at line 2450 of file procsup.c.

References ASSERT, BYTES_TO_PAGES, DbgPrint, FALSE, LOCK_PFN, MI_GET_PAGE_COLOR_FROM_PTE, MI_MAKE_VALID_PTE, MI_SET_PTE_DIRTY, MI_WRITE_VALID_PTE, MiChargeCommitment(), MiEnsureAvailablePageOrWait(), MiGetSystemPteListCount(), MiGetVirtualAddressMappedByPte, MiInitializePfn(), MiRemoveAnyPage(), MiReserveSystemPtes(), MiReturnCommitment(), MM_BUMP_COUNTER, MM_DBG_COMMIT_KERNEL_STACK_CREATE, MM_DBG_COMMIT_RETURN_KERNEL_STACK_FAILURE1, MM_DBG_COMMIT_RETURN_KERNEL_STACK_FAILURE2, MM_KERNEL_DEMAND_ZERO_PTE, MM_KSTACK_OUTSWAPPED, MM_READWRITE, MM_STACK_ALIGNMENT, MM_STACK_OFFSET, MM_TRACK_COMMIT, MmFirstDeadKernelStack, MmKernelStackPages, MmKernelStackResident, MmLargeStacks, MmNumberDeadKernelStacks, MmProcessCommit, MmResidentAvailablePages, MmSmallStacks, NULL, PAGE_SIZE, _MMPFN::PteAddress, SystemPteSpace, _MMPTE::u, _MMPFN::u1, and UNLOCK_PFN.

Referenced by KeStartAllProcessors(), KiInitializeKernel(), PsConvertToGuiThread(), and PspCreateThread().

02456 : 02457 02458 This routine allocates a kernel stack and a no-access page within 02459 the non-pagable portion of the system address space. 02460 02461 Arguments: 02462 02463 LargeStack - Supplies the value TRUE if a large stack should be 02464 created. FALSE if a small stack is to be created. 02465 02466 Return Value: 02467 02468 Returns a pointer to the base of the kernel stack. Note, that the 02469 base address points to the guard page, so space must be allocated 02470 on the stack before accessing the stack. 02471 02472 If a kernel stack cannot be created, the value NULL is returned. 02473 02474 Environment: 02475 02476 Kernel mode. APCs Disabled. 02477 02478 --*/ 02479 02480 { 02481 PMMPTE PointerPte; 02482 MMPTE TempPte; 02483 PFN_NUMBER NumberOfPages; 02484 ULONG NumberOfPtes; 02485 ULONG ChargedPtes; 02486 ULONG RequestedPtes; 02487 #if defined(_IA64_) 02488 ULONG NumberOfBStorePtes; 02489 #endif 02490 PFN_NUMBER PageFrameIndex; 02491 ULONG i; 02492 PVOID StackVa; 02493 KIRQL OldIrql; 02494 02495 // 02496 // Acquire the PFN mutex to synchronize access to the dead stack 02497 // list and to the pfn database. 02498 // 02499 02500 LOCK_PFN (OldIrql); 02501 02502 // 02503 // Check to see if any "unused" stacks are available. 02504 // 02505 02506 if ((!LargeStack) && (MmNumberDeadKernelStacks != 0)) { 02507 02508 #if DBG 02509 { 02510 ULONG i = MmNumberDeadKernelStacks; 02511 PMMPFN PfnList = MmFirstDeadKernelStack; 02512 02513 while (i > 0) { 02514 i--; 02515 if ((PfnList != MmKstacks[i].Pfn) || 02516 (PfnList->PteAddress != MmKstacks[i].Pte)) { 02517 DbgPrint("MMPROCSUP: kstacks %p %ld. %p\n", 02518 PfnList, i, MmKstacks[i].Pfn); 02519 DbgBreakPoint(); 02520 } 02521 PfnList = PfnList->u1.NextStackPfn; 02522 } 02523 } 02524 #if defined(_IA64_) 02525 NumberOfPages = BYTES_TO_PAGES (KERNEL_STACK_SIZE + KERNEL_BSTORE_SIZE); 02526 #else 02527 NumberOfPages = BYTES_TO_PAGES (KERNEL_STACK_SIZE); 02528 #endif 02529 #endif //DBG 02530 02531 MmNumberDeadKernelStacks -= 1; 02532 PointerPte = MmFirstDeadKernelStack->PteAddress; 02533 MmFirstDeadKernelStack = MmFirstDeadKernelStack->u1.NextStackPfn; 02534 02535 } else { 02536 02537 UNLOCK_PFN (OldIrql); 02538 02539 #if defined(_IA64_) 02540 if (LargeStack) { 02541 NumberOfPtes = BYTES_TO_PAGES (KERNEL_LARGE_STACK_SIZE); 02542 NumberOfBStorePtes = BYTES_TO_PAGES (KERNEL_LARGE_BSTORE_SIZE); 02543 NumberOfPages = BYTES_TO_PAGES (KERNEL_LARGE_STACK_COMMIT 02544 + KERNEL_LARGE_BSTORE_COMMIT); 02545 02546 } else { 02547 NumberOfPtes = BYTES_TO_PAGES (KERNEL_STACK_SIZE); 02548 NumberOfBStorePtes = BYTES_TO_PAGES (KERNEL_BSTORE_SIZE); 02549 NumberOfPages = NumberOfPtes + NumberOfBStorePtes; 02550 } 02551 ChargedPtes = NumberOfPtes + NumberOfBStorePtes; 02552 RequestedPtes = ChargedPtes + 2 + (MM_STACK_ALIGNMENT ? 1 : 0); 02553 #else 02554 if (LargeStack) { 02555 NumberOfPtes = BYTES_TO_PAGES (KERNEL_LARGE_STACK_SIZE); 02556 NumberOfPages = BYTES_TO_PAGES (KERNEL_LARGE_STACK_COMMIT); 02557 } else { 02558 NumberOfPtes = BYTES_TO_PAGES (KERNEL_STACK_SIZE); 02559 NumberOfPages = NumberOfPtes; 02560 } 02561 ChargedPtes = NumberOfPtes; 02562 RequestedPtes = ChargedPtes + 1 + (MM_STACK_ALIGNMENT ? 1 : 0); 02563 #endif // _IA64_ 02564 02565 // 02566 // Make sure there are at least 8 of the appropriate system PTE pool. 02567 // 02568 02569 if (MiGetSystemPteListCount (RequestedPtes) < 8) { 02570 return NULL; 02571 } 02572 02573 // 02574 // Charge commitment for the page file space for the kernel stack. 02575 // 02576 02577 if (MiChargeCommitment (ChargedPtes, NULL) == FALSE) { 02578 02579 // 02580 // Commitment exceeded, return NULL, indicating no kernel 02581 // stacks are available. 02582 // 02583 02584 return NULL; 02585 } 02586 MM_TRACK_COMMIT (MM_DBG_COMMIT_KERNEL_STACK_CREATE, ChargedPtes); 02587 02588 LOCK_PFN (OldIrql); 02589 02590 // 02591 // Check to make sure the physical pages are available. 02592 // 02593 02594 if (MmResidentAvailablePages <= (SPFN_NUMBER)NumberOfPages) { 02595 UNLOCK_PFN (OldIrql); 02596 MiReturnCommitment (ChargedPtes); 02597 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_KERNEL_STACK_FAILURE1, 02598 ChargedPtes); 02599 return NULL; 02600 } 02601 02602 MmResidentAvailablePages -= NumberOfPages; 02603 MM_BUMP_COUNTER(9, NumberOfPages); 02604 02605 UNLOCK_PFN (OldIrql); 02606 02607 // 02608 // Obtain enough pages to contain the stack plus a guard page from 02609 // the system PTE pool. The system PTE pool contains non-paged PTEs 02610 // which are currently empty. 02611 // 02612 02613 MmKernelStackPages += RequestedPtes; 02614 02615 PointerPte = MiReserveSystemPtes (RequestedPtes, 02616 SystemPteSpace, 02617 MM_STACK_ALIGNMENT, 02618 MM_STACK_OFFSET, 02619 FALSE); 02620 02621 if (PointerPte == NULL) { 02622 02623 LOCK_PFN (OldIrql); 02624 MmResidentAvailablePages += NumberOfPages; 02625 MM_BUMP_COUNTER(13, NumberOfPages); 02626 UNLOCK_PFN (OldIrql); 02627 02628 MiReturnCommitment (ChargedPtes); 02629 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_KERNEL_STACK_FAILURE2, 02630 ChargedPtes); 02631 return NULL; 02632 } 02633 02634 #if defined(_IA64_) 02635 02636 // 02637 // StackVa is calculated here 02638 // 02639 02640 StackVa = (PVOID)MiGetVirtualAddressMappedByPte (PointerPte + NumberOfPtes + 1); 02641 02642 // 02643 // The PTEs are divided between kernel stack and RSE space. 02644 // 02645 // The kernel stack grows downward and the RSE grows upward. 02646 // 02647 // For large stacks, one chunk is allocated in the middle of the PTE 02648 // range and split here. 02649 // 02650 // need better algorithm for RSE 02651 02652 if (LargeStack) { 02653 PointerPte += BYTES_TO_PAGES (KERNEL_LARGE_STACK_SIZE - KERNEL_LARGE_STACK_COMMIT -1); 02654 } 02655 02656 #else 02657 PointerPte += (NumberOfPtes - NumberOfPages); 02658 #endif // _IA64_ 02659 02660 LOCK_PFN (OldIrql); 02661 02662 for (i = 0; i < NumberOfPages; i += 1) { 02663 PointerPte += 1; 02664 ASSERT (PointerPte->u.Hard.Valid == 0); 02665 MiEnsureAvailablePageOrWait (NULL, NULL); 02666 PageFrameIndex = MiRemoveAnyPage ( 02667 MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); 02668 02669 PointerPte->u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 02670 02671 #ifdef PROTECT_KSTACKS 02672 PointerPte->u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 02673 #endif 02674 02675 MiInitializePfn (PageFrameIndex, PointerPte, 1); 02676 02677 MI_MAKE_VALID_PTE (TempPte, 02678 PageFrameIndex, 02679 MM_READWRITE, 02680 PointerPte ); 02681 MI_SET_PTE_DIRTY (TempPte); 02682 02683 MI_WRITE_VALID_PTE (PointerPte, TempPte); 02684 } 02685 MmProcessCommit += ChargedPtes; 02686 MmKernelStackResident += NumberOfPages; 02687 MmLargeStacks += LargeStack; 02688 MmSmallStacks += !LargeStack; 02689 02690 #if defined(_IA64_) 02691 02692 UNLOCK_PFN (OldIrql); 02693 02694 return StackVa; 02695 #endif 02696 02697 } 02698 02699 UNLOCK_PFN (OldIrql); 02700 02701 PointerPte += 1; 02702 StackVa = (PVOID)MiGetVirtualAddressMappedByPte (PointerPte); 02703 #if !defined(_IA64_) 02704 #if DBG 02705 { 02706 PULONG p; 02707 ULONG_PTR i; 02708 02709 p = (PULONG)((ULONG_PTR)StackVa - ((ULONG_PTR)NumberOfPages * PAGE_SIZE)); 02710 i = ((ULONG_PTR)NumberOfPages * PAGE_SIZE) >> 2; 02711 while(i--) { 02712 *p++ = 0x12345678; 02713 } 02714 02715 } 02716 #endif // DBG 02717 #endif // _IA64_ 02718 02719 return StackVa; 02720 }

PPEB MmCreatePeb IN PEPROCESS  TargetProcess,
IN PINITIAL_PEB  InitialPeb
 

Definition at line 4631 of file procsup.c.

References CmNtCSDVersion, EXCEPTION_EXECUTE_HANDLER, ExRaiseStatus(), FALSE, InitAnsiCodePageDataOffset, InitNlsSectionPointer, InitOemCodePageDataOffset, InitUnicodeCaseTableDataOffset, KeActiveProcessors, KeAttachProcess(), KeDetachProcess(), KeNumberProcessors, L, MI_INIT_PEB_FROM_IMAGE, MiCreatePebOrTeb(), MmCriticalSectionTimeout, MmHeapDeCommitFreeBlockThreshold, MmHeapDeCommitTotalFreeThreshold, MmHeapSegmentCommit, MmHeapSegmentReserve, MmMapViewOfSection(), MmRotatingUniprocessorNumber, NT_SUCCESS, NtBuildNumber, NtGlobalFlag, NtMajorVersion, NtMinorVersion, NTSTATUS(), NULL, PAGE_SIZE, ProbeForRead, RtlImageDirectoryEntryToData(), RtlImageNtHeader(), Status, TRUE, and USHORT.

Referenced by PspCreateProcess().

04638 : 04639 04640 This routine creates a PEB page within the target process 04641 and copies the initial PEB values into it. 04642 04643 Arguments: 04644 04645 TargetProcess - Supplies a pointer to the process in which to create 04646 and initialize the PEB. 04647 04648 InitialPeb - Supplies a pointer to the initial PEB to copy into the 04649 newly created PEB. 04650 04651 Return Value: 04652 04653 Returns the address of the base of the newly created PEB. 04654 04655 Can raise exceptions if no address space is available for the PEB or 04656 the user has exceeded quota (non-paged, pagefile, commit). 04657 04658 Environment: 04659 04660 Kernel mode. 04661 04662 --*/ 04663 04664 { 04665 PPEB PebBase; 04666 USHORT Magic; 04667 USHORT Characteristics; 04668 NTSTATUS Status; 04669 PVOID ViewBase; 04670 LARGE_INTEGER SectionOffset; 04671 PIMAGE_NT_HEADERS NtHeaders; 04672 SIZE_T ViewSize; 04673 ULONG ReturnedSize; 04674 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; 04675 ULONG ProcessAffinityMask; 04676 04677 ViewBase = NULL; 04678 SectionOffset.LowPart = 0; 04679 SectionOffset.HighPart = 0; 04680 ViewSize = 0; 04681 04682 // 04683 // If the specified process is not the current process, attach 04684 // to the specified process. 04685 // 04686 04687 KeAttachProcess (&TargetProcess->Pcb); 04688 04689 // 04690 // Map the NLS tables into the application's address space. 04691 // 04692 04693 Status = MmMapViewOfSection( 04694 InitNlsSectionPointer, 04695 TargetProcess, 04696 &ViewBase, 04697 0L, 04698 0L, 04699 &SectionOffset, 04700 &ViewSize, 04701 ViewShare, 04702 MEM_TOP_DOWN | SEC_NO_CHANGE, 04703 PAGE_READONLY 04704 ); 04705 04706 if ( !NT_SUCCESS(Status) ) { 04707 KeDetachProcess(); 04708 ExRaiseStatus(Status); 04709 } 04710 04711 PebBase = (PPEB)MiCreatePebOrTeb (TargetProcess, 04712 (ULONG)sizeof( PEB )); 04713 04714 // 04715 // Initialize the Peb. 04716 // 04717 04718 PebBase->InheritedAddressSpace = InitialPeb->InheritedAddressSpace; 04719 PebBase->Mutant = InitialPeb->Mutant; 04720 PebBase->ImageBaseAddress = TargetProcess->SectionBaseAddress; 04721 04722 PebBase->AnsiCodePageData = (PVOID)((PUCHAR)ViewBase+InitAnsiCodePageDataOffset); 04723 PebBase->OemCodePageData = (PVOID)((PUCHAR)ViewBase+InitOemCodePageDataOffset); 04724 PebBase->UnicodeCaseTableData = (PVOID)((PUCHAR)ViewBase+InitUnicodeCaseTableDataOffset); 04725 04726 PebBase->NumberOfProcessors = KeNumberProcessors; 04727 PebBase->BeingDebugged = (BOOLEAN)(TargetProcess->DebugPort != NULL ? TRUE : FALSE); 04728 PebBase->NtGlobalFlag = NtGlobalFlag; 04729 PebBase->CriticalSectionTimeout = MmCriticalSectionTimeout; 04730 PebBase->HeapSegmentReserve = MmHeapSegmentReserve; 04731 PebBase->HeapSegmentCommit = MmHeapSegmentCommit; 04732 PebBase->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold; 04733 PebBase->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold; 04734 PebBase->NumberOfHeaps = 0; 04735 PebBase->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof( PEB )) / sizeof( PVOID ); 04736 PebBase->ProcessHeaps = (PVOID *)(PebBase+1); 04737 04738 PebBase->OSMajorVersion = NtMajorVersion; 04739 PebBase->OSMinorVersion = NtMinorVersion; 04740 PebBase->OSBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF); 04741 PebBase->OSPlatformId = 2; // VER_PLATFORM_WIN32_NT from winbase.h 04742 PebBase->OSCSDVersion = (USHORT)CmNtCSDVersion; 04743 04744 // 04745 // Every reference to NtHeaders (including the call to RtlImageNtHeader) 04746 // must be wrapped in try-except in case the inpage fails. The inpage 04747 // can fail for any reason including network failures, low resources, etc. 04748 // 04749 04750 try { 04751 NtHeaders = RtlImageNtHeader( PebBase->ImageBaseAddress ); 04752 Magic = NtHeaders->OptionalHeader.Magic; 04753 Characteristics = NtHeaders->FileHeader.Characteristics; 04754 } except (EXCEPTION_EXECUTE_HANDLER) { 04755 KeDetachProcess(); 04756 ExRaiseStatus(STATUS_INVALID_IMAGE_PROTECT); 04757 } 04758 04759 if (NtHeaders != NULL) { 04760 04761 ProcessAffinityMask = 0; 04762 #if defined(_WIN64) 04763 if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 04764 04765 // 04766 // If this call fails, an exception will be thrown and the 04767 // detach performed so no need to handle errors here. 04768 // 04769 04770 MiInitializeWowPeb (NtHeaders, PebBase, TargetProcess); 04771 04772 } else // a PE32+ image 04773 #endif 04774 { 04775 try { 04776 ImageConfigData = RtlImageDirectoryEntryToData ( 04777 PebBase->ImageBaseAddress, 04778 TRUE, 04779 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, 04780 &ReturnedSize); 04781 04782 ProbeForRead ((PVOID)ImageConfigData, 04783 sizeof (*ImageConfigData), 04784 sizeof (ULONG)); 04785 04786 MI_INIT_PEB_FROM_IMAGE(NtHeaders, ImageConfigData); 04787 04788 if (ImageConfigData != NULL && ImageConfigData->ProcessAffinityMask != 0) { 04789 ProcessAffinityMask = ImageConfigData->ProcessAffinityMask; 04790 } 04791 04792 } except (EXCEPTION_EXECUTE_HANDLER) { 04793 KeDetachProcess(); 04794 ExRaiseStatus(STATUS_INVALID_IMAGE_PROTECT); 04795 } 04796 04797 } 04798 04799 // 04800 // Note NT4 examined the NtHeaders->FileHeader.Characteristics 04801 // for the IMAGE_FILE_AGGRESIVE_WS_TRIM bit, but this is not needed 04802 // or used for NT5 and above. 04803 // 04804 04805 // 04806 // See if image wants to override the default processor affinity mask. 04807 // 04808 04809 if (Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) { 04810 04811 // 04812 // Image is NOT MP safe. Assign it a processor on a rotating 04813 // basis to spread these processes around on MP systems. 04814 // 04815 04816 do { 04817 PebBase->ImageProcessAffinityMask = (KAFFINITY)(0x1 << MmRotatingUniprocessorNumber); 04818 if (++MmRotatingUniprocessorNumber >= KeNumberProcessors) { 04819 MmRotatingUniprocessorNumber = 0; 04820 } 04821 } while ((PebBase->ImageProcessAffinityMask & KeActiveProcessors) == 0); 04822 } else { 04823 04824 if (ProcessAffinityMask != 0) { 04825 04826 // 04827 // Pass the affinity mask from the image header 04828 // to LdrpInitializeProcess via the PEB. 04829 // 04830 04831 PebBase->ImageProcessAffinityMask = ProcessAffinityMask; 04832 } 04833 } 04834 } 04835 04836 PebBase->SessionId = TargetProcess->SessionId; 04837 04838 KeDetachProcess(); 04839 return PebBase; 04840 }

BOOLEAN MmCreateProcessAddressSpace IN ULONG  MinimumWorkingSetSize,
IN PEPROCESS  NewProcess,
OUT PULONG_PTR  DirectoryTableBase
 

Definition at line 190 of file procsup.c.

References ASSERT, CODE_END, CODE_START, CONSISTENCY_LOCK_PFN, CONSISTENCY_UNLOCK_PFN, FALSE, HYPER_SPACE, INITIALIZE_DIRECTORY_TABLE_BASE, KeInitializeSpinLock(), KSEG0_BASE, KSEG2_BASE, KSTACK_POOL_START, LOCK_PFN, LOCK_WS, MI_GET_PAGE_FRAME_FROM_PTE, MI_INITIALIZE_HYPERSPACE_MAP, MI_PAGE_COLOR_PTE_PROCESS, MI_PAGE_COLOR_VA_PROCESS, MI_PFN_ELEMENT, MI_SET_GLOBAL_STATE, MI_WRITE_INVALID_PTE, MI_WRITE_VALID_PTE, MiChargeCommitment(), MiEnsureAvailablePageOrWait(), MiGetPdeAddress, MiGetPdeOffset, MiGetPpeAddress, MiGetPpeOffset, MiGetPteAddress, MiHydra, MiMapPageInHyperSpace(), MiNumberOfExtraSystemPdes, MiRemoveAnyPage(), MiRemoveZeroPageIfAny, MiReturnCommitment(), MiSessionAddProcess(), MiSystemCacheEndExtra, MiSystemCacheStartExtra, MiUnmapPageInHyperSpace, MiZeroPhysicalPage(), MM_BUMP_COUNTER, MM_DBG_COMMIT_PROCESS_CREATE, MM_DBG_COMMIT_RETURN_PROCESS_CREATE_FAILURE1, MM_KSEG0_BASE, MM_PROCESS_COMMIT_CHARGE, MM_SESSION_SPACE_DEFAULT, MM_SYSTEM_CACHE_WORKING_SET, MM_SYSTEM_SPACE_END, MM_SYSTEM_SPACE_START, MM_TRACK_COMMIT, MM_VA_MAPPED_BY_PDE, MmNonPagedSystemStart, MmProcessColorSeed, MmProcessCommit, MMPTE, MmResidentAvailablePages, MmSessionSpace, MmSystemCacheEnd, MmVirtualBias, MmWorkingSetList, _EPROCESS::NextPageColor, NON_PAGED_SYSTEM_END, NULL, PAGE_SHIFT, PsGetCurrentProcess, PTE_PER_PAGE, _MMPFN::PteAddress, RtlRandom(), TRUE, _MMSUPPORT::u, _MMPTE::u, _MMPFN::u3, UNLOCK_PFN, UNLOCK_WS, USHORT, ValidPdePde, and _EPROCESS::Vm.

Referenced by PspCreateProcess().

00198 : 00199 00200 This routine creates an address space which maps the system 00201 portion and contains a hyper space entry. 00202 00203 Arguments: 00204 00205 MinimumWorkingSetSize - Supplies the minimum working set size for 00206 this address space. This value is only used 00207 to ensure that ample physical pages exist 00208 to create this process. 00209 00210 NewProcess - Supplies a pointer to the process object being created. 00211 00212 DirectoryTableBase - Returns the value of the newly created 00213 address space's Page Directory (PD) page and 00214 hyper space page. 00215 00216 Return Value: 00217 00218 Returns TRUE if an address space was successfully created, FALSE 00219 if ample physical pages do not exist. 00220 00221 Environment: 00222 00223 Kernel mode. APCs Disabled. 00224 00225 --*/ 00226 00227 { 00228 PFN_NUMBER HyperDirectoryIndex; 00229 PFN_NUMBER PageDirectoryIndex; 00230 PMMPTE PointerPte; 00231 PMMPTE PointerPde; 00232 PMMPTE PointerPpe; 00233 PFN_NUMBER HyperSpaceIndex; 00234 PFN_NUMBER PageContainingWorkingSet; 00235 MMPTE TempPte; 00236 PMMPTE LastPte; 00237 PMMPTE PointerFillPte; 00238 PMMPTE CurrentAddressSpacePde; 00239 PEPROCESS CurrentProcess; 00240 KIRQL OldIrql; 00241 PMMPFN Pfn1; 00242 ULONG Color; 00243 #if defined (_X86PAE_) 00244 ULONG TopQuad; 00245 MMPTE TopPte; 00246 PPAE_ENTRY PaeVa; 00247 PFN_NUMBER PageDirectoryIndex2; 00248 KIRQL OldIrql2; 00249 ULONG i; 00250 PFN_NUMBER HyperSpaceIndex2; 00251 PVOID PoolBlock; 00252 #endif 00253 #if defined(_IA64_) 00254 PFN_NUMBER SessionParentIndex; 00255 #endif 00256 00257 // 00258 // Get the PFN LOCK to prevent another thread in this 00259 // process from using hyper space and to get physical pages. 00260 // 00261 00262 CurrentProcess = PsGetCurrentProcess (); 00263 00264 // 00265 // Charge commitment for the page directory pages, working set page table 00266 // page, and working set list. 00267 // 00268 00269 if (MiChargeCommitment (MM_PROCESS_COMMIT_CHARGE, NULL) == FALSE) { 00270 return FALSE; 00271 } 00272 00273 MM_TRACK_COMMIT (MM_DBG_COMMIT_PROCESS_CREATE, MM_PROCESS_COMMIT_CHARGE); 00274 00275 NewProcess->NextPageColor = (USHORT)(RtlRandom(&MmProcessColorSeed)); 00276 KeInitializeSpinLock (&NewProcess->HyperSpaceLock); 00277 00278 #if defined (_X86PAE_) 00279 TopQuad = MiPaeAllocate (&PaeVa); 00280 if (TopQuad == 0) { 00281 MiReturnCommitment (MM_PROCESS_COMMIT_CHARGE); 00282 return FALSE; 00283 } 00284 00285 // 00286 // This page must be in the first 4GB of RAM. 00287 // 00288 00289 ASSERT ((TopQuad >> PAGE_SHIFT) <= MM_HIGHEST_PAE_PAGE); 00290 #endif 00291 00292 LOCK_WS (CurrentProcess); 00293 00294 LOCK_PFN (OldIrql); 00295 00296 // 00297 // Check to make sure the physical pages are available. 00298 // 00299 00300 if (MmResidentAvailablePages <= (SPFN_NUMBER)MinimumWorkingSetSize) { 00301 00302 #if defined (_X86PAE_) 00303 PoolBlock = MiPaeFree (PaeVa); 00304 #endif 00305 00306 UNLOCK_PFN (OldIrql); 00307 UNLOCK_WS (CurrentProcess); 00308 MiReturnCommitment (MM_PROCESS_COMMIT_CHARGE); 00309 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PROCESS_CREATE_FAILURE1, MM_PROCESS_COMMIT_CHARGE); 00310 00311 #if defined (_X86PAE_) 00312 if (PoolBlock != NULL) { 00313 MiPaeFreeEntirePage (PoolBlock); 00314 } 00315 #endif 00316 // 00317 // Indicate no directory base was allocated. 00318 // 00319 00320 return FALSE; 00321 } 00322 00323 MmResidentAvailablePages -= MinimumWorkingSetSize; 00324 MM_BUMP_COUNTER(6, MinimumWorkingSetSize); 00325 MmProcessCommit += MM_PROCESS_COMMIT_CHARGE; 00326 00327 NewProcess->AddressSpaceInitialized = 1; 00328 NewProcess->Vm.MinimumWorkingSetSize = MinimumWorkingSetSize; 00329 00330 // 00331 // Allocate a page directory (parent for 64-bit systems) page. 00332 // 00333 00334 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00335 00336 Color = MI_PAGE_COLOR_PTE_PROCESS (PDE_BASE, 00337 &CurrentProcess->NextPageColor); 00338 00339 PageDirectoryIndex = MiRemoveZeroPageIfAny (Color); 00340 if (PageDirectoryIndex == 0) { 00341 PageDirectoryIndex = MiRemoveAnyPage (Color); 00342 UNLOCK_PFN (OldIrql); 00343 MiZeroPhysicalPage (PageDirectoryIndex, Color); 00344 LOCK_PFN (OldIrql); 00345 } 00346 00347 #if defined (_X86PAE_) 00348 TempPte = ValidPdePde; 00349 MI_SET_GLOBAL_STATE (TempPte, 0); 00350 00351 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 00352 00353 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00354 00355 Color = MI_PAGE_COLOR_PTE_PROCESS (PDE_BASE, 00356 &CurrentProcess->NextPageColor); 00357 00358 PageDirectoryIndex2 = MiRemoveZeroPageIfAny (Color); 00359 if (PageDirectoryIndex2 == 0) { 00360 PageDirectoryIndex2 = MiRemoveAnyPage (Color); 00361 UNLOCK_PFN (OldIrql); 00362 MiZeroPhysicalPage (PageDirectoryIndex2, Color); 00363 LOCK_PFN (OldIrql); 00364 } 00365 00366 // 00367 // Recursively map each page directory page so it points to itself. 00368 // 00369 00370 TempPte.u.Hard.PageFrameNumber = PageDirectoryIndex2; 00371 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageDirectoryIndex, 00372 &OldIrql2); 00373 PointerPte[i] = TempPte; 00374 MiUnmapPageInHyperSpace (OldIrql2); 00375 TopPte.u.Long = TempPte.u.Long & ~MM_PAE_PDPTE_MASK; 00376 PaeVa->PteEntry[i].u.Long = TopPte.u.Long; 00377 } 00378 00379 // 00380 // Recursively map the topmost page directory page so it points to itself. 00381 // 00382 00383 TempPte.u.Hard.PageFrameNumber = PageDirectoryIndex; 00384 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageDirectoryIndex, &OldIrql2); 00385 PointerPte[PD_PER_SYSTEM - 1] = TempPte; 00386 MiUnmapPageInHyperSpace (OldIrql2); 00387 TopPte.u.Long = TempPte.u.Long & ~MM_PAE_PDPTE_MASK; 00388 PaeVa->PteEntry[PD_PER_SYSTEM - 1].u.Long = TopPte.u.Long; 00389 NewProcess->PaePageDirectoryPage = PageDirectoryIndex; 00390 NewProcess->PaeTop = (PVOID)PaeVa; 00391 DirectoryTableBase[0] = TopQuad; 00392 #else 00393 INITIALIZE_DIRECTORY_TABLE_BASE(&DirectoryTableBase[0], PageDirectoryIndex); 00394 #endif 00395 00396 #if defined (_WIN64) 00397 00398 PointerPpe = KSEG_ADDRESS (PageDirectoryIndex); 00399 TempPte = ValidPdePde; 00400 00401 // 00402 // Map the top level page directory parent page recursively onto itself. 00403 // 00404 00405 TempPte.u.Hard.PageFrameNumber = PageDirectoryIndex; 00406 00407 #if defined (_AXP64_) 00408 ASSERT (TempPte.u.Hard.Global == 0); 00409 PointerPpe[MiGetPpeOffset(PDE_TBASE)] = TempPte; 00410 #endif 00411 00412 #if defined(_IA64_) 00413 00414 // 00415 // For IA64, the self-mapped entry is forced to be the last entry of 00416 // PPE table. 00417 // 00418 00419 PointerPpe[(PDE_SELFMAP & 00420 ((sizeof(MMPTE)*PTE_PER_PAGE) - 1))/sizeof(MMPTE)] = TempPte; 00421 00422 #endif 00423 00424 // 00425 // Allocate the page directory for hyper space and map this directory 00426 // page into the page directory parent page. 00427 // 00428 00429 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00430 00431 Color = MI_PAGE_COLOR_PTE_PROCESS (MiGetPpeAddress(HYPER_SPACE), 00432 &CurrentProcess->NextPageColor); 00433 00434 HyperDirectoryIndex = MiRemoveZeroPageIfAny (Color); 00435 if (HyperDirectoryIndex == 0) { 00436 HyperDirectoryIndex = MiRemoveAnyPage (Color); 00437 UNLOCK_PFN (OldIrql); 00438 MiZeroPhysicalPage (HyperDirectoryIndex, Color); 00439 LOCK_PFN (OldIrql); 00440 } 00441 00442 TempPte.u.Hard.PageFrameNumber = HyperDirectoryIndex; 00443 PointerPpe[MiGetPpeOffset(HYPER_SPACE)] = TempPte; 00444 00445 #if defined (_IA64_) 00446 00447 // 00448 // Allocate the page directory parent for the session space 00449 // 00450 00451 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00452 00453 Color = MI_PAGE_COLOR_PTE_PROCESS (MiGetPpeAddress(SESSION_SPACE_DEFAULT), 00454 &CurrentProcess->NextPageColor); 00455 00456 SessionParentIndex = MiRemoveZeroPageIfAny (Color); 00457 if (SessionParentIndex == 0) { 00458 SessionParentIndex = MiRemoveAnyPage (Color); 00459 UNLOCK_PFN (OldIrql); 00460 MiZeroPhysicalPage (SessionParentIndex, Color); 00461 LOCK_PFN (OldIrql); 00462 } 00463 00464 INITIALIZE_DIRECTORY_TABLE_BASE(&NewProcess->Pcb.SessionParentBase, SessionParentIndex); 00465 00466 PointerPpe = KSEG_ADDRESS (SessionParentIndex); 00467 00468 TempPte.u.Hard.PageFrameNumber = SessionParentIndex; 00469 00470 PointerPpe[(PDE_SSELFMAP & 00471 ((sizeof(MMPTE)*PTE_PER_PAGE) - 1))/sizeof(MMPTE)] = TempPte; 00472 00473 #endif // _IA64_ 00474 00475 #endif 00476 00477 // 00478 // Allocate the hyper space page table page. 00479 // 00480 00481 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00482 00483 Color = MI_PAGE_COLOR_PTE_PROCESS (MiGetPdeAddress(HYPER_SPACE), 00484 &CurrentProcess->NextPageColor); 00485 00486 HyperSpaceIndex = MiRemoveZeroPageIfAny (Color); 00487 if (HyperSpaceIndex == 0) { 00488 HyperSpaceIndex = MiRemoveAnyPage (Color); 00489 UNLOCK_PFN (OldIrql); 00490 MiZeroPhysicalPage (HyperSpaceIndex, Color); 00491 LOCK_PFN (OldIrql); 00492 } 00493 00494 #if defined (_WIN64) 00495 PointerPde = KSEG_ADDRESS (HyperDirectoryIndex); 00496 TempPte.u.Hard.PageFrameNumber = HyperSpaceIndex; 00497 PointerPde[MiGetPdeOffset(HYPER_SPACE)] = TempPte; 00498 #endif 00499 00500 #if defined (_X86PAE_) 00501 00502 // 00503 // Allocate the second hyper space page table page. 00504 // Save it in the first PTE used by the first hyperspace PDE. 00505 // 00506 00507 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00508 00509 Color = MI_PAGE_COLOR_PTE_PROCESS (MiGetPdeAddress(HYPER_SPACE2), 00510 &CurrentProcess->NextPageColor); 00511 00512 HyperSpaceIndex2 = MiRemoveZeroPageIfAny (Color); 00513 if (HyperSpaceIndex2 == 0) { 00514 HyperSpaceIndex2 = MiRemoveAnyPage (Color); 00515 UNLOCK_PFN (OldIrql); 00516 MiZeroPhysicalPage (HyperSpaceIndex2, Color); 00517 LOCK_PFN (OldIrql); 00518 } 00519 00520 // 00521 // Unlike DirectoryTableBase[0], the HyperSpaceIndex is stored as an 00522 // absolute PFN and does not need to be below 4GB. 00523 // 00524 00525 DirectoryTableBase[1] = HyperSpaceIndex; 00526 #else 00527 INITIALIZE_DIRECTORY_TABLE_BASE(&DirectoryTableBase[1], HyperSpaceIndex); 00528 #endif 00529 00530 // 00531 // Remove page for the working set list. 00532 // 00533 00534 MiEnsureAvailablePageOrWait (CurrentProcess, NULL); 00535 00536 Color = MI_PAGE_COLOR_VA_PROCESS (MmWorkingSetList, 00537 &CurrentProcess->NextPageColor); 00538 00539 PageContainingWorkingSet = MiRemoveZeroPageIfAny (Color); 00540 if (PageContainingWorkingSet == 0) { 00541 PageContainingWorkingSet = MiRemoveAnyPage (Color); 00542 UNLOCK_PFN (OldIrql); 00543 MiZeroPhysicalPage (PageContainingWorkingSet, Color); 00544 LOCK_PFN (OldIrql); 00545 } 00546 00547 // 00548 // Release the PFN mutex as the needed pages have been allocated. 00549 // 00550 00551 UNLOCK_PFN (OldIrql); 00552 00553 NewProcess->WorkingSetPage = PageContainingWorkingSet; 00554 00555 // 00556 // Initialize the page reserved for hyper space. 00557 // 00558 00559 MI_INITIALIZE_HYPERSPACE_MAP (HyperSpaceIndex); 00560 00561 // 00562 // Set the PTE address in the PFN for the top level page directory page. 00563 // 00564 00565 #if defined (_WIN64) 00566 00567 Pfn1 = MI_PFN_ELEMENT (PageDirectoryIndex); 00568 00569 ASSERT (Pfn1->u3.e1.PageColor == 0); 00570 00571 CONSISTENCY_LOCK_PFN (OldIrql); 00572 00573 Pfn1->PteAddress = MiGetPteAddress(PDE_TBASE); 00574 00575 CONSISTENCY_UNLOCK_PFN (OldIrql); 00576 00577 // 00578 // Set the PTE address in the PFN for the hyper space page directory page. 00579 // 00580 00581 Pfn1 = MI_PFN_ELEMENT (HyperDirectoryIndex); 00582 00583 ASSERT (Pfn1->u3.e1.PageColor == 0); 00584 00585 CONSISTENCY_LOCK_PFN (OldIrql); 00586 00587 Pfn1->PteAddress = MiGetPpeAddress(HYPER_SPACE); 00588 00589 CONSISTENCY_UNLOCK_PFN (OldIrql); 00590 00591 #if defined (_AXP64_) 00592 00593 // 00594 // All of the system mappings are global. 00595 // 00596 00597 MI_SET_GLOBAL_STATE (TempPte, 1); 00598 00599 PointerFillPte = &PointerPpe[MiGetPpeOffset(MM_SYSTEM_SPACE_START)]; 00600 CurrentAddressSpacePde = MiGetPpeAddress(MM_SYSTEM_SPACE_START); 00601 RtlCopyMemory (PointerFillPte, 00602 CurrentAddressSpacePde, 00603 ((1 + (MiGetPpeAddress(MM_SYSTEM_SPACE_END) - 00604 MiGetPpeAddress(MM_SYSTEM_SPACE_START))) * sizeof(MMPTE))); 00605 // 00606 // Session space and win32k.sys are local on Hydra configurations. 00607 // However, as an optimization, it can be made global on non-Hydra. 00608 // 00609 00610 if (MiHydra == TRUE) { 00611 MI_SET_GLOBAL_STATE (TempPte, 0); 00612 } 00613 00614 PointerFillPte = &PointerPpe[MiGetPpeOffset(MM_SESSION_SPACE_DEFAULT)]; 00615 CurrentAddressSpacePde = MiGetPpeAddress(MM_SESSION_SPACE_DEFAULT); 00616 MI_WRITE_VALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00617 00618 #endif 00619 00620 #if defined(_IA64_) 00621 if ((MiHydra == TRUE) && (CurrentProcess->Vm.u.Flags.ProcessInSession != 0)) { 00622 PointerPpe = KSEG_ADDRESS(SessionParentIndex); 00623 PointerFillPte = &PointerPpe[MiGetPpeOffset(MM_SESSION_SPACE_DEFAULT)]; 00624 CurrentAddressSpacePde = MiGetPpeAddress(MM_SESSION_SPACE_DEFAULT); 00625 MI_WRITE_VALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00626 } 00627 #endif 00628 00629 #else // the following is for !WIN64 only 00630 00631 #if defined (_X86PAE_) 00632 00633 // 00634 // Stash the second hyperspace PDE in the first PTE for the initial 00635 // hyperspace entry. 00636 // 00637 00638 TempPte = ValidPdePde; 00639 TempPte.u.Hard.PageFrameNumber = HyperSpaceIndex2; 00640 MI_SET_GLOBAL_STATE (TempPte, 0); 00641 00642 PointerPte = (PMMPTE)MiMapPageInHyperSpace (HyperSpaceIndex, &OldIrql2); 00643 PointerPte[0] = TempPte; 00644 MiUnmapPageInHyperSpace (OldIrql2); 00645 00646 #endif 00647 00648 // 00649 // Set the PTE address in the PFN for the page directory page. 00650 // 00651 00652 Pfn1 = MI_PFN_ELEMENT (PageDirectoryIndex); 00653 00654 ASSERT (Pfn1->u3.e1.PageColor == 0); 00655 00656 CONSISTENCY_LOCK_PFN (OldIrql); 00657 00658 Pfn1->PteAddress = (PMMPTE)PDE_BASE; 00659 00660 CONSISTENCY_UNLOCK_PFN (OldIrql); 00661 00662 TempPte = ValidPdePde; 00663 TempPte.u.Hard.PageFrameNumber = HyperSpaceIndex; 00664 MI_SET_GLOBAL_STATE (TempPte, 0); 00665 00666 // 00667 // Map the page directory page in hyperspace. 00668 // Note for PAE, this is the high 1GB virtual only. 00669 // 00670 00671 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageDirectoryIndex, &OldIrql); 00672 PointerPte[MiGetPdeOffset(HYPER_SPACE)] = TempPte; 00673 00674 #if defined (_X86PAE_) 00675 00676 // 00677 // Map in the second hyperspace page directory. 00678 // The page directory page is already recursively mapped. 00679 // 00680 00681 TempPte.u.Hard.PageFrameNumber = HyperSpaceIndex2; 00682 PointerPte[MiGetPdeOffset(HYPER_SPACE2)] = TempPte; 00683 00684 #else 00685 00686 // 00687 // Recursively map the page directory page so it points to itself. 00688 // 00689 00690 TempPte.u.Hard.PageFrameNumber = PageDirectoryIndex; 00691 PointerPte[MiGetPdeOffset(PTE_BASE)] = TempPte; 00692 00693 #endif 00694 00695 // 00696 // Map in the non paged portion of the system. 00697 // 00698 00699 #if defined(_ALPHA_) 00700 00701 PointerFillPte = &PointerPte[MiGetPdeOffset(MM_SYSTEM_SPACE_START)]; 00702 CurrentAddressSpacePde = MiGetPdeAddress(MM_SYSTEM_SPACE_START); 00703 RtlCopyMemory (PointerFillPte, 00704 CurrentAddressSpacePde, 00705 ((1 + (MiGetPdeAddress(MM_SYSTEM_SPACE_END) - 00706 MiGetPdeAddress(MM_SYSTEM_SPACE_START))) * sizeof(MMPTE))); 00707 00708 // 00709 // KSEG0 is identity-mapped on the Alpha. Copy the PDEs for this region. 00710 // 00711 00712 PointerFillPte = &PointerPte[MiGetPdeOffset(MM_KSEG0_BASE)]; 00713 CurrentAddressSpacePde = MiGetPdeAddress(MM_KSEG0_BASE); 00714 RtlCopyMemory (PointerFillPte, 00715 CurrentAddressSpacePde, 00716 MiGetPdeOffset(KSEG2_BASE-KSEG0_BASE) * sizeof(MMPTE)); 00717 00718 #else // the following is for x86 only 00719 00720 // 00721 // If the system has not been loaded at a biased address, then system PDEs 00722 // exist in the 2gb->3gb range which must be copied. 00723 // 00724 00725 #if defined (_X86PAE_) 00726 00727 // 00728 // For the PAE case, only the last page directory is currently mapped, so 00729 // only copy the system PDEs for the last 1GB - any that need copying in 00730 // the 2gb->3gb range will be done a little later. 00731 // 00732 00733 if (MmVirtualBias != 0) { 00734 PointerFillPte = &PointerPte[MiGetPdeOffset(CODE_START + MmVirtualBias)]; 00735 CurrentAddressSpacePde = MiGetPdeAddress(CODE_START + MmVirtualBias); 00736 00737 RtlCopyMemory (PointerFillPte, 00738 CurrentAddressSpacePde, 00739 (((1 + CODE_END) - CODE_START) / MM_VA_MAPPED_BY_PDE) * sizeof(MMPTE)); 00740 } 00741 #else 00742 PointerFillPte = &PointerPte[MiGetPdeOffset(CODE_START + MmVirtualBias)]; 00743 CurrentAddressSpacePde = MiGetPdeAddress(CODE_START + MmVirtualBias); 00744 00745 RtlCopyMemory (PointerFillPte, 00746 CurrentAddressSpacePde, 00747 (((1 + CODE_END) - CODE_START) / MM_VA_MAPPED_BY_PDE) * sizeof(MMPTE)); 00748 #endif 00749 00750 LastPte = &PointerPte[MiGetPdeOffset(NON_PAGED_SYSTEM_END)]; 00751 PointerFillPte = &PointerPte[MiGetPdeOffset(MmNonPagedSystemStart)]; 00752 CurrentAddressSpacePde = MiGetPdeAddress(MmNonPagedSystemStart); 00753 00754 RtlCopyMemory (PointerFillPte, 00755 CurrentAddressSpacePde, 00756 ((1 + (MiGetPdeAddress(NON_PAGED_SYSTEM_END) - 00757 CurrentAddressSpacePde))) * sizeof(MMPTE)); 00758 00759 // 00760 // Map in the system cache page table pages. 00761 // 00762 00763 LastPte = &PointerPte[MiGetPdeOffset(MmSystemCacheEnd)]; 00764 PointerFillPte = &PointerPte[MiGetPdeOffset(MM_SYSTEM_CACHE_WORKING_SET)]; 00765 CurrentAddressSpacePde = MiGetPdeAddress(MM_SYSTEM_CACHE_WORKING_SET); 00766 00767 RtlCopyMemory (PointerFillPte, 00768 CurrentAddressSpacePde, 00769 ((1 + (MiGetPdeAddress(MmSystemCacheEnd) - 00770 CurrentAddressSpacePde))) * sizeof(MMPTE)); 00771 00772 #if !defined (_X86PAE_) 00773 // 00774 // Map in any additional system cache page table pages. 00775 // 00776 00777 if (MiSystemCacheEndExtra != MmSystemCacheEnd) { 00778 LastPte = &PointerPte[MiGetPdeOffset(MiSystemCacheEndExtra)]; 00779 PointerFillPte = &PointerPte[MiGetPdeOffset(MiSystemCacheStartExtra)]; 00780 CurrentAddressSpacePde = MiGetPdeAddress(MiSystemCacheStartExtra); 00781 00782 RtlCopyMemory (PointerFillPte, 00783 CurrentAddressSpacePde, 00784 ((1 + (MiGetPdeAddress(MiSystemCacheEndExtra) - 00785 CurrentAddressSpacePde))) * sizeof(MMPTE)); 00786 } 00787 #endif 00788 00789 #endif // end of x86 specific else 00790 00791 #if !defined (_X86PAE_) 00792 if (MiHydra == TRUE) { 00793 00794 // 00795 // Copy the bootstrap entry for session space. 00796 // The rest is faulted in as needed. 00797 // 00798 00799 PointerFillPte = &PointerPte[MiGetPdeOffset(MmSessionSpace)]; 00800 CurrentAddressSpacePde = MiGetPdeAddress(MmSessionSpace); 00801 if (CurrentAddressSpacePde->u.Hard.Valid == 1) { 00802 MI_WRITE_VALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00803 } 00804 else { 00805 MI_WRITE_INVALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00806 } 00807 } 00808 #endif 00809 00810 #if defined(_X86_) 00811 00812 // 00813 // Map in the additional system PTE range if present. 00814 // 00815 00816 #if !defined (_X86PAE_) 00817 if (MiNumberOfExtraSystemPdes) { 00818 00819 PointerFillPte = &PointerPte[MiGetPdeOffset(KSTACK_POOL_START)]; 00820 CurrentAddressSpacePde = MiGetPdeAddress(KSTACK_POOL_START); 00821 00822 RtlCopyMemory (PointerFillPte, 00823 CurrentAddressSpacePde, 00824 MiNumberOfExtraSystemPdes * sizeof(MMPTE)); 00825 } 00826 #endif 00827 #endif 00828 00829 MiUnmapPageInHyperSpace (OldIrql); 00830 00831 #if defined (_X86PAE_) 00832 00833 // 00834 // Map all the virtual space in the 2GB->3GB range when it's not user space. 00835 // 00836 00837 if (MmVirtualBias == 0) { 00838 00839 PageDirectoryIndex = MI_GET_PAGE_FRAME_FROM_PTE (&PaeVa->PteEntry[PD_PER_SYSTEM - 2]); 00840 00841 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageDirectoryIndex, &OldIrql); 00842 00843 PointerFillPte = &PointerPte[MiGetPdeOffset(CODE_START)]; 00844 CurrentAddressSpacePde = MiGetPdeAddress(CODE_START); 00845 00846 RtlCopyMemory (PointerFillPte, 00847 CurrentAddressSpacePde, 00848 (((1 + CODE_END) - CODE_START) / MM_VA_MAPPED_BY_PDE) * sizeof(MMPTE)); 00849 00850 if (MiSystemCacheEndExtra != MmSystemCacheEnd) { 00851 LastPte = &PointerPte[MiGetPdeOffset(MiSystemCacheEndExtra)]; 00852 PointerFillPte = &PointerPte[MiGetPdeOffset(MiSystemCacheStartExtra)]; 00853 CurrentAddressSpacePde = MiGetPdeAddress(MiSystemCacheStartExtra); 00854 00855 RtlCopyMemory (PointerFillPte, 00856 CurrentAddressSpacePde, 00857 ((1 + (MiGetPdeAddress(MiSystemCacheEndExtra) - 00858 CurrentAddressSpacePde))) * sizeof(MMPTE)); 00859 } 00860 00861 if (MiHydra == TRUE) { 00862 00863 // 00864 // Copy the bootstrap entry for session space. 00865 // The rest is faulted in as needed. 00866 // 00867 00868 PointerFillPte = &PointerPte[MiGetPdeOffset(MmSessionSpace)]; 00869 CurrentAddressSpacePde = MiGetPdeAddress(MmSessionSpace); 00870 if (CurrentAddressSpacePde->u.Hard.Valid == 1) { 00871 MI_WRITE_VALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00872 } 00873 else { 00874 MI_WRITE_INVALID_PTE (PointerFillPte, *CurrentAddressSpacePde); 00875 } 00876 } 00877 00878 if (MiNumberOfExtraSystemPdes) { 00879 00880 PointerFillPte = &PointerPte[MiGetPdeOffset(KSTACK_POOL_START)]; 00881 CurrentAddressSpacePde = MiGetPdeAddress(KSTACK_POOL_START); 00882 00883 RtlCopyMemory (PointerFillPte, 00884 CurrentAddressSpacePde, 00885 MiNumberOfExtraSystemPdes * sizeof(MMPTE)); 00886 } 00887 MiUnmapPageInHyperSpace (OldIrql); 00888 } 00889 #endif 00890 00891 #endif // end of !WIN64 specific else 00892 00893 // 00894 // Up the session space reference count. 00895 // 00896 00897 if (MiHydra == TRUE) { 00898 MiSessionAddProcess (NewProcess); 00899 } 00900 00901 // 00902 // Release working set mutex and lower IRQL. 00903 // 00904 00905 UNLOCK_WS (CurrentProcess); 00906 00907 return TRUE; 00908 }

PTEB MmCreateTeb IN PEPROCESS  TargetProcess,
IN PINITIAL_TEB  InitialTeb,
IN PCLIENT_ID  ClientId
 

Definition at line 4314 of file procsup.c.

References BBTBuffer, InitialTeb, KeAttachProcess(), KeDetachProcess(), MiCreatePebOrTeb(), NULL, and USHORT.

Referenced by PspCreateThread().

04322 : 04323 04324 This routine creates a TEB page within the target process 04325 and copies the initial TEB values into it. 04326 04327 Arguments: 04328 04329 TargetProcess - Supplies a pointer to the process in which to create 04330 and initialize the TEB. 04331 04332 InitialTeb - Supplies a pointer to the initial TEB to copy into the 04333 newly created TEB. 04334 04335 Return Value: 04336 04337 Returns the address of the base of the newly created TEB. 04338 04339 Can raise exceptions if no address space is available for the TEB or 04340 the user has exceeded quota (non-paged, pagefile, commit). 04341 04342 Environment: 04343 04344 Kernel mode. 04345 04346 --*/ 04347 04348 { 04349 PTEB TebBase; 04350 04351 // 04352 // If the specified process is not the current process, attach 04353 // to the specified process. 04354 // 04355 04356 KeAttachProcess (&TargetProcess->Pcb); 04357 04358 TebBase = (PTEB)MiCreatePebOrTeb (TargetProcess, 04359 (ULONG)sizeof(TEB)); 04360 04361 // 04362 // Initialize the TEB. 04363 // 04364 04365 #if defined(_WIN64) 04366 TebBase->NtTib.ExceptionList = NULL; 04367 #else 04368 TebBase->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 04369 #endif 04370 04371 TebBase->NtTib.SubSystemTib = NULL; 04372 TebBase->NtTib.Version = OS2_VERSION; 04373 TebBase->NtTib.ArbitraryUserPointer = NULL; 04374 TebBase->NtTib.Self = (PNT_TIB)TebBase; 04375 TebBase->EnvironmentPointer = NULL; 04376 TebBase->ProcessEnvironmentBlock = TargetProcess->Peb; 04377 TebBase->ClientId = *ClientId; 04378 TebBase->RealClientId = *ClientId; 04379 04380 if ((InitialTeb->OldInitialTeb.OldStackBase == NULL) && 04381 (InitialTeb->OldInitialTeb.OldStackLimit == NULL)) { 04382 04383 TebBase->NtTib.StackBase = InitialTeb->StackBase; 04384 TebBase->NtTib.StackLimit = InitialTeb->StackLimit; 04385 TebBase->DeallocationStack = InitialTeb->StackAllocationBase; 04386 04387 #if defined(_IA64_) 04388 TebBase->BStoreLimit = InitialTeb->BStoreLimit; 04389 TebBase->DeallocationBStore = (PCHAR)InitialTeb->StackBase 04390 + ((ULONG_PTR)InitialTeb->StackBase - (ULONG_PTR)InitialTeb->StackAllocationBase); 04391 #endif 04392 04393 } 04394 else { 04395 TebBase->NtTib.StackBase = InitialTeb->OldInitialTeb.OldStackBase; 04396 TebBase->NtTib.StackLimit = InitialTeb->OldInitialTeb.OldStackLimit; 04397 } 04398 04399 TebBase->StaticUnicodeString.Buffer = TebBase->StaticUnicodeBuffer; 04400 TebBase->StaticUnicodeString.MaximumLength = (USHORT)sizeof( TebBase->StaticUnicodeBuffer ); 04401 TebBase->StaticUnicodeString.Length = (USHORT)0; 04402 04403 // 04404 // Used for BBT of ntdll and kernel32.dll. 04405 // 04406 04407 TebBase->ReservedForPerf = BBTBuffer; 04408 04409 KeDetachProcess(); 04410 return TebBase; 04411 }

VOID MmDeleteKernelStack IN PVOID  PointerKernelStack,
IN BOOLEAN  LargeStack
 

Definition at line 2723 of file procsup.c.

References BYTES_TO_PAGES, DbgPrint, LOCK_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiDecrementShareAndValidCount, MiDecrementShareCountOnly, MiGetPteAddress, MiReleaseSystemPtes(), MiReturnCommitment(), MM_BUMP_COUNTER, MM_DBG_COMMIT_RETURN_KERNEL_STACK_DELETE, MM_STACK_ALIGNMENT, MM_TRACK_COMMIT, MmFirstDeadKernelStack, MmKernelStackPages, MmKernelStackResident, MmLargeStacks, MmMaximumDeadKernelStacks, MmNumberDeadKernelStacks, MmProcessCommit, MmResidentAvailablePages, MmSmallStacks, PERFINFO_DELETE_STACK, _MMPFN::PteAddress, _MMPFN::PteFrame, SystemPteSpace, _MMPTE::u, _MMPFN::u1, and UNLOCK_PFN.

Referenced by KeStartAllProcessors(), PsConvertToGuiThread(), PspCreateThread(), PspReaper(), and PspThreadDelete().

02730 : 02731 02732 This routine deletes a kernel stack and the no-access page within 02733 the non-pagable portion of the system address space. 02734 02735 Arguments: 02736 02737 PointerKernelStack - Supplies a pointer to the base of the kernel stack. 02738 02739 LargeStack - Supplies the value TRUE if a large stack is being deleted. 02740 FALSE if a small stack is to be deleted. 02741 02742 Return Value: 02743 02744 None. 02745 02746 Environment: 02747 02748 Kernel mode. APCs Disabled. 02749 02750 --*/ 02751 02752 { 02753 PMMPTE PointerPte; 02754 PMMPFN Pfn1; 02755 PFN_NUMBER NumberOfPages; 02756 ULONG NumberOfPtes; 02757 PFN_NUMBER PageFrameIndex; 02758 ULONG i; 02759 KIRQL OldIrql; 02760 MMPTE PteContents; 02761 02762 if (LargeStack) { 02763 #if defined(_IA64_) 02764 NumberOfPtes = BYTES_TO_PAGES (KERNEL_LARGE_STACK_SIZE + KERNEL_LARGE_BSTORE_SIZE); 02765 #else 02766 NumberOfPtes = BYTES_TO_PAGES (KERNEL_LARGE_STACK_SIZE); 02767 #endif 02768 } else { 02769 #if defined(_IA64_) 02770 NumberOfPtes = BYTES_TO_PAGES (KERNEL_STACK_SIZE + KERNEL_BSTORE_SIZE); 02771 #else 02772 NumberOfPtes = BYTES_TO_PAGES (KERNEL_STACK_SIZE); 02773 #endif 02774 } 02775 02776 PointerPte = MiGetPteAddress (PointerKernelStack); 02777 02778 // 02779 // PointerPte points to the guard page, point to the previous 02780 // page before removing physical pages. 02781 // 02782 02783 PointerPte -= 1; 02784 02785 LOCK_PFN (OldIrql); 02786 02787 // 02788 // Check to see if the stack page should be placed on the dead 02789 // kernel stack page list. The dead kernel stack list is a 02790 // singly linked list of kernel stacks from terminated threads. 02791 // The stacks are saved on a linked list up to a maximum number 02792 // to avoid the overhead of flushing the entire TB on all processors 02793 // everytime a thread terminates. The TB on all processors must 02794 // be flushed as kernel stacks reside in the non paged system part 02795 // of the address space. 02796 // 02797 02798 if ((!LargeStack) && 02799 (MmNumberDeadKernelStacks < MmMaximumDeadKernelStacks)) { 02800 02801 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 02802 02803 #if DBG 02804 { 02805 ULONG i = MmNumberDeadKernelStacks; 02806 PMMPFN PfnList = MmFirstDeadKernelStack; 02807 02808 while (i > 0) { 02809 i--; 02810 if ((PfnList != MmKstacks[i].Pfn) || 02811 (PfnList->PteAddress != MmKstacks[i].Pte)) { 02812 DbgPrint("MMPROCSUP: kstacks %p %ld. %p\n", 02813 PfnList, i, MmKstacks[i].Pfn); 02814 DbgBreakPoint(); 02815 } 02816 PfnList = PfnList->u1.NextStackPfn; 02817 } 02818 MmKstacks[MmNumberDeadKernelStacks].Pte = Pfn1->PteAddress; 02819 MmKstacks[MmNumberDeadKernelStacks].Pfn = Pfn1; 02820 } 02821 #endif //DBG 02822 02823 MmNumberDeadKernelStacks += 1; 02824 Pfn1->u1.NextStackPfn = MmFirstDeadKernelStack; 02825 MmFirstDeadKernelStack = Pfn1; 02826 02827 PERFINFO_DELETE_STACK(PointerPte, NumberOfPtes); 02828 02829 UNLOCK_PFN (OldIrql); 02830 02831 return; 02832 } 02833 02834 #if defined(_IA64_) 02835 02836 // 02837 // Since PointerKernelStack points to the center of the stack space, 02838 // the size of kernel backing store needs to be added to get the 02839 // top of the stack space. 02840 // 02841 02842 PointerPte = MiGetPteAddress (LargeStack ? 02843 (PCHAR)PointerKernelStack+KERNEL_LARGE_BSTORE_SIZE : 02844 (PCHAR)PointerKernelStack+KERNEL_BSTORE_SIZE); 02845 02846 // 02847 // PointerPte points to the guard page, point to the previous 02848 // page before removing physical pages. 02849 // 02850 02851 PointerPte -= 1; 02852 02853 #endif 02854 02855 // 02856 // We have exceeded the limit of dead kernel stacks or this is a large 02857 // stack, delete this kernel stack. 02858 // 02859 02860 NumberOfPages = 0; 02861 for (i = 0; i < NumberOfPtes; i += 1) { 02862 02863 PteContents = *PointerPte; 02864 02865 if (PteContents.u.Hard.Valid == 1) { 02866 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&PteContents); 02867 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 02868 MiDecrementShareAndValidCount (Pfn1->PteFrame); 02869 02870 // 02871 // Set the pointer to PTE as empty so the page 02872 // is deleted when the reference count goes to zero. 02873 // 02874 02875 MI_SET_PFN_DELETED (Pfn1); 02876 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 02877 NumberOfPages += 1; 02878 } 02879 PointerPte -= 1; 02880 } 02881 02882 #if defined(_IA64_) 02883 MmKernelStackPages -= NumberOfPtes + 2 + (MM_STACK_ALIGNMENT?1:0); 02884 02885 MiReleaseSystemPtes (PointerPte, 02886 NumberOfPtes + 2 + (MM_STACK_ALIGNMENT?1:0), 02887 SystemPteSpace); 02888 #else 02889 MmKernelStackPages -= NumberOfPtes + 1 + (MM_STACK_ALIGNMENT?1:0); 02890 02891 MiReleaseSystemPtes (PointerPte, 02892 NumberOfPtes + 1 + (MM_STACK_ALIGNMENT?1:0), 02893 SystemPteSpace); 02894 #endif 02895 02896 // 02897 // Update the count of available resident pages. 02898 // 02899 02900 MmKernelStackResident -= NumberOfPages; 02901 MmResidentAvailablePages += NumberOfPages; 02902 MM_BUMP_COUNTER(10, NumberOfPages); 02903 MmProcessCommit -= NumberOfPtes; 02904 02905 MmLargeStacks -= LargeStack; 02906 MmSmallStacks -= !LargeStack; 02907 UNLOCK_PFN (OldIrql); 02908 02909 // 02910 // Return commitment. 02911 // 02912 02913 MiReturnCommitment (NumberOfPtes); 02914 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_KERNEL_STACK_DELETE, NumberOfPtes); 02915 02916 return; 02917 }

VOID MmDeleteProcessAddressSpace IN PEPROCESS  Process  ) 
 

Definition at line 1398 of file procsup.c.

References ASSERT, FreePageList, HYPER_SPACE, LOCK_PFN, MI_GET_DIRECTORY_FRAME_FROM_PROCESS, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiContractPagingFiles(), MiDecrementShareAndValidCount, MiDecrementShareCountOnly, MiGetPpeOffset, MiInsertPageInList(), MiMapPageInHyperSpace(), MiReturnCommitment(), MiUnmapPageInHyperSpace, MM_BUMP_COUNTER, MM_DBG_COMMIT_RETURN_PROCESS_DELETE, MM_PROCESS_COMMIT_CHARGE, MM_PROCESS_CREATE_CHARGE, MM_TRACK_COMMIT, MmPageLocationList, MmProcessCommit, MmResidentAvailablePages, NULL, _MMPFN::PteFrame, _MMPFN::u3, and UNLOCK_PFN.

Referenced by PspProcessDelete().

01404 : 01405 01406 This routine deletes a process's Page Directory and working set page. 01407 01408 Arguments: 01409 01410 Process - Supplies a pointer to the deleted process. 01411 01412 Return Value: 01413 01414 None. 01415 01416 Environment: 01417 01418 Kernel mode. APCs Disabled. 01419 01420 --*/ 01421 01422 { 01423 PMMPFN Pfn1; 01424 KIRQL OldIrql; 01425 PFN_NUMBER PageFrameIndex; 01426 PFN_NUMBER PageFrameIndex2; 01427 #if defined (_WIN64) 01428 PMMPTE PageDirectoryParent; 01429 PMMPTE Ppe; 01430 #endif 01431 #if defined (_X86PAE_) 01432 ULONG i; 01433 KIRQL OldIrql2; 01434 PMMPTE PointerPte; 01435 PVOID PoolBlock; 01436 PFN_NUMBER PageDirectories[PD_PER_SYSTEM]; 01437 01438 PoolBlock = NULL; 01439 #endif 01440 01441 // 01442 // Return commitment. 01443 // 01444 01445 MiReturnCommitment (MM_PROCESS_COMMIT_CHARGE); 01446 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PROCESS_DELETE, MM_PROCESS_COMMIT_CHARGE); 01447 ASSERT (Process->CommitCharge == 0); 01448 01449 // 01450 // Remove the working set list page from the deleted process. 01451 // 01452 01453 Pfn1 = MI_PFN_ELEMENT (Process->WorkingSetPage); 01454 01455 LOCK_PFN (OldIrql); 01456 MmProcessCommit -= MM_PROCESS_COMMIT_CHARGE; 01457 01458 if (Process->AddressSpaceInitialized == 2) { 01459 01460 MI_SET_PFN_DELETED (Pfn1); 01461 01462 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01463 MiDecrementShareCountOnly (Process->WorkingSetPage); 01464 01465 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01466 01467 // 01468 // Remove the hyper space page table page from the deleted process. 01469 // 01470 01471 #if defined (_X86PAE_) 01472 01473 PageFrameIndex = (PFN_NUMBER)Process->Pcb.DirectoryTableBase[1]; 01474 // 01475 // Remove the second hyper space page table page. 01476 // 01477 01478 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageFrameIndex, &OldIrql2); 01479 PageFrameIndex2 = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte); 01480 MiUnmapPageInHyperSpace (OldIrql2); 01481 01482 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex2); 01483 01484 MI_SET_PFN_DELETED (Pfn1); 01485 01486 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01487 MiDecrementShareCountOnly (PageFrameIndex2); 01488 01489 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01490 #else 01491 PageFrameIndex = 01492 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(Process->Pcb.DirectoryTableBase[1]))); 01493 #endif 01494 01495 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01496 01497 MI_SET_PFN_DELETED (Pfn1); 01498 01499 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01500 MiDecrementShareCountOnly (PageFrameIndex); 01501 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01502 01503 // 01504 // Remove the page directory page. 01505 // 01506 01507 PageFrameIndex = MI_GET_DIRECTORY_FRAME_FROM_PROCESS(Process); 01508 01509 #if defined (_X86PAE_) 01510 01511 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageFrameIndex, &OldIrql2); 01512 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 01513 PageDirectories[i] = MI_GET_PAGE_FRAME_FROM_PTE(&PointerPte[i]); 01514 } 01515 MiUnmapPageInHyperSpace (OldIrql2); 01516 01517 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 01518 Pfn1 = MI_PFN_ELEMENT (PageDirectories[i]); 01519 01520 MI_SET_PFN_DELETED (Pfn1); 01521 01522 MiDecrementShareAndValidCount (PageDirectories[i]); 01523 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01524 01525 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01526 } 01527 #endif 01528 01529 #if defined (_WIN64) 01530 01531 // 01532 // Get a pointer to the top-level page directory parent page via 01533 // its KSEG0 address. 01534 // 01535 01536 PageDirectoryParent = KSEG_ADDRESS (PageFrameIndex); 01537 01538 // 01539 // Remove the hyper space page directory page from the deleted process. 01540 // 01541 01542 Ppe = &PageDirectoryParent[MiGetPpeOffset(HYPER_SPACE)]; 01543 PageFrameIndex2 = MI_GET_PAGE_FRAME_FROM_PTE(Ppe); 01544 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex2); 01545 01546 MI_SET_PFN_DELETED (Pfn1); 01547 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01548 MiDecrementShareCountOnly (PageFrameIndex2); 01549 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01550 #endif 01551 01552 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01553 01554 MI_SET_PFN_DELETED (Pfn1); 01555 01556 MiDecrementShareAndValidCount (PageFrameIndex); 01557 01558 MiDecrementShareCountOnly (PageFrameIndex); 01559 01560 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01561 01562 #if defined (_X86PAE_) 01563 01564 // 01565 // Free the page directory page pointers. 01566 // 01567 01568 PoolBlock = MiPaeFree ((PPAE_ENTRY)Process->PaeTop); 01569 #endif 01570 01571 #if defined(_IA64_) 01572 01573 // 01574 // Free the session space page directory parent page 01575 // 01576 01577 PageFrameIndex = 01578 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(Process->Pcb.SessionParentBase))); 01579 01580 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01581 01582 MI_SET_PFN_DELETED (Pfn1); 01583 01584 MiDecrementShareAndValidCount (Pfn1->PteFrame); 01585 01586 MiDecrementShareCountOnly (PageFrameIndex); 01587 01588 ASSERT ((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); 01589 01590 #endif 01591 01592 } else { 01593 01594 // 01595 // Process initialization never completed, just return the pages 01596 // to the free list. 01597 // 01598 01599 MiInsertPageInList (MmPageLocationList[FreePageList], 01600 Process->WorkingSetPage); 01601 01602 #if defined (_WIN64) 01603 01604 // 01605 // Get a pointer to the top-level page directory parent page via 01606 // its KSEG0 address. 01607 // 01608 01609 PageFrameIndex = 01610 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(Process->Pcb.DirectoryTableBase[0]))); 01611 01612 PageDirectoryParent = KSEG_ADDRESS (PageFrameIndex); 01613 01614 Ppe = &PageDirectoryParent[MiGetPpeOffset(HYPER_SPACE)]; 01615 PageFrameIndex2 = MI_GET_PAGE_FRAME_FROM_PTE(Ppe); 01616 01617 MiInsertPageInList (MmPageLocationList[FreePageList], 01618 PageFrameIndex2); 01619 #endif 01620 01621 #if defined (_X86PAE_) 01622 PageFrameIndex = MI_GET_DIRECTORY_FRAME_FROM_PROCESS(Process); 01623 01624 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageFrameIndex, &OldIrql2); 01625 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 01626 PageDirectories[i] = MI_GET_PAGE_FRAME_FROM_PTE(&PointerPte[i]); 01627 } 01628 MiUnmapPageInHyperSpace (OldIrql2); 01629 01630 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 01631 MiInsertPageInList (MmPageLocationList[FreePageList], 01632 PageDirectories[i]); 01633 } 01634 01635 // 01636 // Free the second hyper space page table page. 01637 // 01638 01639 PageFrameIndex = (PFN_NUMBER)Process->Pcb.DirectoryTableBase[1]; 01640 01641 PointerPte = (PMMPTE)MiMapPageInHyperSpace (PageFrameIndex, &OldIrql2); 01642 PageFrameIndex2 = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte); 01643 MiUnmapPageInHyperSpace (OldIrql2); 01644 MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex2); 01645 01646 // 01647 // Free the first hyper space page table page. 01648 // 01649 01650 MiInsertPageInList (MmPageLocationList[FreePageList], 01651 (PFN_NUMBER)Process->Pcb.DirectoryTableBase[1]); 01652 01653 MiInsertPageInList (MmPageLocationList[FreePageList], 01654 MI_GET_DIRECTORY_FRAME_FROM_PROCESS(Process)); 01655 01656 // 01657 // Free the page directory page pointers. 01658 // 01659 01660 PoolBlock = MiPaeFree ((PPAE_ENTRY)Process->PaeTop); 01661 #else 01662 01663 MiInsertPageInList (MmPageLocationList[FreePageList], 01664 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(Process->Pcb.DirectoryTableBase[1])))); 01665 01666 MiInsertPageInList (MmPageLocationList[FreePageList], 01667 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(Process->Pcb.DirectoryTableBase[0])))); 01668 #endif 01669 #if defined(_IA64_) 01670 MiInsertPageInList (MmPageLocationList[FreePageList], Process->Pcb.SessionParentBase); 01671 #endif 01672 } 01673 01674 MmResidentAvailablePages += MM_PROCESS_CREATE_CHARGE; 01675 MM_BUMP_COUNTER(7, MM_PROCESS_CREATE_CHARGE); 01676 01677 UNLOCK_PFN (OldIrql); 01678 01679 #if defined (_X86PAE_) 01680 if (PoolBlock != NULL) { 01681 MiPaeFreeEntirePage (PoolBlock); 01682 } 01683 #endif 01684 01685 // 01686 // Check to see if the paging files should be contracted. 01687 // 01688 01689 MiContractPagingFiles (); 01690 01691 return; 01692 }

VOID MmDeleteTeb IN PEPROCESS  TargetProcess,
IN PVOID  TebBase
 

Definition at line 4843 of file procsup.c.

References ASSERT, _MMVAD::EndingVpn, ExFreePool(), KeAttachProcess(), KeDetachProcess(), _MMSECURE_ENTRY::List, List, LOCK_WS_AND_ADDRESS_SPACE, MI_VA_TO_VPN, MiDeleteFreeVm(), MiLocateAddress(), MiRemoveVad(), NT_SUCCESS, NTSTATUS(), NULL, ROUND_TO_PAGES, _MMVAD::StartingVpn, Status, _MMVAD::u, _MMVAD::u2, _MMVAD::u3, and UNLOCK_WS_AND_ADDRESS_SPACE.

Referenced by PspCreateThread(), and PspExitThread().

04850 : 04851 04852 This routine deletes a TEB page within the target process. 04853 04854 Arguments: 04855 04856 TargetProcess - Supplies a pointer to the process in which to delete 04857 the TEB. 04858 04859 TebBase - Supplies the base address of the TEB to delete. 04860 04861 Return Value: 04862 04863 None. 04864 04865 Environment: 04866 04867 Kernel mode. 04868 04869 --*/ 04870 04871 { 04872 PVOID EndingAddress; 04873 PMMVAD Vad; 04874 NTSTATUS Status; 04875 PMMSECURE_ENTRY Secure; 04876 04877 EndingAddress = ((PCHAR)TebBase + 04878 ROUND_TO_PAGES (sizeof(TEB)) - 1); 04879 04880 // 04881 // Attach to the specified process. 04882 // 04883 04884 KeAttachProcess (&TargetProcess->Pcb); 04885 04886 // 04887 // Get the address creation mutex to block multiple threads from 04888 // creating or deleting address space at the same time and 04889 // get the working set mutex so virtual address descriptors can 04890 // be inserted and walked. 04891 // 04892 04893 LOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 04894 04895 Vad = MiLocateAddress (TebBase); 04896 04897 ASSERT (Vad != (PMMVAD)NULL); 04898 04899 ASSERT ((Vad->StartingVpn == MI_VA_TO_VPN (TebBase)) && 04900 (Vad->EndingVpn == MI_VA_TO_VPN (EndingAddress))); 04901 04902 // 04903 // If someone has secured the TEB (in addition to the standard securing 04904 // that was done by memory management on creation, then don't delete it 04905 // now - just leave it around until the entire process is deleted. 04906 // 04907 04908 ASSERT (Vad->u.VadFlags.NoChange == 1); 04909 if (Vad->u2.VadFlags2.OneSecured) { 04910 Status = STATUS_SUCCESS; 04911 } 04912 else { 04913 ASSERT (Vad->u2.VadFlags2.MultipleSecured); 04914 ASSERT (IsListEmpty (&Vad->u3.List) == 0); 04915 04916 // 04917 // If there's only one entry, then that's the one we defined when we 04918 // initially created the TEB. So TEB deletion can take place right 04919 // now. If there's more than one entry, let the TEB sit around until 04920 // the process goes away. 04921 // 04922 04923 Secure = CONTAINING_RECORD (Vad->u3.List.Flink, 04924 MMSECURE_ENTRY, 04925 List); 04926 04927 if (Secure->List.Flink == &Vad->u3.List) { 04928 Status = STATUS_SUCCESS; 04929 } 04930 else { 04931 Status = STATUS_NOT_FOUND; 04932 } 04933 } 04934 04935 if (NT_SUCCESS(Status)) { 04936 04937 MiRemoveVad (Vad); 04938 ExFreePool (Vad); 04939 04940 MiDeleteFreeVm (TebBase, EndingAddress); 04941 } 04942 04943 UNLOCK_WS_AND_ADDRESS_SPACE (TargetProcess); 04944 KeDetachProcess(); 04945 }

NTSTATUS MmGrowKernelStack IN PVOID  CurrentStack  ) 
 

Definition at line 2921 of file procsup.c.

References ASSERT, LOCK_PFN, MI_GET_PAGE_COLOR_FROM_PTE, MI_MAKE_VALID_PTE, MI_SET_PTE_DIRTY, MiEnsureAvailablePageOrWait(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiInitializePfn(), MiRemoveAnyPage(), MM_BUMP_COUNTER, MM_KERNEL_DEMAND_ZERO_PTE, MM_KSTACK_OUTSWAPPED, MM_READWRITE, MmKernelStackResident, MmResidentAvailablePages, NULL, PAGE_SIZE, PERFINFO_GROW_STACK, PsGetCurrentThread, _KTHREAD::StackBase, _KTHREAD::StackLimit, _ETHREAD::Tcb, _MMPTE::u, and UNLOCK_PFN.

02927 : 02928 02929 This function attempts to grows the current thread's kernel stack 02930 such that there is always KERNEL_LARGE_STACK_COMMIT bytes below 02931 the current stack pointer. 02932 02933 Arguments: 02934 02935 CurrentStack - Supplies a pointer to the current stack pointer. 02936 02937 Return Value: 02938 02939 STATUS_SUCCESS is returned if the stack was grown. 02940 02941 STATUS_STACK_OVERFLOW is returned if there was not enough space reserved 02942 for the commitment. 02943 02944 STATUS_NO_MEMORY is returned if there was not enough physical memory 02945 in the system. 02946 02947 --*/ 02948 02949 { 02950 PMMPTE NewLimit; 02951 PMMPTE StackLimit; 02952 PMMPTE EndStack; 02953 PETHREAD Thread; 02954 PFN_NUMBER NumberOfPages; 02955 KIRQL OldIrql; 02956 PFN_NUMBER PageFrameIndex; 02957 MMPTE TempPte; 02958 02959 Thread = PsGetCurrentThread (); 02960 ASSERT (((PCHAR)Thread->Tcb.StackBase - (PCHAR)Thread->Tcb.StackLimit) <= 02961 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE)); 02962 NewLimit = MiGetPteAddress ((PVOID)((PUCHAR)CurrentStack - 02963 KERNEL_LARGE_STACK_COMMIT)); 02964 02965 StackLimit = MiGetPteAddress (Thread->Tcb.StackLimit); 02966 02967 // 02968 // If the new stack limit exceeds the reserved region for the kernel 02969 // stack, then return an error. 02970 // 02971 02972 EndStack = MiGetPteAddress ((PVOID)((PUCHAR)Thread->Tcb.StackBase - 02973 KERNEL_LARGE_STACK_SIZE)); 02974 02975 if (NewLimit < EndStack) { 02976 02977 // 02978 // Don't go into guard page. 02979 // 02980 02981 return STATUS_STACK_OVERFLOW; 02982 02983 } 02984 02985 ASSERT (StackLimit->u.Hard.Valid == 1); 02986 02987 // 02988 // Lock the PFN database and attempt to expand the kernel stack. 02989 // 02990 02991 StackLimit -= 1; 02992 02993 NumberOfPages = (PFN_NUMBER) (StackLimit - NewLimit + 1); 02994 02995 LOCK_PFN (OldIrql); 02996 02997 if (MmResidentAvailablePages <= (SPFN_NUMBER)NumberOfPages) { 02998 UNLOCK_PFN (OldIrql); 02999 return STATUS_NO_MEMORY; 03000 } 03001 03002 // 03003 // Note MmResidentAvailablePages must be charged before calling 03004 // MiEnsureAvailablePageOrWait as it may let go of the PFN lock. 03005 // 03006 03007 MmResidentAvailablePages -= NumberOfPages; 03008 MM_BUMP_COUNTER(11, NumberOfPages); 03009 03010 while (StackLimit >= NewLimit) { 03011 03012 ASSERT (StackLimit->u.Hard.Valid == 0); 03013 03014 MiEnsureAvailablePageOrWait (NULL, NULL); 03015 PageFrameIndex = MiRemoveAnyPage (MI_GET_PAGE_COLOR_FROM_PTE (StackLimit)); 03016 StackLimit->u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 03017 03018 #ifdef PROTECT_KSTACKS 03019 StackLimit->u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03020 #endif 03021 03022 MiInitializePfn (PageFrameIndex, StackLimit, 1); 03023 03024 MI_MAKE_VALID_PTE (TempPte, 03025 PageFrameIndex, 03026 MM_READWRITE, 03027 StackLimit ); 03028 03029 MI_SET_PTE_DIRTY (TempPte); 03030 *StackLimit = TempPte; 03031 StackLimit -= 1; 03032 } 03033 03034 MmKernelStackResident += NumberOfPages; 03035 UNLOCK_PFN (OldIrql); 03036 03037 #if DBG 03038 ASSERT (NewLimit->u.Hard.Valid == 1); 03039 if (NewLimit != EndStack) { 03040 ASSERT ((NewLimit - 1)->u.Hard.Valid == 0); 03041 } 03042 #endif 03043 03044 Thread->Tcb.StackLimit = MiGetVirtualAddressMappedByPte (NewLimit); 03045 03046 PERFINFO_GROW_STACK(Thread); 03047 03048 return STATUS_SUCCESS; 03049 }

NTSTATUS MmInitializeProcessAddressSpace IN PEPROCESS  ProcessToInitialize,
IN PEPROCESS ProcessToClone  OPTIONAL,
IN PVOID SectionToMap  OPTIONAL,
OUT PUNICODE_STRING *AuditName  OPTIONAL
 

Definition at line 911 of file procsup.c.

References _2gb, ASSERT, DbgPrint, ExAllocatePoolWithTag, ExFreePool(), ExInitializeFastMutex, ExVerifySuite(), FALSE, HYPER_SPACE, KeAttachProcess(), KeDetachProcess(), KeInitializeSpinLock(), KeQuerySystemTime(), _LOCK_HEADER::ListHead, LOCK_HEADER, LOCK_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_MAKE_VALID_PTE, MI_SET_PTE_DIRTY, MI_WRITE_VALID_PTE, MiAllocateVad(), MiCheckForConflictingVad, MiCloneProcessAddressSpace(), MiGetPdeAddress, MiGetPpeAddress, MiGetPteAddress, MiInitializeAlternateTable(), MiInitializePfn(), MiInitializeWorkingSetList(), MiInsertVad(), MM_DBG_PTE_UPDATE, MM_DEMAND_ZERO_WRITE_PTE, MM_READWRITE, MmMapViewOfSection(), MmTrackLockedPages, MmVirtualBias, MmWorkingSetList, n, NonPagedPool, NTSTATUS(), NULL, PAGE_SHIFT, PSECTION, PWOW64_PROCESS, Status, TRUE, UNLOCK_PFN, VadTreeWalk(), WOW64_PROCESS, and ZERO_LARGE.

Referenced by MiInitMachineDependent(), and PspCreateProcess().

00920 : 00921 00922 This routine initializes the working set and mutexes within an 00923 newly created address space to support paging. 00924 00925 No page faults may occur in a new process until this routine is 00926 completed. 00927 00928 Arguments: 00929 00930 ProcessToInitialize - Supplies a pointer to the process to initialize. 00931 00932 ProcessToClone - Optionally supplies a pointer to the process whose 00933 address space should be copied into the 00934 ProcessToInitialize address space. 00935 00936 SectionToMap - Optionally supplies a section to map into the newly 00937 initialized address space. 00938 00939 Only one of ProcessToClone and SectionToMap may be specified. 00940 00941 00942 Return Value: 00943 00944 None. 00945 00946 00947 Environment: 00948 00949 Kernel mode. APCs Disabled. 00950 00951 --*/ 00952 00953 00954 { 00955 PMMPTE PointerPte; 00956 MMPTE TempPte; 00957 PVOID BaseAddress; 00958 SIZE_T ViewSize; 00959 KIRQL OldIrql; 00960 NTSTATUS Status; 00961 PFN_NUMBER PpePhysicalPage; 00962 PFN_NUMBER PdePhysicalPage; 00963 PFN_NUMBER PageContainingWorkingSet; 00964 LARGE_INTEGER SectionOffset; 00965 PSECTION_IMAGE_INFORMATION ImageInfo; 00966 PMMVAD VadShare; 00967 PMMVAD VadReserve; 00968 PLOCK_HEADER LockedPagesHeader; 00969 #if defined (_X86PAE_) 00970 ULONG i; 00971 PFN_NUMBER PdePhysicalPage2; 00972 #endif 00973 #if defined (_WIN64) 00974 PWOW64_PROCESS Wow64Process; 00975 #endif 00976 00977 // 00978 // Initialize Working Set Mutex in process header. 00979 // 00980 00981 KeAttachProcess (&ProcessToInitialize->Pcb); 00982 ProcessToInitialize->AddressSpaceInitialized = 2; 00983 00984 ExInitializeFastMutex(&ProcessToInitialize->AddressCreationLock); 00985 00986 ExInitializeFastMutex(&ProcessToInitialize->WorkingSetLock); 00987 00988 // 00989 // NOTE: The process block has been zeroed when allocated, so 00990 // there is no need to zero fields and set pointers to NULL. 00991 // 00992 00993 ASSERT (ProcessToInitialize->VadRoot == NULL); 00994 00995 KeQuerySystemTime(&ProcessToInitialize->Vm.LastTrimTime); 00996 ProcessToInitialize->Vm.VmWorkingSetList = MmWorkingSetList; 00997 00998 // 00999 // Obtain a page to map the working set and initialize the 01000 // working set. Get PFN mutex to allocate physical pages. 01001 // 01002 01003 LOCK_PFN (OldIrql); 01004 01005 // 01006 // Initialize the PFN database for the Page Directory and the 01007 // PDE which maps hyper space. 01008 // 01009 01010 #if defined (_WIN64) 01011 01012 PointerPte = MiGetPteAddress (PDE_TBASE); 01013 PpePhysicalPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 01014 01015 MiInitializePfn (PpePhysicalPage, PointerPte, 1); 01016 01017 PointerPte = MiGetPpeAddress (HYPER_SPACE); 01018 MiInitializePfn (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte), PointerPte, 1); 01019 01020 #if defined(_IA64_) 01021 PointerPte = MiGetPteAddress (PDE_STBASE); 01022 MiInitializePfn (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte), PointerPte, 1); 01023 #endif 01024 01025 #else 01026 01027 #if defined (_X86PAE_) 01028 PointerPte = MiGetPdeAddress (PDE_BASE); 01029 #else 01030 PointerPte = MiGetPteAddress (PDE_BASE); 01031 #endif 01032 PdePhysicalPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 01033 01034 MiInitializePfn (PdePhysicalPage, PointerPte, 1); 01035 01036 #endif 01037 01038 PointerPte = MiGetPdeAddress (HYPER_SPACE); 01039 MiInitializePfn (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte), PointerPte, 1); 01040 01041 #if defined (_X86PAE_) 01042 01043 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 01044 PointerPte = MiGetPteAddress (PDE_BASE + (i << PAGE_SHIFT)); 01045 PdePhysicalPage2 = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 01046 MiInitializePfn (PdePhysicalPage2, PointerPte, 1); 01047 } 01048 01049 PointerPte = MiGetPdeAddress (HYPER_SPACE2); 01050 MiInitializePfn (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte), PointerPte, 1); 01051 #endif 01052 01053 PageContainingWorkingSet = ProcessToInitialize->WorkingSetPage; 01054 01055 PointerPte = MiGetPteAddress (MmWorkingSetList); 01056 PointerPte->u.Long = MM_DEMAND_ZERO_WRITE_PTE; 01057 01058 MiInitializePfn (PageContainingWorkingSet, PointerPte, 1); 01059 01060 UNLOCK_PFN (OldIrql); 01061 01062 MI_MAKE_VALID_PTE (TempPte, 01063 PageContainingWorkingSet, 01064 MM_READWRITE, 01065 PointerPte ); 01066 01067 MI_SET_PTE_DIRTY (TempPte); 01068 MI_WRITE_VALID_PTE (PointerPte, TempPte); 01069 01070 ASSERT (ProcessToInitialize->LockedPagesList == NULL); 01071 01072 if (MmTrackLockedPages == TRUE) { 01073 LockedPagesHeader = ExAllocatePoolWithTag (NonPagedPool, 01074 sizeof(LOCK_HEADER), 01075 'xTmM'); 01076 01077 if (LockedPagesHeader) { 01078 RtlZeroMemory (LockedPagesHeader, sizeof(LOCK_HEADER)); 01079 ProcessToInitialize->LockedPagesList = (PVOID)LockedPagesHeader; 01080 InitializeListHead (&LockedPagesHeader->ListHead); 01081 } 01082 } 01083 01084 MiInitializeWorkingSetList (ProcessToInitialize); 01085 01086 KeInitializeSpinLock (&ProcessToInitialize->AweLock); 01087 InitializeListHead (&ProcessToInitialize->PhysicalVadList); 01088 01089 // 01090 // Page faults may be taken now. 01091 // 01092 // If the system has been biased to an alternate base address to allow 01093 // 3gb of user address space and a process is not being cloned, then 01094 // create a VAD for the shared memory page. 01095 // 01096 01097 #if defined(_X86_) && defined(MM_SHARED_USER_DATA_VA) 01098 01099 if ((MmVirtualBias != 0) && (ProcessToClone == NULL)) { 01100 01101 // 01102 // Allocate a VAD to map the shared memory page. If a VAD cannot be 01103 // allocated, then detach from the target process and return a failure 01104 // status. This VAD is marked as not deletable. 01105 // 01106 01107 VadShare = MiAllocateVad (MM_SHARED_USER_DATA_VA, 01108 MM_SHARED_USER_DATA_VA, 01109 FALSE); 01110 01111 if (VadShare == NULL) { 01112 KeDetachProcess (); 01113 return STATUS_NO_MEMORY; 01114 } 01115 01116 // 01117 // If a section is being mapped and the executable is not large 01118 // address space aware, then create a VAD that reserves the address 01119 // space between 2gb and the highest user address. 01120 // 01121 01122 if (SectionToMap != NULL) { 01123 if (!((PSECTION)SectionToMap)->u.Flags.Image) { 01124 KeDetachProcess (); 01125 ExFreePool (VadShare); 01126 return STATUS_SECTION_NOT_IMAGE; 01127 } 01128 ImageInfo = ((PSECTION)SectionToMap)->Segment->ImageInformation; 01129 if ((ExVerifySuite(Enterprise) == FALSE) || 01130 ((ImageInfo->ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) == 0)) { 01131 01132 // 01133 // Allocate a VAD to map the address space between 2gb and 01134 // the highest user address. If a VAD can not be allocated, 01135 // then deallocate the shared address space VAD, detach from 01136 // the target process, and return a failure status. 01137 // This VAD is marked as not deletable. 01138 // 01139 01140 VadReserve = MiAllocateVad (_2gb, 01141 (ULONG_PTR)MM_HIGHEST_USER_ADDRESS, 01142 FALSE); 01143 01144 if (VadReserve == NULL) { 01145 KeDetachProcess (); 01146 ExFreePool (VadShare); 01147 return STATUS_NO_MEMORY; 01148 } 01149 01150 // 01151 // Insert the VAD. 01152 // 01153 // N.B. No exception can occur since there is no commit charge. 01154 // 01155 01156 MiInsertVad (VadReserve); 01157 } 01158 } 01159 01160 // 01161 // Insert the VAD. 01162 // 01163 // N.B. No exception can occur since there is no commit charge. 01164 // 01165 01166 MiInsertVad (VadShare); 01167 } 01168 01169 #endif 01170 01171 #if defined(_WIN64) 01172 01173 if (ProcessToClone == NULL) { 01174 01175 // 01176 // Reserve the address space just below KUSER_SHARED_DATA as the 01177 // compatibility area. This range can be unreserved by user mode 01178 // code such as WOW64 or csrss. 01179 // 01180 01181 ASSERT(MiCheckForConflictingVad(WOW64_COMPATIBILITY_AREA_ADDRESS, MM_SHARED_USER_DATA_VA) == NULL); 01182 01183 VadShare = MiAllocateVad (WOW64_COMPATIBILITY_AREA_ADDRESS, 01184 MM_SHARED_USER_DATA_VA, 01185 TRUE); 01186 01187 if (VadShare == NULL) { 01188 KeDetachProcess (); 01189 return STATUS_NO_MEMORY; 01190 } 01191 01192 // 01193 // Reserve the memory above 2GB to prevent 32 bit (WOW64) process 01194 // access. 01195 // 01196 01197 if (SectionToMap != NULL) { 01198 if (!((PSECTION)SectionToMap)->u.Flags.Image) { 01199 KeDetachProcess (); 01200 ExFreePool (VadShare); 01201 return STATUS_SECTION_NOT_IMAGE; 01202 } 01203 ImageInfo = ((PSECTION)SectionToMap)->Segment->ImageInformation; 01204 01205 if ((ImageInfo->ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) == 0 || 01206 #if defined(_AXP64_) 01207 ImageInfo->Machine == IMAGE_FILE_MACHINE_ALPHA || 01208 #endif 01209 ImageInfo->Machine == IMAGE_FILE_MACHINE_I386) { 01210 01211 // 01212 // Allocate a VAD to reserve the address space between 2gb and 01213 // the highest user address. If a VAD cannot be allocated, 01214 // then deallocate the compatibility VAD, detach from the target 01215 // process and return a failure status. 01216 // 01217 01218 VadReserve = MiAllocateVad (_2gb, 01219 (ULONG_PTR)MM_HIGHEST_USER_ADDRESS, 01220 TRUE); 01221 01222 if (VadReserve == NULL) { 01223 KeDetachProcess (); 01224 ExFreePool (VadShare); 01225 return STATUS_NO_MEMORY; 01226 } 01227 01228 // 01229 // Insert the VAD. 01230 // 01231 // N.B. No exception can occur since there is no commit charge. 01232 // 01233 01234 MiInsertVad (VadReserve); 01235 01236 // 01237 // Initialize Wow64 Process structure 01238 // 01239 01240 Wow64Process = 01241 (PWOW64_PROCESS) ExAllocatePoolWithTag (NonPagedPool, 01242 sizeof(WOW64_PROCESS), 01243 'WowM'); 01244 01245 if (Wow64Process == (PWOW64_PROCESS) NULL) { 01246 KeDetachProcess (); 01247 return STATUS_NO_MEMORY; 01248 } 01249 01250 RtlZeroMemory(Wow64Process, sizeof(WOW64_PROCESS)); 01251 01252 ProcessToInitialize->Wow64Process = Wow64Process; 01253 01254 #if defined(_MIALT4K_) 01255 01256 // 01257 // Initialize the alternate page table for the 4kb page function 01258 // 01259 01260 Status = MiInitializeAlternateTable (ProcessToInitialize); 01261 if (Status != STATUS_SUCCESS) { 01262 KeDetachProcess (); 01263 return Status; 01264 } 01265 01266 #endif 01267 } 01268 } 01269 01270 // 01271 // Insert the VAD. 01272 // 01273 // N.B. No exception can occur since there is no commit charge. 01274 // 01275 01276 MiInsertVad (VadShare); 01277 } 01278 01279 #endif 01280 01281 if (SectionToMap != (PSECTION)NULL) { 01282 01283 // 01284 // Map the specified section into the address space of the 01285 // process but only if it is an image section. 01286 // 01287 01288 if (!((PSECTION)SectionToMap)->u.Flags.Image) { 01289 Status = STATUS_SECTION_NOT_IMAGE; 01290 } else { 01291 UNICODE_STRING UnicodeString; 01292 ULONG n; 01293 PWSTR Src; 01294 PCHAR Dst; 01295 01296 UnicodeString = ((PSECTION)SectionToMap)->Segment->ControlArea->FilePointer->FileName; 01297 Src = (PWSTR)((PCHAR)UnicodeString.Buffer + UnicodeString.Length); 01298 n = 0; 01299 if (UnicodeString.Buffer != NULL) { 01300 while (Src > UnicodeString.Buffer) { 01301 if (*--Src == OBJ_NAME_PATH_SEPARATOR) { 01302 Src += 1; 01303 break; 01304 } 01305 else { 01306 n += 1; 01307 } 01308 } 01309 } 01310 Dst = ProcessToInitialize->ImageFileName; 01311 if (n >= sizeof( ProcessToInitialize->ImageFileName )) { 01312 n = sizeof( ProcessToInitialize->ImageFileName ) - 1; 01313 } 01314 01315 while (n--) { 01316 *Dst++ = (UCHAR)*Src++; 01317 } 01318 *Dst = '\0'; 01319 01320 if (AuditName) { 01321 *AuditName = &((PSECTION)SectionToMap)->Segment->ControlArea->FilePointer->FileName ; 01322 } 01323 01324 ProcessToInitialize->SubSystemMajorVersion = 01325 (UCHAR)((PSECTION)SectionToMap)->Segment->ImageInformation->SubSystemMajorVersion; 01326 ProcessToInitialize->SubSystemMinorVersion = 01327 (UCHAR)((PSECTION)SectionToMap)->Segment->ImageInformation->SubSystemMinorVersion; 01328 01329 BaseAddress = NULL; 01330 ViewSize = 0; 01331 ZERO_LARGE (SectionOffset); 01332 01333 Status = MmMapViewOfSection ( (PSECTION)SectionToMap, 01334 ProcessToInitialize, 01335 &BaseAddress, 01336 0, // ZeroBits, 01337 0, // CommitSize, 01338 &SectionOffset, //SectionOffset, 01339 &ViewSize, 01340 ViewShare, //InheritDisposition, 01341 0, //allocation type 01342 PAGE_READWRITE // Protect 01343 ); 01344 01345 ProcessToInitialize->SectionBaseAddress = BaseAddress; 01346 01347 #if DBG 01348 if (MmDebug & MM_DBG_PTE_UPDATE) { 01349 DbgPrint("mapped image section vads\n"); 01350 VadTreeWalk(ProcessToInitialize->VadRoot); 01351 } 01352 #endif //DBG 01353 } 01354 01355 KeDetachProcess (); 01356 return Status; 01357 } 01358 01359 if (ProcessToClone != (PEPROCESS)NULL) { 01360 #if DEVL 01361 strcpy( ProcessToInitialize->ImageFileName, ProcessToClone->ImageFileName ); 01362 #endif // DEVL 01363 01364 // 01365 // Clone the address space of the specified process. 01366 // 01367 01368 // 01369 // As the page directory and page tables are private to each 01370 // process, the physical pages which map the directory page 01371 // and the page table usage must be mapped into system space 01372 // so they can be updated while in the context of the process 01373 // we are cloning. 01374 // 01375 01376 KeDetachProcess (); 01377 return MiCloneProcessAddressSpace (ProcessToClone, 01378 ProcessToInitialize, 01379 #if defined (_WIN64) 01380 PpePhysicalPage, 01381 #else 01382 PdePhysicalPage, 01383 #endif 01384 PageContainingWorkingSet 01385 ); 01386 01387 } 01388 01389 // 01390 // System Process. 01391 // 01392 01393 KeDetachProcess (); 01394 return STATUS_SUCCESS; 01395 }

VOID MmInPageKernelStack IN PKTHREAD  Thread  ) 
 

Definition at line 3445 of file procsup.c.

References ASSERT, KeBugCheckEx(), KernelDemandZeroPte, LOCK_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiMakeOutswappedPageResident(), MM_KERNEL_DEMAND_ZERO_PTE, MM_KSTACK_OUTSWAPPED, MmKernelStackResident, NtGlobalFlag, PAGE_SIZE, _MMPTE::u, and UNLOCK_PFN.

Referenced by KiInSwapKernelStacks().

03451 : 03452 03453 This routine makes the specified kernel stack resident. 03454 03455 Arguments: 03456 03457 Supplies a pointer to the base of the kernel stack. 03458 03459 Return Value: 03460 03461 Thread - Supplies a pointer to the thread whose stack should be 03462 made resident. 03463 03464 Environment: 03465 03466 Kernel mode. 03467 03468 --*/ 03469 03470 { 03471 PVOID BaseOfKernelStack; 03472 PMMPTE PointerPte; 03473 PMMPTE EndOfStackPte; 03474 PMMPTE SignaturePte; 03475 ULONG DiskRead; 03476 PFN_NUMBER ContainingPage; 03477 KIRQL OldIrql; 03478 03479 ASSERT (((PCHAR)Thread->StackBase - (PCHAR)Thread->StackLimit) <= 03480 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE)); 03481 03482 if (NtGlobalFlag & FLG_DISABLE_PAGE_KERNEL_STACKS) { 03483 return; 03484 } 03485 03486 // 03487 // The first page of the stack is the page before the base 03488 // of the stack. 03489 // 03490 03491 if (Thread->LargeStack) { 03492 PointerPte = MiGetPteAddress ((PVOID)((PUCHAR)Thread->StackLimit)); 03493 03494 EndOfStackPte = MiGetPteAddress ((PVOID)((PUCHAR)Thread->InitialStack - 03495 KERNEL_LARGE_STACK_COMMIT)); 03496 // 03497 // Trim back the stack. Make sure that the stack does not grow, i.e. 03498 // StackLimit remains the limit. 03499 // 03500 03501 if (EndOfStackPte < PointerPte) { 03502 EndOfStackPte = PointerPte; 03503 } 03504 Thread->StackLimit = MiGetVirtualAddressMappedByPte (EndOfStackPte); 03505 } else { 03506 EndOfStackPte = MiGetPteAddress (Thread->StackLimit); 03507 } 03508 03509 #if defined(_IA64_) 03510 03511 if (Thread->LargeStack) { 03512 03513 PVOID TempAddress = (PVOID)((PUCHAR)Thread->BStoreLimit); 03514 03515 BaseOfKernelStack = (PVOID)(((ULONG_PTR)Thread->InitialBStore + 03516 KERNEL_LARGE_BSTORE_COMMIT) & 03517 ~(ULONG_PTR)(PAGE_SIZE - 1)); 03518 03519 // 03520 // Make sure the guard page is not set to valid. 03521 // 03522 03523 if (BaseOfKernelStack > TempAddress) { 03524 BaseOfKernelStack = TempAddress; 03525 } 03526 Thread->BStoreLimit = BaseOfKernelStack; 03527 } 03528 BaseOfKernelStack = ((PCHAR)Thread->BStoreLimit - PAGE_SIZE); 03529 #else 03530 BaseOfKernelStack = ((PCHAR)Thread->StackBase - PAGE_SIZE); 03531 #endif // _IA64_ 03532 03533 PointerPte = MiGetPteAddress (BaseOfKernelStack); 03534 03535 DiskRead = 0; 03536 SignaturePte = MiGetPteAddress ((PULONG_PTR)Thread->KernelStack - 1); 03537 ASSERT (SignaturePte->u.Hard.Valid == 0); 03538 if ((SignaturePte->u.Long != MM_KERNEL_DEMAND_ZERO_PTE) && 03539 (SignaturePte->u.Soft.Transition == 0)) { 03540 DiskRead = 1; 03541 } 03542 03543 LOCK_PFN (OldIrql); 03544 03545 while (PointerPte >= EndOfStackPte) { 03546 03547 #ifdef PROTECT_KSTACKS 03548 if (!((PointerPte->u.Long == KernelDemandZeroPte.u.Long) || 03549 (PointerPte->u.Soft.Protection == MM_KSTACK_OUTSWAPPED))) { 03550 KeBugCheckEx (MEMORY_MANAGEMENT, 03551 0x3451, 03552 (ULONG_PTR)PointerPte, 03553 (ULONG_PTR)Thread, 03554 0); 03555 } 03556 ASSERT (PointerPte->u.Hard.Valid == 0); 03557 if (PointerPte->u.Soft.Protection == MM_KSTACK_OUTSWAPPED) { 03558 PointerPte->u.Soft.Protection = PAGE_READWRITE; 03559 } 03560 #endif 03561 03562 ContainingPage = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress (PointerPte)); 03563 MiMakeOutswappedPageResident (PointerPte, 03564 PointerPte, 03565 1, 03566 ContainingPage); 03567 03568 PointerPte -= 1; 03569 MmKernelStackResident += 1; 03570 } 03571 03572 // 03573 // Check the signature at the current stack location - 4. 03574 // 03575 03576 if (*((PULONG_PTR)Thread->KernelStack - 1) != (ULONG_PTR)Thread) { 03577 KeBugCheckEx (KERNEL_STACK_INPAGE_ERROR, 03578 DiskRead, 03579 *((PULONG_PTR)Thread->KernelStack - 1), 03580 0, 03581 (ULONG_PTR)Thread->KernelStack); 03582 } 03583 03584 UNLOCK_PFN (OldIrql); 03585 return; 03586 }

VOID MmInSwapProcess IN PKPROCESS  Process  ) 
 

Definition at line 3910 of file procsup.c.

References _MMSUPPORT::AllowWorkingSetAdjustment, ASSERT, FALSE, HYPER_SPACE, INITIALIZE_DIRECTORY_TABLE_BASE, _MMWORKING_SET_EXPANSION_HEAD::ListHead, LOCK_EXPANSION, LOCK_PFN, MI_CONVERT_PHYSICAL_TO_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_IS_PHYSICAL_ADDRESS, MI_PFN_ELEMENT, MiGetPdeAddress, MiGetPdeOffset, MiGetPpeAddress, MiGetPpeOffset, MiGetPteAddress, MiGetPteOffset, MiHydra, MiMakeOutswappedPageResident(), MiMapPageInHyperSpace(), MiSessionInSwapProcess(), MiUnmapPageInHyperSpace, MM_WS_SWAPPED_OUT, MmWorkingSetExpansionHead, MmWorkingSetList, _EPROCESS::PaePageDirectoryPage, _EPROCESS::PaeTop, PAGE_SHIFT, _EPROCESS::PageDirectoryPte, _EPROCESS::ProcessOutswapEnabled, _EPROCESS::ProcessOutswapped, _MMPFN::PteAddress, _MMPFN::PteFrame, TRUE, _MMSUPPORT::u, _MMPTE::u, _MMPFN::u1, _MMPFN::u2, UNLOCK_EXPANSION, UNLOCK_PFN, _EPROCESS::Vm, _MMSUPPORT::WorkingSetExpansionLinks, _EPROCESS::WorkingSetPage, and _MMSUPPORT::WorkingSetSize.

Referenced by KiInSwapProcesses().

03916 : 03917 03918 This routine in swaps the specified process. 03919 03920 Arguments: 03921 03922 Process - Supplies a pointer to the process that is to be swapped 03923 into memory. 03924 03925 Return Value: 03926 03927 None. 03928 03929 --*/ 03930 03931 { 03932 KIRQL OldIrql; 03933 KIRQL OldIrql2; 03934 PEPROCESS OutProcess; 03935 PFN_NUMBER PdePage; 03936 PFN_NUMBER PageDirectoryPage; 03937 PMMPTE PageDirectoryMap; 03938 PMMPTE PageDirectoryParentMap; 03939 MMPTE TempPte; 03940 MMPTE TempPte2; 03941 PFN_NUMBER HyperSpacePageTable; 03942 PMMPTE HyperSpacePageTableMap; 03943 PFN_NUMBER WorkingSetPage; 03944 PMMPFN Pfn1; 03945 PMMPTE PointerPte; 03946 PFN_NUMBER ProcessPage; 03947 #if defined (_X86PAE_) 03948 ULONG i; 03949 PPAE_ENTRY PaeVa; 03950 PFN_NUMBER PdePage2; 03951 #endif 03952 03953 OutProcess = CONTAINING_RECORD (Process, EPROCESS, Pcb); 03954 03955 if (OutProcess->ProcessOutswapped == TRUE) { 03956 03957 // 03958 // The process is out of memory, rebuild the initialized page 03959 // structure. 03960 // 03961 03962 if (MI_IS_PHYSICAL_ADDRESS(OutProcess)) { 03963 ProcessPage = MI_CONVERT_PHYSICAL_TO_PFN (OutProcess); 03964 } else { 03965 PointerPte = MiGetPteAddress (OutProcess); 03966 ProcessPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03967 } 03968 03969 LOCK_PFN (OldIrql); 03970 03971 #if defined (_WIN64) 03972 PdePage = MiMakeOutswappedPageResident (MiGetPteAddress (PDE_TBASE), 03973 (PMMPTE)&OutProcess->PageDirectoryPte, 03974 0, 03975 ProcessPage); 03976 #else 03977 PdePage = MiMakeOutswappedPageResident (MiGetPteAddress (PDE_BASE), 03978 (PMMPTE)&OutProcess->PageDirectoryPte, 03979 0, 03980 ProcessPage); 03981 #endif 03982 03983 // 03984 // Adjust the counts for the process page. 03985 // 03986 03987 Pfn1 = MI_PFN_ELEMENT (ProcessPage); 03988 Pfn1->u2.ShareCount -= 1; 03989 03990 ASSERT ((LONG)Pfn1->u2.ShareCount >= 1); 03991 03992 // 03993 // Adjust the counts properly for the page directory page. 03994 // 03995 03996 Pfn1 = MI_PFN_ELEMENT (PdePage); 03997 Pfn1->u2.ShareCount += 1; 03998 #if !defined (_WIN64) 03999 Pfn1->u1.Event = (PVOID)OutProcess; 04000 #endif 04001 Pfn1->PteFrame = PdePage; 04002 Pfn1->PteAddress = MiGetPteAddress (PDE_BASE); 04003 04004 #if defined (_WIN64) 04005 04006 // 04007 // Only the page directory parent page has really been read in above. 04008 // Get the page directory page now also. 04009 // 04010 04011 PageDirectoryParentMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04012 04013 TempPte = PageDirectoryParentMap[MiGetPpeOffset(MmWorkingSetList)]; 04014 04015 MiUnmapPageInHyperSpace (OldIrql2); 04016 04017 PageDirectoryPage = MiMakeOutswappedPageResident ( 04018 MiGetPpeAddress (MmWorkingSetList), 04019 &TempPte, 04020 0, 04021 PdePage); 04022 04023 ASSERT (PageDirectoryPage == TempPte.u.Hard.PageFrameNumber); 04024 ASSERT (Pfn1->u2.ShareCount >= 3); 04025 04026 PageDirectoryParentMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04027 04028 PageDirectoryParentMap[MiGetPpeOffset(PDE_TBASE)].u.Flush = 04029 OutProcess->PageDirectoryPte; 04030 PageDirectoryParentMap[MiGetPpeOffset(MmWorkingSetList)] = TempPte; 04031 04032 MiUnmapPageInHyperSpace (OldIrql2); 04033 04034 PdePage = PageDirectoryPage; 04035 #endif 04036 04037 #if defined (_X86PAE_) 04038 04039 OutProcess->PaePageDirectoryPage = PdePage; 04040 04041 // 04042 // Locate the additional page directory pages and make them resident. 04043 // 04044 04045 PaeVa = (PPAE_ENTRY)OutProcess->PaeTop; 04046 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 04047 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04048 04049 TempPte = PageDirectoryMap[i]; 04050 04051 MiUnmapPageInHyperSpace (OldIrql2); 04052 04053 PdePage2 = MiMakeOutswappedPageResident ( 04054 MiGetPteAddress (PDE_BASE + (i << PAGE_SHIFT)), 04055 &TempPte, 04056 0, 04057 PdePage); 04058 04059 ASSERT (Pfn1->u2.ShareCount >= 1); 04060 04061 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04062 PageDirectoryMap[i] = TempPte; 04063 MiUnmapPageInHyperSpace (OldIrql2); 04064 PaeVa->PteEntry[i].u.Long = (TempPte.u.Long & ~MM_PAE_PDPTE_MASK); 04065 } 04066 04067 TempPte.u.Flush = OutProcess->PageDirectoryPte; 04068 TempPte.u.Long &= ~MM_PAE_PDPTE_MASK; 04069 PaeVa->PteEntry[i].u.Flush = TempPte.u.Flush; 04070 04071 // 04072 // Locate the second page table page for hyperspace & make it resident. 04073 // 04074 04075 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04076 04077 TempPte = PageDirectoryMap[MiGetPdeOffset(HYPER_SPACE2)]; 04078 04079 MiUnmapPageInHyperSpace (OldIrql2); 04080 04081 HyperSpacePageTable = MiMakeOutswappedPageResident ( 04082 MiGetPdeAddress (HYPER_SPACE2), 04083 &TempPte, 04084 0, 04085 PdePage); 04086 04087 ASSERT (Pfn1->u2.ShareCount >= 1); 04088 04089 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04090 PageDirectoryMap[MiGetPdeOffset(HYPER_SPACE2)] = TempPte; 04091 MiUnmapPageInHyperSpace (OldIrql2); 04092 TempPte2 = TempPte; 04093 #endif 04094 04095 // 04096 // Locate the page table page for hyperspace and make it resident. 04097 // 04098 04099 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04100 04101 TempPte = PageDirectoryMap[MiGetPdeOffset(MmWorkingSetList)]; 04102 04103 MiUnmapPageInHyperSpace (OldIrql2); 04104 04105 HyperSpacePageTable = MiMakeOutswappedPageResident ( 04106 MiGetPdeAddress (HYPER_SPACE), 04107 &TempPte, 04108 0, 04109 PdePage); 04110 04111 ASSERT (Pfn1->u2.ShareCount >= 3); 04112 04113 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 04114 04115 #if !defined (_WIN64) 04116 PageDirectoryMap[MiGetPdeOffset(PDE_BASE)].u.Flush = 04117 OutProcess->PageDirectoryPte; 04118 #endif 04119 04120 PageDirectoryMap[MiGetPdeOffset(MmWorkingSetList)] = TempPte; 04121 04122 MiUnmapPageInHyperSpace (OldIrql2); 04123 04124 // 04125 // Map in the hyper space page table page and retrieve the 04126 // PTE that maps the working set list. 04127 // 04128 04129 HyperSpacePageTableMap = MiMapPageInHyperSpace (HyperSpacePageTable, &OldIrql2); 04130 TempPte = HyperSpacePageTableMap[MiGetPteOffset(MmWorkingSetList)]; 04131 MiUnmapPageInHyperSpace (OldIrql2); 04132 Pfn1 = MI_PFN_ELEMENT (HyperSpacePageTable); 04133 04134 Pfn1->u1.WsIndex = 1; 04135 04136 WorkingSetPage = MiMakeOutswappedPageResident ( 04137 MiGetPteAddress (MmWorkingSetList), 04138 &TempPte, 04139 0, 04140 HyperSpacePageTable); 04141 04142 HyperSpacePageTableMap = MiMapPageInHyperSpace (HyperSpacePageTable, &OldIrql2); 04143 HyperSpacePageTableMap[MiGetPteOffset(MmWorkingSetList)] = TempPte; 04144 #if defined (_X86PAE_) 04145 HyperSpacePageTableMap[0] = TempPte2; 04146 #endif 04147 MiUnmapPageInHyperSpace (OldIrql2); 04148 04149 Pfn1 = MI_PFN_ELEMENT (WorkingSetPage); 04150 04151 Pfn1->u1.WsIndex = 2; 04152 04153 UNLOCK_PFN (OldIrql); 04154 04155 LOCK_EXPANSION (OldIrql); 04156 04157 // 04158 // Allow working set trimming on this process. 04159 // 04160 04161 OutProcess->Vm.AllowWorkingSetAdjustment = TRUE; 04162 if (OutProcess->Vm.WorkingSetExpansionLinks.Flink == MM_WS_SWAPPED_OUT) { 04163 InsertTailList (&MmWorkingSetExpansionHead.ListHead, 04164 &OutProcess->Vm.WorkingSetExpansionLinks); 04165 } 04166 UNLOCK_EXPANSION (OldIrql); 04167 04168 // 04169 // Set up process structures. 04170 // 04171 04172 OutProcess->WorkingSetPage = WorkingSetPage; 04173 04174 #if !defined (_X86PAE_) 04175 OutProcess->Vm.WorkingSetSize = 3; 04176 04177 INITIALIZE_DIRECTORY_TABLE_BASE (&Process->DirectoryTableBase[0], 04178 PdePage); 04179 INITIALIZE_DIRECTORY_TABLE_BASE (&Process->DirectoryTableBase[1], 04180 HyperSpacePageTable); 04181 #else 04182 // 04183 // The DirectoryTableBase[0] never changes for PAE processes. 04184 // 04185 04186 OutProcess->Vm.WorkingSetSize = 7; 04187 Process->DirectoryTableBase[1] = HyperSpacePageTable; 04188 #endif 04189 04190 OutProcess->ProcessOutswapped = FALSE; 04191 } 04192 04193 if (MiHydra == TRUE && OutProcess->Vm.u.Flags.ProcessInSession == 1) { 04194 MiSessionInSwapProcess (OutProcess); 04195 } 04196 04197 OutProcess->ProcessOutswapEnabled = FALSE; 04198 return; 04199 }

VOID MmOutPageKernelStack IN PKTHREAD  Thread  ) 
 

Definition at line 3180 of file procsup.c.

References ASSERT, Count, KeFlushEntireTb(), KeFlushMultipleTb(), KernelDemandZeroPte, LOCK_PFN, MAX_STACK_PAGES, MI_GET_PAGE_FRAME_FROM_PTE, MI_MAKE_VALID_PTE_TRANSITION, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiDecrementShareAndValidCount, MiDecrementShareCount(), MiDecrementShareCountOnly, MiGetPteAddress, MM_BUMP_COUNTER, MM_KSTACK_OUTSWAPPED, MM_MAXIMUM_FLUSH_COUNT, MmKernelStackResident, MmResidentAvailablePages, NtGlobalFlag, _MMPFN::OriginalPte, PAGE_SHIFT, PAGE_SIZE, _MMPFN::PteFrame, TRUE, _MMPTE::u, UNLOCK_PFN, and ZeroPte.

Referenced by KiOutSwapKernelStacks().

03186 : 03187 03188 This routine makes the specified kernel stack non-resident and 03189 puts the pages on the transition list. Note, that if the 03190 CurrentStackPointer is within the first page of the stack, the 03191 contents of the second page of the stack is not useful and the 03192 page is freed. 03193 03194 Arguments: 03195 03196 Thread - Supplies a pointer to the thread whose stack should be 03197 removed. 03198 03199 Return Value: 03200 03201 None. 03202 03203 Environment: 03204 03205 Kernel mode. 03206 03207 --*/ 03208 03209 #if defined(_IA64_) 03210 #define MAX_STACK_PAGES ((KERNEL_LARGE_STACK_SIZE + KERNEL_LARGE_BSTORE_SIZE) / PAGE_SIZE) 03211 #else 03212 #define MAX_STACK_PAGES (KERNEL_LARGE_STACK_SIZE / PAGE_SIZE) 03213 #endif 03214 03215 { 03216 PMMPTE PointerPte; 03217 PMMPTE LastPte; 03218 PMMPTE EndOfStackPte; 03219 PMMPFN Pfn1; 03220 PFN_NUMBER PageFrameIndex; 03221 KIRQL OldIrql; 03222 MMPTE TempPte; 03223 PVOID BaseOfKernelStack; 03224 PMMPTE FlushPte[MAX_STACK_PAGES]; 03225 PVOID FlushVa[MAX_STACK_PAGES]; 03226 MMPTE FlushPteSave[MAX_STACK_PAGES]; 03227 ULONG StackSize; 03228 ULONG Count; 03229 PMMPTE LimitPte; 03230 PMMPTE LowestLivePte; 03231 03232 ASSERT (((PCHAR)Thread->StackBase - (PCHAR)Thread->StackLimit) <= 03233 (KERNEL_LARGE_STACK_SIZE + PAGE_SIZE)); 03234 03235 if (NtGlobalFlag & FLG_DISABLE_PAGE_KERNEL_STACKS) { 03236 return; 03237 } 03238 03239 // 03240 // The first page of the stack is the page before the base 03241 // of the stack. 03242 // 03243 03244 BaseOfKernelStack = ((PCHAR)Thread->StackBase - PAGE_SIZE); 03245 PointerPte = MiGetPteAddress (BaseOfKernelStack); 03246 LastPte = MiGetPteAddress ((PULONG)Thread->KernelStack - 1); 03247 if (Thread->LargeStack) { 03248 StackSize = KERNEL_LARGE_STACK_SIZE >> PAGE_SHIFT; 03249 03250 // 03251 // The stack pagein won't necessarily bring back all the pages. 03252 // Make sure that we account now for the ones that will disappear. 03253 // 03254 03255 LimitPte = MiGetPteAddress (Thread->StackLimit); 03256 03257 LowestLivePte = MiGetPteAddress ((PVOID)((PUCHAR)Thread->InitialStack - 03258 KERNEL_LARGE_STACK_COMMIT)); 03259 03260 if (LowestLivePte < LimitPte) { 03261 LowestLivePte = LimitPte; 03262 } 03263 } else { 03264 StackSize = KERNEL_STACK_SIZE >> PAGE_SHIFT; 03265 LowestLivePte = MiGetPteAddress (Thread->StackLimit); 03266 } 03267 EndOfStackPte = PointerPte - StackSize; 03268 03269 ASSERT (LowestLivePte <= LastPte); 03270 03271 // 03272 // Put a signature at the current stack location - 4. 03273 // 03274 03275 *((PULONG_PTR)Thread->KernelStack - 1) = (ULONG_PTR)Thread; 03276 03277 Count = 0; 03278 03279 LOCK_PFN (OldIrql); 03280 03281 do { 03282 ASSERT (PointerPte->u.Hard.Valid == 1); 03283 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03284 TempPte = *PointerPte; 03285 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 0); 03286 03287 #ifdef PROTECT_KSTACKS 03288 TempPte.u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03289 { 03290 PMMPFN x; 03291 x = MI_PFN_ELEMENT(PageFrameIndex); 03292 x->OriginalPte.u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03293 } 03294 #endif 03295 03296 FlushPteSave[Count] = TempPte; 03297 FlushPte[Count] = PointerPte; 03298 FlushVa[Count] = BaseOfKernelStack; 03299 03300 MiDecrementShareCount (PageFrameIndex); 03301 PointerPte -= 1; 03302 Count += 1; 03303 BaseOfKernelStack = ((PCHAR)BaseOfKernelStack - PAGE_SIZE); 03304 } while (PointerPte >= LastPte); 03305 03306 while (PointerPte != EndOfStackPte) { 03307 if (PointerPte->u.Hard.Valid == 0) { 03308 break; 03309 } 03310 03311 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03312 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 03313 MiDecrementShareAndValidCount (Pfn1->PteFrame); 03314 MI_SET_PFN_DELETED (Pfn1); 03315 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte)); 03316 03317 FlushPteSave[Count] = KernelDemandZeroPte; 03318 03319 #ifdef PROTECT_KSTACKS 03320 FlushPteSave[Count].u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03321 #endif 03322 03323 FlushPte[Count] = PointerPte; 03324 03325 FlushVa[Count] = BaseOfKernelStack; 03326 Count += 1; 03327 03328 // 03329 // Account for any pages that won't ever come back in. 03330 // 03331 03332 if (PointerPte < LowestLivePte) { 03333 ASSERT (Thread->LargeStack); 03334 MmResidentAvailablePages += 1; 03335 MM_BUMP_COUNTER(12, 1); 03336 } 03337 03338 PointerPte -= 1; 03339 BaseOfKernelStack = ((PCHAR)BaseOfKernelStack - PAGE_SIZE); 03340 } 03341 03342 #if defined(_IA64_) 03343 // 03344 // do for RSE stack space too. 03345 // 03346 03347 BaseOfKernelStack = Thread->StackBase; 03348 PointerPte = MiGetPteAddress (BaseOfKernelStack); 03349 LastPte = MiGetPteAddress ((PULONG)Thread->KernelBStore); 03350 03351 if (Thread->LargeStack) { 03352 StackSize = KERNEL_LARGE_BSTORE_SIZE >> PAGE_SHIFT; 03353 } else { 03354 StackSize = KERNEL_BSTORE_SIZE >> PAGE_SHIFT; 03355 } 03356 EndOfStackPte = PointerPte + StackSize; 03357 03358 do { 03359 ASSERT (PointerPte->u.Hard.Valid == 1); 03360 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03361 TempPte = *PointerPte; 03362 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 0); 03363 03364 #ifdef PROTECT_KSTACKS 03365 TempPte.u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03366 { 03367 PMMPFN x; 03368 x = MI_PFN_ELEMENT(PageFrameIndex); 03369 x->OriginalPte.u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03370 } 03371 #endif 03372 03373 FlushPteSave[Count] = TempPte; 03374 FlushPte[Count] = PointerPte; 03375 FlushVa[Count] = BaseOfKernelStack; 03376 03377 MiDecrementShareCount (PageFrameIndex); 03378 PointerPte += 1; 03379 Count += 1; 03380 BaseOfKernelStack = ((PCHAR)BaseOfKernelStack + PAGE_SIZE); 03381 } while (PointerPte <= LastPte); 03382 03383 while (PointerPte != EndOfStackPte) { 03384 if (PointerPte->u.Hard.Valid == 0) { 03385 break; 03386 } 03387 03388 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03389 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 03390 MiDecrementShareAndValidCount (Pfn1->PteFrame); 03391 MI_SET_PFN_DELETED (Pfn1); 03392 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (PointerPte)); 03393 03394 FlushPteSave[Count] = KernelDemandZeroPte; 03395 03396 #ifdef PROTECT_KSTACKS 03397 FlushPteSave[Count].u.Soft.Protection = MM_KSTACK_OUTSWAPPED; 03398 #endif 03399 03400 FlushPte[Count] = PointerPte; 03401 FlushVa[Count] = BaseOfKernelStack; 03402 Count += 1; 03403 03404 PointerPte += 1; 03405 BaseOfKernelStack = ((PCHAR)BaseOfKernelStack + PAGE_SIZE); 03406 } 03407 03408 #endif // _IA64_ 03409 03410 ASSERT (Count <= MAX_STACK_PAGES); 03411 03412 if (Count < MM_MAXIMUM_FLUSH_COUNT) { 03413 KeFlushMultipleTb (Count, 03414 &FlushVa[0], 03415 TRUE, 03416 TRUE, 03417 &((PHARDWARE_PTE)FlushPte[0]), 03418 ZeroPte.u.Flush); 03419 } else { 03420 KeFlushEntireTb (TRUE, TRUE); 03421 } 03422 03423 // 03424 // Increase the available pages by the number of pages that where 03425 // deleted and turned into demand zero. 03426 // 03427 03428 MmKernelStackResident -= Count; 03429 03430 // 03431 // Put the right contents back into the PTEs 03432 // 03433 03434 do { 03435 Count -= 1; 03436 *FlushPte[Count] = FlushPteSave[Count]; 03437 } while (Count != 0); 03438 03439 03440 UNLOCK_PFN (OldIrql); 03441 return; 03442 }

VOID MmOutSwapProcess IN PKPROCESS  Process  ) 
 

Definition at line 3590 of file procsup.c.

References _MMSUPPORT::AllowWorkingSetAdjustment, ASSERT, _KPROCESS::DirectoryTableBase, FALSE, LOCK_EXPANSION, LOCK_PFN, MI_CONVERT_PHYSICAL_TO_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_IS_PHYSICAL_ADDRESS, MI_MAKE_VALID_PTE_TRANSITION, MI_PFN_ELEMENT, MiDecrementShareCount(), MiGetPdeOffset, MiGetPpeOffset, MiGetPteAddress, MiGetPteOffset, MiHydra, MiMapPageInHyperSpace(), MiSessionOutSwapProcess(), MiUnmapPageInHyperSpace, MM_DBG_SWAP_PROCESS, MM_IO_IN_PROGRESS, MM_PROCESS_COMMIT_CHARGE, MM_READWRITE, MM_WS_SWAPPED_OUT, MmWorkingSetList, _EPROCESS::PaeTop, _EPROCESS::PageDirectoryPte, _EPROCESS::Pcb, PMMPTE, _EPROCESS::ProcessOutswapEnabled, _EPROCESS::ProcessOutswapped, _MMPFN::PteAddress, _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMSUPPORT::u, _MMPFN::u2, _MMPFN::u3, UNLOCK_EXPANSION, UNLOCK_PFN, _EPROCESS::Vm, _MMSUPPORT::WorkingSetExpansionLinks, _EPROCESS::WorkingSetPage, and _MMSUPPORT::WorkingSetSize.

Referenced by KiOutSwapProcesses().

03596 : 03597 03598 This routine out swaps the specified process. 03599 03600 Arguments: 03601 03602 Process - Supplies a pointer to the process that is swapped out of memory. 03603 03604 Return Value: 03605 03606 None. 03607 03608 --*/ 03609 03610 { 03611 KIRQL OldIrql; 03612 KIRQL OldIrql2; 03613 PEPROCESS OutProcess; 03614 PMMPTE PointerPte; 03615 PMMPFN Pfn1; 03616 PFN_NUMBER HyperSpacePageTable; 03617 PMMPTE HyperSpacePageTableMap; 03618 PFN_NUMBER PpePage; 03619 PFN_NUMBER PdePage; 03620 PMMPTE PageDirectoryMap; 03621 PFN_NUMBER ProcessPage; 03622 MMPTE TempPte; 03623 #if defined (_X86PAE_) 03624 ULONG i; 03625 MMPTE TempPte2; 03626 PFN_NUMBER PdePage2; 03627 PFN_NUMBER HyperPage2; 03628 PPAE_ENTRY PaeVa; 03629 #endif 03630 03631 OutProcess = CONTAINING_RECORD (Process, EPROCESS, Pcb); 03632 03633 OutProcess->ProcessOutswapEnabled = TRUE; 03634 03635 #if DBG 03636 if ((MmDebug & MM_DBG_SWAP_PROCESS) != 0) { 03637 return; 03638 } 03639 #endif //DBG 03640 03641 if (MiHydra == TRUE && OutProcess->Vm.u.Flags.ProcessInSession == 1) { 03642 MiSessionOutSwapProcess (OutProcess); 03643 } 03644 03645 if ((OutProcess->Vm.WorkingSetSize == MM_PROCESS_COMMIT_CHARGE) && 03646 (OutProcess->Vm.AllowWorkingSetAdjustment)) { 03647 03648 LOCK_EXPANSION (OldIrql); 03649 03650 ASSERT (OutProcess->ProcessOutswapped == FALSE); 03651 03652 if (OutProcess->Vm.u.Flags.BeingTrimmed == TRUE) { 03653 03654 // 03655 // An outswap is not allowed at this point because the process 03656 // has been attached to and is being trimmed. 03657 // 03658 03659 UNLOCK_EXPANSION (OldIrql); 03660 return; 03661 } 03662 03663 // 03664 // Swap the process working set info and page parent/directory/table 03665 // pages from memory. 03666 // 03667 03668 OutProcess->ProcessOutswapped = TRUE; 03669 03670 UNLOCK_EXPANSION (OldIrql); 03671 03672 LOCK_PFN (OldIrql); 03673 03674 // 03675 // Remove the working set list page from the process. 03676 // 03677 03678 #if !defined (_X86PAE_) 03679 HyperSpacePageTable = 03680 MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(OutProcess->Pcb.DirectoryTableBase[1]))); 03681 #else 03682 HyperSpacePageTable = (PFN_NUMBER)OutProcess->Pcb.DirectoryTableBase[1]; 03683 #endif 03684 03685 HyperSpacePageTableMap = MiMapPageInHyperSpace (HyperSpacePageTable, &OldIrql2); 03686 03687 TempPte = HyperSpacePageTableMap[MiGetPteOffset(MmWorkingSetList)]; 03688 03689 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03690 MM_READWRITE); 03691 03692 HyperSpacePageTableMap[MiGetPteOffset(MmWorkingSetList)] = TempPte; 03693 03694 #if defined (_X86PAE_) 03695 TempPte2 = HyperSpacePageTableMap[0]; 03696 03697 HyperPage2 = MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)&TempPte2); 03698 03699 MI_MAKE_VALID_PTE_TRANSITION (TempPte2, 03700 MM_READWRITE); 03701 03702 HyperSpacePageTableMap[0] = TempPte2; 03703 #endif 03704 03705 MiUnmapPageInHyperSpace (OldIrql2); 03706 03707 #if DBG 03708 Pfn1 = MI_PFN_ELEMENT (OutProcess->WorkingSetPage); 03709 ASSERT (Pfn1->u3.e1.Modified == 1); 03710 #endif 03711 MiDecrementShareCount (OutProcess->WorkingSetPage); 03712 03713 // 03714 // Remove the hyper space page from the process. 03715 // 03716 03717 Pfn1 = MI_PFN_ELEMENT (HyperSpacePageTable); 03718 PdePage = Pfn1->PteFrame; 03719 ASSERT (PdePage); 03720 03721 PageDirectoryMap = MiMapPageInHyperSpace (PdePage, &OldIrql2); 03722 03723 TempPte = PageDirectoryMap[MiGetPdeOffset(MmWorkingSetList)]; 03724 03725 ASSERT (TempPte.u.Hard.Valid == 1); 03726 ASSERT (TempPte.u.Hard.PageFrameNumber == HyperSpacePageTable); 03727 03728 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03729 MM_READWRITE); 03730 03731 PageDirectoryMap[MiGetPdeOffset(MmWorkingSetList)] = TempPte; 03732 03733 ASSERT (Pfn1->u3.e1.Modified == 1); 03734 03735 MiDecrementShareCount (HyperSpacePageTable); 03736 03737 #if defined (_X86PAE_) 03738 03739 // 03740 // Remove the second hyper space page from the process. 03741 // 03742 03743 Pfn1 = MI_PFN_ELEMENT (HyperPage2); 03744 03745 ASSERT (Pfn1->u3.e1.Modified == 1); 03746 03747 PdePage = Pfn1->PteFrame; 03748 ASSERT (PdePage); 03749 03750 PageDirectoryMap[MiGetPdeOffset(HYPER_SPACE2)] = TempPte2; 03751 03752 MiDecrementShareCount (HyperPage2); 03753 03754 // 03755 // Remove the additional page directory pages. 03756 // 03757 03758 PaeVa = (PPAE_ENTRY)OutProcess->PaeTop; 03759 for (i = 0; i < PD_PER_SYSTEM - 1; i += 1) { 03760 03761 TempPte = PageDirectoryMap[i]; 03762 PdePage2 = MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)&TempPte); 03763 03764 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03765 MM_READWRITE); 03766 03767 PageDirectoryMap[i] = TempPte; 03768 Pfn1 = MI_PFN_ELEMENT (PdePage2); 03769 ASSERT (Pfn1->u3.e1.Modified == 1); 03770 03771 MiDecrementShareCount (PdePage2); 03772 PaeVa->PteEntry[i].u.Long = TempPte.u.Long; 03773 } 03774 03775 #if DBG 03776 TempPte = PageDirectoryMap[i]; 03777 PdePage2 = MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)&TempPte); 03778 Pfn1 = MI_PFN_ELEMENT (PdePage2); 03779 ASSERT (Pfn1->u3.e1.Modified == 1); 03780 #endif 03781 03782 #endif 03783 03784 #if defined (_WIN64) 03785 03786 MiUnmapPageInHyperSpace (OldIrql2); 03787 03788 // 03789 // Remove the page directory page (64-bit version). 03790 // 03791 03792 Pfn1 = MI_PFN_ELEMENT (PdePage); 03793 PpePage = Pfn1->PteFrame; 03794 ASSERT (PpePage); 03795 ASSERT (PpePage == MI_GET_PAGE_FRAME_FROM_PTE((PMMPTE)(&(OutProcess->Pcb.DirectoryTableBase[0])))); 03796 03797 PageDirectoryMap = MiMapPageInHyperSpace (PpePage, &OldIrql2); 03798 03799 TempPte = PageDirectoryMap[MiGetPpeOffset(MmWorkingSetList)]; 03800 03801 ASSERT (TempPte.u.Hard.Valid == 1); 03802 ASSERT (TempPte.u.Hard.PageFrameNumber == PdePage); 03803 03804 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03805 MM_READWRITE); 03806 03807 PageDirectoryMap[MiGetPpeOffset(MmWorkingSetList)] = TempPte; 03808 03809 ASSERT (Pfn1->u3.e1.Modified == 1); 03810 03811 MiDecrementShareCount (HyperSpacePageTable); 03812 03813 // 03814 // Remove the top level page directory parent page. 03815 // 03816 03817 TempPte = PageDirectoryMap[MiGetPpeOffset(PDE_TBASE)]; 03818 03819 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03820 MM_READWRITE); 03821 03822 PageDirectoryMap[MiGetPpeOffset(PDE_TBASE)] = TempPte; 03823 03824 Pfn1 = MI_PFN_ELEMENT (PpePage); 03825 03826 #else 03827 03828 // 03829 // Remove the top level page directory page. 03830 // 03831 03832 TempPte = PageDirectoryMap[MiGetPdeOffset(PDE_BASE)]; 03833 03834 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03835 MM_READWRITE); 03836 03837 PageDirectoryMap[MiGetPdeOffset(PDE_BASE)] = TempPte; 03838 03839 Pfn1 = MI_PFN_ELEMENT (PdePage); 03840 03841 #endif 03842 03843 MiUnmapPageInHyperSpace (OldIrql2); 03844 03845 // 03846 // Decrement share count so the top level page directory page gets 03847 // removed. This can cause the PteCount to equal the sharecount as the 03848 // page directory page no longer contains itself, yet can have 03849 // itself as a transition page. 03850 // 03851 03852 Pfn1->u2.ShareCount -= 2; 03853 Pfn1->PteAddress = (PMMPTE)&OutProcess->PageDirectoryPte; 03854 03855 OutProcess->PageDirectoryPte = TempPte.u.Flush; 03856 03857 #if defined (_X86PAE_) 03858 PaeVa->PteEntry[i].u.Long = TempPte.u.Long; 03859 #endif 03860 03861 if (MI_IS_PHYSICAL_ADDRESS(OutProcess)) { 03862 ProcessPage = MI_CONVERT_PHYSICAL_TO_PFN (OutProcess); 03863 } else { 03864 PointerPte = MiGetPteAddress (OutProcess); 03865 ProcessPage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 03866 } 03867 03868 Pfn1->PteFrame = ProcessPage; 03869 Pfn1 = MI_PFN_ELEMENT (ProcessPage); 03870 03871 // 03872 // Increment the share count for the process page. 03873 // 03874 03875 Pfn1->u2.ShareCount += 1; 03876 UNLOCK_PFN (OldIrql); 03877 03878 LOCK_EXPANSION (OldIrql); 03879 if (OutProcess->Vm.WorkingSetExpansionLinks.Flink > 03880 MM_IO_IN_PROGRESS) { 03881 03882 // 03883 // The entry must be on the list. 03884 // 03885 RemoveEntryList (&OutProcess->Vm.WorkingSetExpansionLinks); 03886 OutProcess->Vm.WorkingSetExpansionLinks.Flink = MM_WS_SWAPPED_OUT; 03887 } 03888 UNLOCK_EXPANSION (OldIrql); 03889 03890 OutProcess->WorkingSetPage = 0; 03891 OutProcess->Vm.WorkingSetSize = 0; 03892 #if defined(_IA64_) 03893 03894 // 03895 // Force assignment of new PID as we have removed 03896 // the page directory page. 03897 // Note that a TB flush would not work here as we 03898 // are in the wrong process context. 03899 // 03900 03901 Process->ProcessRegion.SequenceNumber = 0; 03902 #endif _IA64_ 03903 03904 } 03905 03906 return; 03907 }

VOID MmSetMemoryPriorityProcess IN PEPROCESS  Process,
IN UCHAR  MemoryPriority
 

Definition at line 5567 of file procsup.c.

References FALSE, KeAttachProcess(), KeDetachProcess(), LOCK_EXPANSION, LOCK_WS, _MMSUPPORT::MaximumWorkingSetSize, MEMORY_PRIORITY_BACKGROUND, _MMSUPPORT::MinimumWorkingSetSize, MiTrimWorkingSet(), MmAvailablePages, MmMoreThanEnoughFreePages, MmNumberOfPhysicalPages, MmSmallSystem, MmSystemSize, MmWorkingSetList, MmWorkingSetReductionMax, PAGE_SIZE, PsGetCurrentProcess, _MMWSL::Quota, TRUE, UNLOCK_EXPANSION, UNLOCK_WS, and _MMSUPPORT::WorkingSetSize.

Referenced by NtSetInformationProcess(), and PsSetProcessPriorityByClass().

05574 : 05575 05576 Sets the memory priority of a process. 05577 05578 Arguments: 05579 05580 Process - Supplies the process to update 05581 05582 MemoryPriority - Supplies the new memory priority of the process 05583 05584 Return Value: 05585 05586 None. 05587 05588 --*/ 05589 05590 { 05591 KIRQL OldIrql; 05592 UCHAR OldPriority; 05593 05594 if (MmSystemSize == MmSmallSystem && MmNumberOfPhysicalPages < ((15*1024*1024)/PAGE_SIZE)) { 05595 05596 // 05597 // If this is a small system, make every process BACKGROUND. 05598 // 05599 05600 MemoryPriority = MEMORY_PRIORITY_BACKGROUND; 05601 } 05602 05603 LOCK_EXPANSION (OldIrql); 05604 05605 OldPriority = Process->Vm.MemoryPriority; 05606 Process->Vm.MemoryPriority = MemoryPriority; 05607 05608 UNLOCK_EXPANSION (OldIrql); 05609 05610 #ifndef _MI_USE_CLAIMS_ 05611 if (OldPriority > MemoryPriority && MmAvailablePages < MmMoreThanEnoughFreePages) { 05612 // 05613 // The priority is being lowered, see if the working set 05614 // should be trimmed. 05615 // 05616 05617 PMMSUPPORT VmSupport; 05618 ULONG i; 05619 ULONG Trim; 05620 LOGICAL Attached; 05621 05622 VmSupport = &Process->Vm; 05623 i = VmSupport->WorkingSetSize - VmSupport->MaximumWorkingSetSize; 05624 if ((LONG)i > 0) { 05625 Trim = i; 05626 if (Trim > MmWorkingSetReductionMax) { 05627 Trim = MmWorkingSetReductionMax; 05628 } 05629 if (Process != PsGetCurrentProcess()) { 05630 KeAttachProcess (&Process->Pcb); 05631 Attached = TRUE; 05632 } 05633 else { 05634 Attached = FALSE; 05635 } 05636 LOCK_WS (Process); 05637 05638 Trim = MiTrimWorkingSet (Trim, 05639 VmSupport, 05640 FALSE); 05641 05642 MmWorkingSetList->Quota = VmSupport->WorkingSetSize; 05643 if (MmWorkingSetList->Quota < VmSupport->MinimumWorkingSetSize) { 05644 MmWorkingSetList->Quota = VmSupport->MinimumWorkingSetSize; 05645 } 05646 05647 UNLOCK_WS (Process); 05648 if (Attached == TRUE) { 05649 KeDetachProcess(); 05650 } 05651 } 05652 } 05653 #endif 05654 return; 05655 }

VOID VadTreeWalk IN PMMVAD  Start  ) 
 


Variable Documentation

PVOID BBTBuffer
 

Definition at line 92 of file procsup.c.

MMPTE KernelDemandZeroPte = {MM_KERNEL_DEMAND_ZERO_PTE}
 

Definition at line 101 of file procsup.c.

Referenced by MmInPageKernelStack(), and MmOutPageKernelStack().

ULONG MiFaultRetries
 

Definition at line 105 of file procsup.c.

LOGICAL MiNoLowMemory
 

Definition at line 160 of file procsup.c.

ULONG MmKernelStackPages
 

Definition at line 96 of file procsup.c.

Referenced by MmCreateKernelStack(), and MmDeleteKernelStack().

PFN_NUMBER MmKernelStackResident
 

Definition at line 97 of file procsup.c.

Referenced by MmCreateKernelStack(), MmDeleteKernelStack(), MmGrowKernelStack(), MmInPageKernelStack(), and MmOutPageKernelStack().

ULONG MmLargeStacks
 

Definition at line 98 of file procsup.c.

Referenced by MmCreateKernelStack(), and MmDeleteKernelStack().

SIZE_T MmProcessCommit
 

Definition at line 94 of file procsup.c.

ULONG MmProductType
 

Definition at line 86 of file procsup.c.

CCHAR MmRotatingUniprocessorNumber
 

Definition at line 103 of file procsup.c.

Referenced by MmCreatePeb().

ULONG MmSmallStacks
 

Definition at line 99 of file procsup.c.

Referenced by MmCreateKernelStack(), and MmDeleteKernelStack().

MM_SYSTEMSIZE MmSystemSize
 

Definition at line 90 of file procsup.c.

Referenced by MmInitSystem(), MmQuerySystemSize(), and MmSetMemoryPriorityProcess().

ULONG MmWorkingSetReductionMax
 

Definition at line 88 of file procsup.c.

Referenced by MiAdjustWorkingSetManagerParameters(), MiDetermineWsTrimAmount(), and MmSetMemoryPriorityProcess().


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