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.

1000 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. umapview.c
  5. Abstract:
  6. This module contains the routines which implement the
  7. NtUnmapViewOfSection service.
  8. Author:
  9. Lou Perazzoli (loup) 22-May-1989
  10. Landy Wang (landyw) 02-June-1997
  11. --*/
  12. #include "mi.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,NtUnmapViewOfSection)
  15. #pragma alloc_text(PAGE,MmUnmapViewOfSection)
  16. #pragma alloc_text(PAGE,MiUnmapViewOfSection)
  17. #endif
  18. NTSTATUS
  19. NtUnmapViewOfSection (
  20. IN HANDLE ProcessHandle,
  21. IN PVOID BaseAddress
  22. )
  23. /*++
  24. Routine Description:
  25. This function unmaps a previously created view to a section.
  26. Arguments:
  27. ProcessHandle - Supplies an open handle to a process object.
  28. BaseAddress - Supplies the base address of the view.
  29. Return Value:
  30. NTSTATUS.
  31. --*/
  32. {
  33. PEPROCESS Process;
  34. KPROCESSOR_MODE PreviousMode;
  35. NTSTATUS Status;
  36. PAGED_CODE();
  37. PreviousMode = KeGetPreviousMode();
  38. if ((PreviousMode == UserMode) && (BaseAddress > MM_HIGHEST_USER_ADDRESS)) {
  39. return STATUS_NOT_MAPPED_VIEW;
  40. }
  41. Status = ObReferenceObjectByHandle ( ProcessHandle,
  42. PROCESS_VM_OPERATION,
  43. PsProcessType,
  44. PreviousMode,
  45. (PVOID *)&Process,
  46. NULL );
  47. if (!NT_SUCCESS(Status)) {
  48. return Status;
  49. }
  50. Status = MiUnmapViewOfSection ( Process, BaseAddress, FALSE);
  51. ObDereferenceObject (Process);
  52. return Status;
  53. }
  54. NTSTATUS
  55. MiUnmapViewOfSection (
  56. IN PEPROCESS Process,
  57. IN PVOID BaseAddress,
  58. IN LOGICAL AddressSpaceMutexHeld
  59. )
  60. /*++
  61. Routine Description:
  62. This function unmaps a previously created view to a section.
  63. Arguments:
  64. Process - Supplies a referenced pointer to a process object.
  65. BaseAddress - Supplies the base address of the view.
  66. AddressSpaceMutexHeld - Supplies TRUE if the address space mutex is held.
  67. Return Value:
  68. NTSTATUS.
  69. --*/
  70. {
  71. PMMVAD Vad;
  72. PMMVAD PreviousVad;
  73. PMMVAD NextVad;
  74. SIZE_T RegionSize;
  75. PVOID UnMapImageBase;
  76. PVOID StartingVa;
  77. PVOID EndingVa;
  78. NTSTATUS status;
  79. LOGICAL Attached;
  80. KAPC_STATE ApcState;
  81. PAGED_CODE();
  82. Attached = FALSE;
  83. UnMapImageBase = NULL;
  84. //
  85. // If the specified process is not the current process, attach
  86. // to the specified process.
  87. //
  88. if (PsGetCurrentProcess() != Process) {
  89. KeStackAttachProcess (&Process->Pcb, &ApcState);
  90. Attached = TRUE;
  91. }
  92. //
  93. // Get the address creation mutex to block multiple threads from
  94. // creating or deleting address space at the same time and
  95. // get the working set mutex so virtual address descriptors can
  96. // be removed. Raise IRQL to block APCs.
  97. //
  98. if (AddressSpaceMutexHeld == FALSE) {
  99. LOCK_ADDRESS_SPACE (Process);
  100. }
  101. //
  102. // Make sure the address space was not deleted, if so, return an error.
  103. //
  104. if (Process->Flags & PS_PROCESS_FLAGS_VM_DELETED) {
  105. if (AddressSpaceMutexHeld == FALSE) {
  106. UNLOCK_ADDRESS_SPACE (Process);
  107. }
  108. status = STATUS_PROCESS_IS_TERMINATING;
  109. goto ErrorReturn;
  110. }
  111. //
  112. // Find the associated vad.
  113. //
  114. Vad = MiLocateAddress (BaseAddress);
  115. if ((Vad == NULL) || (Vad->u.VadFlags.PrivateMemory)) {
  116. //
  117. // No Virtual Address Descriptor located for Base Address.
  118. //
  119. if (AddressSpaceMutexHeld == FALSE) {
  120. UNLOCK_ADDRESS_SPACE (Process);
  121. }
  122. status = STATUS_NOT_MAPPED_VIEW;
  123. goto ErrorReturn;
  124. }
  125. StartingVa = MI_VPN_TO_VA (Vad->StartingVpn);
  126. EndingVa = MI_VPN_TO_VA_ENDING (Vad->EndingVpn);
  127. //
  128. // If this Vad is for an image section, then
  129. // get the base address of the section.
  130. //
  131. ASSERT (Process == PsGetCurrentProcess());
  132. if (Vad->u.VadFlags.ImageMap == 1) {
  133. UnMapImageBase = StartingVa;
  134. }
  135. RegionSize = PAGE_SIZE + ((Vad->EndingVpn - Vad->StartingVpn) << PAGE_SHIFT);
  136. if (Vad->u.VadFlags.NoChange == 1) {
  137. //
  138. // An attempt is being made to delete a secured VAD, check
  139. // the whole VAD to see if this deletion is allowed.
  140. //
  141. status = MiCheckSecuredVad (Vad,
  142. StartingVa,
  143. RegionSize - 1,
  144. MM_SECURE_DELETE_CHECK);
  145. if (!NT_SUCCESS (status)) {
  146. if (AddressSpaceMutexHeld == FALSE) {
  147. UNLOCK_ADDRESS_SPACE (Process);
  148. }
  149. goto ErrorReturn;
  150. }
  151. }
  152. PreviousVad = MiGetPreviousVad (Vad);
  153. NextVad = MiGetNextVad (Vad);
  154. LOCK_WS_UNSAFE (Process);
  155. MiRemoveVad (Vad);
  156. //
  157. // Return commitment for page table pages if possible.
  158. //
  159. MiReturnPageTablePageCommitment (StartingVa,
  160. EndingVa,
  161. Process,
  162. PreviousVad,
  163. NextVad);
  164. MiRemoveMappedView (Process, Vad);
  165. UNLOCK_WS_UNSAFE (Process);
  166. #if defined(_MIALT4K_)
  167. if (Process->Wow64Process != NULL) {
  168. MiDeleteFor4kPage (StartingVa, EndingVa, Process);
  169. }
  170. #endif
  171. //
  172. // Update the current virtual size in the process header.
  173. //
  174. Process->VirtualSize -= RegionSize;
  175. if (AddressSpaceMutexHeld == FALSE) {
  176. UNLOCK_ADDRESS_SPACE (Process);
  177. }
  178. ExFreePool (Vad);
  179. status = STATUS_SUCCESS;
  180. ErrorReturn:
  181. if (UnMapImageBase) {
  182. DbgkUnMapViewOfSection (UnMapImageBase);
  183. }
  184. if (Attached == TRUE) {
  185. KeUnstackDetachProcess (&ApcState);
  186. }
  187. return status;
  188. }
  189. NTSTATUS
  190. MmUnmapViewOfSection (
  191. IN PEPROCESS Process,
  192. IN PVOID BaseAddress
  193. )
  194. /*++
  195. Routine Description:
  196. This function unmaps a previously created view to a section.
  197. Arguments:
  198. Process - Supplies a referenced pointer to a process object.
  199. BaseAddress - Supplies the base address of the view.
  200. Return Value:
  201. NTSTATUS.
  202. --*/
  203. {
  204. return MiUnmapViewOfSection (Process, BaseAddress, FALSE);
  205. }
  206. VOID
  207. MiDecrementSubsections (
  208. IN PSUBSECTION FirstSubsection,
  209. IN PSUBSECTION LastSubsection OPTIONAL
  210. )
  211. /*++
  212. Routine Description:
  213. This function decrements the subsections, inserting them on the unused
  214. subsection list if they qualify.
  215. Arguments:
  216. FirstSubsection - Supplies the subsection to start at.
  217. LastSubsection - Supplies the last subsection to insert. Supplies NULL
  218. to decrement all the subsections in the chain.
  219. Return Value:
  220. None.
  221. Environment:
  222. PFN lock held.
  223. --*/
  224. {
  225. PMSUBSECTION MappedSubsection;
  226. ASSERT ((FirstSubsection->ControlArea->u.Flags.Image == 0) &&
  227. (FirstSubsection->ControlArea->FilePointer != NULL) &&
  228. (FirstSubsection->ControlArea->u.Flags.PhysicalMemory == 0));
  229. MM_PFN_LOCK_ASSERT();
  230. do {
  231. MappedSubsection = (PMSUBSECTION) FirstSubsection;
  232. ASSERT (MappedSubsection->DereferenceList.Flink == NULL);
  233. MappedSubsection->NumberOfMappedViews -= 1;
  234. if ((MappedSubsection->NumberOfMappedViews == 0) &&
  235. (MappedSubsection->u.SubsectionFlags.SubsectionStatic == 0)) {
  236. //
  237. // Insert this subsection into the unused subsection list.
  238. //
  239. InsertTailList (&MmUnusedSubsectionList,
  240. &MappedSubsection->DereferenceList);
  241. MI_UNUSED_SUBSECTIONS_COUNT_INSERT (MappedSubsection);
  242. }
  243. if (ARGUMENT_PRESENT (LastSubsection)) {
  244. if (FirstSubsection == LastSubsection) {
  245. break;
  246. }
  247. }
  248. else {
  249. if (FirstSubsection->NextSubsection == NULL) {
  250. break;
  251. }
  252. }
  253. FirstSubsection = FirstSubsection->NextSubsection;
  254. } while (TRUE);
  255. }
  256. VOID
  257. MiRemoveMappedView (
  258. IN PEPROCESS CurrentProcess,
  259. IN PMMVAD Vad
  260. )
  261. /*++
  262. Routine Description:
  263. This function removes the mapping from the current process's
  264. address space. The physical VAD may be a normal mapping (backed by
  265. a control area) or it may have no control area (it was mapped by a driver).
  266. Arguments:
  267. Process - Supplies a referenced pointer to the current process object.
  268. Vad - Supplies the VAD which maps the view.
  269. Return Value:
  270. None.
  271. Environment:
  272. APC level, working set mutex and address creation mutex held.
  273. NOTE: THE WORKING SET MUTEXES MAY BE RELEASED THEN REACQUIRED!!!!
  274. SINCE MiCheckControlArea releases unsafe, the WS mutex must be
  275. acquired UNSAFE.
  276. --*/
  277. {
  278. KIRQL OldIrql;
  279. PCONTROL_AREA ControlArea;
  280. PMMPTE PointerPte;
  281. PMMPTE PointerPde;
  282. PMMPTE LastPte;
  283. PFN_NUMBER PdePage;
  284. PVOID TempVa;
  285. MMPTE_FLUSH_LIST PteFlushList;
  286. PVOID UsedPageTableHandle;
  287. PMMPFN Pfn2;
  288. PSUBSECTION FirstSubsection;
  289. PSUBSECTION LastSubsection;
  290. #if (_MI_PAGING_LEVELS >= 3)
  291. PMMPTE PointerPpe;
  292. PVOID UsedPageDirectoryHandle;
  293. #endif
  294. #if (_MI_PAGING_LEVELS >= 4)
  295. PMMPTE PointerPxe;
  296. PVOID UsedPageDirectoryParentHandle;
  297. #endif
  298. ControlArea = Vad->ControlArea;
  299. if (Vad->u.VadFlags.PhysicalMapping == 1) {
  300. #if defined(_MIALT4K_)
  301. ASSERT (((PMMVAD_LONG)Vad)->AliasInformation == NULL);
  302. #endif
  303. if (((PMMVAD_LONG)Vad)->u4.Banked != NULL) {
  304. ExFreePool (((PMMVAD_LONG)Vad)->u4.Banked);
  305. }
  306. #ifdef LARGE_PAGES
  307. if (Vad->u.VadFlags.LargePages == 1) {
  308. //
  309. // Delete the subsection allocated to hold the large pages.
  310. //
  311. ExFreePool (Vad->FirstPrototypePte);
  312. Vad->FirstPrototypePte = NULL;
  313. KeFlushEntireTb (TRUE, FALSE);
  314. LOCK_PFN (OldIrql);
  315. }
  316. else {
  317. #endif //LARGE_PAGES
  318. //
  319. // This is a physical memory view. The pages map physical memory
  320. // and are not accounted for in the working set list or in the PFN
  321. // database.
  322. //
  323. MiPhysicalViewRemover (CurrentProcess, Vad);
  324. //
  325. // Set count so only flush entire TB operations are performed.
  326. //
  327. PteFlushList.Count = MM_MAXIMUM_FLUSH_COUNT;
  328. PointerPde = MiGetPdeAddress (MI_VPN_TO_VA (Vad->StartingVpn));
  329. PointerPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->StartingVpn));
  330. LastPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->EndingVpn));
  331. LOCK_PFN (OldIrql);
  332. //
  333. // Remove the PTES from the address space.
  334. //
  335. PdePage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPde);
  336. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MI_VPN_TO_VA (Vad->StartingVpn));
  337. while (PointerPte <= LastPte) {
  338. if (MiIsPteOnPdeBoundary (PointerPte)) {
  339. PointerPde = MiGetPteAddress (PointerPte);
  340. PdePage = MI_GET_PAGE_FRAME_FROM_PTE (PointerPde);
  341. UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte));
  342. }
  343. //
  344. // Decrement the count of non-zero page table entries for this
  345. // page table.
  346. //
  347. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle);
  348. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  349. Pfn2 = MI_PFN_ELEMENT (PdePage);
  350. MiDecrementShareCountInline (Pfn2, PdePage);
  351. //
  352. // If all the entries have been eliminated from the previous
  353. // page table page, delete the page table page itself. And if
  354. // this results in an empty page directory page, then delete
  355. // that too.
  356. //
  357. if (MI_GET_USED_PTES_FROM_HANDLE(UsedPageTableHandle) == 0) {
  358. TempVa = MiGetVirtualAddressMappedByPte(PointerPde);
  359. PteFlushList.Count = MM_MAXIMUM_FLUSH_COUNT;
  360. #if (_MI_PAGING_LEVELS >= 3)
  361. UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte);
  362. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle);
  363. #endif
  364. MiDeletePte (PointerPde,
  365. TempVa,
  366. FALSE,
  367. CurrentProcess,
  368. (PMMPTE)NULL,
  369. &PteFlushList);
  370. //
  371. // Add back in the private page MiDeletePte subtracted.
  372. //
  373. CurrentProcess->NumberOfPrivatePages += 1;
  374. #if (_MI_PAGING_LEVELS >= 3)
  375. if (MI_GET_USED_PTES_FROM_HANDLE(UsedPageDirectoryHandle) == 0) {
  376. PointerPpe = MiGetPdeAddress(PointerPte);
  377. TempVa = MiGetVirtualAddressMappedByPte(PointerPpe);
  378. PteFlushList.Count = MM_MAXIMUM_FLUSH_COUNT;
  379. #if (_MI_PAGING_LEVELS >= 4)
  380. UsedPageDirectoryParentHandle = MI_GET_USED_PTES_HANDLE (PointerPde);
  381. MI_DECREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryParentHandle);
  382. #endif
  383. MiDeletePte (PointerPpe,
  384. TempVa,
  385. FALSE,
  386. CurrentProcess,
  387. (PMMPTE)NULL,
  388. &PteFlushList);
  389. //
  390. // Add back in the private page MiDeletePte subtracted.
  391. //
  392. CurrentProcess->NumberOfPrivatePages += 1;
  393. #if (_MI_PAGING_LEVELS >= 4)
  394. if (MI_GET_USED_PTES_FROM_HANDLE(UsedPageDirectoryParentHandle) == 0) {
  395. PointerPxe = MiGetPpeAddress(PointerPte);
  396. TempVa = MiGetVirtualAddressMappedByPte(PointerPxe);
  397. PteFlushList.Count = MM_MAXIMUM_FLUSH_COUNT;
  398. MiDeletePte (PointerPxe,
  399. TempVa,
  400. FALSE,
  401. CurrentProcess,
  402. NULL,
  403. &PteFlushList);
  404. //
  405. // Add back in the private page MiDeletePte subtracted.
  406. //
  407. CurrentProcess->NumberOfPrivatePages += 1;
  408. }
  409. #endif
  410. }
  411. #endif
  412. }
  413. PointerPte += 1;
  414. }
  415. KeFlushEntireTb (TRUE, FALSE);
  416. #ifdef LARGE_PAGES
  417. }
  418. #endif //LARGE_PAGES
  419. } else {
  420. if (Vad->u2.VadFlags2.ExtendableFile) {
  421. PMMEXTEND_INFO ExtendedInfo;
  422. PMMVAD_LONG VadLong;
  423. ExtendedInfo = NULL;
  424. VadLong = (PMMVAD_LONG) Vad;
  425. ExAcquireFastMutexUnsafe (&MmSectionBasedMutex);
  426. ASSERT (Vad->ControlArea->Segment->ExtendInfo == VadLong->u4.ExtendedInfo);
  427. VadLong->u4.ExtendedInfo->ReferenceCount -= 1;
  428. if (VadLong->u4.ExtendedInfo->ReferenceCount == 0) {
  429. ExtendedInfo = VadLong->u4.ExtendedInfo;
  430. VadLong->ControlArea->Segment->ExtendInfo = NULL;
  431. }
  432. ExReleaseFastMutexUnsafe (&MmSectionBasedMutex);
  433. if (ExtendedInfo != NULL) {
  434. ExFreePool (ExtendedInfo);
  435. }
  436. }
  437. FirstSubsection = NULL;
  438. if (Vad->u.VadFlags.ImageMap == 0) {
  439. #if defined (_MIALT4K_)
  440. if ((Vad->u2.VadFlags2.LongVad == 1) &&
  441. (((PMMVAD_LONG)Vad)->AliasInformation != NULL)) {
  442. MiRemoveAliasedVads (CurrentProcess, Vad);
  443. }
  444. #endif
  445. if (ControlArea->FilePointer != NULL) {
  446. if (Vad->u.VadFlags.Protection & MM_READWRITE) {
  447. //
  448. // Adjust the count of writable user mappings
  449. // to support transactions.
  450. //
  451. InterlockedDecrement ((PLONG)&ControlArea->Segment->WritableUserReferences);
  452. }
  453. FirstSubsection = (PSUBSECTION)1;
  454. }
  455. }
  456. LOCK_PFN (OldIrql);
  457. MiDeleteVirtualAddresses (MI_VPN_TO_VA (Vad->StartingVpn),
  458. MI_VPN_TO_VA_ENDING (Vad->EndingVpn),
  459. FALSE,
  460. Vad);
  461. if (FirstSubsection != NULL) {
  462. FirstSubsection = MiLocateSubsection (Vad, Vad->StartingVpn);
  463. //
  464. // Note LastSubsection may be NULL for extendable VADs when the
  465. // EndingVpn is past the end of the section. In this case,
  466. // all the subsections can be safely decremented.
  467. //
  468. LastSubsection = MiLocateSubsection (Vad, Vad->EndingVpn);
  469. //
  470. // The subsections can only be decremented after all the
  471. // PTEs have been cleared and PFN sharecounts decremented so no
  472. // prototype PTEs will be valid if it is indeed the final subsection
  473. // dereference. This is critical so the dereference segment
  474. // thread doesn't free pool containing valid prototype PTEs.
  475. //
  476. MiDecrementSubsections (FirstSubsection, LastSubsection);
  477. }
  478. }
  479. //
  480. // Only physical VADs mapped by drivers don't have control areas.
  481. // If this view has a control area, the view count must be decremented now.
  482. //
  483. if (ControlArea) {
  484. //
  485. // Decrement the count of the number of views for the
  486. // Segment object. This requires the PFN lock to be held (it is
  487. // already).
  488. //
  489. ControlArea->NumberOfMappedViews -= 1;
  490. ControlArea->NumberOfUserReferences -= 1;
  491. //
  492. // Check to see if the control area (segment) should be deleted.
  493. // This routine releases the PFN lock.
  494. //
  495. MiCheckControlArea (ControlArea, CurrentProcess, OldIrql);
  496. }
  497. else {
  498. UNLOCK_PFN (OldIrql);
  499. //
  500. // Even though it says short VAD in VadFlags, it better be a long VAD.
  501. //
  502. ASSERT (Vad->u.VadFlags.PhysicalMapping == 1);
  503. ASSERT (((PMMVAD_LONG)Vad)->u4.Banked == NULL);
  504. ASSERT (Vad->ControlArea == NULL);
  505. ASSERT (Vad->FirstPrototypePte == NULL);
  506. }
  507. return;
  508. }
  509. VOID
  510. MiPurgeImageSection (
  511. IN PCONTROL_AREA ControlArea,
  512. IN PEPROCESS Process OPTIONAL
  513. )
  514. /*++
  515. Routine Description:
  516. This function locates subsections within an image section that
  517. contain global memory and resets the global memory back to
  518. the initial subsection contents.
  519. Note, that for this routine to be called the section is not
  520. referenced nor is it mapped in any process.
  521. Arguments:
  522. ControlArea - Supplies a pointer to the control area for the section.
  523. Process - Supplies a pointer to the process IFF the working set mutex
  524. is held, else NULL is supplied. Note that IFF the working set
  525. mutex is held, it must always be acquired unsafe.
  526. Return Value:
  527. None.
  528. Environment:
  529. PFN LOCK held.
  530. --*/
  531. {
  532. PMMPTE PointerPte;
  533. PMMPTE LastPte;
  534. PMMPFN Pfn1;
  535. PMMPFN Pfn2;
  536. PFN_NUMBER PageTableFrameIndex;
  537. MMPTE PteContents;
  538. MMPTE NewContents;
  539. MMPTE NewContentsDemandZero;
  540. KIRQL OldIrql;
  541. ULONG i;
  542. ULONG SizeOfRawData;
  543. ULONG OffsetIntoSubsection;
  544. PSUBSECTION Subsection;
  545. #if DBG
  546. ULONG DelayCount = 0;
  547. #endif //DBG
  548. ASSERT (ControlArea->u.Flags.Image != 0);
  549. OldIrql = APC_LEVEL;
  550. i = ControlArea->NumberOfSubsections;
  551. if ((ControlArea->u.Flags.GlobalOnlyPerSession == 0) &&
  552. (ControlArea->u.Flags.Rom == 0)) {
  553. Subsection = (PSUBSECTION)(ControlArea + 1);
  554. }
  555. else {
  556. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  557. }
  558. //
  559. // Loop through all the subsections
  560. while (i > 0) {
  561. if (Subsection->u.SubsectionFlags.GlobalMemory == 1) {
  562. NewContents.u.Long = 0;
  563. NewContentsDemandZero.u.Long = 0;
  564. SizeOfRawData = 0;
  565. OffsetIntoSubsection = 0;
  566. //
  567. // Purge this section.
  568. //
  569. if (Subsection->StartingSector != 0) {
  570. //
  571. // This is not a demand zero section.
  572. //
  573. NewContents.u.Long = MiGetSubsectionAddressForPte(Subsection);
  574. NewContents.u.Soft.Prototype = 1;
  575. SizeOfRawData = (Subsection->NumberOfFullSectors << MMSECTOR_SHIFT) |
  576. Subsection->u.SubsectionFlags.SectorEndOffset;
  577. }
  578. NewContents.u.Soft.Protection =
  579. Subsection->u.SubsectionFlags.Protection;
  580. NewContentsDemandZero.u.Soft.Protection =
  581. NewContents.u.Soft.Protection;
  582. PointerPte = Subsection->SubsectionBase;
  583. LastPte = &Subsection->SubsectionBase[Subsection->PtesInSubsection];
  584. ControlArea = Subsection->ControlArea;
  585. //
  586. // The WS lock may be released and reacquired and our callers
  587. // always acquire it unsafe.
  588. //
  589. MiMakeSystemAddressValidPfnWs (PointerPte, Process);
  590. while (PointerPte < LastPte) {
  591. if (MiIsPteOnPdeBoundary(PointerPte)) {
  592. //
  593. // We are on a page boundary, make sure this PTE is resident.
  594. //
  595. MiMakeSystemAddressValidPfnWs (PointerPte, Process);
  596. }
  597. PteContents = *PointerPte;
  598. if (PteContents.u.Long == 0) {
  599. //
  600. // No more valid PTEs to deal with.
  601. //
  602. break;
  603. }
  604. ASSERT (PteContents.u.Hard.Valid == 0);
  605. if ((PteContents.u.Soft.Prototype == 0) &&
  606. (PteContents.u.Soft.Transition == 1)) {
  607. //
  608. // The prototype PTE is in transition format.
  609. //
  610. Pfn1 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber);
  611. //
  612. // If the prototype PTE is no longer pointing to
  613. // the original image page (not in protopte format),
  614. // or has been modified, remove it from memory.
  615. //
  616. if ((Pfn1->u3.e1.Modified == 1) ||
  617. (Pfn1->OriginalPte.u.Soft.Prototype == 0)) {
  618. ASSERT (Pfn1->OriginalPte.u.Hard.Valid == 0);
  619. //
  620. // This is a transition PTE which has been
  621. // modified or is no longer in protopte format.
  622. //
  623. if (Pfn1->u3.e2.ReferenceCount != 0) {
  624. //
  625. // There must be an I/O in progress on this
  626. // page. Wait for the I/O operation to complete.
  627. //
  628. UNLOCK_PFN (OldIrql);
  629. //
  630. // Drain the deferred lists as these pages may be
  631. // sitting in there right now.
  632. //
  633. MiDeferredUnlockPages (0);
  634. KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmShortTime);
  635. //
  636. // Redo the loop.
  637. //
  638. #if DBG
  639. if ((DelayCount % 1024) == 0) {
  640. DbgPrint("MMFLUSHSEC: waiting for i/o to complete PFN %p\n",
  641. Pfn1);
  642. }
  643. DelayCount += 1;
  644. #endif //DBG
  645. LOCK_PFN (OldIrql);
  646. MiMakeSystemAddressValidPfnWs (PointerPte, Process);
  647. continue;
  648. }
  649. ASSERT (!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
  650. (Pfn1->OriginalPte.u.Soft.Transition == 1)));
  651. MI_WRITE_INVALID_PTE (PointerPte, Pfn1->OriginalPte);
  652. ASSERT (Pfn1->OriginalPte.u.Hard.Valid == 0);
  653. //
  654. // Only reduce the number of PFN references if
  655. // the original PTE is still in prototype PTE
  656. // format.
  657. //
  658. if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
  659. ControlArea->NumberOfPfnReferences -= 1;
  660. ASSERT ((LONG)ControlArea->NumberOfPfnReferences >= 0);
  661. }
  662. MiUnlinkPageFromList (Pfn1);
  663. MI_SET_PFN_DELETED (Pfn1);
  664. PageTableFrameIndex = Pfn1->u4.PteFrame;
  665. Pfn2 = MI_PFN_ELEMENT (PageTableFrameIndex);
  666. MiDecrementShareCountInline (Pfn2, PageTableFrameIndex);
  667. //
  668. // If the reference count for the page is zero, insert
  669. // it into the free page list, otherwise leave it alone
  670. // and when the reference count is decremented to zero
  671. // the page will go to the free list.
  672. //
  673. if (Pfn1->u3.e2.ReferenceCount == 0) {
  674. MiReleasePageFileSpace (Pfn1->OriginalPte);
  675. MiInsertPageInFreeList (MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (&PteContents));
  676. }
  677. MI_WRITE_INVALID_PTE (PointerPte, NewContents);
  678. }
  679. } else {
  680. //
  681. // Prototype PTE is not in transition format.
  682. //
  683. if (PteContents.u.Soft.Prototype == 0) {
  684. //
  685. // This refers to a page in the paging file,
  686. // as it no longer references the image,
  687. // restore the PTE contents to what they were
  688. // at the initial image creation.
  689. //
  690. if (PteContents.u.Long != NoAccessPte.u.Long) {
  691. MiReleasePageFileSpace (PteContents);
  692. MI_WRITE_INVALID_PTE (PointerPte, NewContents);
  693. }
  694. }
  695. }
  696. PointerPte += 1;
  697. OffsetIntoSubsection += PAGE_SIZE;
  698. if (OffsetIntoSubsection >= SizeOfRawData) {
  699. //
  700. // There are trailing demand zero pages in this
  701. // subsection, set the PTE contents to be demand
  702. // zero for the remainder of the PTEs in this
  703. // subsection.
  704. //
  705. NewContents = NewContentsDemandZero;
  706. }
  707. #if DBG
  708. DelayCount = 0;
  709. #endif //DBG
  710. } //end while
  711. }
  712. i -=1;
  713. Subsection += 1;
  714. }
  715. return;
  716. }