Leaked source code of windows server 2003
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.

782 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. mirror.c
  5. Abstract:
  6. This module contains the routines to support memory mirroring.
  7. Author:
  8. Landy Wang (landyw) 17-Jan-2000
  9. Revision History:
  10. --*/
  11. #include "mi.h"
  12. #define MIRROR_MAX_PHASE_ZERO_PASSES 8
  13. //
  14. // This is set via the registry.
  15. //
  16. ULONG MmMirroring = 0;
  17. //
  18. // These bitmaps are allocated at system startup if the
  19. // registry key above is set.
  20. //
  21. PRTL_BITMAP MiMirrorBitMap;
  22. PRTL_BITMAP MiMirrorBitMap2;
  23. //
  24. // This is set if a mirroring operation is in progress.
  25. //
  26. LOGICAL MiMirroringActive = FALSE;
  27. extern LOGICAL MiZeroingDisabled;
  28. #if DBG
  29. ULONG MiMirrorDebug = 1;
  30. ULONG MiMirrorPassMax[2];
  31. #endif
  32. #pragma alloc_text(PAGELK, MmCreateMirror)
  33. NTKERNELAPI
  34. NTSTATUS
  35. MmCreateMirror (
  36. VOID
  37. )
  38. {
  39. KIRQL OldIrql;
  40. KIRQL ExitIrql;
  41. ULONG Limit;
  42. ULONG Color;
  43. ULONG IterationCount;
  44. PMMPFN Pfn1;
  45. PMMPFNLIST ListHead;
  46. PFN_NUMBER PreviousPage;
  47. PFN_NUMBER ThisPage;
  48. PFN_NUMBER PageFrameIndex;
  49. MMLISTS MemoryList;
  50. ULONG LengthOfClearRun;
  51. ULONG LengthOfSetRun;
  52. ULONG StartingRunIndex;
  53. ULONG BitMapIndex;
  54. ULONG BitMapHint;
  55. ULONG BitMapBytes;
  56. PULONG BitMap1;
  57. PULONG BitMap2;
  58. PHYSICAL_ADDRESS PhysicalAddress;
  59. LARGE_INTEGER PhysicalBytes;
  60. NTSTATUS Status;
  61. ULONG BitMapSize;
  62. PFN_NUMBER PagesWritten;
  63. PFN_NUMBER PagesWrittenLast;
  64. KPROCESSOR_MODE PreviousMode;
  65. #if DBG
  66. ULONG PassMaxRun;
  67. PFN_NUMBER PagesVerified;
  68. #endif
  69. ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  70. PreviousMode = KeGetPreviousMode ();
  71. if ((PreviousMode != KernelMode) &&
  72. (SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode) == FALSE)) {
  73. return STATUS_PRIVILEGE_NOT_HELD;
  74. }
  75. if ((MmMirroring & MM_MIRRORING_ENABLED) == 0) {
  76. return STATUS_NOT_SUPPORTED;
  77. }
  78. if (MiMirrorBitMap == NULL) {
  79. return STATUS_INSUFFICIENT_RESOURCES;
  80. }
  81. if ((ExVerifySuite(DataCenter) == TRUE) ||
  82. ((MmProductType != 0x00690057) && (ExVerifySuite(Enterprise) == TRUE))) {
  83. //
  84. // DataCenter and Advanced Server are the only appropriate mirroring
  85. // platforms, allow them to proceed.
  86. //
  87. NOTHING;
  88. }
  89. else {
  90. return STATUS_LICENSE_VIOLATION;
  91. }
  92. //
  93. // Serialize here with dynamic memory additions and removals.
  94. //
  95. KeAcquireGuardedMutex (&MmDynamicMemoryMutex);
  96. ASSERT (MiMirroringActive == FALSE);
  97. MmLockPagableSectionByHandle (ExPageLockHandle);
  98. //
  99. // Setting all the bits here states all the pages need to be mirrored.
  100. // In the Phase0 loop below, the bits will be cleared as pages are
  101. // found on the lists and marked to be sent to the mirror. Bits are
  102. // set again if the pages are reclaimed for active use.
  103. //
  104. RtlSetAllBits (MiMirrorBitMap2);
  105. //
  106. // Put all readonly nonpaged kernel and HAL subsection pages into the
  107. // Phase0 list. The only way these could get written between Phase0
  108. // starting and Phase1 ending is via debugger breakpoints and those
  109. // don't matter. This is worth a couple of megabytes and could be done
  110. // at some point in the future if a reasonable perf gain can be shown.
  111. //
  112. MiZeroingDisabled = TRUE;
  113. IterationCount = 0;
  114. //
  115. // Compute initial "pages copied" so convergence can be ascertained
  116. // in the main loop below.
  117. //
  118. PagesWrittenLast = 0;
  119. #if DBG
  120. if (MiMirrorDebug != 0) {
  121. for (MemoryList = ZeroedPageList; MemoryList <= ModifiedNoWritePageList; MemoryList += 1) {
  122. PagesWrittenLast += (PFN_COUNT)MmPageLocationList[MemoryList]->Total;
  123. }
  124. DbgPrint ("Mirror P0 starting with %x pages\n", PagesWrittenLast);
  125. PagesWrittenLast = 0;
  126. }
  127. #endif
  128. //
  129. // Initiate Phase0 copying.
  130. // Inform the HAL so it can initialize if need be.
  131. //
  132. Status = HalStartMirroring ();
  133. if (!NT_SUCCESS(Status)) {
  134. MmUnlockPagableImageSection(ExPageLockHandle);
  135. MiZeroingDisabled = FALSE;
  136. ASSERT (MiMirroringActive == FALSE);
  137. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  138. return Status;
  139. }
  140. //
  141. // Scan system memory and mirror pages until a pass
  142. // doesn't find many pages to transfer.
  143. //
  144. do {
  145. //
  146. // The list of pages to be transferred on this iteration will be
  147. // formed in the MiMirrorBitMap array. Clear out prior usage.
  148. //
  149. RtlClearAllBits (MiMirrorBitMap);
  150. //
  151. // Trim all pages from all process working sets so that as many pages
  152. // as possible will be on the standby, modified and modnowrite lists.
  153. // These lists are written during Phase0 mirroring where locks are
  154. // not held and thus the system is still somewhat operational from
  155. // an application's perspective.
  156. //
  157. MmEmptyAllWorkingSets ();
  158. MiFreeAllExpansionNonPagedPool ();
  159. LOCK_PFN (OldIrql);
  160. //
  161. // Scan all the page lists so they can be copied during Phase0
  162. // mirroring.
  163. //
  164. for (MemoryList = ZeroedPageList; MemoryList <= ModifiedNoWritePageList; MemoryList += 1) {
  165. ListHead = MmPageLocationList[MemoryList];
  166. if (ListHead->Total == 0) {
  167. continue;
  168. }
  169. if ((MemoryList == ModifiedPageList) &&
  170. (ListHead->Total == MmTotalPagesForPagingFile)) {
  171. continue;
  172. }
  173. PageFrameIndex = ListHead->Flink;
  174. do {
  175. //
  176. // The scan is operating via the lists rather than the PFN
  177. // entries as read-in-progress pages are not on lists and
  178. // therefore do not have to be special cased here and elsewhere.
  179. //
  180. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  181. ASSERT (Pfn1->u3.e1.ReadInProgress == 0);
  182. //
  183. // Setting the bit in BitMap means this page is to be copied
  184. // in this Phase0 iteration. If it is reused after this
  185. // point (as indicated by its bit being set again in BitMap2),
  186. // it will be recopied on a later iteration or in Phase1.
  187. //
  188. if (RtlCheckBit(MiMirrorBitMap2, (ULONG)PageFrameIndex)) {
  189. RtlSetBit (MiMirrorBitMap, (ULONG)PageFrameIndex);
  190. RtlClearBit (MiMirrorBitMap2, (ULONG)PageFrameIndex);
  191. }
  192. PageFrameIndex = Pfn1->u1.Flink;
  193. } while (PageFrameIndex != MM_EMPTY_LIST);
  194. }
  195. //
  196. // Scan for modified pages destined for the paging file.
  197. //
  198. for (Color = 0; Color < MM_MAXIMUM_NUMBER_OF_COLORS; Color += 1) {
  199. ListHead = &MmModifiedPageListByColor[Color];
  200. if (ListHead->Total == 0) {
  201. continue;
  202. }
  203. PageFrameIndex = ListHead->Flink;
  204. do {
  205. //
  206. // The scan is operating via the lists rather than the PFN
  207. // entries as read-in-progress are not on lists. Thus this
  208. // case does not have to be handled here and just works out.
  209. //
  210. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  211. ASSERT (Pfn1->u3.e1.ReadInProgress == 0);
  212. //
  213. // Setting the bit in BitMap means this page is to be copied
  214. // on this iteration of Phase0. If it is reused after this
  215. // point (as indicated by its bit being set again in BitMap2),
  216. // it will be recopied on a later iteration or in Phase1.
  217. //
  218. if (RtlCheckBit(MiMirrorBitMap2, (ULONG)PageFrameIndex)) {
  219. RtlSetBit (MiMirrorBitMap, (ULONG)PageFrameIndex);
  220. RtlClearBit (MiMirrorBitMap2, (ULONG)PageFrameIndex);
  221. }
  222. PageFrameIndex = Pfn1->u1.Flink;
  223. } while (PageFrameIndex != MM_EMPTY_LIST);
  224. }
  225. #if DBG
  226. if (MiMirrorDebug != 0) {
  227. DbgPrint ("Mirror P0 pass %d: Transfer %x pages\n",
  228. IterationCount,
  229. RtlNumberOfSetBits(MiMirrorBitMap));
  230. }
  231. #endif
  232. MiMirroringActive = TRUE;
  233. //
  234. // The dirty PFN bitmap has been initialized and the flag set.
  235. // There are very intricate rules governing how different places in
  236. // memory management MUST update the bitmap when we are in this mode.
  237. //
  238. // The rules are:
  239. //
  240. // Anyone REMOVING a page from the zeroed, free, transition, modified
  241. // or modnowrite lists must update the bitmap IFF that page could
  242. // potentially be subsequently modified. Pages that are in transition
  243. // BUT NOT on one of these lists (ie inpages, freed pages that are
  244. // dangling due to nonzero reference counts, etc) do NOT need to
  245. // update the bitmap as they are not one of these lists. If the page
  246. // is removed from one of the five lists just to be immediately
  247. // placed--without modification--on another list, then the bitmap
  248. // does NOT need updating.
  249. //
  250. // Therefore :
  251. //
  252. // MiUnlinkPageFromList updates the bitmap. While some callers
  253. // immediately put a page acquired this way back on one of the 3 lists
  254. // above, this is generally rare. Having this routine update the
  255. // bitmap means cases like restoring a transition PTE "just work".
  256. //
  257. // Callers of MiRemovePageFromList where list >= Transition, must do the
  258. // bitmap updates as only they know if the page is immediately going
  259. // back to one of the five lists above or being
  260. // reused (reused == update REQUIRED).
  261. //
  262. // MiRemoveZeroPage updates the bitmap as the page is immediately
  263. // going to be modified. MiRemoveAnyPage does this also.
  264. //
  265. // Inserts into ANY list do not need to update bitmaps, as a remove had
  266. // to occur first (which would do the update) or it wasn't on a list to
  267. // begin with and thus wasn't subtracted above and therefore doesn't
  268. // need to update the bitmap either.
  269. //
  270. UNLOCK_PFN (OldIrql);
  271. BitMapHint = 0;
  272. PagesWritten = 0;
  273. #if DBG
  274. PassMaxRun = 0;
  275. #endif
  276. do {
  277. BitMapIndex = RtlFindSetBits (MiMirrorBitMap, 1, BitMapHint);
  278. if (BitMapIndex < BitMapHint) {
  279. break;
  280. }
  281. if (BitMapIndex == NO_BITS_FOUND) {
  282. break;
  283. }
  284. //
  285. // Found at least one page to copy - try for a cluster.
  286. //
  287. LengthOfClearRun = RtlFindNextForwardRunClear (MiMirrorBitMap,
  288. BitMapIndex,
  289. &StartingRunIndex);
  290. if (LengthOfClearRun != 0) {
  291. LengthOfSetRun = StartingRunIndex - BitMapIndex;
  292. }
  293. else {
  294. LengthOfSetRun = MiMirrorBitMap->SizeOfBitMap - BitMapIndex;
  295. }
  296. PagesWritten += LengthOfSetRun;
  297. #if DBG
  298. if (LengthOfSetRun > PassMaxRun) {
  299. PassMaxRun = LengthOfSetRun;
  300. }
  301. #endif
  302. //
  303. // Write out the page(s).
  304. //
  305. PhysicalAddress.QuadPart = BitMapIndex;
  306. PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
  307. PhysicalBytes.QuadPart = LengthOfSetRun;
  308. PhysicalBytes.QuadPart = PhysicalBytes.QuadPart << PAGE_SHIFT;
  309. Status = HalMirrorPhysicalMemory (PhysicalAddress, PhysicalBytes);
  310. if (!NT_SUCCESS(Status)) {
  311. MiZeroingDisabled = FALSE;
  312. MmUnlockPagableImageSection(ExPageLockHandle);
  313. MiMirroringActive = FALSE;
  314. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  315. return Status;
  316. }
  317. BitMapHint = BitMapIndex + LengthOfSetRun + LengthOfClearRun;
  318. } while (BitMapHint < MiMirrorBitMap->SizeOfBitMap);
  319. ASSERT (RtlNumberOfSetBits(MiMirrorBitMap) == PagesWritten);
  320. #if DBG
  321. if (PassMaxRun > MiMirrorPassMax[0]) {
  322. MiMirrorPassMax[0] = PassMaxRun;
  323. }
  324. if (MiMirrorDebug != 0) {
  325. DbgPrint ("Mirror P0 pass %d: ended with %x (last= %x) pages\n",
  326. IterationCount, PagesWritten, PagesWrittenLast);
  327. }
  328. #endif
  329. ASSERT (MiMirroringActive == TRUE);
  330. //
  331. // Stop when PagesWritten by the current pass is not somewhat
  332. // better than the preceeding pass. If improvement is vanishing,
  333. // the method is at the steady state where working set removals and
  334. // transition faults are in balance. Also stop if PagesWritten is
  335. // small in absolute terms. Finally, there is a limit on iterations
  336. // for the misbehaving cases.
  337. //
  338. if (((PagesWritten > PagesWrittenLast - 256) && (IterationCount > 0)) ||
  339. (PagesWritten < 1024)) {
  340. break;
  341. }
  342. ASSERT (MiMirroringActive == TRUE);
  343. PagesWrittenLast = PagesWritten;
  344. IterationCount += 1;
  345. if (IterationCount == 2) {
  346. //
  347. // We've made 2 passes at trimming pages without getting enough
  348. // to move to Phase1. Throttle faults so threads cannot add
  349. // these back quickly.
  350. //
  351. InterlockedIncrement (&MiDelayPageFaults);
  352. }
  353. } while (IterationCount < MIRROR_MAX_PHASE_ZERO_PASSES);
  354. ASSERT (MiMirroringActive == TRUE);
  355. //
  356. // Notify the HAL that Phase0 is complete. The HAL is responsible for
  357. // doing things like disabling interrupts, processors and preparing the
  358. // hardware for Phase1. Note that some HALs may return from this
  359. // call at DISPATCH_LEVEL, so snap current IRQL now.
  360. //
  361. ExitIrql = KeGetCurrentIrql ();
  362. ASSERT (ExitIrql <= APC_LEVEL);
  363. ASSERT (KeAreAllApcsDisabled () == TRUE);
  364. Status = HalEndMirroring (0);
  365. if (!NT_SUCCESS(Status)) {
  366. if (IterationCount >= 2) {
  367. InterlockedDecrement (&MiDelayPageFaults);
  368. }
  369. ASSERT (KeGetCurrentIrql () <= APC_LEVEL);
  370. MmUnlockPagableImageSection(ExPageLockHandle);
  371. MiZeroingDisabled = FALSE;
  372. MiMirroringActive = FALSE;
  373. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  374. return Status;
  375. }
  376. ASSERT (KeGetCurrentIrql () <= DISPATCH_LEVEL);
  377. //
  378. // Phase0 copying is now complete.
  379. //
  380. // BitMap2 contains the list of safely transmitted (bit == 0) and
  381. // pages needing transmission (bit == 1).
  382. //
  383. // BitMap content is obsolete and if mirror verification is enabled,
  384. // BitMap will be reused below to accumulate the pages needing
  385. // verification in the following steps.
  386. //
  387. // Prepare for Phase1:
  388. //
  389. // 1. Assume all pages are to be verified (set all bits in BitMap).
  390. // 2. Synchronize list updates by acquiring the PFN lock.
  391. // 3. Exclude all holes in the PFN database.
  392. //
  393. // Phase 1:
  394. //
  395. // 4. Copy all the remaining pages whose bits are set.
  396. // 5. Transmit the list of pages to be verified if so configured.
  397. //
  398. BitMapBytes = (ULONG)((((MiMirrorBitMap->SizeOfBitMap) + 31) / 32) * 4);
  399. BitMap1 = MiMirrorBitMap->Buffer;
  400. BitMap2 = MiMirrorBitMap2->Buffer;
  401. BitMapSize = MiMirrorBitMap->SizeOfBitMap;
  402. ASSERT (BitMapSize == MiMirrorBitMap2->SizeOfBitMap);
  403. //
  404. // Step 1: Assume all pages are to be verified (set all bits in BitMap).
  405. //
  406. if (MmMirroring & MM_MIRRORING_VERIFYING) {
  407. RtlSetAllBits(MiMirrorBitMap);
  408. }
  409. //
  410. // Step 2: Synchronize list updates by acquiring the PFN lock.
  411. //
  412. LOCK_PFN2 (OldIrql);
  413. //
  414. // No need to throttle faults at this point now that the PFN lock is held.
  415. //
  416. if (IterationCount >= 2) {
  417. InterlockedDecrement (&MiDelayPageFaults);
  418. }
  419. //
  420. // No more updates of the bitmaps are needed - we've already snapped the
  421. // information we need and are going to hold the PFN lock from here until
  422. // we're done.
  423. //
  424. MiMirroringActive = FALSE;
  425. //
  426. // Step 3: Exclude any memory gaps.
  427. //
  428. Limit = 0;
  429. PreviousPage = 0;
  430. do {
  431. ThisPage = MmPhysicalMemoryBlock->Run[Limit].BasePage;
  432. if (ThisPage != PreviousPage) {
  433. RtlClearBits (MiMirrorBitMap2,
  434. (ULONG)PreviousPage,
  435. (ULONG)(ThisPage - PreviousPage));
  436. if (MmMirroring & MM_MIRRORING_VERIFYING) {
  437. RtlClearBits (MiMirrorBitMap,
  438. (ULONG)PreviousPage,
  439. (ULONG)(ThisPage - PreviousPage));
  440. }
  441. }
  442. PreviousPage = ThisPage + MmPhysicalMemoryBlock->Run[Limit].PageCount;
  443. Limit += 1;
  444. } while (Limit != MmPhysicalMemoryBlock->NumberOfRuns);
  445. if (PreviousPage != MmHighestPossiblePhysicalPage + 1) {
  446. RtlClearBits (MiMirrorBitMap2,
  447. (ULONG)PreviousPage,
  448. (ULONG)(MmHighestPossiblePhysicalPage + 1 - PreviousPage));
  449. if (MmMirroring & MM_MIRRORING_VERIFYING) {
  450. RtlClearBits (MiMirrorBitMap,
  451. (ULONG)PreviousPage,
  452. (ULONG)(MmHighestPossiblePhysicalPage + 1 - PreviousPage));
  453. }
  454. }
  455. //
  456. // Step 4: Initiate Phase1 copying.
  457. //
  458. // N.B. If this code or code that it calls, writes to non-stack
  459. // memory between this point and the completion of the call to
  460. // HalEndMirroring(1), the mirror *BREAKS*, because MmCreateMirror
  461. // does not know when that non-stack data will be transferred to
  462. // the new memory. [This rule can be broken if special arrangements
  463. // are made to re-copy the memory after the final write takes place.]
  464. //
  465. // N.B. The HAL *MUST* handle the writes into this routine's stack
  466. // frame at the same time it deals with the stack frame of HalEndMirroring
  467. // and any other frames pushed by the HAL.
  468. //
  469. BitMapHint = 0;
  470. #if DBG
  471. PagesWritten = 0;
  472. PassMaxRun = 0;
  473. #endif
  474. do {
  475. BitMapIndex = RtlFindSetBits (MiMirrorBitMap2, 1, BitMapHint);
  476. if (BitMapIndex < BitMapHint) {
  477. break;
  478. }
  479. if (BitMapIndex == NO_BITS_FOUND) {
  480. break;
  481. }
  482. //
  483. // Found at least one page to copy - try for a cluster.
  484. //
  485. LengthOfClearRun = RtlFindNextForwardRunClear (MiMirrorBitMap2,
  486. BitMapIndex,
  487. &StartingRunIndex);
  488. if (LengthOfClearRun != 0) {
  489. LengthOfSetRun = StartingRunIndex - BitMapIndex;
  490. }
  491. else {
  492. LengthOfSetRun = MiMirrorBitMap2->SizeOfBitMap - BitMapIndex;
  493. }
  494. #if DBG
  495. PagesWritten += LengthOfSetRun;
  496. if (LengthOfSetRun > PassMaxRun) {
  497. PassMaxRun = LengthOfSetRun;
  498. }
  499. #endif
  500. //
  501. // Write out the page(s).
  502. //
  503. PhysicalAddress.QuadPart = BitMapIndex;
  504. PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
  505. PhysicalBytes.QuadPart = LengthOfSetRun;
  506. PhysicalBytes.QuadPart = PhysicalBytes.QuadPart << PAGE_SHIFT;
  507. Status = HalMirrorPhysicalMemory (PhysicalAddress, PhysicalBytes);
  508. if (!NT_SUCCESS(Status)) {
  509. UNLOCK_PFN2 (ExitIrql);
  510. MiZeroingDisabled = FALSE;
  511. MmUnlockPagableImageSection(ExPageLockHandle);
  512. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  513. return Status;
  514. }
  515. BitMapHint = BitMapIndex + LengthOfSetRun + LengthOfClearRun;
  516. } while (BitMapHint < MiMirrorBitMap2->SizeOfBitMap);
  517. //
  518. // Phase1 copying is now complete.
  519. //
  520. //
  521. // Step 5:
  522. //
  523. // If HAL verification is enabled, inform the HAL of the ranges the
  524. // systems expects were mirrored. Any range not in this list means
  525. // that the system doesn't care if it was mirrored and the contents may
  526. // very well be different between the mirrors. Note the PFN lock is still
  527. // held so that the HAL can see things consistently.
  528. //
  529. #if DBG
  530. PagesVerified = 0;
  531. #endif
  532. if (MmMirroring & MM_MIRRORING_VERIFYING) {
  533. BitMapHint = 0;
  534. do {
  535. BitMapIndex = RtlFindSetBits (MiMirrorBitMap, 1, BitMapHint);
  536. if (BitMapIndex < BitMapHint) {
  537. break;
  538. }
  539. if (BitMapIndex == NO_BITS_FOUND) {
  540. break;
  541. }
  542. //
  543. // Found at least one page in this mirror range - try for a cluster.
  544. //
  545. LengthOfClearRun = RtlFindNextForwardRunClear (MiMirrorBitMap,
  546. BitMapIndex,
  547. &StartingRunIndex);
  548. if (LengthOfClearRun != 0) {
  549. LengthOfSetRun = StartingRunIndex - BitMapIndex;
  550. }
  551. else {
  552. LengthOfSetRun = MiMirrorBitMap->SizeOfBitMap - BitMapIndex;
  553. }
  554. #if DBG
  555. PagesVerified += LengthOfSetRun;
  556. #endif
  557. //
  558. // Tell the HAL that this range must be in a mirrored state.
  559. //
  560. PhysicalAddress.QuadPart = BitMapIndex;
  561. PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
  562. PhysicalBytes.QuadPart = LengthOfSetRun;
  563. PhysicalBytes.QuadPart = PhysicalBytes.QuadPart << PAGE_SHIFT;
  564. Status = HalMirrorVerify (PhysicalAddress, PhysicalBytes);
  565. if (!NT_SUCCESS(Status)) {
  566. UNLOCK_PFN2 (ExitIrql);
  567. MiZeroingDisabled = FALSE;
  568. MmUnlockPagableImageSection(ExPageLockHandle);
  569. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  570. return Status;
  571. }
  572. BitMapHint = BitMapIndex + LengthOfSetRun + LengthOfClearRun;
  573. } while (BitMapHint < MiMirrorBitMap->SizeOfBitMap);
  574. }
  575. //
  576. // Phase1 verification is now complete.
  577. //
  578. //
  579. // Notify the HAL that everything's done while still holding
  580. // the PFN lock - the HAL will now complete copying of all pages and
  581. // any other needed state before returning from this call.
  582. //
  583. Status = HalEndMirroring (1);
  584. UNLOCK_PFN2 (ExitIrql);
  585. #if DBG
  586. if (MiMirrorDebug != 0) {
  587. DbgPrint ("Mirror P1: %x pages copied\n", PagesWritten);
  588. if (MmMirroring & MM_MIRRORING_VERIFYING) {
  589. DbgPrint ("Mirror P1: %x pages verified\n", PagesVerified);
  590. }
  591. }
  592. if (PassMaxRun > MiMirrorPassMax[1]) {
  593. MiMirrorPassMax[1] = PassMaxRun;
  594. }
  595. #endif
  596. MiZeroingDisabled = FALSE;
  597. MmUnlockPagableImageSection(ExPageLockHandle);
  598. KeReleaseGuardedMutex (&MmDynamicMemoryMutex);
  599. return Status;
  600. }