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.

262 lines
6.4 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. zeropage.c
  5. Abstract:
  6. This module contains the zero page thread for memory management.
  7. Author:
  8. Lou Perazzoli (loup) 6-Apr-1991
  9. Landy Wang (landyw) 02-June-1997
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. #define MM_ZERO_PAGE_OBJECT 0
  14. #define PO_SYS_IDLE_OBJECT 1
  15. #define NUMBER_WAIT_OBJECTS 2
  16. #define MACHINE_ZERO_PAGE() KeZeroPageFromIdleThread(ZeroBase)
  17. LOGICAL MiZeroingDisabled = FALSE;
  18. ULONG MmLastNodeZeroing = 0;
  19. VOID
  20. MmZeroPageThread (
  21. VOID
  22. )
  23. /*++
  24. Routine Description:
  25. Implements the NT zeroing page thread. This thread runs
  26. at priority zero and removes a page from the free list,
  27. zeroes it, and places it on the zeroed page list.
  28. Arguments:
  29. StartContext - not used.
  30. Return Value:
  31. None.
  32. Environment:
  33. Kernel mode.
  34. --*/
  35. {
  36. KIRQL OldIrql;
  37. PFN_NUMBER PageFrame;
  38. PMMPFN Pfn1;
  39. PKTHREAD Thread;
  40. PVOID ZeroBase;
  41. PFN_NUMBER NewPage;
  42. PVOID WaitObjects[NUMBER_WAIT_OBJECTS];
  43. NTSTATUS Status;
  44. PVOID StartVa;
  45. PVOID EndVa;
  46. #if defined(MI_MULTINODE)
  47. ULONG i, n;
  48. ULONG Color = 0;
  49. ULONG StartColor;
  50. #endif
  51. //
  52. // Before this becomes the zero page thread, free the kernel
  53. // initialization code.
  54. //
  55. MiFindInitializationCode (&StartVa, &EndVa);
  56. if (StartVa != NULL) {
  57. MiFreeInitializationCode (StartVa, EndVa);
  58. }
  59. //
  60. // The following code sets the current thread's base priority to zero
  61. // and then sets its current priority to zero. This ensures that the
  62. // thread always runs at a priority of zero.
  63. //
  64. Thread = KeGetCurrentThread();
  65. Thread->BasePriority = 0;
  66. KeSetPriorityThread (Thread, 0);
  67. //
  68. // Initialize wait object array for multiple wait
  69. //
  70. WaitObjects[MM_ZERO_PAGE_OBJECT] = &MmZeroingPageEvent;
  71. WaitObjects[PO_SYS_IDLE_OBJECT] = &PoSystemIdleTimer;
  72. //
  73. // Loop forever zeroing pages.
  74. //
  75. do {
  76. //
  77. // Wait until there are at least MmZeroPageMinimum pages
  78. // on the free list.
  79. //
  80. Status = KeWaitForMultipleObjects (NUMBER_WAIT_OBJECTS,
  81. WaitObjects,
  82. WaitAny,
  83. WrFreePage,
  84. KernelMode,
  85. FALSE,
  86. (PLARGE_INTEGER) NULL,
  87. (PKWAIT_BLOCK) NULL
  88. );
  89. if (Status == PO_SYS_IDLE_OBJECT) {
  90. PoSystemIdleWorker (TRUE);
  91. continue;
  92. }
  93. LOCK_PFN_WITH_TRY (OldIrql);
  94. do {
  95. if (*(PFN_NUMBER volatile*)&MmFreePageListHead.Total == 0) {
  96. //
  97. // No pages on the free list at this time, wait for
  98. // some more.
  99. //
  100. MmZeroingPageThreadActive = FALSE;
  101. UNLOCK_PFN (OldIrql);
  102. break;
  103. }
  104. if (MiZeroingDisabled == TRUE) {
  105. MmZeroingPageThreadActive = FALSE;
  106. UNLOCK_PFN (OldIrql);
  107. KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmHalfSecond);
  108. break;
  109. }
  110. //
  111. // In a multinode system, zero pages by node. Starting with
  112. // the last node examined, find a node with free pages that
  113. // need to be zeroed.
  114. //
  115. #if defined(MI_MULTINODE)
  116. if (KeNumberNodes > 1) {
  117. n = MmLastNodeZeroing;
  118. for (i = 0; i < KeNumberNodes; i += 1) {
  119. if (KeNodeBlock[n]->FreeCount[FreePageList] != 0) {
  120. break;
  121. }
  122. n = (n + 1) % KeNumberNodes;
  123. }
  124. ASSERT (KeNodeBlock[n]->FreeCount[FreePageList]);
  125. if (n != MmLastNodeZeroing) {
  126. Color = KeNodeBlock[n]->MmShiftedColor;
  127. }
  128. //
  129. // Must start with a color MiRemoveAnyPage will
  130. // satisfy from the free list otherwise it will
  131. // return an already zeroed page.
  132. //
  133. StartColor = Color;
  134. do {
  135. if (MmFreePagesByColor[FreePageList][Color].Flink !=
  136. MM_EMPTY_LIST) {
  137. break;
  138. }
  139. Color = (Color & ~MmSecondaryColorMask) |
  140. ((Color + 1) & MmSecondaryColorMask);
  141. ASSERT(StartColor != Color);
  142. } while (TRUE);
  143. PageFrame = MiRemoveAnyPage(Color);
  144. }
  145. else {
  146. n = 0;
  147. #endif
  148. PageFrame = MmFreePageListHead.Flink;
  149. ASSERT (PageFrame != MM_EMPTY_LIST);
  150. Pfn1 = MI_PFN_ELEMENT(PageFrame);
  151. NewPage = MiRemoveAnyPage(MI_GET_COLOR_FROM_LIST_ENTRY(PageFrame, Pfn1));
  152. if (NewPage != PageFrame) {
  153. //
  154. // Someone has removed a page from the colored lists
  155. // chain without updating the freelist chain.
  156. //
  157. KeBugCheckEx (PFN_LIST_CORRUPT,
  158. 0x8F,
  159. NewPage,
  160. PageFrame,
  161. 0);
  162. }
  163. #if defined(MI_MULTINODE)
  164. }
  165. #endif
  166. //
  167. // Zero the page using the last color used to map the page.
  168. //
  169. UNLOCK_PFN (OldIrql);
  170. ZeroBase = MiMapPageToZeroInHyperSpace (PageFrame);
  171. //
  172. // If a node switch is in order, do it now that the PFN
  173. // lock has been released.
  174. //
  175. #if defined(MI_MULTINODE)
  176. if ((KeNumberNodes > 1) && (n != MmLastNodeZeroing)) {
  177. MmLastNodeZeroing = n;
  178. KeFindFirstSetLeftAffinity(KeNodeBlock[n]->ProcessorMask, &i);
  179. KeSetIdealProcessorThread(Thread, (UCHAR)i);
  180. }
  181. #endif
  182. MACHINE_ZERO_PAGE();
  183. MiUnmapPageInZeroSpace (ZeroBase);
  184. LOCK_PFN_WITH_TRY (OldIrql);
  185. MiInsertPageInList (&MmZeroedPageListHead, PageFrame);
  186. } while(TRUE);
  187. } while (TRUE);
  188. }