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

deleteva.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 deleteva.c 00008 00009 Abstract: 00010 00011 This module contains the routines for deleting virtual address space. 00012 00013 Author: 00014 00015 Lou Perazzoli (loup) 11-May-1989 00016 00017 Revision History: 00018 00019 Landy Wang (landyw) 08-April-1998 : Modifications for 3-level 64-bit NT. 00020 00021 --*/ 00022 00023 #include "mi.h" 00024 00025 VOID 00026 MiDeleteVirtualAddresses ( 00027 IN PUCHAR StartingAddress, 00028 IN PUCHAR EndingAddress, 00029 IN ULONG AddressSpaceDeletion, 00030 IN PMMVAD Vad 00031 ) 00032 00033 /*++ 00034 00035 Routine Description: 00036 00037 This routine deletes the specified virtual address range within 00038 the current process. 00039 00040 Arguments: 00041 00042 StartingAddress - Supplies the first virtual address to delete. 00043 00044 EndingAddress - Supplies the last address to delete. 00045 00046 AddressSpaceDeletion - Supplies TRUE if the address space is being 00047 deleted, FALSE otherwise. If TRUE is specified 00048 the TB is not flushed and valid addresses are 00049 not removed from the working set. 00050 00051 Vad - Supplies the virtual address descriptor which maps this range 00052 or NULL if we are not concerned about views. From the Vad the 00053 range of prototype PTEs is determined and this information is 00054 used to uncover if the PTE refers to a prototype PTE or a 00055 fork PTE. 00056 00057 Return Value: 00058 00059 None. 00060 00061 00062 Environment: 00063 00064 Kernel mode, called with APCs disabled, working set mutex and PFN lock 00065 held. These mutexes may be released and reacquired to fault pages in. 00066 00067 --*/ 00068 00069 { 00070 PUCHAR Va; 00071 PUCHAR FirstValidVa; 00072 PVOID TempVa; 00073 PMMPTE PointerPte; 00074 PMMPTE PointerPde; 00075 PMMPTE PointerPpe; 00076 PMMPTE OriginalPointerPte; 00077 PMMPTE ProtoPte; 00078 PMMPTE ProtoPte2; 00079 PMMPTE LastProtoPte; 00080 PMMPTE LastProtoPte2; 00081 PEPROCESS CurrentProcess; 00082 PSUBSECTION Subsection; 00083 PVOID UsedPageTableHandle; 00084 PVOID UsedPageDirectoryHandle; 00085 KIRQL OldIrql; 00086 MMPTE_FLUSH_LIST FlushList; 00087 ULONG Waited; 00088 LOGICAL Skipped; 00089 00090 OldIrql = APC_LEVEL; 00091 FlushList.Count = 0; 00092 00093 MM_PFN_LOCK_ASSERT(); 00094 CurrentProcess = PsGetCurrentProcess(); 00095 00096 Va = StartingAddress; 00097 PointerPpe = MiGetPpeAddress (Va); 00098 PointerPde = MiGetPdeAddress (Va); 00099 PointerPte = MiGetPteAddress (Va); 00100 OriginalPointerPte = PointerPte; 00101 00102 do { 00103 00104 while (MiDoesPpeExistAndMakeValid (PointerPpe, 00105 CurrentProcess, 00106 TRUE, 00107 &Waited) == FALSE) { 00108 00109 // 00110 // This page directory parent entry is empty, go to the next one. 00111 // 00112 00113 PointerPpe += 1; 00114 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00115 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00116 Va = MiGetVirtualAddressMappedByPte (PointerPte); 00117 00118 if (Va > EndingAddress) { 00119 00120 // 00121 // All done, return. 00122 // 00123 00124 return; 00125 } 00126 } 00127 00128 Waited = 0; 00129 00130 while (MiDoesPdeExistAndMakeValid (PointerPde, 00131 CurrentProcess, 00132 TRUE, 00133 &Waited) == FALSE) { 00134 00135 // 00136 // This page directory entry is empty, go to the next one. 00137 // 00138 00139 PointerPde += 1; 00140 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00141 Va = MiGetVirtualAddressMappedByPte (PointerPte); 00142 00143 if (Va > EndingAddress) { 00144 00145 // 00146 // All done, return. 00147 // 00148 00149 return; 00150 } 00151 #if defined (_WIN64) 00152 if (MiIsPteOnPdeBoundary (PointerPde)) { 00153 PointerPpe = MiGetPteAddress (PointerPde); 00154 Waited = 1; 00155 break; 00156 } 00157 #endif 00158 } 00159 00160 } while (Waited != 0); 00161 00162 FirstValidVa = Va; 00163 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va); 00164 00165 // 00166 // A valid PDE has been located, examine each PTE and delete them. 00167 // 00168 00169 if ((Vad == (PMMVAD)NULL) || 00170 (Vad->u.VadFlags.PrivateMemory) || 00171 (Vad->FirstPrototypePte == (PMMPTE)NULL)) { 00172 ProtoPte = (PMMPTE)NULL; 00173 LastProtoPte = (PMMPTE)NULL; 00174 } else { 00175 ProtoPte = Vad->FirstPrototypePte; 00176 LastProtoPte = (PMMPTE)4; 00177 } 00178 00179 // 00180 // Examine each PTE within the address range and delete it. 00181 // 00182 00183 while (Va <= EndingAddress) { 00184 00185 // 00186 // Note that the initial address could be aligned on a PPE or PDE 00187 // boundary so we must check for it here. 00188 // 00189 00190 if (MiIsVirtualAddressOnPdeBoundary(Va)) { 00191 00192 // 00193 // The virtual address is on a page directory boundary, 00194 // check the next PDE for validity and flush PTEs for the 00195 // previous page table page. 00196 // 00197 00198 MiFlushPteList (&FlushList, FALSE, ZeroPte); 00199 00200 // 00201 // If all the entries have been eliminated from the previous 00202 // page table page, delete the page table page itself. 00203 // 00204 00205 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) && 00206 (PointerPde->u.Long != 0)) { 00207 00208 TempVa = MiGetVirtualAddressMappedByPte(PointerPde); 00209 MiDeletePte (PointerPde, 00210 TempVa, 00211 AddressSpaceDeletion, 00212 CurrentProcess, 00213 NULL, 00214 NULL); 00215 00216 #if defined (_WIN64) 00217 if (Va == FirstValidVa) { 00218 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00219 } 00220 else { 00221 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1); 00222 } 00223 00224 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00225 #endif 00226 00227 } 00228 00229 if (MiIsVirtualAddressOnPpeBoundary(Va)) { 00230 00231 if (Va == FirstValidVa) { 00232 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00233 } 00234 else { 00235 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1); 00236 } 00237 00238 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) && 00239 (PointerPpe->u.Long != 0)) { 00240 00241 TempVa = MiGetVirtualAddressMappedByPte(PointerPpe); 00242 MiDeletePte (PointerPpe, 00243 TempVa, 00244 AddressSpaceDeletion, 00245 CurrentProcess, 00246 NULL, 00247 NULL); 00248 } 00249 } 00250 00251 // 00252 // Release the PFN lock. This prevents a single thread 00253 // from forcing other high priority threads from being 00254 // blocked while a large address range is deleted. There 00255 // is nothing magic about the instructions within the 00256 // lock and unlock. 00257 // 00258 00259 UNLOCK_PFN (OldIrql); 00260 PointerPde = MiGetPdeAddress (Va); 00261 PointerPpe = MiGetPpeAddress (Va); 00262 Skipped = FALSE; 00263 LOCK_PFN (OldIrql); 00264 00265 do { 00266 while (MiDoesPpeExistAndMakeValid (PointerPpe, 00267 CurrentProcess, 00268 TRUE, 00269 &Waited) == FALSE) { 00270 00271 // 00272 // This page directory parent entry is empty, 00273 // go to the next one. 00274 // 00275 00276 Skipped = TRUE; 00277 PointerPpe += 1; 00278 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00279 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00280 Va = MiGetVirtualAddressMappedByPte (PointerPte); 00281 00282 if (Va > EndingAddress) { 00283 00284 // 00285 // All done, return. 00286 // 00287 00288 return; 00289 } 00290 } 00291 00292 Waited = 0; 00293 00294 while (MiDoesPdeExistAndMakeValid (PointerPde, 00295 CurrentProcess, 00296 TRUE, 00297 &Waited) == FALSE) { 00298 00299 // 00300 // This page directory entry is empty, go to the next one. 00301 // 00302 00303 Skipped = TRUE; 00304 PointerPde += 1; 00305 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00306 Va = MiGetVirtualAddressMappedByPte (PointerPte); 00307 00308 if (Va > EndingAddress) { 00309 00310 // 00311 // All done, remove any straggling page directories and 00312 // return. 00313 // 00314 00315 #if defined (_WIN64) 00316 00317 PointerPde -= 1; 00318 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00319 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00320 00321 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) && 00322 (PointerPpe->u.Long != 0)) { 00323 00324 TempVa = MiGetVirtualAddressMappedByPte(PointerPpe); 00325 MiDeletePte (PointerPpe, 00326 TempVa, 00327 AddressSpaceDeletion, 00328 CurrentProcess, 00329 NULL, 00330 NULL); 00331 } 00332 #endif 00333 00334 return; 00335 } 00336 00337 #if defined (_WIN64) 00338 if (MiIsPteOnPdeBoundary (PointerPde)) { 00339 PointerPpe = MiGetPteAddress (PointerPde); 00340 Waited = 1; 00341 break; 00342 } 00343 #endif 00344 00345 #if DBG 00346 if ((LastProtoPte != NULL) && 00347 (Vad->u2.VadFlags2.ExtendableFile == 0)) { 00348 ProtoPte2 = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN (Va)); 00349 Subsection = MiLocateSubsection (Vad,MI_VA_TO_VPN (Va)); 00350 LastProtoPte2 = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00351 if (Vad->u.VadFlags.ImageMap != 1) { 00352 if ((ProtoPte2 < Subsection->SubsectionBase) || 00353 (ProtoPte2 >= LastProtoPte2)) { 00354 DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n", 00355 ProtoPte2,Va,Vad,Subsection); 00356 DbgBreakPoint(); 00357 } 00358 } 00359 } 00360 #endif //DBG 00361 } 00362 00363 } while (Waited != 0); 00364 00365 // 00366 // The PPE and PDE are now valid, get the page table use count. 00367 // 00368 00369 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va); 00370 00371 // 00372 // If we skipped chunks of address space, the prototype PTE pointer 00373 // must be updated now so VADs that span multiple subsections 00374 // are handled properly. 00375 // 00376 00377 if ((Skipped == TRUE) && (LastProtoPte != NULL)) { 00378 00379 ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va)); 00380 Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va)); 00381 00382 if (Subsection != NULL) { 00383 LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00384 #if DBG 00385 if (Vad->u.VadFlags.ImageMap != 1) { 00386 if ((ProtoPte < Subsection->SubsectionBase) || 00387 (ProtoPte >= LastProtoPte)) { 00388 DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n", 00389 ProtoPte,Va,Vad,Subsection); 00390 DbgBreakPoint(); 00391 } 00392 } 00393 #endif //DBG 00394 } 00395 else { 00396 00397 // 00398 // The Vad span is larger than the section being mapped. 00399 // Null the proto PTE local as no more proto PTEs will 00400 // need to be deleted at this point. 00401 // 00402 00403 LastProtoPte = (PMMPTE)NULL; 00404 } 00405 } 00406 } 00407 00408 // 00409 // The PPE and PDE are now valid, delete the PTEs. 00410 // 00411 00412 if (PointerPte->u.Long != 0) { 00413 00414 // 00415 // One less used page table entry in this page table page. 00416 // 00417 00418 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 00419 00420 if (IS_PTE_NOT_DEMAND_ZERO (*PointerPte)) { 00421 00422 if (LastProtoPte != NULL) { 00423 if (ProtoPte >= LastProtoPte) { 00424 ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va)); 00425 Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va)); 00426 LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00427 } 00428 #if DBG 00429 if (Vad->u.VadFlags.ImageMap != 1) { 00430 if ((ProtoPte < Subsection->SubsectionBase) || 00431 (ProtoPte >= LastProtoPte)) { 00432 DbgPrint ("bad proto pte %p va %p Vad %p sub %p\n", 00433 ProtoPte,Va,Vad,Subsection); 00434 DbgBreakPoint(); 00435 } 00436 } 00437 #endif //DBG 00438 } 00439 00440 MiDeletePte (PointerPte, 00441 (PVOID)Va, 00442 AddressSpaceDeletion, 00443 CurrentProcess, 00444 ProtoPte, 00445 &FlushList); 00446 } else { 00447 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 00448 } 00449 } 00450 00451 Va += PAGE_SIZE; 00452 PointerPte += 1; 00453 ProtoPte += 1; 00454 } 00455 00456 // 00457 // Flush out entries for the last page table page. 00458 // 00459 00460 MiFlushPteList (&FlushList, FALSE, ZeroPte); 00461 00462 // 00463 // If all the entries have been eliminated from the previous 00464 // page table page, delete the page table page itself. 00465 // 00466 00467 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) && 00468 (PointerPde->u.Long != 0)) { 00469 00470 TempVa = MiGetVirtualAddressMappedByPte(PointerPde); 00471 MiDeletePte (PointerPde, 00472 TempVa, 00473 AddressSpaceDeletion, 00474 CurrentProcess, 00475 NULL, 00476 NULL); 00477 00478 #if defined (_WIN64) 00479 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1); 00480 00481 MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00482 00483 if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) && 00484 (PointerPpe->u.Long != 0)) { 00485 00486 TempVa = MiGetVirtualAddressMappedByPte(PointerPpe); 00487 MiDeletePte (PointerPpe, 00488 TempVa, 00489 AddressSpaceDeletion, 00490 CurrentProcess, 00491 NULL, 00492 NULL); 00493 } 00494 #endif 00495 } 00496 00497 // 00498 // All done, return. 00499 // 00500 00501 return; 00502 } 00503 00504 00505 VOID 00506 MiDeletePte ( 00507 IN PMMPTE PointerPte, 00508 IN PVOID VirtualAddress, 00509 IN ULONG AddressSpaceDeletion, 00510 IN PEPROCESS CurrentProcess, 00511 IN PMMPTE PrototypePte, 00512 IN PMMPTE_FLUSH_LIST PteFlushList OPTIONAL 00513 ) 00514 00515 /*++ 00516 00517 Routine Description: 00518 00519 This routine deletes the contents of the specified PTE. The PTE 00520 can be in one of the following states: 00521 00522 - active and valid 00523 - transition 00524 - in paging file 00525 - in prototype PTE format 00526 00527 Arguments: 00528 00529 PointerPte - Supplies a pointer to the PTE to delete. 00530 00531 VirtualAddress - Supplies the virtual address which corresponds to 00532 the PTE. This is used to locate the working set entry 00533 to eliminate it. 00534 00535 AddressSpaceDeletion - Supplies TRUE if the address space is being 00536 deleted, FALSE otherwise. If TRUE is specified 00537 the TB is not flushed and valid addresses are 00538 not removed from the working set. 00539 00540 00541 CurrentProcess - Supplies a pointer to the current process. 00542 00543 PrototypePte - Supplies a pointer to the prototype PTE which currently 00544 or originally mapped this page. This is used to determine 00545 if the PTE is a fork PTE and should have its reference block 00546 decremented. 00547 00548 Return Value: 00549 00550 None. 00551 00552 Environment: 00553 00554 Kernel mode, APCs disabled, PFN lock and working set mutex held. 00555 00556 --*/ 00557 00558 { 00559 PMMPTE PointerPde; 00560 PMMPTE PointerPpe; 00561 PMMPFN Pfn1; 00562 PMMPFN Pfn2; 00563 MMPTE PteContents; 00564 ULONG WorkingSetIndex; 00565 ULONG Entry; 00566 PVOID SwapVa; 00567 MMWSLENTRY Locked; 00568 ULONG WsPfnIndex; 00569 PMMCLONE_BLOCK CloneBlock; 00570 PMMCLONE_DESCRIPTOR CloneDescriptor; 00571 ULONG Waited; 00572 00573 MM_PFN_LOCK_ASSERT(); 00574 00575 #if DBG 00576 if (MmDebug & MM_DBG_PTE_UPDATE) { 00577 DbgPrint("deleting PTE\n"); 00578 MiFormatPte(PointerPte); 00579 } 00580 #endif //DBG 00581 00582 PteContents = *PointerPte; 00583 00584 if (PteContents.u.Hard.Valid == 1) { 00585 00586 #ifdef _X86_ 00587 #if DBG 00588 #if !defined(NT_UP) 00589 00590 if (PteContents.u.Hard.Writable == 1) { 00591 ASSERT (PteContents.u.Hard.Dirty == 1); 00592 } 00593 ASSERT (PteContents.u.Hard.Accessed == 1); 00594 #endif //NTUP 00595 #endif //DBG 00596 #endif //X86 00597 00598 // 00599 // PTE is valid. Check PFN database to see if this is a prototype PTE. 00600 // 00601 00602 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 00603 WsPfnIndex = Pfn1->u1.WsIndex; 00604 00605 #if DBG 00606 if (MmDebug & MM_DBG_PTE_UPDATE) { 00607 MiFormatPfn(Pfn1); 00608 } 00609 #endif //DBG 00610 00611 CloneDescriptor = NULL; 00612 00613 if (Pfn1->u3.e1.PrototypePte == 1) { 00614 00615 CloneBlock = (PMMCLONE_BLOCK)Pfn1->PteAddress; 00616 00617 // 00618 // Capture the state of the modified bit for this PTE. 00619 // 00620 00621 MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1); 00622 00623 // 00624 // Decrement the share and valid counts of the page table 00625 // page which maps this PTE. 00626 // 00627 00628 PointerPde = MiGetPteAddress (PointerPte); 00629 if (PointerPde->u.Hard.Valid == 0) { 00630 #if !defined (_WIN64) 00631 if (!NT_SUCCESS(MiCheckPdeForPagedPool (PointerPte))) { 00632 #endif 00633 KeBugCheckEx (MEMORY_MANAGEMENT, 00634 0x61940, 00635 (ULONG_PTR)PointerPte, 00636 (ULONG_PTR)PointerPde->u.Long, 00637 (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPte)); 00638 #if !defined (_WIN64) 00639 } 00640 #endif 00641 } 00642 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 00643 00644 // 00645 // Decrement the share count for the physical page. 00646 // 00647 00648 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 00649 00650 // 00651 // Check to see if this is a fork prototype PTE and if so 00652 // update the clone descriptor address. 00653 // 00654 00655 if (PointerPte <= MiHighestUserPte) { 00656 00657 if (PrototypePte != Pfn1->PteAddress) { 00658 00659 // 00660 // Locate the clone descriptor within the clone tree. 00661 // 00662 00663 CloneDescriptor = MiLocateCloneAddress ((PVOID)CloneBlock); 00664 00665 #if DBG 00666 if (CloneDescriptor == NULL) { 00667 DbgPrint("1PrototypePte %p Clone desc %p pfn pte addr %p\n", 00668 PrototypePte, CloneDescriptor, Pfn1->PteAddress); 00669 MiFormatPte(PointerPte); 00670 ASSERT (FALSE); 00671 } 00672 #endif // DBG 00673 00674 } 00675 } 00676 } else { 00677 00678 ASSERT (Pfn1->u2.ShareCount == 1); 00679 00680 // 00681 // This PTE is a NOT a prototype PTE, delete the physical page. 00682 // 00683 00684 // 00685 // Decrement the share and valid counts of the page table 00686 // page which maps this PTE. 00687 // 00688 00689 MiDecrementShareAndValidCount (Pfn1->PteFrame); 00690 00691 MI_SET_PFN_DELETED (Pfn1); 00692 00693 // 00694 // Decrement the share count for the physical page. As the page 00695 // is private it will be put on the free list. 00696 // 00697 00698 MiDecrementShareCountOnly (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 00699 00700 // 00701 // Decrement the count for the number of private pages. 00702 // 00703 00704 CurrentProcess->NumberOfPrivatePages -= 1; 00705 } 00706 00707 // 00708 // Find the WSLE for this page and eliminate it. 00709 // 00710 00711 // 00712 // If we are deleting the system portion of the address space, do 00713 // not remove WSLEs or flush translation buffers as there can be 00714 // no other usage of this address space. 00715 // 00716 00717 if (AddressSpaceDeletion == FALSE) { 00718 00719 WorkingSetIndex = MiLocateWsle (VirtualAddress, 00720 MmWorkingSetList, 00721 WsPfnIndex ); 00722 00723 ASSERT (WorkingSetIndex != WSLE_NULL_INDEX); 00724 00725 // 00726 // Check to see if this entry is locked in the working set 00727 // or locked in memory. 00728 // 00729 00730 Locked = MmWsle[WorkingSetIndex].u1.e1; 00731 00732 MiRemoveWsle (WorkingSetIndex, MmWorkingSetList); 00733 00734 // 00735 // Add this entry to the list of free working set entries 00736 // and adjust the working set count. 00737 // 00738 00739 MiReleaseWsle (WorkingSetIndex, &CurrentProcess->Vm); 00740 00741 if ((Locked.LockedInWs == 1) || (Locked.LockedInMemory == 1)) { 00742 00743 // 00744 // This entry is locked. 00745 // 00746 00747 ASSERT (WorkingSetIndex < MmWorkingSetList->FirstDynamic); 00748 MmWorkingSetList->FirstDynamic -= 1; 00749 00750 if (WorkingSetIndex != MmWorkingSetList->FirstDynamic) { 00751 00752 Entry = MmWorkingSetList->FirstDynamic; 00753 ASSERT (MmWsle[Entry].u1.e1.Valid); 00754 SwapVa = MmWsle[Entry].u1.VirtualAddress; 00755 SwapVa = PAGE_ALIGN (SwapVa); 00756 Pfn2 = MI_PFN_ELEMENT ( 00757 MiGetPteAddress (SwapVa)->u.Hard.PageFrameNumber); 00758 #if 0 00759 Entry = MiLocateWsleAndParent (SwapVa, 00760 &Parent, 00761 MmWorkingSetList, 00762 Pfn2->u1.WsIndex); 00763 00764 // 00765 // Swap the removed entry with the last locked entry 00766 // which is located at first dynamic. 00767 // 00768 00769 MiSwapWslEntries (Entry, 00770 Parent, 00771 WorkingSetIndex, 00772 MmWorkingSetList); 00773 #endif //0 00774 00775 MiSwapWslEntries (Entry, 00776 WorkingSetIndex, 00777 &CurrentProcess->Vm); 00778 } 00779 } else { 00780 ASSERT (WorkingSetIndex >= MmWorkingSetList->FirstDynamic); 00781 } 00782 00783 // 00784 // Flush the entry out of the TB. 00785 // 00786 00787 if (!ARGUMENT_PRESENT (PteFlushList)) { 00788 KeFlushSingleTb (VirtualAddress, 00789 TRUE, 00790 FALSE, 00791 (PHARDWARE_PTE)PointerPte, 00792 ZeroPte.u.Flush); 00793 } else { 00794 if (PteFlushList->Count != MM_MAXIMUM_FLUSH_COUNT) { 00795 PteFlushList->FlushPte[PteFlushList->Count] = PointerPte; 00796 PteFlushList->FlushVa[PteFlushList->Count] = VirtualAddress; 00797 PteFlushList->Count += 1; 00798 } 00799 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 00800 } 00801 00802 if (CloneDescriptor != NULL) { 00803 00804 // 00805 // Flush PTEs as this could release the PFN_LOCK. 00806 // 00807 00808 if (ARGUMENT_PRESENT (PteFlushList)) { 00809 MiFlushPteList (PteFlushList, FALSE, ZeroPte); 00810 } 00811 00812 // 00813 // Decrement the reference count for the clone block, 00814 // note that this could release and reacquire 00815 // the mutexes hence cannot be done until after the 00816 // working set index has been removed. 00817 // 00818 00819 if (MiDecrementCloneBlockReference ( CloneDescriptor, 00820 CloneBlock, 00821 CurrentProcess )) { 00822 00823 // 00824 // The working set mutex was released. This may 00825 // have removed the current page directory & table page. 00826 // 00827 00828 PointerPpe = MiGetPteAddress (PointerPde); 00829 00830 do { 00831 00832 MiDoesPpeExistAndMakeValid (PointerPpe, 00833 CurrentProcess, 00834 TRUE, 00835 &Waited); 00836 00837 Waited = 0; 00838 00839 // 00840 // If the call below results in a PFN release and 00841 // reacquire, then we must redo them both. 00842 // 00843 00844 MiDoesPdeExistAndMakeValid (PointerPde, 00845 CurrentProcess, 00846 TRUE, 00847 &Waited); 00848 00849 } while (Waited != 0); 00850 } 00851 } 00852 } 00853 00854 } else if (PteContents.u.Soft.Prototype == 1) { 00855 00856 // 00857 // This is a prototype PTE, if it is a fork PTE clean up the 00858 // fork structures. 00859 // 00860 00861 if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) { 00862 00863 // 00864 // Check to see if the prototype PTE is a fork prototype PTE. 00865 // 00866 00867 if (PointerPte <= MiHighestUserPte) { 00868 00869 if (PrototypePte != MiPteToProto (PointerPte)) { 00870 00871 CloneBlock = (PMMCLONE_BLOCK)MiPteToProto (PointerPte); 00872 CloneDescriptor = MiLocateCloneAddress ((PVOID)CloneBlock); 00873 00874 00875 #if DBG 00876 if (CloneDescriptor == NULL) { 00877 DbgPrint("1PrototypePte %p Clone desc %p \n", 00878 PrototypePte, CloneDescriptor); 00879 MiFormatPte(PointerPte); 00880 ASSERT (FALSE); 00881 } 00882 #endif //DBG 00883 00884 // 00885 // Decrement the reference count for the clone block, 00886 // note that this could release and reacquire 00887 // the mutexes. 00888 // 00889 00890 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 00891 00892 if (ARGUMENT_PRESENT (PteFlushList)) { 00893 MiFlushPteList (PteFlushList, FALSE, ZeroPte); 00894 } 00895 00896 if (MiDecrementCloneBlockReference ( CloneDescriptor, 00897 CloneBlock, 00898 CurrentProcess )) { 00899 00900 // 00901 // The working set mutex was released. This may 00902 // have removed the current page directory & table page. 00903 // 00904 00905 PointerPde = MiGetPteAddress (PointerPte); 00906 PointerPpe = MiGetPteAddress (PointerPde); 00907 00908 // 00909 // If either call below results in a PFN release and 00910 // reacquire, then we must redo them both. 00911 // 00912 00913 do { 00914 00915 if (MiDoesPpeExistAndMakeValid (PointerPpe, 00916 CurrentProcess, 00917 TRUE, 00918 &Waited) == FALSE) { 00919 00920 // 00921 // The PPE has been deleted when the PFN lock 00922 // was released. Just bail as the PDE/PTE are 00923 // gone now anyway. 00924 // 00925 00926 return; 00927 } 00928 00929 Waited = 0; 00930 00931 // 00932 // If the call below results in a PFN release and 00933 // reacquire, then we must redo them both. If the 00934 // PDE was deleted when the PFN lock was released 00935 // then we just bail as the PTE is gone anyway. 00936 // 00937 00938 if (MiDoesPdeExistAndMakeValid (PointerPde, 00939 CurrentProcess, 00940 TRUE, 00941 &Waited) == FALSE) { 00942 return; 00943 } 00944 00945 } while (Waited != 0); 00946 } 00947 } 00948 } 00949 } 00950 00951 } else if (PteContents.u.Soft.Transition == 1) { 00952 00953 // 00954 // This is a transition PTE. (Page is private) 00955 // 00956 00957 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 00958 00959 MI_SET_PFN_DELETED (Pfn1); 00960 00961 MiDecrementShareCount (Pfn1->PteFrame); 00962 00963 // 00964 // Check the reference count for the page, if the reference 00965 // count is zero, move the page to the free list, if the reference 00966 // count is not zero, ignore this page. When the reference count 00967 // goes to zero, it will be placed on the free list. 00968 // 00969 00970 if (Pfn1->u3.e2.ReferenceCount == 0) { 00971 MiUnlinkPageFromList (Pfn1); 00972 MiReleasePageFileSpace (Pfn1->OriginalPte); 00973 MiInsertPageInList (MmPageLocationList[FreePageList], 00974 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents)); 00975 } 00976 00977 // 00978 // Decrement the count for the number of private pages. 00979 // 00980 00981 CurrentProcess->NumberOfPrivatePages -= 1; 00982 00983 } else { 00984 00985 // 00986 // Must be page file space. 00987 // 00988 00989 if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) { 00990 00991 if (MiReleasePageFileSpace (*PointerPte)) { 00992 00993 // 00994 // Decrement the count for the number of private pages. 00995 // 00996 00997 CurrentProcess->NumberOfPrivatePages -= 1; 00998 } 00999 } 01000 } 01001 01002 // 01003 // Zero the PTE contents. 01004 // 01005 01006 MI_WRITE_INVALID_PTE (PointerPte, ZeroPte); 01007 01008 return; 01009 } 01010 01011 01012 ULONG 01013 FASTCALL 01014 MiReleasePageFileSpace ( 01015 IN MMPTE PteContents 01016 ) 01017 01018 /*++ 01019 01020 Routine Description: 01021 01022 This routine frees the paging file allocated to the specified PTE 01023 and adjusts the necessary quotas. 01024 01025 Arguments: 01026 01027 PteContents - Supplies the PTE which is in page file format. 01028 01029 Return Value: 01030 01031 Returns TRUE if any paging file space was deallocated. 01032 01033 Environment: 01034 01035 Kernel mode, APCs disabled, PFN lock held. 01036 01037 --*/ 01038 01039 { 01040 ULONG FreeBit; 01041 ULONG PageFileNumber; 01042 01043 MM_PFN_LOCK_ASSERT(); 01044 01045 if (PteContents.u.Soft.Prototype == 1) { 01046 01047 // 01048 // Not in page file format. 01049 // 01050 01051 return FALSE; 01052 } 01053 01054 FreeBit = GET_PAGING_FILE_OFFSET (PteContents); 01055 01056 if ((FreeBit == 0) || (FreeBit == 0xFFFFF)) { 01057 01058 // 01059 // Page is not in a paging file, just return. 01060 // 01061 01062 return FALSE; 01063 } 01064 01065 PageFileNumber = GET_PAGING_FILE_NUMBER (PteContents); 01066 01067 ASSERT (RtlCheckBit( MmPagingFile[PageFileNumber]->Bitmap, FreeBit) == 1); 01068 01069 #if DBG 01070 if ((FreeBit < 8192) && (PageFileNumber == 0)) { 01071 ASSERT ((MmPagingFileDebug[FreeBit] & 1) != 0); 01072 MmPagingFileDebug[FreeBit] ^= 1; 01073 } 01074 #endif //DBG 01075 01076 RtlClearBits ( MmPagingFile[PageFileNumber]->Bitmap, FreeBit, 1); 01077 01078 MmPagingFile[PageFileNumber]->FreeSpace += 1; 01079 MmPagingFile[PageFileNumber]->CurrentUsage -= 1; 01080 01081 // 01082 // Check to see if we should move some MDL entries for the 01083 // modified page writer now that more free space is available. 01084 // 01085 01086 if ((MmNumberOfActiveMdlEntries == 0) || 01087 (MmPagingFile[PageFileNumber]->FreeSpace == MM_USABLE_PAGES_FREE)) { 01088 01089 MiUpdateModifiedWriterMdls (PageFileNumber); 01090 } 01091 01092 return TRUE; 01093 } 01094 01095 01096 VOID 01097 FASTCALL 01098 MiUpdateModifiedWriterMdls ( 01099 IN ULONG PageFileNumber 01100 ) 01101 01102 /*++ 01103 01104 Routine Description: 01105 01106 This routine ensures the MDLs for the specified paging file 01107 are in the proper state such that paging i/o can continue. 01108 01109 Arguments: 01110 01111 PageFileNumber - Supplies the page file number to check the MDLs for. 01112 01113 Return Value: 01114 01115 None. 01116 01117 Environment: 01118 01119 Kernel mode, PFN lock held. 01120 01121 --*/ 01122 01123 { 01124 ULONG i; 01125 PMMMOD_WRITER_MDL_ENTRY WriterEntry; 01126 01127 // 01128 // Put the MDL entries into the active list. 01129 // 01130 01131 for (i = 0; i < MM_PAGING_FILE_MDLS; i += 1) { 01132 01133 if ((MmPagingFile[PageFileNumber]->Entry[i]->Links.Flink != 01134 MM_IO_IN_PROGRESS) 01135 && 01136 (MmPagingFile[PageFileNumber]->Entry[i]->CurrentList == 01137 &MmFreePagingSpaceLow)) { 01138 01139 // 01140 // Remove this entry and put it on the active list. 01141 // 01142 01143 WriterEntry = MmPagingFile[PageFileNumber]->Entry[i]; 01144 RemoveEntryList (&WriterEntry->Links); 01145 WriterEntry->CurrentList = &MmPagingFileHeader.ListHead; 01146 01147 KeSetEvent (&WriterEntry->PagingListHead->Event, 0, FALSE); 01148 01149 InsertTailList (&WriterEntry->PagingListHead->ListHead, 01150 &WriterEntry->Links); 01151 MmNumberOfActiveMdlEntries += 1; 01152 } 01153 } 01154 01155 return; 01156 } 01157 01158 01159 VOID 01160 MiFlushPteList ( 01161 IN PMMPTE_FLUSH_LIST PteFlushList, 01162 IN ULONG AllProcessors, 01163 IN MMPTE FillPte 01164 ) 01165 01166 /*++ 01167 01168 Routine Description: 01169 01170 This routine flushes all the PTEs in the PTE flush list. 01171 If the list has overflowed, the entire TB is flushed. 01172 01173 Arguments: 01174 01175 PteFlushList - Supplies an optional pointer to the list to be flushed. 01176 01177 AllProcessors - Supplies TRUE if the flush occurs on all processors. 01178 01179 FillPte - Supplies the PTE to fill with. 01180 01181 Return Value: 01182 01183 None. 01184 01185 Environment: 01186 01187 Kernel mode, PFN lock held. 01188 01189 --*/ 01190 01191 { 01192 ULONG count; 01193 01194 ASSERT (ARGUMENT_PRESENT (PteFlushList)); 01195 MM_PFN_LOCK_ASSERT (); 01196 01197 count = PteFlushList->Count; 01198 01199 if (count != 0) { 01200 if (count != 1) { 01201 if (count < MM_MAXIMUM_FLUSH_COUNT) { 01202 KeFlushMultipleTb (count, 01203 &PteFlushList->FlushVa[0], 01204 TRUE, 01205 (BOOLEAN)AllProcessors, 01206 &((PHARDWARE_PTE)PteFlushList->FlushPte[0]), 01207 FillPte.u.Flush); 01208 } else { 01209 01210 // 01211 // Array has overflowed, flush the entire TB. 01212 // 01213 01214 if (AllProcessors == TRUE) { 01215 MiLockSystemSpaceAtDpcLevel(); 01216 KeFlushEntireTb (TRUE, TRUE); 01217 MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK; 01218 MiUnlockSystemSpaceFromDpcLevel(); 01219 } else { 01220 KeFlushEntireTb (TRUE, FALSE); 01221 } 01222 } 01223 } else { 01224 KeFlushSingleTb (PteFlushList->FlushVa[0], 01225 TRUE, 01226 (BOOLEAN)AllProcessors, 01227 (PHARDWARE_PTE)PteFlushList->FlushPte[0], 01228 FillPte.u.Flush); 01229 } 01230 PteFlushList->Count = 0; 01231 } 01232 return; 01233 }

Generated on Sat May 15 19:39:40 2004 for test by doxygen 1.3.7