VOID MmZeroPageThread ( VOID ) /*++ Routine Description: Implements the NT zeroing page thread. This thread runs at priority zero and removes a page from the free list, zeroes it, and places it on the zeroed page list. Arguments: StartContext - not used. Return Value: None. Environment: Kernel mode. --*/ { PVOID EndVa; KIRQL OldIrql; ULONG PageFrame; PMMPFN Pfn1; PVOID StartVa; PKTHREAD Thread; PVOID ZeroBase; ULONG i; // // Before this becomes the zero page thread, free the kernel // initialization code. // MiFindInitializationCode (&StartVa, &EndVa); if (StartVa != NULL) { MiFreeInitializationCode (StartVa, EndVa); } // // The following code sets the current thread's base priority to zero // and then sets its current priority to zero. This ensures that the // thread always runs at a priority of zero. // Thread = KeGetCurrentThread(); Thread->BasePriority = 0; KeSetPriorityThread (Thread, 0); // // Loop forever zeroing pages. // do { // // Wait until there are at least MmZeroPageMinimum pages // on the free list. // KeWaitForSingleObject (&MmZeroingPageEvent, WrFreePage, KernelMode, FALSE, (PLARGE_INTEGER)NULL); LOCK_PFN_WITH_TRY (OldIrql); do { if ((volatile)MmFreePageListHead.Total == 0) { // // No pages on the free list at this time, wait for // some more. // MmZeroingPageThreadActive = FALSE; UNLOCK_PFN (OldIrql); break; } else { #if MM_MAXIMUM_NUMBER_OF_COLORS > 1 for (i = 0; i < MM_MAXIMUM_NUMBER_OF_COLORS; i++) { PageFrame = MmFreePagesByPrimaryColor[FreePageList][i].Flink; if (PageFrame != MM_EMPTY_LIST) { break; } } #else //MM_MAXIMUM_NUMBER_OF_COLORS > 1 PageFrame = MmFreePageListHead.Flink; #endif //MM_MAXIMUM_NUMBER_OF_COLORS > 1 Pfn1 = MI_PFN_ELEMENT(PageFrame); ASSERT (PageFrame != MM_EMPTY_LIST); Pfn1 = MI_PFN_ELEMENT(PageFrame); MiRemoveAnyPage (MI_GET_SECONDARY_COLOR (PageFrame, Pfn1)); // // Zero the page using the last color used to map the page. // #if defined(_X86_) ZeroBase = MiMapPageToZeroInHyperSpace (PageFrame); UNLOCK_PFN (OldIrql); RtlZeroMemory (ZeroBase, PAGE_SIZE); #elif defined(_PPC_) UNLOCK_PFN (OldIrql); KeZeroPage(PageFrame); #else ZeroBase = (PVOID)(Pfn1->u3.e1.PageColor << PAGE_SHIFT); UNLOCK_PFN (OldIrql); HalZeroPage(ZeroBase, ZeroBase, PageFrame); #endif //X86 LOCK_PFN_WITH_TRY (OldIrql); MiInsertPageInList (MmPageLocationList[ZeroedPageList], PageFrame); } } while(TRUE); } while (TRUE); }
VOID NTAPI MmZeroPageThread(VOID) { PKTHREAD Thread = KeGetCurrentThread(); PVOID StartAddress, EndAddress; PVOID WaitObjects[2]; KIRQL OldIrql; PVOID ZeroAddress; PFN_NUMBER PageIndex, FreePage; PMMPFN Pfn1; /* Get the discardable sections to free them */ MiFindInitializationCode(&StartAddress, &EndAddress); if (StartAddress) MiFreeInitializationCode(StartAddress, EndAddress); DPRINT("Free non-cache pages: %lx\n", MmAvailablePages + MiMemoryConsumers[MC_CACHE].PagesUsed); /* Set our priority to 0 */ Thread->BasePriority = 0; KeSetPriorityThread(Thread, 0); /* Setup the wait objects */ WaitObjects[0] = &MmZeroingPageEvent; // WaitObjects[1] = &PoSystemIdleTimer; FIXME: Implement idle timer while (TRUE) { KeWaitForMultipleObjects(1, // 2 WaitObjects, WaitAny, WrFreePage, KernelMode, FALSE, NULL, NULL); OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); while (TRUE) { if (!MmFreePageListHead.Total) { MmZeroingPageThreadActive = FALSE; KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); break; } PageIndex = MmFreePageListHead.Flink; ASSERT(PageIndex != LIST_HEAD); Pfn1 = MiGetPfnEntry(PageIndex); MI_SET_USAGE(MI_USAGE_ZERO_LOOP); MI_SET_PROCESS2("Kernel 0 Loop"); FreePage = MiRemoveAnyPage(MI_GET_PAGE_COLOR(PageIndex)); /* The first global free page should also be the first on its own list */ if (FreePage != PageIndex) { KeBugCheckEx(PFN_LIST_CORRUPT, 0x8F, FreePage, PageIndex, 0); } Pfn1->u1.Flink = LIST_HEAD; KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); ZeroAddress = MiMapPagesInZeroSpace(Pfn1, 1); ASSERT(ZeroAddress); RtlZeroMemory(ZeroAddress, PAGE_SIZE); MiUnmapPagesInZeroSpace(ZeroAddress, 1); OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); MiInsertPageInList(&MmZeroedPageListHead, PageIndex); } } }