Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1661 lines
47 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. deleteva.c
  5. Abstract:
  6. This module contains the routines for deleting virtual address space.
  7. Author:
  8. Lou Perazzoli (loup) 11-May-1989
  9. Landy Wang (landyw) 02-June-1997
  10. --*/
  11. #include "mi.h"
  12. #if defined (_WIN64_) && defined (DBG_VERBOSE)
  13. typedef struct _MI_TRACK_USE {
  14. PFN_NUMBER Pfn;
  15. PVOID Va;
  16. ULONG Id;
  17. ULONG PfnUse;
  18. ULONG PfnUseCounted;
  19. ULONG TickCount;
  20. PKTHREAD Thread;
  21. PEPROCESS Process;
  22. } MI_TRACK_USE, *PMI_TRACK_USE;
  23. ULONG MiTrackUseSize = 8192;
  24. PMI_TRACK_USE MiTrackUse;
  25. LONG MiTrackUseIndex;
  26. VOID
  27. MiInitUseCounts (
  28. VOID
  29. )
  30. {
  31. MiTrackUse = ExAllocatePoolWithTag (NonPagedPool,
  32. MiTrackUseSize * sizeof (MI_TRACK_USE),
  33. 'lqrI');
  34. ASSERT (MiTrackUse != NULL);
  35. }
  36. VOID
  37. MiCheckUseCounts (
  38. PVOID TempHandle,
  39. PVOID Va,
  40. ULONG Id
  41. )
  42. /*++
  43. Routine Description:
  44. This routine ensures that all the counters are correct.
  45. Arguments:
  46. TempHandle - Supplies the handle for used page table counts.
  47. Va - Supplies the virtual address.
  48. Id - Supplies the ID.
  49. Return Value:
  50. None.
  51. Environment:
  52. Kernel mode, called with APCs disabled, working set mutex and PFN lock
  53. held.
  54. --*/
  55. {
  56. LOGICAL LogIt;
  57. ULONG i;
  58. ULONG TempHandleCount;
  59. ULONG TempCounted;
  60. PMMPTE TempPage;
  61. KIRQL OldIrql;
  62. ULONG Index;
  63. PFN_NUMBER PageFrameIndex;
  64. PMI_TRACK_USE Information;
  65. LARGE_INTEGER TimeStamp;
  66. PMMPFN Pfn1;
  67. PEPROCESS Process;
  68. Process = PsGetCurrentProcess ();
  69. //
  70. // TempHandle is really the PMMPFN containing the UsedPageTableEntries.
  71. //
  72. Pfn1 = (PMMPFN)TempHandle;
  73. PageFrameIndex = Pfn1 - MmPfnDatabase;
  74. TempHandleCount = MI_GET_USED_PTES_FROM_HANDLE (TempHandle);
  75. if (Id & 0x80000000) {
  76. ASSERT (TempHandleCount != 0);
  77. }
  78. TempPage = (PMMPTE) MiMapPageInHyperSpace (Process, PageFrameIndex, &OldIrql);
  79. TempCounted = 0;
  80. for (i = 0; i < PTE_PER_PAGE; i += 1) {
  81. if (TempPage->u.Long != 0) {
  82. TempCounted += 1;
  83. }
  84. TempPage += 1;
  85. }
  86. #if 0
  87. if (zz & 0x4) {
  88. LogIt = FALSE;
  89. if (Pfn1->PteFrame == PageFrameIndex) {
  90. // TopLevel parent page, not interesting to us.
  91. }
  92. else {
  93. PMMPFN Pfn2;
  94. Pfn2 = MI_PFN_ELEMENT (Pfn1->PteFrame);
  95. if (Pfn2->PteFrame == Pfn1->PteFrame) {
  96. // our parent is the toplevel, so very interesting.
  97. LogIt = TRUE;
  98. }
  99. }
  100. }
  101. else {
  102. LogIt = TRUE;
  103. }
  104. #else
  105. LogIt = TRUE;
  106. #endif
  107. if (LogIt == TRUE) {
  108. //
  109. // Capture information
  110. //
  111. Index = InterlockedExchangeAdd(&MiTrackUseIndex, 1);
  112. Index &= (MiTrackUseSize - 1);
  113. Information = &(MiTrackUse[Index]);
  114. Information->Thread = KeGetCurrentThread();
  115. Information->Process = (PEPROCESS)((ULONG_PTR)PsGetCurrentProcess() + KeGetCurrentProcessorNumber());
  116. Information->Va = Va;
  117. Information->Id = Id;
  118. KeQueryTickCount(&TimeStamp);
  119. Information->TickCount = TimeStamp.LowPart;
  120. Information->Pfn = PageFrameIndex;
  121. Information->PfnUse = TempHandleCount;
  122. Information->PfnUseCounted = TempCounted;
  123. if (TempCounted != TempHandleCount) {
  124. DbgPrint ("MiCheckUseCounts %p %x %x %x %x\n", Va, Id, PageFrameIndex, TempHandleCount, TempCounted);
  125. DbgBreakPoint ();
  126. }
  127. }
  128. MiUnmapPageInHyperSpace (Process, TempPage, OldIrql);
  129. return;
  130. }
  131. #endif
  132. VOID
  133. MiDeleteVirtualAddresses (
  134. IN PUCHAR StartingAddress,
  135. IN PUCHAR EndingAddress,
  136. IN ULONG AddressSpaceDeletion,
  137. IN PMMVAD Vad
  138. )
  139. /*++
  140. Routine Description:
  141. This routine deletes the specified virtual address range within
  142. the current process.
  143. Arguments:
  144. StartingAddress - Supplies the first virtual address to delete.
  145. EndingAddress - Supplies the last address to delete.
  146. AddressSpaceDeletion - Supplies TRUE if the address space is being
  147. deleted, FALSE otherwise. If TRUE is specified
  148. the TB is not flushed and valid addresses are
  149. not removed from the working set.
  150. Vad - Supplies the virtual address descriptor which maps this range
  151. or NULL if we are not concerned about views. From the Vad the
  152. range of prototype PTEs is determined and this information is
  153. used to uncover if the PTE refers to a prototype PTE or a
  154. fork PTE.
  155. Return Value:
  156. None.
  157. Environment:
  158. Kernel mode, called with APCs disabled, working set mutex and PFN lock
  159. held. These mutexes may be released and reacquired to fault pages in.
  160. --*/
  161. {
  162. PUCHAR Va;
  163. PVOID TempVa;
  164. PMMPTE PointerPte;
  165. PMMPTE PointerPde;
  166. PMMPTE PointerPpe;
  167. PMMPTE PointerPxe;
  168. PMMPTE OriginalPointerPte;
  169. PMMPTE ProtoPte;
  170. PMMPTE LastProtoPte;
  171. PEPROCESS CurrentProcess;
  172. PSUBSECTION Subsection;
  173. PVOID UsedPageTableHandle;
  174. KIRQL OldIrql;
  175. MMPTE_FLUSH_LIST FlushList;
  176. ULONG Waited;
  177. LOGICAL Skipped;
  178. #if DBG
  179. PMMPTE ProtoPte2;
  180. PMMPTE LastProtoPte2;
  181. #endif
  182. #if (_MI_PAGING_LEVELS >= 3)
  183. PVOID UsedPageDirectoryHandle;
  184. PVOID TempHandle;
  185. #endif
  186. OldIrql = APC_LEVEL;
  187. FlushList.Count = 0;
  188. MM_PFN_LOCK_ASSERT();
  189. CurrentProcess = PsGetCurrentProcess();
  190. Va = StartingAddress;
  191. PointerPpe = MiGetPpeAddress (Va);
  192. PointerPde = MiGetPdeAddress (Va);
  193. PointerPte = MiGetPteAddress (Va);
  194. PointerPxe = MiGetPxeAddress (Va);
  195. OriginalPointerPte = PointerPte;
  196. do {
  197. #if (_MI_PAGING_LEVELS >= 3)
  198. restart:
  199. #endif
  200. while (MiDoesPxeExistAndMakeValid (PointerPxe,
  201. CurrentProcess,
  202. TRUE,
  203. &Waited) == FALSE) {
  204. //
  205. // This extended page directory parent entry is empty,
  206. // go to the next one.
  207. //
  208. PointerPxe += 1;
  209. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  210. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  211. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  212. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  213. if (Va > EndingAddress) {
  214. //
  215. // All done, return.
  216. //
  217. return;
  218. }
  219. }
  220. #if (_MI_PAGING_LEVELS >= 4)
  221. Waited = 0;
  222. #endif
  223. while (MiDoesPpeExistAndMakeValid (PointerPpe,
  224. CurrentProcess,
  225. TRUE,
  226. &Waited) == FALSE) {
  227. //
  228. // This page directory parent entry is empty, go to the next one.
  229. //
  230. PointerPpe += 1;
  231. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  232. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  233. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  234. if (Va > EndingAddress) {
  235. //
  236. // All done, return.
  237. //
  238. return;
  239. }
  240. #if (_MI_PAGING_LEVELS >= 4)
  241. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  242. PointerPxe += 1;
  243. ASSERT (PointerPxe == MiGetPteAddress (PointerPpe));
  244. goto restart;
  245. }
  246. #endif
  247. }
  248. #if (_MI_PAGING_LEVELS < 4)
  249. Waited = 0;
  250. #endif
  251. #if (_MI_PAGING_LEVELS >= 3) && defined (DBG)
  252. MI_CHECK_USED_PTES_HANDLE (PointerPte);
  253. TempHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
  254. ASSERT ((MI_GET_USED_PTES_FROM_HANDLE (TempHandle) != 0) ||
  255. (PointerPde->u.Long == 0));
  256. #endif
  257. while (MiDoesPdeExistAndMakeValid (PointerPde,
  258. CurrentProcess,
  259. TRUE,
  260. &Waited) == FALSE) {
  261. //
  262. // This page directory entry is empty, go to the next one.
  263. //
  264. PointerPde += 1;
  265. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  266. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  267. if (Va > EndingAddress) {
  268. //
  269. // All done, return.
  270. //
  271. return;
  272. }
  273. #if (_MI_PAGING_LEVELS >= 3)
  274. if (MiIsPteOnPdeBoundary (PointerPde)) {
  275. PointerPpe += 1;
  276. ASSERT (PointerPpe == MiGetPteAddress (PointerPde));
  277. PointerPxe = MiGetPteAddress (PointerPpe);
  278. goto restart;
  279. }
  280. #endif
  281. }
  282. #if (_MI_PAGING_LEVELS >= 3) && defined (DBG)
  283. MI_CHECK_USED_PTES_HANDLE (Va);
  284. TempHandle = MI_GET_USED_PTES_HANDLE (Va);
  285. ASSERT ((MI_GET_USED_PTES_FROM_HANDLE (TempHandle) != 0) ||
  286. (PointerPte->u.Long == 0));
  287. #endif
  288. } while (Waited != 0);
  289. //
  290. // A valid PDE has been located, examine each PTE and delete them.
  291. //
  292. ASSERT64 (PointerPpe->u.Hard.Valid == 1);
  293. ASSERT (PointerPde->u.Hard.Valid == 1);
  294. ASSERT (Va <= EndingAddress);
  295. MI_CHECK_USED_PTES_HANDLE (Va);
  296. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va);
  297. if ((Vad == (PMMVAD)NULL) ||
  298. (Vad->u.VadFlags.PrivateMemory) ||
  299. (Vad->FirstPrototypePte == (PMMPTE)NULL)) {
  300. ProtoPte = (PMMPTE)NULL;
  301. LastProtoPte = (PMMPTE)NULL;
  302. }
  303. else {
  304. ProtoPte = Vad->FirstPrototypePte;
  305. LastProtoPte = (PMMPTE)4;
  306. }
  307. //
  308. // Initializing Subsection is not needed for correctness, but
  309. // without it the compiler cannot compile this code W4 to check
  310. // for use of uninitialized variables.
  311. //
  312. Subsection = NULL;
  313. //
  314. // Examine each PTE within the address range and delete it.
  315. //
  316. do {
  317. //
  318. // The PPE and PDE are now valid, delete the PTE.
  319. //
  320. ASSERT64 (PointerPpe->u.Hard.Valid == 1);
  321. ASSERT (PointerPde->u.Hard.Valid == 1);
  322. ASSERT (Va <= EndingAddress);
  323. MI_CHECK_USED_PTES_HANDLE (Va);
  324. ASSERT (UsedPageTableHandle == MI_GET_USED_PTES_HANDLE (Va));
  325. if (PointerPte->u.Long != 0) {
  326. //
  327. // One less used page table entry in this page table page.
  328. //
  329. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
  330. if (IS_PTE_NOT_DEMAND_ZERO (*PointerPte)) {
  331. if (LastProtoPte != NULL) {
  332. if (ProtoPte >= LastProtoPte) {
  333. ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va));
  334. Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va));
  335. LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
  336. }
  337. #if DBG
  338. if (Vad->u.VadFlags.ImageMap != 1) {
  339. if ((ProtoPte < Subsection->SubsectionBase) ||
  340. (ProtoPte >= LastProtoPte)) {
  341. DbgPrint ("bad proto PTE %p va %p Vad %p sub %p\n",
  342. ProtoPte,Va,Vad,Subsection);
  343. DbgBreakPoint();
  344. }
  345. }
  346. #endif
  347. }
  348. Waited = MiDeletePte (PointerPte,
  349. (PVOID)Va,
  350. AddressSpaceDeletion,
  351. CurrentProcess,
  352. ProtoPte,
  353. &FlushList);
  354. #if (_MI_PAGING_LEVELS >= 3)
  355. //
  356. // This must be recalculated here if MiDeletePte dropped the
  357. // PFN lock (this can happen when dealing with POSIX forked
  358. // pages. Since the used PTE count is kept in the PFN entry
  359. // which could have been paged out and replaced during this
  360. // window, recomputation of its address (not the contents)
  361. // is necessary.
  362. //
  363. if (Waited != 0) {
  364. MI_CHECK_USED_PTES_HANDLE (Va);
  365. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va);
  366. }
  367. #endif
  368. }
  369. else {
  370. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  371. }
  372. }
  373. Va += PAGE_SIZE;
  374. PointerPte += 1;
  375. ProtoPte += 1;
  376. ASSERT64 (PointerPpe->u.Hard.Valid == 1);
  377. ASSERT (PointerPde->u.Hard.Valid == 1);
  378. //
  379. // If not at the end of a page table and still within the specified
  380. // range, then just march directly on to the next PTE.
  381. //
  382. if ((!MiIsVirtualAddressOnPdeBoundary(Va)) && (Va <= EndingAddress)) {
  383. continue;
  384. }
  385. //
  386. // The virtual address is on a page directory boundary:
  387. //
  388. // 1. Flush the PTEs for the previous page table page.
  389. // 2. Delete the previous page directory & page table if appropriate.
  390. // 3. Attempt to leap forward skipping over empty page directories
  391. // and page tables where possible.
  392. //
  393. //
  394. // If all the entries have been eliminated from the previous
  395. // page table page, delete the page table page itself.
  396. //
  397. MiFlushPteList (&FlushList, FALSE, ZeroPte);
  398. //
  399. // If all the entries have been eliminated from the previous
  400. // page table page, delete the page table page itself.
  401. //
  402. ASSERT64 (PointerPpe->u.Hard.Valid == 1);
  403. ASSERT (PointerPde->u.Hard.Valid == 1);
  404. #if (_MI_PAGING_LEVELS >= 3)
  405. MI_CHECK_USED_PTES_HANDLE (PointerPte - 1);
  406. #endif
  407. if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageTableHandle) == 0) &&
  408. (PointerPde->u.Long != 0)) {
  409. #if (_MI_PAGING_LEVELS >= 3)
  410. UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte - 1);
  411. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
  412. #endif
  413. TempVa = MiGetVirtualAddressMappedByPte(PointerPde);
  414. MiDeletePte (PointerPde,
  415. TempVa,
  416. AddressSpaceDeletion,
  417. CurrentProcess,
  418. NULL,
  419. NULL);
  420. #if (_MI_PAGING_LEVELS >= 3)
  421. if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) &&
  422. (PointerPpe->u.Long != 0)) {
  423. #if (_MI_PAGING_LEVELS >= 4)
  424. UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPde);
  425. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
  426. #endif
  427. TempVa = MiGetVirtualAddressMappedByPte(PointerPpe);
  428. MiDeletePte (PointerPpe,
  429. TempVa,
  430. AddressSpaceDeletion,
  431. CurrentProcess,
  432. NULL,
  433. NULL);
  434. #if (_MI_PAGING_LEVELS >= 4)
  435. if ((MI_GET_USED_PTES_FROM_HANDLE (UsedPageDirectoryHandle) == 0) &&
  436. (PointerPxe->u.Long != 0)) {
  437. TempVa = MiGetVirtualAddressMappedByPte(PointerPxe);
  438. MiDeletePte (PointerPxe,
  439. TempVa,
  440. AddressSpaceDeletion,
  441. CurrentProcess,
  442. NULL,
  443. NULL);
  444. }
  445. #endif
  446. }
  447. #endif
  448. }
  449. if (Va > EndingAddress) {
  450. //
  451. // All done, return.
  452. //
  453. return;
  454. }
  455. //
  456. // Release the PFN lock. This prevents a single thread
  457. // from forcing other high priority threads from being
  458. // blocked while a large address range is deleted. There
  459. // is nothing magic about the instructions within the
  460. // lock and unlock.
  461. //
  462. UNLOCK_PFN (OldIrql);
  463. PointerPde = MiGetPdeAddress (Va);
  464. PointerPpe = MiGetPpeAddress (Va);
  465. PointerPxe = MiGetPxeAddress (Va);
  466. Skipped = FALSE;
  467. LOCK_PFN (OldIrql);
  468. //
  469. // Attempt to leap forward skipping over empty page directories
  470. // and page tables where possible.
  471. //
  472. do {
  473. #if (_MI_PAGING_LEVELS >= 3)
  474. restart2:
  475. #endif
  476. while (MiDoesPxeExistAndMakeValid (PointerPxe,
  477. CurrentProcess,
  478. TRUE,
  479. &Waited) == FALSE) {
  480. //
  481. // This extended page directory parent entry is empty,
  482. // go to the next one.
  483. //
  484. Skipped = TRUE;
  485. PointerPxe += 1;
  486. PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
  487. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  488. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  489. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  490. if (Va > EndingAddress) {
  491. //
  492. // All done, return.
  493. //
  494. return;
  495. }
  496. }
  497. #if (_MI_PAGING_LEVELS >= 4)
  498. Waited = 0;
  499. #endif
  500. while (MiDoesPpeExistAndMakeValid (PointerPpe,
  501. CurrentProcess,
  502. TRUE,
  503. &Waited) == FALSE) {
  504. //
  505. // This page directory parent entry is empty,
  506. // go to the next one.
  507. //
  508. Skipped = TRUE;
  509. PointerPpe += 1;
  510. PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
  511. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  512. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  513. if (Va > EndingAddress) {
  514. //
  515. // All done, return.
  516. //
  517. return;
  518. }
  519. #if (_MI_PAGING_LEVELS >= 4)
  520. if (MiIsPteOnPdeBoundary (PointerPpe)) {
  521. PointerPxe += 1;
  522. ASSERT (PointerPxe == MiGetPteAddress (PointerPpe));
  523. goto restart2;
  524. }
  525. #endif
  526. }
  527. #if (_MI_PAGING_LEVELS >= 3) && defined (DBG)
  528. MI_CHECK_USED_PTES_HANDLE (PointerPte);
  529. TempHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
  530. ASSERT ((MI_GET_USED_PTES_FROM_HANDLE (TempHandle) != 0) ||
  531. (PointerPde->u.Long == 0));
  532. #endif
  533. #if (_MI_PAGING_LEVELS < 4)
  534. Waited = 0;
  535. #endif
  536. while (MiDoesPdeExistAndMakeValid (PointerPde,
  537. CurrentProcess,
  538. TRUE,
  539. &Waited) == FALSE) {
  540. //
  541. // This page directory entry is empty, go to the next one.
  542. //
  543. Skipped = TRUE;
  544. PointerPde += 1;
  545. PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
  546. Va = MiGetVirtualAddressMappedByPte (PointerPte);
  547. if (Va > EndingAddress) {
  548. //
  549. // All done, remove any straggling page directories and
  550. // return.
  551. //
  552. return;
  553. }
  554. #if (_MI_PAGING_LEVELS >= 3)
  555. if (MiIsPteOnPdeBoundary (PointerPde)) {
  556. PointerPpe += 1;
  557. ASSERT (PointerPpe == MiGetPteAddress (PointerPde));
  558. PointerPxe = MiGetPteAddress (PointerPpe);
  559. goto restart2;
  560. }
  561. #endif
  562. #if DBG
  563. if ((LastProtoPte != NULL) &&
  564. (Vad->u2.VadFlags2.ExtendableFile == 0)) {
  565. ProtoPte2 = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN (Va));
  566. Subsection = MiLocateSubsection (Vad,MI_VA_TO_VPN (Va));
  567. LastProtoPte2 = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
  568. if (Vad->u.VadFlags.ImageMap != 1) {
  569. if ((ProtoPte2 < Subsection->SubsectionBase) ||
  570. (ProtoPte2 >= LastProtoPte2)) {
  571. DbgPrint ("bad proto PTE %p va %p Vad %p sub %p\n",
  572. ProtoPte2,Va,Vad,Subsection);
  573. DbgBreakPoint();
  574. }
  575. }
  576. }
  577. #endif
  578. }
  579. #if (_MI_PAGING_LEVELS >= 3) && defined (DBG)
  580. MI_CHECK_USED_PTES_HANDLE (Va);
  581. TempHandle = MI_GET_USED_PTES_HANDLE (Va);
  582. ASSERT ((MI_GET_USED_PTES_FROM_HANDLE (TempHandle) != 0) ||
  583. (PointerPte->u.Long == 0));
  584. #endif
  585. } while (Waited != 0);
  586. //
  587. // The PPE and PDE are now valid, get the page table use address
  588. // as it changes whenever the PDE does.
  589. //
  590. #if (_MI_PAGING_LEVELS >= 4)
  591. ASSERT64 (PointerPxe->u.Hard.Valid == 1);
  592. #endif
  593. ASSERT64 (PointerPpe->u.Hard.Valid == 1);
  594. ASSERT (PointerPde->u.Hard.Valid == 1);
  595. ASSERT (Va <= EndingAddress);
  596. MI_CHECK_USED_PTES_HANDLE (Va);
  597. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (Va);
  598. //
  599. // If we skipped chunks of address space, the prototype PTE pointer
  600. // must be updated now so VADs that span multiple subsections
  601. // are handled properly.
  602. //
  603. if ((Skipped == TRUE) && (LastProtoPte != NULL)) {
  604. ProtoPte = MiGetProtoPteAddress(Vad, MI_VA_TO_VPN(Va));
  605. Subsection = MiLocateSubsection (Vad, MI_VA_TO_VPN(Va));
  606. if (Subsection != NULL) {
  607. LastProtoPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
  608. #if DBG
  609. if (Vad->u.VadFlags.ImageMap != 1) {
  610. if ((ProtoPte < Subsection->SubsectionBase) ||
  611. (ProtoPte >= LastProtoPte)) {
  612. DbgPrint ("bad proto PTE %p va %p Vad %p sub %p\n",
  613. ProtoPte,Va,Vad,Subsection);
  614. DbgBreakPoint();
  615. }
  616. }
  617. #endif
  618. }
  619. else {
  620. //
  621. // The Vad span is larger than the section being mapped.
  622. // Null the proto PTE local as no more proto PTEs will
  623. // need to be deleted at this point.
  624. //
  625. LastProtoPte = NULL;
  626. }
  627. }
  628. ASSERT (Va <= EndingAddress);
  629. } while (TRUE);
  630. }
  631. ULONG
  632. MiDeletePte (
  633. IN PMMPTE PointerPte,
  634. IN PVOID VirtualAddress,
  635. IN ULONG AddressSpaceDeletion,
  636. IN PEPROCESS CurrentProcess,
  637. IN PMMPTE PrototypePte,
  638. IN PMMPTE_FLUSH_LIST PteFlushList OPTIONAL
  639. )
  640. /*++
  641. Routine Description:
  642. This routine deletes the contents of the specified PTE. The PTE
  643. can be in one of the following states:
  644. - active and valid
  645. - transition
  646. - in paging file
  647. - in prototype PTE format
  648. Arguments:
  649. PointerPte - Supplies a pointer to the PTE to delete.
  650. VirtualAddress - Supplies the virtual address which corresponds to
  651. the PTE. This is used to locate the working set entry
  652. to eliminate it.
  653. AddressSpaceDeletion - Supplies TRUE if the address space is being
  654. deleted, FALSE otherwise. If TRUE is specified
  655. the TB is not flushed and valid addresses are
  656. not removed from the working set.
  657. CurrentProcess - Supplies a pointer to the current process.
  658. PrototypePte - Supplies a pointer to the prototype PTE which currently
  659. or originally mapped this page. This is used to determine
  660. if the PTE is a fork PTE and should have its reference block
  661. decremented.
  662. Return Value:
  663. Nonzero if this routine released mutexes and locks, FALSE if not.
  664. Environment:
  665. Kernel mode, APCs disabled, PFN lock and working set mutex held.
  666. --*/
  667. {
  668. PMMPTE PointerPde;
  669. PMMPTE PointerPpe;
  670. PMMPTE PointerPxe;
  671. PMMPFN Pfn1;
  672. PMMPFN Pfn2;
  673. MMPTE PteContents;
  674. WSLE_NUMBER WorkingSetIndex;
  675. WSLE_NUMBER Entry;
  676. MMWSLENTRY Locked;
  677. WSLE_NUMBER WsPfnIndex;
  678. PMMCLONE_BLOCK CloneBlock;
  679. PMMCLONE_DESCRIPTOR CloneDescriptor;
  680. ULONG Waited;
  681. ULONG DroppedLocks;
  682. PFN_NUMBER PageFrameIndex;
  683. PFN_NUMBER PageTableFrameIndex;
  684. MM_PFN_LOCK_ASSERT();
  685. DroppedLocks = 0;
  686. #if DBG
  687. if (MmDebug & MM_DBG_PTE_UPDATE) {
  688. DbgPrint("deleting PTE\n");
  689. MiFormatPte(PointerPte);
  690. }
  691. #endif
  692. PteContents = *PointerPte;
  693. if (PteContents.u.Hard.Valid == 1) {
  694. #ifdef _X86_
  695. #if DBG
  696. #if !defined(NT_UP)
  697. if (PteContents.u.Hard.Writable == 1) {
  698. ASSERT (PteContents.u.Hard.Dirty == 1);
  699. }
  700. #endif //NTUP
  701. #endif //DBG
  702. #endif //X86
  703. //
  704. // PTE is valid. Check PFN database to see if this is a prototype PTE.
  705. //
  706. PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE(&PteContents);
  707. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  708. WsPfnIndex = Pfn1->u1.WsIndex;
  709. #if DBG
  710. if (MmDebug & MM_DBG_PTE_UPDATE) {
  711. MiFormatPfn(Pfn1);
  712. }
  713. #endif
  714. CloneDescriptor = NULL;
  715. if (Pfn1->u3.e1.PrototypePte == 1) {
  716. CloneBlock = (PMMCLONE_BLOCK)Pfn1->PteAddress;
  717. //
  718. // Capture the state of the modified bit for this PTE.
  719. //
  720. MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1);
  721. //
  722. // Decrement the share and valid counts of the page table
  723. // page which maps this PTE.
  724. //
  725. PointerPde = MiGetPteAddress (PointerPte);
  726. if (PointerPde->u.Hard.Valid == 0) {
  727. #if (_MI_PAGING_LEVELS < 3)
  728. if (!NT_SUCCESS(MiCheckPdeForPagedPool (PointerPte))) {
  729. #endif
  730. KeBugCheckEx (MEMORY_MANAGEMENT,
  731. 0x61940,
  732. (ULONG_PTR)PointerPte,
  733. (ULONG_PTR)PointerPde->u.Long,
  734. (ULONG_PTR)MiGetVirtualAddressMappedByPte(PointerPte));
  735. #if (_MI_PAGING_LEVELS < 3)
  736. }
  737. #endif
  738. }
  739. PageTableFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE(PointerPde);
  740. Pfn2 = MI_PFN_ELEMENT (PageTableFrameIndex);
  741. MiDecrementShareCountInline (Pfn2, PageTableFrameIndex);
  742. //
  743. // Decrement the share count for the physical page.
  744. //
  745. MiDecrementShareCountInline (Pfn1, PageFrameIndex);
  746. //
  747. // Check to see if this is a fork prototype PTE and if so
  748. // update the clone descriptor address.
  749. //
  750. if (PointerPte <= MiHighestUserPte) {
  751. if (PrototypePte != Pfn1->PteAddress) {
  752. //
  753. // Locate the clone descriptor within the clone tree.
  754. //
  755. CloneDescriptor = MiLocateCloneAddress (CurrentProcess, (PVOID)CloneBlock);
  756. #if DBG
  757. if (CloneDescriptor == NULL) {
  758. DbgPrint("1PrototypePte %p Clone desc %p pfn PTE addr %p\n",
  759. PrototypePte, CloneDescriptor, Pfn1->PteAddress);
  760. MiFormatPte(PointerPte);
  761. ASSERT (FALSE);
  762. }
  763. #endif
  764. }
  765. }
  766. }
  767. else {
  768. //
  769. // Initializing CloneBlock & PointerPde is not needed for
  770. // correctness but without it the compiler cannot compile this code
  771. // W4 to check for use of uninitialized variables.
  772. //
  773. CloneBlock = NULL;
  774. PointerPde = NULL;
  775. ASSERT (Pfn1->u2.ShareCount == 1);
  776. //
  777. // This PTE is a NOT a prototype PTE, delete the physical page.
  778. //
  779. //
  780. // Decrement the share and valid counts of the page table
  781. // page which maps this PTE.
  782. //
  783. MiDecrementShareCountInline (MI_PFN_ELEMENT(Pfn1->u4.PteFrame),
  784. Pfn1->u4.PteFrame);
  785. MI_SET_PFN_DELETED (Pfn1);
  786. //
  787. // Decrement the share count for the physical page. As the page
  788. // is private it will be put on the free list.
  789. //
  790. MiDecrementShareCountOnly (PageFrameIndex);
  791. //
  792. // Decrement the count for the number of private pages.
  793. //
  794. CurrentProcess->NumberOfPrivatePages -= 1;
  795. }
  796. //
  797. // Find the WSLE for this page and eliminate it.
  798. //
  799. //
  800. // If we are deleting the system portion of the address space, do
  801. // not remove WSLEs or flush translation buffers as there can be
  802. // no other usage of this address space.
  803. //
  804. if (AddressSpaceDeletion == FALSE) {
  805. WorkingSetIndex = MiLocateWsle (VirtualAddress,
  806. MmWorkingSetList,
  807. WsPfnIndex);
  808. ASSERT (WorkingSetIndex != WSLE_NULL_INDEX);
  809. //
  810. // Check to see if this entry is locked in the working set
  811. // or locked in memory.
  812. //
  813. Locked = MmWsle[WorkingSetIndex].u1.e1;
  814. MiRemoveWsle (WorkingSetIndex, MmWorkingSetList);
  815. //
  816. // Add this entry to the list of free working set entries
  817. // and adjust the working set count.
  818. //
  819. MiReleaseWsle (WorkingSetIndex, &CurrentProcess->Vm);
  820. if ((Locked.LockedInWs == 1) || (Locked.LockedInMemory == 1)) {
  821. //
  822. // This entry is locked.
  823. //
  824. ASSERT (WorkingSetIndex < MmWorkingSetList->FirstDynamic);
  825. MmWorkingSetList->FirstDynamic -= 1;
  826. if (WorkingSetIndex != MmWorkingSetList->FirstDynamic) {
  827. Entry = MmWorkingSetList->FirstDynamic;
  828. ASSERT (MmWsle[Entry].u1.e1.Valid);
  829. #if 0
  830. SwapVa = MmWsle[Entry].u1.VirtualAddress;
  831. SwapVa = PAGE_ALIGN (SwapVa);
  832. Pfn2 = MI_PFN_ELEMENT (
  833. MiGetPteAddress (SwapVa)->u.Hard.PageFrameNumber);
  834. Entry = MiLocateWsleAndParent (SwapVa,
  835. &Parent,
  836. MmWorkingSetList,
  837. Pfn2->u1.WsIndex);
  838. //
  839. // Swap the removed entry with the last locked entry
  840. // which is located at first dynamic.
  841. //
  842. MiSwapWslEntries (Entry,
  843. Parent,
  844. WorkingSetIndex,
  845. MmWorkingSetList);
  846. #endif //0
  847. MiSwapWslEntries (Entry,
  848. WorkingSetIndex,
  849. &CurrentProcess->Vm);
  850. }
  851. }
  852. else {
  853. ASSERT (WorkingSetIndex >= MmWorkingSetList->FirstDynamic);
  854. }
  855. //
  856. // Flush the entry out of the TB.
  857. //
  858. if (!ARGUMENT_PRESENT (PteFlushList)) {
  859. KeFlushSingleTb (VirtualAddress,
  860. TRUE,
  861. FALSE,
  862. (PHARDWARE_PTE)PointerPte,
  863. ZeroPte.u.Flush);
  864. }
  865. else {
  866. if (PteFlushList->Count != MM_MAXIMUM_FLUSH_COUNT) {
  867. PteFlushList->FlushPte[PteFlushList->Count] = PointerPte;
  868. PteFlushList->FlushVa[PteFlushList->Count] = VirtualAddress;
  869. PteFlushList->Count += 1;
  870. }
  871. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  872. }
  873. if (CloneDescriptor != NULL) {
  874. //
  875. // Flush PTEs as this could release the PFN lock.
  876. //
  877. if (ARGUMENT_PRESENT (PteFlushList)) {
  878. MiFlushPteList (PteFlushList, FALSE, ZeroPte);
  879. }
  880. //
  881. // Decrement the reference count for the clone block,
  882. // note that this could release and reacquire
  883. // the mutexes hence cannot be done until after the
  884. // working set index has been removed.
  885. //
  886. if (MiDecrementCloneBlockReference (CloneDescriptor,
  887. CloneBlock,
  888. CurrentProcess)) {
  889. //
  890. // The working set mutex was released. This may
  891. // have removed the current page directory & table page.
  892. //
  893. DroppedLocks = 1;
  894. PointerPpe = MiGetPteAddress (PointerPde);
  895. PointerPxe = MiGetPdeAddress (PointerPde);
  896. do {
  897. MiDoesPxeExistAndMakeValid (PointerPxe,
  898. CurrentProcess,
  899. TRUE,
  900. &Waited);
  901. #if (_MI_PAGING_LEVELS >= 4)
  902. Waited = 0;
  903. #endif
  904. MiDoesPpeExistAndMakeValid (PointerPpe,
  905. CurrentProcess,
  906. TRUE,
  907. &Waited);
  908. #if (_MI_PAGING_LEVELS < 4)
  909. Waited = 0;
  910. #endif
  911. //
  912. // If the call below results in a PFN release and
  913. // reacquire, then we must redo them both.
  914. //
  915. MiDoesPdeExistAndMakeValid (PointerPde,
  916. CurrentProcess,
  917. TRUE,
  918. &Waited);
  919. } while (Waited != 0);
  920. }
  921. }
  922. }
  923. }
  924. else if (PteContents.u.Soft.Prototype == 1) {
  925. //
  926. // This is a prototype PTE, if it is a fork PTE clean up the
  927. // fork structures.
  928. //
  929. if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) {
  930. //
  931. // Check to see if the prototype PTE is a fork prototype PTE.
  932. //
  933. if (PointerPte <= MiHighestUserPte) {
  934. if (PrototypePte != MiPteToProto (PointerPte)) {
  935. CloneBlock = (PMMCLONE_BLOCK)MiPteToProto (PointerPte);
  936. CloneDescriptor = MiLocateCloneAddress (CurrentProcess, (PVOID)CloneBlock);
  937. #if DBG
  938. if (CloneDescriptor == NULL) {
  939. DbgPrint("1PrototypePte %p Clone desc %p \n",
  940. PrototypePte, CloneDescriptor);
  941. MiFormatPte(PointerPte);
  942. ASSERT (FALSE);
  943. }
  944. #endif
  945. //
  946. // Decrement the reference count for the clone block,
  947. // note that this could release and reacquire
  948. // the mutexes.
  949. //
  950. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  951. if (ARGUMENT_PRESENT (PteFlushList)) {
  952. MiFlushPteList (PteFlushList, FALSE, ZeroPte);
  953. }
  954. if (MiDecrementCloneBlockReference ( CloneDescriptor,
  955. CloneBlock,
  956. CurrentProcess )) {
  957. //
  958. // The working set mutex was released. This may
  959. // have removed the current page directory & table page.
  960. //
  961. DroppedLocks = 1;
  962. PointerPde = MiGetPteAddress (PointerPte);
  963. PointerPpe = MiGetPteAddress (PointerPde);
  964. PointerPxe = MiGetPdeAddress (PointerPde);
  965. //
  966. // If either call below results in a PFN release and
  967. // reacquire, then we must redo them both.
  968. //
  969. do {
  970. if (MiDoesPxeExistAndMakeValid (PointerPxe,
  971. CurrentProcess,
  972. TRUE,
  973. &Waited) == FALSE) {
  974. //
  975. // The PXE has been deleted when the PFN lock
  976. // was released. Just bail as the PPE/PDE/PTE
  977. // are gone now anyway.
  978. //
  979. return DroppedLocks;
  980. }
  981. #if (_MI_PAGING_LEVELS >= 4)
  982. Waited = 0;
  983. #endif
  984. if (MiDoesPpeExistAndMakeValid (PointerPpe,
  985. CurrentProcess,
  986. TRUE,
  987. &Waited) == FALSE) {
  988. //
  989. // The PPE has been deleted when the PFN lock
  990. // was released. Just bail as the PDE/PTE are
  991. // gone now anyway.
  992. //
  993. return DroppedLocks;
  994. }
  995. #if (_MI_PAGING_LEVELS < 4)
  996. Waited = 0;
  997. #endif
  998. //
  999. // If the call below results in a PFN release and
  1000. // reacquire, then we must redo them both. If the
  1001. // PDE was deleted when the PFN lock was released
  1002. // then we just bail as the PTE is gone anyway.
  1003. //
  1004. if (MiDoesPdeExistAndMakeValid (PointerPde,
  1005. CurrentProcess,
  1006. TRUE,
  1007. &Waited) == FALSE) {
  1008. return DroppedLocks;
  1009. }
  1010. } while (Waited != 0);
  1011. }
  1012. }
  1013. }
  1014. }
  1015. }
  1016. else if (PteContents.u.Soft.Transition == 1) {
  1017. //
  1018. // This is a transition PTE. (Page is private)
  1019. //
  1020. Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber);
  1021. MI_SET_PFN_DELETED (Pfn1);
  1022. PageTableFrameIndex = Pfn1->u4.PteFrame;
  1023. Pfn2 = MI_PFN_ELEMENT (PageTableFrameIndex);
  1024. MiDecrementShareCountInline (Pfn2, PageTableFrameIndex);
  1025. //
  1026. // Check the reference count for the page, if the reference
  1027. // count is zero, move the page to the free list, if the reference
  1028. // count is not zero, ignore this page. When the reference count
  1029. // goes to zero, it will be placed on the free list.
  1030. //
  1031. if (Pfn1->u3.e2.ReferenceCount == 0) {
  1032. MiUnlinkPageFromList (Pfn1);
  1033. MiReleasePageFileSpace (Pfn1->OriginalPte);
  1034. MiInsertPageInFreeList (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&PteContents));
  1035. }
  1036. //
  1037. // Decrement the count for the number of private pages.
  1038. //
  1039. CurrentProcess->NumberOfPrivatePages -= 1;
  1040. }
  1041. else {
  1042. //
  1043. // Must be page file space.
  1044. //
  1045. if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) {
  1046. if (MiReleasePageFileSpace (*PointerPte)) {
  1047. //
  1048. // Decrement the count for the number of private pages.
  1049. //
  1050. CurrentProcess->NumberOfPrivatePages -= 1;
  1051. }
  1052. }
  1053. }
  1054. //
  1055. // Zero the PTE contents.
  1056. //
  1057. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  1058. return DroppedLocks;
  1059. }
  1060. ULONG
  1061. FASTCALL
  1062. MiReleasePageFileSpace (
  1063. IN MMPTE PteContents
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This routine frees the paging file allocated to the specified PTE.
  1068. Arguments:
  1069. PteContents - Supplies the PTE which is in page file format.
  1070. Return Value:
  1071. Returns TRUE if any paging file space was deallocated.
  1072. Environment:
  1073. Kernel mode, APCs disabled, PFN lock held.
  1074. --*/
  1075. {
  1076. ULONG FreeBit;
  1077. ULONG PageFileNumber;
  1078. PMMPAGING_FILE PageFile;
  1079. MM_PFN_LOCK_ASSERT();
  1080. if (PteContents.u.Soft.Prototype == 1) {
  1081. //
  1082. // Not in page file format.
  1083. //
  1084. return FALSE;
  1085. }
  1086. FreeBit = GET_PAGING_FILE_OFFSET (PteContents);
  1087. if ((FreeBit == 0) || (FreeBit == MI_PTE_LOOKUP_NEEDED)) {
  1088. //
  1089. // Page is not in a paging file, just return.
  1090. //
  1091. return FALSE;
  1092. }
  1093. PageFileNumber = GET_PAGING_FILE_NUMBER (PteContents);
  1094. ASSERT (RtlCheckBit( MmPagingFile[PageFileNumber]->Bitmap, FreeBit) == 1);
  1095. #if DBG
  1096. if ((FreeBit < 8192) && (PageFileNumber == 0)) {
  1097. ASSERT ((MmPagingFileDebug[FreeBit] & 1) != 0);
  1098. MmPagingFileDebug[FreeBit] ^= 1;
  1099. }
  1100. #endif
  1101. PageFile = MmPagingFile[PageFileNumber];
  1102. MI_CLEAR_BIT (PageFile->Bitmap->Buffer, FreeBit);
  1103. PageFile->FreeSpace += 1;
  1104. PageFile->CurrentUsage -= 1;
  1105. //
  1106. // Check to see if we should move some MDL entries for the
  1107. // modified page writer now that more free space is available.
  1108. //
  1109. if ((MmNumberOfActiveMdlEntries == 0) ||
  1110. (PageFile->FreeSpace == MM_USABLE_PAGES_FREE)) {
  1111. MiUpdateModifiedWriterMdls (PageFileNumber);
  1112. }
  1113. return TRUE;
  1114. }
  1115. VOID
  1116. FASTCALL
  1117. MiReleaseConfirmedPageFileSpace (
  1118. IN MMPTE PteContents
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. This routine frees the paging file allocated to the specified PTE.
  1123. Arguments:
  1124. PteContents - Supplies the PTE which is in page file format.
  1125. Return Value:
  1126. Returns TRUE if any paging file space was deallocated.
  1127. Environment:
  1128. Kernel mode, APCs disabled, PFN lock held.
  1129. --*/
  1130. {
  1131. ULONG FreeBit;
  1132. ULONG PageFileNumber;
  1133. PMMPAGING_FILE PageFile;
  1134. MM_PFN_LOCK_ASSERT();
  1135. ASSERT (PteContents.u.Soft.Prototype == 0);
  1136. FreeBit = GET_PAGING_FILE_OFFSET (PteContents);
  1137. ASSERT ((FreeBit != 0) && (FreeBit != MI_PTE_LOOKUP_NEEDED));
  1138. PageFileNumber = GET_PAGING_FILE_NUMBER (PteContents);
  1139. PageFile = MmPagingFile[PageFileNumber];
  1140. ASSERT (RtlCheckBit( PageFile->Bitmap, FreeBit) == 1);
  1141. #if DBG
  1142. if ((FreeBit < 8192) && (PageFileNumber == 0)) {
  1143. ASSERT ((MmPagingFileDebug[FreeBit] & 1) != 0);
  1144. MmPagingFileDebug[FreeBit] ^= 1;
  1145. }
  1146. #endif
  1147. MI_CLEAR_BIT (PageFile->Bitmap->Buffer, FreeBit);
  1148. PageFile->FreeSpace += 1;
  1149. PageFile->CurrentUsage -= 1;
  1150. //
  1151. // Check to see if we should move some MDL entries for the
  1152. // modified page writer now that more free space is available.
  1153. //
  1154. if ((MmNumberOfActiveMdlEntries == 0) ||
  1155. (PageFile->FreeSpace == MM_USABLE_PAGES_FREE)) {
  1156. MiUpdateModifiedWriterMdls (PageFileNumber);
  1157. }
  1158. }
  1159. VOID
  1160. FASTCALL
  1161. MiUpdateModifiedWriterMdls (
  1162. IN ULONG PageFileNumber
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. This routine ensures the MDLs for the specified paging file
  1167. are in the proper state such that paging i/o can continue.
  1168. Arguments:
  1169. PageFileNumber - Supplies the page file number to check the MDLs for.
  1170. Return Value:
  1171. None.
  1172. Environment:
  1173. Kernel mode, PFN lock held.
  1174. --*/
  1175. {
  1176. ULONG i;
  1177. PMMMOD_WRITER_MDL_ENTRY WriterEntry;
  1178. //
  1179. // Put the MDL entries into the active list.
  1180. //
  1181. for (i = 0; i < MM_PAGING_FILE_MDLS; i += 1) {
  1182. if ((MmPagingFile[PageFileNumber]->Entry[i]->Links.Flink !=
  1183. MM_IO_IN_PROGRESS)
  1184. &&
  1185. (MmPagingFile[PageFileNumber]->Entry[i]->CurrentList ==
  1186. &MmFreePagingSpaceLow)) {
  1187. //
  1188. // Remove this entry and put it on the active list.
  1189. //
  1190. WriterEntry = MmPagingFile[PageFileNumber]->Entry[i];
  1191. RemoveEntryList (&WriterEntry->Links);
  1192. WriterEntry->CurrentList = &MmPagingFileHeader.ListHead;
  1193. KeSetEvent (&WriterEntry->PagingListHead->Event, 0, FALSE);
  1194. InsertTailList (&WriterEntry->PagingListHead->ListHead,
  1195. &WriterEntry->Links);
  1196. MmNumberOfActiveMdlEntries += 1;
  1197. }
  1198. }
  1199. return;
  1200. }
  1201. VOID
  1202. MiFlushPteList (
  1203. IN PMMPTE_FLUSH_LIST PteFlushList,
  1204. IN ULONG AllProcessors,
  1205. IN MMPTE FillPte
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine flushes all the PTEs in the PTE flush list.
  1210. If the list has overflowed, the entire TB is flushed.
  1211. Arguments:
  1212. PteFlushList - Supplies an optional pointer to the list to be flushed.
  1213. AllProcessors - Supplies TRUE if the flush occurs on all processors.
  1214. FillPte - Supplies the PTE to fill with.
  1215. Return Value:
  1216. None.
  1217. Environment:
  1218. Kernel mode, PFN or a pre-process AWE lock may optionally be held.
  1219. --*/
  1220. {
  1221. ULONG count;
  1222. ASSERT (ARGUMENT_PRESENT (PteFlushList));
  1223. count = PteFlushList->Count;
  1224. if (count != 0) {
  1225. if (count != 1) {
  1226. if (count < MM_MAXIMUM_FLUSH_COUNT) {
  1227. KeFlushMultipleTb (count,
  1228. &PteFlushList->FlushVa[0],
  1229. TRUE,
  1230. (BOOLEAN)AllProcessors,
  1231. &((PHARDWARE_PTE)PteFlushList->FlushPte[0]),
  1232. FillPte.u.Flush);
  1233. }
  1234. else {
  1235. //
  1236. // Array has overflowed, flush the entire TB.
  1237. //
  1238. KeFlushEntireTb (TRUE, (BOOLEAN)AllProcessors);
  1239. }
  1240. }
  1241. else {
  1242. KeFlushSingleTb (PteFlushList->FlushVa[0],
  1243. TRUE,
  1244. (BOOLEAN)AllProcessors,
  1245. (PHARDWARE_PTE)PteFlushList->FlushPte[0],
  1246. FillPte.u.Flush);
  1247. }
  1248. PteFlushList->Count = 0;
  1249. }
  1250. return;
  1251. }