b6b9806e4b00a7c6c7f888af44126952df076573
[reactos.git] / reactos / ntoskrnl / mm / freelist.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/freelist.c
5 * PURPOSE: Handle the list of free physical pages
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Robert Bergkvist
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitializePageList)
19 #endif
20
21 #define MODULE_INVOLVED_IN_ARM3
22 #include "ARM3/miarm.h"
23
24 /* GLOBALS ****************************************************************/
25
26 //
27 //
28 // ReactOS to NT Physical Page Descriptor Entry Legacy Mapping Definitions
29 //
30 // REACTOS NT
31 //
32 #define RmapListHead AweReferenceCount
33 #define PHYSICAL_PAGE MMPFN
34 #define PPHYSICAL_PAGE PMMPFN
35
36 /* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
37 PPHYSICAL_PAGE MmPfnDatabase[2];
38
39 PFN_NUMBER MmAvailablePages;
40 PFN_NUMBER MmResidentAvailablePages;
41 PFN_NUMBER MmResidentAvailableAtInit;
42
43 SIZE_T MmTotalCommitLimit;
44 SIZE_T MmTotalCommittedPages;
45 SIZE_T MmSharedCommit;
46 SIZE_T MmDriverCommit;
47 SIZE_T MmProcessCommit;
48 SIZE_T MmPagedPoolCommit;
49 SIZE_T MmPeakCommitment;
50 SIZE_T MmtotalCommitLimitMaximum;
51
52 KEVENT ZeroPageThreadEvent;
53 static BOOLEAN ZeroPageThreadShouldTerminate = FALSE;
54 static RTL_BITMAP MiUserPfnBitMap;
55
56 /* FUNCTIONS *************************************************************/
57
58 VOID
59 NTAPI
60 MiInitializeUserPfnBitmap(VOID)
61 {
62 PVOID Bitmap;
63
64 /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
65 Bitmap = ExAllocatePoolWithTag(NonPagedPool,
66 (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
67 ' mM');
68 ASSERT(Bitmap);
69
70 /* Initialize it and clear all the bits to begin with */
71 RtlInitializeBitMap(&MiUserPfnBitMap,
72 Bitmap,
73 MmHighestPhysicalPage + 1);
74 RtlClearAllBits(&MiUserPfnBitMap);
75 }
76
77 PFN_TYPE
78 NTAPI
79 MmGetLRUFirstUserPage(VOID)
80 {
81 ULONG Position;
82 KIRQL OldIrql;
83
84 /* Find the first user page */
85 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
86 Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
87 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
88 if (Position == 0xFFFFFFFF) return 0;
89
90 /* Return it */
91 return Position;
92 }
93
94 VOID
95 NTAPI
96 MmInsertLRULastUserPage(PFN_TYPE Pfn)
97 {
98 KIRQL OldIrql;
99
100 /* Set the page as a user page */
101 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
102 RtlSetBit(&MiUserPfnBitMap, Pfn);
103 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
104 }
105
106 PFN_TYPE
107 NTAPI
108 MmGetLRUNextUserPage(PFN_TYPE PreviousPfn)
109 {
110 ULONG Position;
111 KIRQL OldIrql;
112
113 /* Find the next user page */
114 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
115 Position = RtlFindSetBits(&MiUserPfnBitMap, 1, PreviousPfn + 1);
116 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
117 if (Position == 0xFFFFFFFF) return 0;
118
119 /* Return it */
120 return Position;
121 }
122
123 VOID
124 NTAPI
125 MmRemoveLRUUserPage(PFN_TYPE Page)
126 {
127 /* Unset the page as a user page */
128 RtlClearBit(&MiUserPfnBitMap, Page);
129 }
130
131 BOOLEAN
132 NTAPI
133 MiIsPfnFree(IN PMMPFN Pfn1)
134 {
135 /* Must be a free or zero page, with no references, linked */
136 return ((Pfn1->u3.e1.PageLocation <= StandbyPageList) &&
137 (Pfn1->u1.Flink) &&
138 (Pfn1->u2.Blink) &&
139 !(Pfn1->u3.e2.ReferenceCount));
140 }
141
142 BOOLEAN
143 NTAPI
144 MiIsPfnInUse(IN PMMPFN Pfn1)
145 {
146 /* Standby list or higher, unlinked, and with references */
147 return !MiIsPfnFree(Pfn1);
148 }
149
150 PMDL
151 NTAPI
152 MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
153 IN PHYSICAL_ADDRESS HighAddress,
154 IN PHYSICAL_ADDRESS SkipBytes,
155 IN SIZE_T TotalBytes,
156 IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute,
157 IN ULONG MdlFlags)
158 {
159 PMDL Mdl;
160 PFN_NUMBER PageCount, LowPage, HighPage, SkipPages, PagesFound = 0, Page;
161 PPFN_NUMBER MdlPage, LastMdlPage;
162 KIRQL OldIrql;
163 PPHYSICAL_PAGE Pfn1;
164 INT LookForZeroedPages;
165 ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
166
167 //
168 // Convert the low address into a PFN
169 //
170 LowPage = (PFN_NUMBER)(LowAddress.QuadPart >> PAGE_SHIFT);
171
172 //
173 // Convert, and normalize, the high address into a PFN
174 //
175 HighPage = (PFN_NUMBER)(HighAddress.QuadPart >> PAGE_SHIFT);
176 if (HighPage > MmHighestPhysicalPage) HighPage = MmHighestPhysicalPage;
177
178 //
179 // Validate skipbytes and convert them into pages
180 //
181 if (BYTE_OFFSET(SkipBytes.LowPart)) return NULL;
182 SkipPages = (PFN_NUMBER)(SkipBytes.QuadPart >> PAGE_SHIFT);
183
184 //
185 // Now compute the number of pages the MDL will cover
186 //
187 PageCount = (PFN_NUMBER)ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, TotalBytes);
188 do
189 {
190 //
191 // Try creating an MDL for these many pages
192 //
193 Mdl = MmCreateMdl(NULL, NULL, PageCount << PAGE_SHIFT);
194 if (Mdl) break;
195
196 //
197 // This function is not required to return the amount of pages requested
198 // In fact, it can return as little as 1 page, and callers are supposed
199 // to deal with this scenario. So re-attempt the allocation with less
200 // pages than before, and see if it worked this time.
201 //
202 PageCount -= (PageCount >> 4);
203 } while (PageCount);
204
205 //
206 // Wow, not even a single page was around!
207 //
208 if (!Mdl) return NULL;
209
210 //
211 // This is where the page array starts....
212 //
213 MdlPage = (PPFN_NUMBER)(Mdl + 1);
214
215 //
216 // Lock the PFN database
217 //
218 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
219
220 //
221 // Are we looking for any pages, without discriminating?
222 //
223 if ((LowPage == 0) && (HighPage == MmHighestPhysicalPage))
224 {
225 //
226 // Well then, let's go shopping
227 //
228 while (PagesFound < PageCount)
229 {
230 //
231 // Do we have zeroed pages?
232 //
233 if (MmZeroedPageListHead.Total)
234 {
235 //
236 // Grab a zero page
237 //
238 Pfn1 = MiRemoveHeadList(&MmZeroedPageListHead);
239 }
240 else if (MmFreePageListHead.Total)
241 {
242 //
243 // Nope, grab an unzeroed page
244 //
245 Pfn1 = MiRemoveHeadList(&MmFreePageListHead);
246 }
247 else
248 {
249 //
250 // This is not good... hopefully we have at least SOME pages
251 //
252 ASSERT(PagesFound);
253 break;
254 }
255
256 //
257 // Make sure it's really free
258 //
259 ASSERT(MiIsPfnInUse(Pfn1) == FALSE);
260 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
261
262 //
263 // Allocate it and mark it
264 //
265 Pfn1->u3.e1.StartOfAllocation = 1;
266 Pfn1->u3.e1.EndOfAllocation = 1;
267 Pfn1->u3.e2.ReferenceCount = 1;
268
269 //
270 // Decrease available pages
271 //
272 MmAvailablePages--;
273
274 //
275 // Save it into the MDL
276 //
277 *MdlPage++ = MiGetPfnEntryIndex(Pfn1);
278 PagesFound++;
279 }
280 }
281 else
282 {
283 //
284 // You want specific range of pages. We'll do this in two runs
285 //
286 for (LookForZeroedPages = 1; LookForZeroedPages >= 0; LookForZeroedPages--)
287 {
288 //
289 // Scan the range you specified
290 //
291 for (Page = LowPage; Page < HighPage; Page++)
292 {
293 //
294 // Get the PFN entry for this page
295 //
296 Pfn1 = MiGetPfnEntry(Page);
297 ASSERT(Pfn1);
298
299 //
300 // Make sure it's free and if this is our first pass, zeroed
301 //
302 if (MiIsPfnInUse(Pfn1)) continue;
303 if ((Pfn1->u3.e1.PageLocation == ZeroedPageList) != LookForZeroedPages) continue;
304
305 //
306 // Sanity checks
307 //
308 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
309
310 //
311 // Now setup the page and mark it
312 //
313 Pfn1->u3.e2.ReferenceCount = 1;
314 Pfn1->u3.e1.StartOfAllocation = 1;
315 Pfn1->u3.e1.EndOfAllocation = 1;
316
317 //
318 // Decrease available pages
319 //
320 MmAvailablePages--;
321
322 //
323 // Save this page into the MDL
324 //
325 *MdlPage++ = Page;
326 if (++PagesFound == PageCount) break;
327 }
328
329 //
330 // If the first pass was enough, don't keep going, otherwise, go again
331 //
332 if (PagesFound == PageCount) break;
333 }
334 }
335
336 //
337 // Now release the PFN count
338 //
339 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
340
341 //
342 // We might've found less pages, but not more ;-)
343 //
344 if (PagesFound != PageCount) ASSERT(PagesFound < PageCount);
345 if (!PagesFound)
346 {
347 //
348 // If we didn' tfind any pages at all, fail
349 //
350 DPRINT1("NO MDL PAGES!\n");
351 ExFreePool(Mdl);
352 return NULL;
353 }
354
355 //
356 // Write out how many pages we found
357 //
358 Mdl->ByteCount = (ULONG)(PagesFound << PAGE_SHIFT);
359
360 //
361 // Terminate the MDL array if there's certain missing pages
362 //
363 if (PagesFound != PageCount) *MdlPage = -1;
364
365 //
366 // Now go back and loop over all the MDL pages
367 //
368 MdlPage = (PPFN_NUMBER)(Mdl + 1);
369 LastMdlPage = MdlPage + PagesFound;
370 while (MdlPage < LastMdlPage)
371 {
372 //
373 // Check if we've reached the end
374 //
375 Page = *MdlPage++;
376 if (Page == (PFN_NUMBER)-1) break;
377
378 //
379 // Get the PFN entry for the page and check if we should zero it out
380 //
381 Pfn1 = MiGetPfnEntry(Page);
382 ASSERT(Pfn1);
383 if (Pfn1->u3.e1.PageLocation != ZeroedPageList) MiZeroPage(Page);
384 Pfn1->u3.e1.PageLocation = ActiveAndValid;
385 }
386
387 //
388 // We're done, mark the pages as locked (should we lock them, though???)
389 //
390 Mdl->Process = NULL;
391 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
392 return Mdl;
393 }
394
395 VOID
396 NTAPI
397 MmDumpPfnDatabase(VOID)
398 {
399 ULONG i;
400 PPHYSICAL_PAGE Pfn1;
401 PCHAR State = "????", Type = "Unknown";
402 KIRQL OldIrql;
403 ULONG Totals[5] = {0}, FreePages = 0;
404
405 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
406
407 //
408 // Loop the PFN database
409 //
410 for (i = 0; i <= MmHighestPhysicalPage; i++)
411 {
412 Pfn1 = MiGetPfnEntry(i);
413 if (!Pfn1) continue;
414
415 //
416 // Get the type
417 //
418 if (MiIsPfnInUse(Pfn1))
419 {
420 State = "Used";
421 }
422 else
423 {
424 State = "Free";
425 Type = "Free";
426 FreePages++;
427 break;
428 }
429
430 //
431 // Pretty-print the page
432 //
433 DbgPrint("0x%08p:\t%04s\t%20s\t(%02d) [%08p])\n",
434 i << PAGE_SHIFT,
435 State,
436 Type,
437 Pfn1->u3.e2.ReferenceCount,
438 Pfn1->RmapListHead);
439 }
440
441 DbgPrint("Nonpaged Pool: %d pages\t[%d KB]\n", Totals[MC_NPPOOL], (Totals[MC_NPPOOL] << PAGE_SHIFT) / 1024);
442 DbgPrint("Paged Pool: %d pages\t[%d KB]\n", Totals[MC_PPOOL], (Totals[MC_PPOOL] << PAGE_SHIFT) / 1024);
443 DbgPrint("File System Cache: %d pages\t[%d KB]\n", Totals[MC_CACHE], (Totals[MC_CACHE] << PAGE_SHIFT) / 1024);
444 DbgPrint("Process Working Set: %d pages\t[%d KB]\n", Totals[MC_USER], (Totals[MC_USER] << PAGE_SHIFT) / 1024);
445 DbgPrint("System: %d pages\t[%d KB]\n", Totals[MC_SYSTEM], (Totals[MC_SYSTEM] << PAGE_SHIFT) / 1024);
446 DbgPrint("Free: %d pages\t[%d KB]\n", FreePages, (FreePages << PAGE_SHIFT) / 1024);
447
448 KeLowerIrql(OldIrql);
449 }
450
451 VOID
452 NTAPI
453 MmInitializePageList(VOID)
454 {
455 ULONG i;
456 PHYSICAL_PAGE UsedPage;
457 PMEMORY_ALLOCATION_DESCRIPTOR Md;
458 PLIST_ENTRY NextEntry;
459 ULONG NrSystemPages = 0;
460
461 /* This is what a used page looks like */
462 RtlZeroMemory(&UsedPage, sizeof(UsedPage));
463 UsedPage.u3.e1.PageLocation = ActiveAndValid;
464 UsedPage.u3.e2.ReferenceCount = 1;
465
466 /* Loop the memory descriptors */
467 for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
468 NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
469 NextEntry = NextEntry->Flink)
470 {
471 /* Get the descriptor */
472 Md = CONTAINING_RECORD(NextEntry,
473 MEMORY_ALLOCATION_DESCRIPTOR,
474 ListEntry);
475
476 /* Skip bad memory */
477 if ((Md->MemoryType == LoaderFirmwarePermanent) ||
478 (Md->MemoryType == LoaderBBTMemory) ||
479 (Md->MemoryType == LoaderSpecialMemory) ||
480 (Md->MemoryType == LoaderBad))
481 {
482 //
483 // We do not build PFN entries for this
484 //
485 continue;
486 }
487 else if ((Md->MemoryType == LoaderFree) ||
488 (Md->MemoryType == LoaderLoadedProgram) ||
489 (Md->MemoryType == LoaderFirmwareTemporary) ||
490 (Md->MemoryType == LoaderOsloaderStack))
491 {
492 /* Loop every page part of the block */
493 for (i = 0; i < Md->PageCount; i++)
494 {
495 /* Mark it as a free page */
496 MmPfnDatabase[0][Md->BasePage + i].u3.e1.PageLocation = FreePageList;
497 MiInsertInListTail(&MmFreePageListHead,
498 &MmPfnDatabase[0][Md->BasePage + i]);
499 MmAvailablePages++;
500 }
501 }
502 else
503 {
504 /* Loop every page part of the block */
505 for (i = 0; i < Md->PageCount; i++)
506 {
507 /* Everything else is used memory */
508 MmPfnDatabase[0][Md->BasePage + i] = UsedPage;
509 NrSystemPages++;
510 }
511 }
512 }
513
514 /* Finally handle the pages describing the PFN database themselves */
515 for (i = MxOldFreeDescriptor.BasePage; i < MxFreeDescriptor->BasePage; i++)
516 {
517 /* Mark it as used kernel memory */
518 MmPfnDatabase[0][i] = UsedPage;
519 NrSystemPages++;
520 }
521
522 KeInitializeEvent(&ZeroPageThreadEvent, NotificationEvent, TRUE);
523 DPRINT("Pages: %x %x\n", MmAvailablePages, NrSystemPages);
524 MmInitializeBalancer(MmAvailablePages, NrSystemPages);
525 }
526
527 VOID
528 NTAPI
529 MmSetRmapListHeadPage(PFN_TYPE Pfn, struct _MM_RMAP_ENTRY* ListHead)
530 {
531 KIRQL oldIrql;
532
533 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
534 MiGetPfnEntry(Pfn)->RmapListHead = (LONG)ListHead;
535 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
536 }
537
538 struct _MM_RMAP_ENTRY*
539 NTAPI
540 MmGetRmapListHeadPage(PFN_TYPE Pfn)
541 {
542 KIRQL oldIrql;
543 struct _MM_RMAP_ENTRY* ListHead;
544
545 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
546 ListHead = (struct _MM_RMAP_ENTRY*)MiGetPfnEntry(Pfn)->RmapListHead;
547 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
548
549 return(ListHead);
550 }
551
552 VOID
553 NTAPI
554 MmSetSavedSwapEntryPage(PFN_TYPE Pfn, SWAPENTRY SwapEntry)
555 {
556 KIRQL oldIrql;
557
558 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
559 MiGetPfnEntry(Pfn)->u1.WsIndex = SwapEntry;
560 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
561 }
562
563 SWAPENTRY
564 NTAPI
565 MmGetSavedSwapEntryPage(PFN_TYPE Pfn)
566 {
567 SWAPENTRY SwapEntry;
568 KIRQL oldIrql;
569
570 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
571 SwapEntry = MiGetPfnEntry(Pfn)->u1.WsIndex;
572 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
573
574 return(SwapEntry);
575 }
576
577 VOID
578 NTAPI
579 MmReferencePage(PFN_TYPE Pfn)
580 {
581 PPHYSICAL_PAGE Page;
582
583 DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn << PAGE_SHIFT);
584
585 if (Pfn == 0 || Pfn > MmHighestPhysicalPage)
586 {
587 return;
588 }
589
590 Page = MiGetPfnEntry(Pfn);
591 ASSERT(Page);
592
593 Page->u3.e2.ReferenceCount++;
594 }
595
596 ULONG
597 NTAPI
598 MmGetReferenceCountPage(PFN_TYPE Pfn)
599 {
600 KIRQL oldIrql;
601 ULONG RCount;
602 PPHYSICAL_PAGE Page;
603
604 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
605
606 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
607 Page = MiGetPfnEntry(Pfn);
608 ASSERT(Page);
609
610 RCount = Page->u3.e2.ReferenceCount;
611
612 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
613 return(RCount);
614 }
615
616 BOOLEAN
617 NTAPI
618 MmIsPageInUse(PFN_TYPE Pfn)
619 {
620 return MiIsPfnInUse(MiGetPfnEntry(Pfn));
621 }
622
623 VOID
624 NTAPI
625 MiSetConsumer(IN PFN_TYPE Pfn,
626 IN ULONG Type)
627 {
628 MiGetPfnEntry(Pfn)->u3.e1.PageLocation = ActiveAndValid;
629 }
630
631 VOID
632 NTAPI
633 MmDereferencePage(PFN_TYPE Pfn)
634 {
635 PPHYSICAL_PAGE Page;
636
637 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
638
639 Page = MiGetPfnEntry(Pfn);
640 ASSERT(Page);
641
642 Page->u3.e2.ReferenceCount--;
643 if (Page->u3.e2.ReferenceCount == 0)
644 {
645 MmAvailablePages++;
646 Page->u3.e1.PageLocation = FreePageList;
647 MiInsertInListTail(&MmFreePageListHead, Page);
648 if (MmFreePageListHead.Total > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
649 {
650 KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
651 }
652 }
653 }
654
655 PFN_TYPE
656 NTAPI
657 MmAllocPage(ULONG Type)
658 {
659 PFN_TYPE PfnOffset;
660 PPHYSICAL_PAGE PageDescriptor;
661 BOOLEAN NeedClear = FALSE;
662
663 DPRINT("MmAllocPage()\n");
664
665 if (MmZeroedPageListHead.Total == 0)
666 {
667 if (MmFreePageListHead.Total == 0)
668 {
669 /* Check if this allocation is for the PFN DB itself */
670 if (MmNumberOfPhysicalPages == 0)
671 {
672 ASSERT(FALSE);
673 }
674
675 DPRINT1("MmAllocPage(): Out of memory\n");
676 return 0;
677 }
678 PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
679
680 NeedClear = TRUE;
681 }
682 else
683 {
684 PageDescriptor = MiRemoveHeadList(&MmZeroedPageListHead);
685 }
686
687 PageDescriptor->u3.e2.ReferenceCount = 1;
688
689 MmAvailablePages--;
690
691 PfnOffset = PageDescriptor - MmPfnDatabase[0];
692 if ((NeedClear) && (Type != MC_SYSTEM))
693 {
694 MiZeroPage(PfnOffset);
695 }
696
697 PageDescriptor->u3.e1.PageLocation = ActiveAndValid;
698 return PfnOffset;
699 }
700
701 NTSTATUS
702 NTAPI
703 MiZeroPage(PFN_TYPE Page)
704 {
705 KIRQL Irql;
706 PVOID TempAddress;
707
708 Irql = KeRaiseIrqlToDpcLevel();
709 TempAddress = MiMapPageToZeroInHyperSpace(Page);
710 if (TempAddress == NULL)
711 {
712 return(STATUS_NO_MEMORY);
713 }
714 memset(TempAddress, 0, PAGE_SIZE);
715 MiUnmapPagesInZeroSpace(TempAddress, 1);
716 KeLowerIrql(Irql);
717 return(STATUS_SUCCESS);
718 }
719
720 NTSTATUS
721 NTAPI
722 MmZeroPageThreadMain(PVOID Ignored)
723 {
724 NTSTATUS Status;
725 KIRQL oldIrql;
726 PPHYSICAL_PAGE PageDescriptor;
727 PFN_TYPE Pfn;
728 ULONG Count;
729
730 /* Free initial kernel memory */
731 //MiFreeInitMemory();
732
733 /* Set our priority to 0 */
734 KeGetCurrentThread()->BasePriority = 0;
735 KeSetPriorityThread(KeGetCurrentThread(), 0);
736
737 while(1)
738 {
739 Status = KeWaitForSingleObject(&ZeroPageThreadEvent,
740 0,
741 KernelMode,
742 FALSE,
743 NULL);
744
745 if (ZeroPageThreadShouldTerminate)
746 {
747 DPRINT1("ZeroPageThread: Terminating\n");
748 return STATUS_SUCCESS;
749 }
750 Count = 0;
751 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
752 while (MmFreePageListHead.Total)
753 {
754 PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
755 /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
756 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
757 Pfn = PageDescriptor - MmPfnDatabase[0];
758 Status = MiZeroPage(Pfn);
759
760 oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
761 if (NT_SUCCESS(Status))
762 {
763 MiInsertZeroListAtBack(Pfn);
764 Count++;
765 }
766 else
767 {
768 MiInsertInListTail(&MmFreePageListHead, PageDescriptor);
769 PageDescriptor->u3.e1.PageLocation = FreePageList;
770 }
771
772 }
773 DPRINT("Zeroed %d pages.\n", Count);
774 KeResetEvent(&ZeroPageThreadEvent);
775 KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
776 }
777
778 return STATUS_SUCCESS;
779 }
780
781 /* EOF */