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.

951 lines
28 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. shutdown.c
  5. Abstract:
  6. This module contains the shutdown code for the memory management system.
  7. Author:
  8. Lou Perazzoli (loup) 21-Aug-1991
  9. Landy Wang (landyw) 02-June-1997
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. extern ULONG MmSystemShutdown;
  14. VOID
  15. MiReleaseAllMemory (
  16. VOID
  17. );
  18. BOOLEAN
  19. MiShutdownSystem (
  20. VOID
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGELK,MiShutdownSystem)
  24. #pragma alloc_text(PAGELK,MiReleaseAllMemory)
  25. #pragma alloc_text(PAGELK,MmShutdownSystem)
  26. #endif
  27. ULONG MmZeroPageFile;
  28. extern ULONG MmUnusedSegmentForceFree;
  29. extern LIST_ENTRY MmSessionWideAddressList;
  30. extern LIST_ENTRY MiVerifierDriverAddedThunkListHead;
  31. extern LIST_ENTRY MmLoadedUserImageList;
  32. extern PRTL_BITMAP MiSessionIdBitmap;
  33. extern LOGICAL MiZeroingDisabled;
  34. extern ULONG MmNumberOfMappedMdls;
  35. extern ULONG MmNumberOfMappedMdlsInUse;
  36. BOOLEAN
  37. MiShutdownSystem (
  38. VOID
  39. )
  40. /*++
  41. Routine Description:
  42. This function performs the shutdown of memory management. This
  43. is accomplished by writing out all modified pages which are
  44. destined for files other than the paging file.
  45. All processes have already been killed, the registry shutdown and
  46. shutdown IRPs already sent. On return from this phase all mapped
  47. file data must be flushed and the unused segment list emptied.
  48. This releases all the Mm references to file objects, allowing many
  49. drivers (especially the network) to unload.
  50. Arguments:
  51. None.
  52. Return Value:
  53. TRUE if the pages were successfully written, FALSE otherwise.
  54. --*/
  55. {
  56. LOGICAL PageLk;
  57. SIZE_T ImportListSize;
  58. PLOAD_IMPORTS ImportList;
  59. PLOAD_IMPORTS ImportListNonPaged;
  60. PLIST_ENTRY NextEntry;
  61. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  62. PFN_NUMBER ModifiedPage;
  63. PMMPFN Pfn1;
  64. PSUBSECTION Subsection;
  65. PCONTROL_AREA ControlArea;
  66. PPFN_NUMBER Page;
  67. PFILE_OBJECT FilePointer;
  68. ULONG ConsecutiveFileLockFailures;
  69. PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + MM_MAXIMUM_WRITE_CLUSTER];
  70. PMDL Mdl;
  71. NTSTATUS Status;
  72. KEVENT IoEvent;
  73. IO_STATUS_BLOCK IoStatus;
  74. KIRQL OldIrql;
  75. LARGE_INTEGER StartingOffset;
  76. ULONG count;
  77. PFN_NUMBER j;
  78. ULONG k;
  79. PFN_NUMBER first;
  80. ULONG write;
  81. PMMPAGING_FILE PagingFile;
  82. PageLk = FALSE;
  83. //
  84. // Don't do this more than once.
  85. //
  86. if (MmSystemShutdown == 0) {
  87. PageLk = TRUE;
  88. MmLockPagableSectionByHandle (ExPageLockHandle);
  89. Mdl = (PMDL)&MdlHack;
  90. Page = (PPFN_NUMBER)(Mdl + 1);
  91. KeInitializeEvent (&IoEvent, NotificationEvent, FALSE);
  92. MmInitializeMdl(Mdl,
  93. NULL,
  94. PAGE_SIZE);
  95. Mdl->MdlFlags |= MDL_PAGES_LOCKED;
  96. LOCK_PFN (OldIrql);
  97. ModifiedPage = MmModifiedPageListHead.Flink;
  98. while (ModifiedPage != MM_EMPTY_LIST) {
  99. //
  100. // There are modified pages.
  101. //
  102. Pfn1 = MI_PFN_ELEMENT (ModifiedPage);
  103. if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
  104. //
  105. // This page is destined for a file.
  106. //
  107. Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
  108. ControlArea = Subsection->ControlArea;
  109. if ((!ControlArea->u.Flags.Image) &&
  110. (!ControlArea->u.Flags.NoModifiedWriting)) {
  111. MiUnlinkPageFromList (Pfn1);
  112. //
  113. // Issue the write.
  114. //
  115. MI_SET_MODIFIED (Pfn1, 0, 0x28);
  116. //
  117. // Up the reference count for the physical page as there
  118. // is I/O in progress.
  119. //
  120. MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1, 26);
  121. Pfn1->u3.e2.ReferenceCount += 1;
  122. *Page = ModifiedPage;
  123. ControlArea->NumberOfMappedViews += 1;
  124. ControlArea->NumberOfPfnReferences += 1;
  125. UNLOCK_PFN (OldIrql);
  126. StartingOffset.QuadPart = MiStartingOffset (Subsection,
  127. Pfn1->PteAddress);
  128. Mdl->StartVa = NULL;
  129. ConsecutiveFileLockFailures = 0;
  130. FilePointer = ControlArea->FilePointer;
  131. retry:
  132. KeClearEvent (&IoEvent);
  133. Status = FsRtlAcquireFileForCcFlushEx (FilePointer);
  134. if (NT_SUCCESS(Status)) {
  135. Status = IoSynchronousPageWrite (FilePointer,
  136. Mdl,
  137. &StartingOffset,
  138. &IoEvent,
  139. &IoStatus);
  140. //
  141. // Release the file we acquired.
  142. //
  143. FsRtlReleaseFileForCcFlush (FilePointer);
  144. }
  145. if (!NT_SUCCESS(Status)) {
  146. //
  147. // Only try the request more than once if the
  148. // filesystem said it had a deadlock.
  149. //
  150. if (Status == STATUS_FILE_LOCK_CONFLICT) {
  151. ConsecutiveFileLockFailures += 1;
  152. if (ConsecutiveFileLockFailures < 5) {
  153. KeDelayExecutionThread (KernelMode,
  154. FALSE,
  155. (PLARGE_INTEGER)&MmShortTime);
  156. goto retry;
  157. }
  158. goto wait_complete;
  159. }
  160. //
  161. // Ignore all I/O failures - there is nothing that
  162. // can be done at this point.
  163. //
  164. KeSetEvent (&IoEvent, 0, FALSE);
  165. }
  166. Status = KeWaitForSingleObject (&IoEvent,
  167. WrPageOut,
  168. KernelMode,
  169. FALSE,
  170. (PLARGE_INTEGER)&MmTwentySeconds);
  171. wait_complete:
  172. if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  173. MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
  174. }
  175. if (Status == STATUS_TIMEOUT) {
  176. //
  177. // The write did not complete in 20 seconds, assume
  178. // that the file systems are hung and return an
  179. // error.
  180. //
  181. LOCK_PFN (OldIrql);
  182. MI_SET_MODIFIED (Pfn1, 1, 0xF);
  183. MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1, 27);
  184. ControlArea->NumberOfMappedViews -= 1;
  185. ControlArea->NumberOfPfnReferences -= 1;
  186. //
  187. // This routine returns with the PFN lock released!
  188. //
  189. MiCheckControlArea (ControlArea, NULL, OldIrql);
  190. MmUnlockPagableImageSection (ExPageLockHandle);
  191. return FALSE;
  192. }
  193. LOCK_PFN (OldIrql);
  194. MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1, 27);
  195. ControlArea->NumberOfMappedViews -= 1;
  196. ControlArea->NumberOfPfnReferences -= 1;
  197. //
  198. // This routine returns with the PFN lock released!
  199. //
  200. MiCheckControlArea (ControlArea, NULL, OldIrql);
  201. LOCK_PFN (OldIrql);
  202. //
  203. // Restart scan at the front of the list.
  204. //
  205. ModifiedPage = MmModifiedPageListHead.Flink;
  206. continue;
  207. }
  208. }
  209. ModifiedPage = Pfn1->u1.Flink;
  210. }
  211. UNLOCK_PFN (OldIrql);
  212. //
  213. // If a high number of modified pages still exist, start the
  214. // modified page writer and wait for 5 seconds.
  215. //
  216. if (MmAvailablePages < (MmFreeGoal * 2)) {
  217. LARGE_INTEGER FiveSeconds = {(ULONG)(-5 * 1000 * 1000 * 10), -1};
  218. KeSetEvent (&MmModifiedPageWriterEvent, 0, FALSE);
  219. KeDelayExecutionThread (KernelMode,
  220. FALSE,
  221. (PLARGE_INTEGER)&FiveSeconds);
  222. }
  223. //
  224. // Indicate to the modified page writer that the system has
  225. // shutdown.
  226. //
  227. MmSystemShutdown = 1;
  228. //
  229. // Check to see if the paging file should be overwritten.
  230. // Only free blocks are written.
  231. //
  232. if (MmZeroPageFile) {
  233. //
  234. // Get pages to complete the write request.
  235. //
  236. Mdl->StartVa = NULL;
  237. j = 0;
  238. k = 0;
  239. Page = (PPFN_NUMBER)(Mdl + 1);
  240. LOCK_PFN (OldIrql);
  241. if (MmAvailablePages < (MmModifiedWriteClusterSize + 20)) {
  242. UNLOCK_PFN(OldIrql);
  243. goto freecache;
  244. }
  245. do {
  246. *Page = MiRemoveZeroPage ((ULONG)j & MmSecondaryColorMask);
  247. Pfn1 = MI_PFN_ELEMENT (*Page);
  248. Pfn1->u3.e2.ReferenceCount = 1;
  249. ASSERT (Pfn1->u2.ShareCount == 0);
  250. Pfn1->OriginalPte.u.Long = 0;
  251. MI_SET_PFN_DELETED (Pfn1);
  252. Page += 1;
  253. j += 1;
  254. } while (j < MmModifiedWriteClusterSize);
  255. while (k < MmNumberOfPagingFiles) {
  256. PagingFile = MmPagingFile[k];
  257. count = 0;
  258. write = FALSE;
  259. //
  260. // Initializing first is not needed for correctness, but
  261. // without it the compiler cannot compile this code W4 to
  262. // check for use of uninitialized variables.
  263. //
  264. first = 0;
  265. for (j = 1; j < PagingFile->Size; j += 1) {
  266. if (RtlCheckBit (PagingFile->Bitmap, j) == 0) {
  267. if (count == 0) {
  268. first = j;
  269. }
  270. count += 1;
  271. if (count == MmModifiedWriteClusterSize) {
  272. write = TRUE;
  273. }
  274. } else {
  275. if (count != 0) {
  276. //
  277. // Issue a write.
  278. //
  279. write = TRUE;
  280. }
  281. }
  282. if ((j == (PagingFile->Size - 1)) &&
  283. (count != 0)) {
  284. write = TRUE;
  285. }
  286. if (write) {
  287. UNLOCK_PFN (OldIrql);
  288. StartingOffset.QuadPart = (LONGLONG)first << PAGE_SHIFT;
  289. Mdl->ByteCount = count << PAGE_SHIFT;
  290. KeClearEvent (&IoEvent);
  291. Status = IoSynchronousPageWrite (PagingFile->File,
  292. Mdl,
  293. &StartingOffset,
  294. &IoEvent,
  295. &IoStatus);
  296. //
  297. // Ignore all I/O failures - there is nothing that can
  298. // be done at this point.
  299. //
  300. if (!NT_SUCCESS(Status)) {
  301. KeSetEvent (&IoEvent, 0, FALSE);
  302. }
  303. Status = KeWaitForSingleObject (&IoEvent,
  304. WrPageOut,
  305. KernelMode,
  306. FALSE,
  307. (PLARGE_INTEGER)&MmTwentySeconds);
  308. if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
  309. MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
  310. }
  311. if (Status == STATUS_TIMEOUT) {
  312. //
  313. // The write did not complete in 20 seconds, assume
  314. // that the file systems are hung and return an
  315. // error.
  316. //
  317. j = 0;
  318. Page = (PPFN_NUMBER)(Mdl + 1);
  319. LOCK_PFN (OldIrql);
  320. do {
  321. MiDecrementReferenceCount (*Page);
  322. Page += 1;
  323. j += 1;
  324. } while (j < MmModifiedWriteClusterSize);
  325. UNLOCK_PFN (OldIrql);
  326. MmUnlockPagableImageSection (ExPageLockHandle);
  327. return FALSE;
  328. }
  329. count = 0;
  330. write = FALSE;
  331. LOCK_PFN (OldIrql);
  332. }
  333. }
  334. k += 1;
  335. }
  336. j = 0;
  337. Page = (PPFN_NUMBER)(Mdl + 1);
  338. do {
  339. MiDecrementReferenceCount (*Page);
  340. Page += 1;
  341. j += 1;
  342. } while (j < MmModifiedWriteClusterSize);
  343. UNLOCK_PFN (OldIrql);
  344. }
  345. }
  346. freecache:
  347. if (PageLk == TRUE) {
  348. MmUnlockPagableImageSection (ExPageLockHandle);
  349. }
  350. if (PoCleanShutdownEnabled ()) {
  351. //
  352. // Empty the unused segment list.
  353. //
  354. LOCK_PFN (OldIrql);
  355. MmUnusedSegmentForceFree = (ULONG)-1;
  356. KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);
  357. //
  358. // Give it 5 seconds to empty otherwise assume the filesystems are
  359. // hung and march on.
  360. //
  361. for (count = 0; count < 500; count += 1) {
  362. if (IsListEmpty(&MmUnusedSegmentList)) {
  363. break;
  364. }
  365. UNLOCK_PFN (OldIrql);
  366. KeDelayExecutionThread (KernelMode,
  367. FALSE,
  368. (PLARGE_INTEGER)&MmShortTime);
  369. LOCK_PFN (OldIrql);
  370. #if DBG
  371. if (count == 400) {
  372. //
  373. // Everything should have been flushed by now. Give the
  374. // filesystem team a chance to debug this on checked builds.
  375. //
  376. ASSERT (FALSE);
  377. }
  378. #endif
  379. //
  380. // Resignal if needed in case more closed file objects triggered
  381. // additional entries.
  382. //
  383. if (MmUnusedSegmentForceFree == 0) {
  384. MmUnusedSegmentForceFree = (ULONG)-1;
  385. KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);
  386. }
  387. }
  388. UNLOCK_PFN (OldIrql);
  389. //
  390. // Get rid of any paged pool references as they will be illegal
  391. // by the time MmShutdownSystem is called again since the filesystems
  392. // will have shutdown.
  393. //
  394. KeWaitForSingleObject (&MmSystemLoadLock,
  395. WrVirtualMemory,
  396. KernelMode,
  397. FALSE,
  398. (PLARGE_INTEGER)NULL);
  399. NextEntry = PsLoadedModuleList.Flink;
  400. while (NextEntry != &PsLoadedModuleList) {
  401. DataTableEntry = CONTAINING_RECORD (NextEntry,
  402. KLDR_DATA_TABLE_ENTRY,
  403. InLoadOrderLinks);
  404. ImportList = (PLOAD_IMPORTS)DataTableEntry->LoadedImports;
  405. if ((ImportList != (PVOID)LOADED_AT_BOOT) &&
  406. (ImportList != (PVOID)NO_IMPORTS_USED) &&
  407. (!SINGLE_ENTRY(ImportList))) {
  408. ImportListSize = ImportList->Count * sizeof(PVOID) + sizeof(SIZE_T);
  409. ImportListNonPaged = (PLOAD_IMPORTS) ExAllocatePoolWithTag (NonPagedPool,
  410. ImportListSize,
  411. 'TDmM');
  412. if (ImportListNonPaged != NULL) {
  413. RtlCopyMemory (ImportListNonPaged, ImportList, ImportListSize);
  414. ExFreePool (ImportList);
  415. DataTableEntry->LoadedImports = ImportListNonPaged;
  416. }
  417. else {
  418. //
  419. // Don't bother with the clean shutdown at this point.
  420. //
  421. PopShutdownCleanly = FALSE;
  422. break;
  423. }
  424. }
  425. //
  426. // Free the full DLL name as it is pagable.
  427. //
  428. if (DataTableEntry->FullDllName.Buffer != NULL) {
  429. ExFreePool (DataTableEntry->FullDllName.Buffer);
  430. DataTableEntry->FullDllName.Buffer = NULL;
  431. }
  432. NextEntry = NextEntry->Flink;
  433. }
  434. //
  435. // Free any Hydra resources. Note that if any session is still alive
  436. // (ie: all processes must be gone at this point) then the session
  437. // drivers will not have unloaded. This is not supposed to happen
  438. // so assert here to ensure this.
  439. //
  440. if (PoCleanShutdownEnabled()) {
  441. ASSERT (IsListEmpty (&MmSessionWideAddressList) != 0);
  442. ExFreePool (MiSessionIdBitmap);
  443. }
  444. KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE);
  445. //
  446. // Close all the pagefile handles, note we still have an object
  447. // reference to each keeping the underlying object resident.
  448. // At the end of Phase1 shutdown we'll release those references
  449. // to trigger the storage stack unload. The handle close must be
  450. // done here however as it will reference pagable structures.
  451. //
  452. for (k = 0; k < MmNumberOfPagingFiles; k += 1) {
  453. //
  454. // Free each pagefile name now as it resides in paged pool and
  455. // may need to be inpaged to be freed. Since the paging files
  456. // are going to be shutdown shortly, now is the time to access
  457. // pagable stuff and get rid of it. Zeroing the buffer pointer
  458. // is sufficient as the only accesses to this are from the
  459. // try-except-wrapped GetSystemInformation APIs and all the
  460. // user processes are gone already.
  461. //
  462. ASSERT (MmPagingFile[k]->PageFileName.Buffer != NULL);
  463. ExFreePool (MmPagingFile[k]->PageFileName.Buffer);
  464. MmPagingFile[k]->PageFileName.Buffer = NULL;
  465. ZwClose (MmPagingFile[k]->FileHandle);
  466. }
  467. }
  468. return TRUE;
  469. }
  470. BOOLEAN
  471. MmShutdownSystem (
  472. IN ULONG Phase
  473. )
  474. /*++
  475. Routine Description:
  476. This function performs the shutdown of memory management. This
  477. is accomplished by writing out all modified pages which are
  478. destined for files other than the paging file.
  479. Arguments:
  480. Phase - Supplies 0 on the initiation of shutdown. All processes have
  481. already been killed, the registry shutdown and shutdown IRPs already
  482. sent. On return from this phase all mapped file data must be
  483. flushed and the unused segment list emptied. This releases all
  484. the Mm references to file objects, allowing many drivers (especially
  485. the network) to unload.
  486. Supplies 1 on the initiation of shutdown. The filesystem stack
  487. has received its shutdown IRPs (the stack must free its paged pool
  488. allocations here and lock down any pagable code it intends to call)
  489. as no more references to pagable code or data are allowed on return.
  490. ie: Any IoPageRead at this point is illegal.
  491. Close the pagefile handles here so the filesystem stack will be
  492. dereferenced causing those drivers to unload as well.
  493. Supplies 2 on final shutdown of the system. Any resources not
  494. freed by this point are treated as leaks and cause a bugcheck.
  495. Return Value:
  496. TRUE if the pages were successfully written, FALSE otherwise.
  497. --*/
  498. {
  499. ULONG i;
  500. if (Phase == 0) {
  501. return MiShutdownSystem ();
  502. }
  503. if (Phase == 1) {
  504. //
  505. // The filesystem has shutdown. References to pagable code or data
  506. // is no longer allowed at this point.
  507. //
  508. // Close the pagefile handles here so the filesystem stack will be
  509. // dereferenced causing those drivers to unload as well.
  510. //
  511. if (MmSystemShutdown < 2) {
  512. MmSystemShutdown = 2;
  513. if (PoCleanShutdownEnabled() & PO_CLEAN_SHUTDOWN_PAGING) {
  514. //
  515. // Make any IoPageRead at this point illegal. Detect this by
  516. // purging all system pagable memory.
  517. //
  518. MmTrimAllSystemPagableMemory (TRUE);
  519. //
  520. // There should be no dirty pages destined for the filesystem.
  521. // Give the filesystem team a shot to debug this on checked
  522. // builds.
  523. //
  524. ASSERT (MmModifiedPageListHead.Total == MmTotalPagesForPagingFile);
  525. //
  526. // Dereference all the pagefile objects to trigger a cascading
  527. // unload of the storage stack as this should be the last
  528. // reference to their driver objects.
  529. //
  530. for (i = 0; i < MmNumberOfPagingFiles; i += 1) {
  531. ObDereferenceObject (MmPagingFile[i]->File);
  532. }
  533. }
  534. }
  535. return TRUE;
  536. }
  537. ASSERT (Phase == 2);
  538. //
  539. // Check for resource leaks and bugcheck if any are found.
  540. //
  541. if (MmSystemShutdown < 3) {
  542. MmSystemShutdown = 3;
  543. if (PoCleanShutdownEnabled ()) {
  544. MiReleaseAllMemory ();
  545. }
  546. }
  547. return TRUE;
  548. }
  549. VOID
  550. MiReleaseAllMemory (
  551. VOID
  552. )
  553. /*++
  554. Routine Description:
  555. This function performs the final release of memory management allocations.
  556. Arguments:
  557. None.
  558. Return Value:
  559. None.
  560. Environment:
  561. No references to paged pool or pagable code/data are allowed.
  562. --*/
  563. {
  564. ULONG i;
  565. PEVENT_COUNTER EventSupport;
  566. PUNLOADED_DRIVERS Entry;
  567. PLIST_ENTRY NextEntry;
  568. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  569. PLOAD_IMPORTS ImportList;
  570. PMI_VERIFIER_DRIVER_ENTRY Verifier;
  571. PMMINPAGE_SUPPORT Support;
  572. PSINGLE_LIST_ENTRY SingleListEntry;
  573. PDRIVER_SPECIFIED_VERIFIER_THUNKS ThunkTableBase;
  574. PMMMOD_WRITER_MDL_ENTRY ModWriterEntry;
  575. ASSERT (MmUnusedSegmentList.Flink == &MmUnusedSegmentList);
  576. //
  577. // Don't clear free pages so problems can be debugged.
  578. //
  579. MiZeroingDisabled = TRUE;
  580. if (MiMirrorBitMap != NULL) {
  581. ExFreePool (MiMirrorBitMap);
  582. ASSERT (MiMirrorBitMap2);
  583. ExFreePool (MiMirrorBitMap2);
  584. }
  585. //
  586. // Free the unloaded driver list.
  587. //
  588. if (MmUnloadedDrivers != NULL) {
  589. Entry = &MmUnloadedDrivers[0];
  590. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) {
  591. if (Entry->Name.Buffer != NULL) {
  592. RtlFreeUnicodeString (&Entry->Name);
  593. }
  594. Entry += 1;
  595. }
  596. ExFreePool (MmUnloadedDrivers);
  597. }
  598. NextEntry = MmLoadedUserImageList.Flink;
  599. while (NextEntry != &MmLoadedUserImageList) {
  600. DataTableEntry = CONTAINING_RECORD (NextEntry,
  601. KLDR_DATA_TABLE_ENTRY,
  602. InLoadOrderLinks);
  603. NextEntry = NextEntry->Flink;
  604. ExFreePool ((PVOID)DataTableEntry);
  605. }
  606. //
  607. // Release the loaded module list entries.
  608. //
  609. NextEntry = PsLoadedModuleList.Flink;
  610. while (NextEntry != &PsLoadedModuleList) {
  611. DataTableEntry = CONTAINING_RECORD (NextEntry,
  612. KLDR_DATA_TABLE_ENTRY,
  613. InLoadOrderLinks);
  614. ImportList = (PLOAD_IMPORTS)DataTableEntry->LoadedImports;
  615. if ((ImportList != (PVOID)LOADED_AT_BOOT) &&
  616. (ImportList != (PVOID)NO_IMPORTS_USED) &&
  617. (!SINGLE_ENTRY(ImportList))) {
  618. ExFreePool (ImportList);
  619. }
  620. if (DataTableEntry->FullDllName.Buffer != NULL) {
  621. ASSERT (DataTableEntry->FullDllName.Buffer == DataTableEntry->BaseDllName.Buffer);
  622. }
  623. NextEntry = NextEntry->Flink;
  624. ExFreePool ((PVOID)DataTableEntry);
  625. }
  626. //
  627. // Free the physical memory descriptor block.
  628. //
  629. ExFreePool (MmPhysicalMemoryBlock);
  630. //
  631. // Free the system views structure.
  632. //
  633. if (MmSession.SystemSpaceViewTable != NULL) {
  634. ExFreePool (MmSession.SystemSpaceViewTable);
  635. }
  636. if (MmSession.SystemSpaceBitMap != NULL) {
  637. ExFreePool (MmSession.SystemSpaceBitMap);
  638. }
  639. //
  640. // Free the pagefile structures - note the PageFileName buffer was freed
  641. // earlier as it resided in paged pool and may have needed an inpage
  642. // to be freed.
  643. //
  644. for (i = 0; i < MmNumberOfPagingFiles; i += 1) {
  645. ASSERT (MmPagingFile[i]->PageFileName.Buffer == NULL);
  646. ExFreePool (MmPagingFile[i]->Entry[0]);
  647. ExFreePool (MmPagingFile[i]->Entry[1]);
  648. ExFreePool (MmPagingFile[i]->Bitmap);
  649. ExFreePool (MmPagingFile[i]);
  650. }
  651. ASSERT (MmNumberOfMappedMdlsInUse == 0);
  652. i = 0;
  653. while (IsListEmpty (&MmMappedFileHeader.ListHead) != 0) {
  654. ModWriterEntry = (PMMMOD_WRITER_MDL_ENTRY)RemoveHeadList (
  655. &MmMappedFileHeader.ListHead);
  656. ExFreePool (ModWriterEntry);
  657. i += 1;
  658. }
  659. ASSERT (i == MmNumberOfMappedMdls);
  660. //
  661. // Free the paged pool bitmaps.
  662. //
  663. ExFreePool (MmPagedPoolInfo.PagedPoolAllocationMap);
  664. ExFreePool (MmPagedPoolInfo.EndOfPagedPoolBitmap);
  665. if (VerifierLargePagedPoolMap != NULL) {
  666. ExFreePool (VerifierLargePagedPoolMap);
  667. }
  668. //
  669. // Free the inpage structures.
  670. //
  671. while (ExQueryDepthSList (&MmInPageSupportSListHead) != 0) {
  672. SingleListEntry = InterlockedPopEntrySList (&MmInPageSupportSListHead);
  673. if (SingleListEntry != NULL) {
  674. Support = CONTAINING_RECORD (SingleListEntry,
  675. MMINPAGE_SUPPORT,
  676. ListEntry);
  677. ASSERT (Support->u1.e1.PrefetchMdlHighBits == 0);
  678. ExFreePool (Support);
  679. }
  680. }
  681. while (ExQueryDepthSList (&MmEventCountSListHead) != 0) {
  682. EventSupport = (PEVENT_COUNTER) InterlockedPopEntrySList (&MmEventCountSListHead);
  683. if (EventSupport != NULL) {
  684. ExFreePool (EventSupport);
  685. }
  686. }
  687. //
  688. // Free the verifier list last because it must be consulted to debug
  689. // any bugchecks.
  690. //
  691. NextEntry = MiVerifierDriverAddedThunkListHead.Flink;
  692. if (NextEntry != NULL) {
  693. while (NextEntry != &MiVerifierDriverAddedThunkListHead) {
  694. ThunkTableBase = CONTAINING_RECORD (NextEntry,
  695. DRIVER_SPECIFIED_VERIFIER_THUNKS,
  696. ListEntry );
  697. NextEntry = NextEntry->Flink;
  698. ExFreePool (ThunkTableBase);
  699. }
  700. }
  701. NextEntry = MiSuspectDriverList.Flink;
  702. while (NextEntry != &MiSuspectDriverList) {
  703. Verifier = CONTAINING_RECORD(NextEntry,
  704. MI_VERIFIER_DRIVER_ENTRY,
  705. Links);
  706. NextEntry = NextEntry->Flink;
  707. ExFreePool (Verifier);
  708. }
  709. }