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

vadtree.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 vadtree.c 00008 00009 Abstract: 00010 00011 This module contains the routine to manipulate the virtual address 00012 descriptor tree. 00013 00014 Author: 00015 00016 Lou Perazzoli (loup) 19-May-1989 00017 Landy Wang (landyw) 02-June-1997 00018 00019 Environment: 00020 00021 Kernel mode only, working set mutex held, APCs disabled. 00022 00023 Revision History: 00024 00025 --*/ 00026 00027 #include "mi.h" 00028 00029 VOID 00030 MiInsertVad ( 00031 IN PMMVAD Vad 00032 ) 00033 00034 /*++ 00035 00036 Routine Description: 00037 00038 This function inserts a virtual address descriptor into the tree and 00039 reorders the splay tree as appropriate. 00040 00041 Arguments: 00042 00043 Vad - Supplies a pointer to a virtual address descriptor 00044 00045 00046 Return Value: 00047 00048 None - An exception is raised if quota is exceeded. 00049 00050 --*/ 00051 00052 { 00053 PMMADDRESS_NODE *Root; 00054 PEPROCESS CurrentProcess; 00055 SIZE_T RealCharge; 00056 SIZE_T PageCharge; 00057 SIZE_T PagedQuotaCharged; 00058 ULONG FirstPage; 00059 ULONG LastPage; 00060 SIZE_T PagedPoolCharge; 00061 LOGICAL ChargedPageFileQuota; 00062 LOGICAL ChargedJobCommit; 00063 00064 ASSERT (Vad->EndingVpn >= Vad->StartingVpn); 00065 00066 CurrentProcess = PsGetCurrentProcess(); 00067 00068 // 00069 // Commit charge of MAX_COMMIT means don't charge quota. 00070 // 00071 00072 if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) { 00073 00074 PageCharge = 0; 00075 PagedQuotaCharged = 0; 00076 ChargedPageFileQuota = FALSE; 00077 ChargedJobCommit = FALSE; 00078 00079 // 00080 // Charge quota for the nonpaged pool for the VAD. This is 00081 // done here rather than by using ExAllocatePoolWithQuota 00082 // so the process object is not referenced by the quota charge. 00083 // 00084 00085 PsChargePoolQuota (CurrentProcess, NonPagedPool, sizeof(MMVAD)); 00086 00087 try { 00088 00089 // 00090 // Charge quota for the prototype PTEs if this is a mapped view. 00091 // 00092 00093 if ((Vad->u.VadFlags.PrivateMemory == 0) && 00094 (Vad->ControlArea != NULL)) { 00095 PagedPoolCharge = 00096 (Vad->EndingVpn - Vad->StartingVpn) << PTE_SHIFT; 00097 PsChargePoolQuota (CurrentProcess, PagedPool, PagedPoolCharge); 00098 PagedQuotaCharged = PagedPoolCharge; 00099 } 00100 00101 #if !defined (_WIN64) 00102 // 00103 // Add in the charge for page table pages. 00104 // 00105 00106 FirstPage = MiGetPpePdeOffset (MI_VPN_TO_VA (Vad->StartingVpn)); 00107 LastPage = MiGetPpePdeOffset (MI_VPN_TO_VA (Vad->EndingVpn)); 00108 00109 while (FirstPage <= LastPage) { 00110 00111 if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables, 00112 FirstPage)) { 00113 PageCharge += 1; 00114 } 00115 FirstPage += 1; 00116 } 00117 #endif 00118 00119 RealCharge = Vad->u.VadFlags.CommitCharge + PageCharge; 00120 00121 if (RealCharge != 0) { 00122 00123 MiChargePageFileQuota (RealCharge, CurrentProcess); 00124 ChargedPageFileQuota = TRUE; 00125 00126 #if 0 //commented out so page file quota is meaningful. 00127 if (Vad->u.VadFlags.PrivateMemory == 0) { 00128 00129 if ((Vad->ControlArea->FilePointer == NULL) && 00130 (Vad->u.VadFlags.PhysicalMapping == 0)) { 00131 00132 // 00133 // Don't charge commitment for the page file space 00134 // occupied by a page file section. This will be 00135 // charged as the shared memory is committed. 00136 // 00137 00138 RealCharge -= 1 + (Vad->EndingVpn - 00139 Vad->StartingVpn); 00140 } 00141 } 00142 #endif //0 00143 if (CurrentProcess->CommitChargeLimit) { 00144 if (CurrentProcess->CommitCharge + RealCharge > CurrentProcess->CommitChargeLimit) { 00145 if (CurrentProcess->Job) { 00146 PsReportProcessMemoryLimitViolation (); 00147 } 00148 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 00149 } 00150 } 00151 if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00152 if (PsChangeJobMemoryUsage(RealCharge) == FALSE) { 00153 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 00154 } 00155 ChargedJobCommit = TRUE; 00156 } 00157 00158 if (MiChargeCommitment (RealCharge, CurrentProcess) == FALSE) { 00159 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 00160 } 00161 00162 CurrentProcess->CommitCharge += RealCharge; 00163 if (CurrentProcess->CommitCharge > CurrentProcess->CommitChargePeak) { 00164 CurrentProcess->CommitChargePeak = CurrentProcess->CommitCharge; 00165 } 00166 } 00167 } except (EXCEPTION_EXECUTE_HANDLER) { 00168 00169 // 00170 // Return any quotas charged thus far. 00171 // 00172 00173 PsReturnPoolQuota (CurrentProcess, NonPagedPool, sizeof(MMVAD)); 00174 00175 if (PagedQuotaCharged != 0) { 00176 PsReturnPoolQuota (CurrentProcess, PagedPool, PagedPoolCharge); 00177 } 00178 00179 if (ChargedPageFileQuota == TRUE) { 00180 00181 MiReturnPageFileQuota (RealCharge, 00182 CurrentProcess); 00183 } 00184 00185 if (ChargedJobCommit == TRUE) { 00186 00187 // 00188 // Temporarily up the process commit charge as the 00189 // job code will be referencing it as though everything 00190 // has succeeded. 00191 // 00192 00193 CurrentProcess->CommitCharge += RealCharge; 00194 PsChangeJobMemoryUsage(-(SSIZE_T)RealCharge); 00195 CurrentProcess->CommitCharge -= RealCharge; 00196 } 00197 00198 ExRaiseStatus (GetExceptionCode()); 00199 } 00200 00201 MM_TRACK_COMMIT (MM_DBG_COMMIT_INSERT_VAD, RealCharge); 00202 00203 #if !defined (_WIN64) 00204 if (PageCharge != 0) { 00205 00206 // 00207 // Since the commitment was successful, charge the page 00208 // table pages. 00209 // 00210 00211 FirstPage = MiGetPpePdeOffset (MI_VPN_TO_VA (Vad->StartingVpn)); 00212 00213 while (FirstPage <= LastPage) { 00214 00215 if (!MI_CHECK_BIT (MmWorkingSetList->CommittedPageTables, 00216 FirstPage)) { 00217 MI_SET_BIT (MmWorkingSetList->CommittedPageTables, 00218 FirstPage); 00219 MmWorkingSetList->NumberOfCommittedPageTables += 1; 00220 #if defined (_X86PAE_) 00221 ASSERT (MmWorkingSetList->NumberOfCommittedPageTables < 00222 PD_PER_SYSTEM * PDE_PER_PAGE); 00223 #else 00224 ASSERT (MmWorkingSetList->NumberOfCommittedPageTables < 00225 PDE_PER_PAGE); 00226 #endif 00227 } 00228 FirstPage += 1; 00229 } 00230 } 00231 #endif 00232 } 00233 00234 Root = (PMMADDRESS_NODE *)&CurrentProcess->VadRoot; 00235 00236 // 00237 // Set the hint field in the process to this Vad. 00238 // 00239 00240 CurrentProcess->VadHint = Vad; 00241 00242 if (CurrentProcess->VadFreeHint != NULL) { 00243 if (((ULONG)((PMMVAD)CurrentProcess->VadFreeHint)->EndingVpn + 00244 MI_VA_TO_VPN (X64K)) >= 00245 Vad->StartingVpn) { 00246 CurrentProcess->VadFreeHint = Vad; 00247 } 00248 } 00249 00250 MiInsertNode ( (PMMADDRESS_NODE)Vad, Root); 00251 return; 00252 } 00253 00254 00255 VOID 00256 MiRemoveVad ( 00257 IN PMMVAD Vad 00258 ) 00259 00260 /*++ 00261 00262 Routine Description: 00263 00264 This function removes a virtual address descriptor from the tree and 00265 reorders the splay tree as appropriate. If any quota or commitment 00266 was charged by the VAD (as indicated by the CommitCharge field) it 00267 is released. 00268 00269 Arguments: 00270 00271 Vad - Supplies a pointer to a virtual address descriptor. 00272 00273 Return Value: 00274 00275 None. 00276 00277 --*/ 00278 00279 { 00280 PMMADDRESS_NODE *Root; 00281 PEPROCESS CurrentProcess; 00282 SIZE_T RealCharge; 00283 PLIST_ENTRY Next; 00284 PMMSECURE_ENTRY Entry; 00285 00286 CurrentProcess = PsGetCurrentProcess(); 00287 00288 00289 // 00290 // Commit charge of MAX_COMMIT means don't charge quota. 00291 // 00292 00293 if (Vad->u.VadFlags.CommitCharge != MM_MAX_COMMIT) { 00294 00295 // 00296 // Return the quota charge to the process. 00297 // 00298 00299 PsReturnPoolQuota (CurrentProcess, NonPagedPool, sizeof(MMVAD)); 00300 00301 if ((Vad->u.VadFlags.PrivateMemory == 0) && 00302 (Vad->ControlArea != NULL)) { 00303 PsReturnPoolQuota (CurrentProcess, 00304 PagedPool, 00305 (Vad->EndingVpn - Vad->StartingVpn) << PTE_SHIFT); 00306 } 00307 00308 RealCharge = Vad->u.VadFlags.CommitCharge; 00309 00310 if (RealCharge != 0) { 00311 00312 MiReturnPageFileQuota (RealCharge, CurrentProcess); 00313 00314 if ((Vad->u.VadFlags.PrivateMemory == 0) && 00315 (Vad->ControlArea != NULL)) { 00316 00317 #if 0 //commented out so page file quota is meaningful. 00318 if (Vad->ControlArea->FilePointer == NULL) { 00319 00320 // 00321 // Don't release commitment for the page file space 00322 // occupied by a page file section. This will be charged 00323 // as the shared memory is committed. 00324 // 00325 00326 RealCharge -= BYTES_TO_PAGES ((ULONG)Vad->EndingVa - 00327 (ULONG)Vad->StartingVa); 00328 } 00329 #endif 00330 } 00331 00332 MiReturnCommitment (RealCharge); 00333 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_VAD, RealCharge); 00334 if (CurrentProcess->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 00335 PsChangeJobMemoryUsage(-(SSIZE_T)RealCharge); 00336 } 00337 CurrentProcess->CommitCharge -= RealCharge; 00338 } 00339 } 00340 00341 if (Vad == CurrentProcess->VadFreeHint) { 00342 CurrentProcess->VadFreeHint = MiGetPreviousVad (Vad); 00343 } 00344 00345 Root = (PMMADDRESS_NODE *)&CurrentProcess->VadRoot; 00346 00347 MiRemoveNode ( (PMMADDRESS_NODE)Vad, Root); 00348 00349 if (Vad->u.VadFlags.NoChange) { 00350 if (Vad->u2.VadFlags2.MultipleSecured) { 00351 00352 // 00353 // Free the oustanding pool allocations. 00354 // 00355 00356 Next = Vad->u3.List.Flink; 00357 do { 00358 Entry = CONTAINING_RECORD( Next, 00359 MMSECURE_ENTRY, 00360 List); 00361 00362 Next = Entry->List.Flink; 00363 ExFreePool (Entry); 00364 } while (Next != &Vad->u3.List); 00365 } 00366 } 00367 00368 // 00369 // If the VadHint was the removed Vad, change the Hint. 00370 00371 if (CurrentProcess->VadHint == Vad) { 00372 CurrentProcess->VadHint = CurrentProcess->VadRoot; 00373 } 00374 00375 return; 00376 } 00377 00378 PMMVAD 00379 FASTCALL 00380 MiLocateAddress ( 00381 IN PVOID VirtualAddress 00382 ) 00383 00384 /*++ 00385 00386 Routine Description: 00387 00388 The function locates the virtual address descriptor which describes 00389 a given address. 00390 00391 Arguments: 00392 00393 VirtualAddress - Supplies the virtual address to locate a descriptor 00394 for. 00395 00396 Return Value: 00397 00398 Returns a pointer to the virtual address descriptor which contains 00399 the supplied virtual address or NULL if none was located. 00400 00401 --*/ 00402 00403 { 00404 PMMVAD FoundVad; 00405 PEPROCESS CurrentProcess; 00406 ULONG_PTR Vpn; 00407 00408 CurrentProcess = PsGetCurrentProcess(); 00409 00410 if (CurrentProcess->VadHint == NULL) { 00411 return NULL; 00412 } 00413 00414 Vpn = MI_VA_TO_VPN (VirtualAddress); 00415 if ((Vpn >= ((PMMADDRESS_NODE)CurrentProcess->VadHint)->StartingVpn) && 00416 (Vpn <= ((PMMADDRESS_NODE)CurrentProcess->VadHint)->EndingVpn)) { 00417 00418 return (PMMVAD)CurrentProcess->VadHint; 00419 } 00420 00421 FoundVad = (PMMVAD)MiLocateAddressInTree ( Vpn, 00422 (PMMADDRESS_NODE *)&(CurrentProcess->VadRoot)); 00423 00424 if (FoundVad != NULL) { 00425 CurrentProcess->VadHint = (PVOID)FoundVad; 00426 } 00427 return FoundVad; 00428 } 00429 00430 PVOID 00431 MiFindEmptyAddressRange ( 00432 IN SIZE_T SizeOfRange, 00433 IN ULONG_PTR Alignment, 00434 IN ULONG QuickCheck 00435 ) 00436 00437 /*++ 00438 00439 Routine Description: 00440 00441 The function examines the virtual address descriptors to locate 00442 an unused range of the specified size and returns the starting 00443 address of the range. 00444 00445 Arguments: 00446 00447 SizeOfRange - Supplies the size in bytes of the range to locate. 00448 00449 Alignment - Supplies the alignment for the address. Must be 00450 a power of 2 and greater than the page_size. 00451 00452 QuickCheck - Supplies a zero if a quick check for free memory 00453 after the VadFreeHint exists, non-zero if checking 00454 should start at the lowest address. 00455 00456 Return Value: 00457 00458 Returns the starting address of a suitable range. 00459 00460 --*/ 00461 00462 { 00463 PMMVAD NextVad; 00464 PMMVAD FreeHint; 00465 PEPROCESS CurrentProcess; 00466 PVOID StartingVa; 00467 PVOID EndingVa; 00468 00469 CurrentProcess = PsGetCurrentProcess(); 00470 FreeHint = CurrentProcess->VadFreeHint; 00471 00472 if ((QuickCheck == 0) && (FreeHint != NULL)) { 00473 00474 EndingVa = MI_VPN_TO_VA_ENDING (FreeHint->EndingVpn); 00475 NextVad = MiGetNextVad (FreeHint); 00476 if (NextVad == NULL) { 00477 00478 if (SizeOfRange < 00479 (((ULONG_PTR)MM_HIGHEST_USER_ADDRESS + 1) - 00480 MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) { 00481 return (PMMADDRESS_NODE)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, 00482 Alignment); 00483 } 00484 } else { 00485 StartingVa = MI_VPN_TO_VA (NextVad->StartingVpn); 00486 00487 if (SizeOfRange < 00488 ((ULONG_PTR)StartingVa - 00489 MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, Alignment))) { 00490 00491 // 00492 // Check to ensure that the ending address aligned upwards 00493 // is not greater than the starting address. 00494 // 00495 00496 if ((ULONG_PTR)StartingVa > 00497 MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa,Alignment)) { 00498 return (PMMADDRESS_NODE)MI_ROUND_TO_SIZE((ULONG_PTR)EndingVa, 00499 Alignment); 00500 } 00501 } 00502 } 00503 } 00504 00505 return (PMMVAD)MiFindEmptyAddressRangeInTree ( 00506 SizeOfRange, 00507 Alignment, 00508 (PMMADDRESS_NODE)(CurrentProcess->VadRoot), 00509 (PMMADDRESS_NODE *)&CurrentProcess->VadFreeHint); 00510 00511 } 00512 00513 #if DBG 00514 VOID 00515 VadTreeWalk ( 00516 PMMVAD Start 00517 ) 00518 00519 { 00520 UNREFERENCED_PARAMETER (Start); 00521 00522 NodeTreeWalk ( (PMMADDRESS_NODE)(PsGetCurrentProcess()->VadRoot)); 00523 00524 return; 00525 } 00526 #endif //DBG

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