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
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES ****************************************************************/
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitializePageList)
21 #define MODULE_INVOLVED_IN_ARM3
22 #include "ARM3/miarm.h"
24 /* GLOBALS ****************************************************************/
28 // ReactOS to NT Physical Page Descriptor Entry Legacy Mapping Definitions
32 #define Consumer u3.e1.PageColor
33 #define RmapListHead AweReferenceCount
34 #define SavedSwapEntry u4.EntireFrame
35 #define RemoveEntryList(x) RemoveEntryList((PLIST_ENTRY)x)
36 #define InsertTailList(x, y) InsertTailList(x, (PLIST_ENTRY)y)
38 #define PHYSICAL_PAGE MMPFN
39 #define PPHYSICAL_PAGE PMMPFN
41 /* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
42 PPHYSICAL_PAGE MmPfnDatabase
[2];
44 ULONG MmAvailablePages
;
45 ULONG MmResidentAvailablePages
;
47 SIZE_T MmTotalCommitLimit
;
48 SIZE_T MmTotalCommittedPages
;
49 SIZE_T MmSharedCommit
;
50 SIZE_T MmDriverCommit
;
51 SIZE_T MmProcessCommit
;
52 SIZE_T MmPagedPoolCommit
;
53 SIZE_T MmPeakCommitment
;
54 SIZE_T MmtotalCommitLimitMaximum
;
56 MMPFNLIST MmZeroedPageListHead
;
57 MMPFNLIST MmFreePageListHead
;
58 MMPFNLIST MmStandbyPageListHead
;
59 MMPFNLIST MmModifiedPageListHead
;
60 MMPFNLIST MmModifiedNoWritePageListHead
;
62 /* List of pages allocated to the MC_USER Consumer */
63 static LIST_ENTRY UserPageListHead
;
64 /* List of pages zeroed by the ZPW (MmZeroPageThreadMain) */
65 static LIST_ENTRY FreeZeroedPageListHead
;
66 /* List of free pages, filled by MmGetReferenceCountPage and
67 * and MmInitializePageList */
68 static LIST_ENTRY FreeUnzeroedPageListHead
;
70 static KEVENT ZeroPageThreadEvent
;
71 static BOOLEAN ZeroPageThreadShouldTerminate
= FALSE
;
73 static ULONG UnzeroedPageCount
= 0;
75 /* FUNCTIONS *************************************************************/
77 static RTL_BITMAP MiUserPfnBitMap
;
79 /* FUNCTIONS *************************************************************/
83 MiInitializeUserPfnBitmap(VOID
)
87 /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
88 Bitmap
= ExAllocatePoolWithTag(NonPagedPool
,
89 (((MmHighestPhysicalPage
+ 1) + 31) / 32) * 4,
93 /* Initialize it and clear all the bits to begin with */
94 RtlInitializeBitMap(&MiUserPfnBitMap
,
96 MmHighestPhysicalPage
+ 1);
97 RtlClearAllBits(&MiUserPfnBitMap
);
102 MmGetLRUFirstUserPage(VOID
)
107 /* Find the first user page */
108 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
109 Position
= RtlFindSetBits(&MiUserPfnBitMap
, 1, 0);
110 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
111 if (Position
== 0xFFFFFFFF) return 0;
119 MmInsertLRULastUserPage(PFN_TYPE Pfn
)
123 /* Set the page as a user page */
124 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
125 RtlSetBit(&MiUserPfnBitMap
, Pfn
);
126 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
131 MmGetLRUNextUserPage(PFN_TYPE PreviousPfn
)
136 /* Find the next user page */
137 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
138 Position
= RtlFindSetBits(&MiUserPfnBitMap
, 1, PreviousPfn
+ 1);
139 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
140 if (Position
== 0xFFFFFFFF) return 0;
148 MmRemoveLRUUserPage(PFN_TYPE Page
)
150 /* Unset the page as a user page */
151 RtlClearBit(&MiUserPfnBitMap
, Page
);
156 MiIsPfnInUse(IN PMMPFN Pfn1
)
158 return ((Pfn1
->u3
.e1
.PageLocation
!= FreePageList
) &&
159 (Pfn1
->u3
.e1
.PageLocation
!= ZeroedPageList
));
164 MiFindContiguousPages(IN PFN_NUMBER LowestPfn
,
165 IN PFN_NUMBER HighestPfn
,
166 IN PFN_NUMBER BoundaryPfn
,
167 IN PFN_NUMBER SizeInPages
,
168 IN MEMORY_CACHING_TYPE CacheType
)
170 PFN_NUMBER Page
, PageCount
, LastPage
, Length
, BoundaryMask
;
175 ASSERT(SizeInPages
!= 0);
178 // Convert the boundary PFN into an alignment mask
180 BoundaryMask
= ~(BoundaryPfn
- 1);
183 // Loop all the physical memory blocks
188 // Capture the base page and length of this memory block
190 Page
= MmPhysicalMemoryBlock
->Run
[i
].BasePage
;
191 PageCount
= MmPhysicalMemoryBlock
->Run
[i
].PageCount
;
194 // Check how far this memory block will go
196 LastPage
= Page
+ PageCount
;
199 // Trim it down to only the PFNs we're actually interested in
201 if ((LastPage
- 1) > HighestPfn
) LastPage
= HighestPfn
+ 1;
202 if (Page
< LowestPfn
) Page
= LowestPfn
;
205 // Skip this run if it's empty or fails to contain all the pages we need
207 if (!(PageCount
) || ((Page
+ SizeInPages
) > LastPage
)) continue;
210 // Now scan all the relevant PFNs in this run
213 for (Pfn1
= MiGetPfnEntry(Page
); Page
< LastPage
; Page
++, Pfn1
++)
216 // If this PFN is in use, ignore it
218 if (MiIsPfnInUse(Pfn1
)) continue;
221 // If we haven't chosen a start PFN yet and the caller specified an
222 // alignment, make sure the page matches the alignment restriction
224 if ((!(Length
) && (BoundaryPfn
)) &&
225 (((Page
^ (Page
+ SizeInPages
- 1)) & BoundaryMask
)))
228 // It does not, so bail out
234 // Increase the number of valid pages, and check if we have enough
236 if (++Length
== SizeInPages
)
239 // It appears we've amassed enough legitimate pages, rollback
241 Pfn1
-= (Length
- 1);
242 Page
-= (Length
- 1);
245 // Acquire the PFN lock
247 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
251 // Things might've changed for us. Is the page still free?
253 if (MiIsPfnInUse(Pfn1
)) break;
256 // So far so good. Is this the last confirmed valid page?
261 // Sanity check that we didn't go out of bounds
263 ASSERT(i
!= MmPhysicalMemoryBlock
->NumberOfRuns
);
266 // Loop until all PFN entries have been processed
268 EndPfn
= Pfn1
- SizeInPages
+ 1;
272 // If this was an unzeroed page, there are now less
274 if (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
) UnzeroedPageCount
--;
277 // One less free page
282 // This PFN is now a used page, set it up
284 RemoveEntryList(&Pfn1
->ListEntry
);
285 Pfn1
->Consumer
= MC_NPPOOL
;
286 Pfn1
->u3
.e2
.ReferenceCount
= 1;
287 Pfn1
->SavedSwapEntry
= 0;
290 // Check if it was already zeroed
292 if (Pfn1
->u3
.e1
.PageLocation
!= ZeroedPageList
)
295 // It wasn't, so zero it
297 MiZeroPage(MiGetPfnEntryIndex(Pfn1
));
303 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
306 // Check if this is the last PFN, otherwise go on
308 if (Pfn1
== EndPfn
) break;
313 // Mark the first and last PFN so we can find them later
315 Pfn1
->u3
.e1
.StartOfAllocation
= 1;
316 (Pfn1
+ SizeInPages
- 1)->u3
.e1
.EndOfAllocation
= 1;
319 // Now it's safe to let go of the PFN lock
321 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
324 // Quick sanity check that the last PFN is consistent
326 EndPfn
= Pfn1
+ SizeInPages
;
327 ASSERT(EndPfn
== MiGetPfnEntry(Page
+ 1));
330 // Compute the first page, and make sure it's consistent
332 Page
-= SizeInPages
- 1;
333 ASSERT(Pfn1
== MiGetPfnEntry(Page
));
339 // Keep going. The purpose of this loop is to reconfirm that
340 // after acquiring the PFN lock these pages are still usable
347 // If we got here, something changed while we hadn't acquired
348 // the PFN lock yet, so we'll have to restart
350 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
354 } while (++i
!= MmPhysicalMemoryBlock
->NumberOfRuns
);
357 // And if we get here, it means no suitable physical memory runs were found
364 MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress
,
365 IN PHYSICAL_ADDRESS HighAddress
,
366 IN PHYSICAL_ADDRESS SkipBytes
,
367 IN SIZE_T TotalBytes
,
368 IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
,
372 PFN_NUMBER PageCount
, LowPage
, HighPage
, SkipPages
, PagesFound
= 0, Page
;
373 PPFN_NUMBER MdlPage
, LastMdlPage
;
375 PLIST_ENTRY ListEntry
;
377 INT LookForZeroedPages
;
378 ASSERT (KeGetCurrentIrql() <= APC_LEVEL
);
381 // Convert the low address into a PFN
383 LowPage
= (PFN_NUMBER
)(LowAddress
.QuadPart
>> PAGE_SHIFT
);
386 // Convert, and normalize, the high address into a PFN
388 HighPage
= (PFN_NUMBER
)(HighAddress
.QuadPart
>> PAGE_SHIFT
);
389 if (HighPage
> MmHighestPhysicalPage
) HighPage
= MmHighestPhysicalPage
;
392 // Validate skipbytes and convert them into pages
394 if (BYTE_OFFSET(SkipBytes
.LowPart
)) return NULL
;
395 SkipPages
= (PFN_NUMBER
)(SkipBytes
.QuadPart
>> PAGE_SHIFT
);
398 // Now compute the number of pages the MDL will cover
400 PageCount
= (PFN_NUMBER
)ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, TotalBytes
);
404 // Try creating an MDL for these many pages
406 Mdl
= MmCreateMdl(NULL
, NULL
, PageCount
<< PAGE_SHIFT
);
410 // This function is not required to return the amount of pages requested
411 // In fact, it can return as little as 1 page, and callers are supposed
412 // to deal with this scenario. So re-attempt the allocation with less
413 // pages than before, and see if it worked this time.
415 PageCount
-= (PageCount
>> 4);
419 // Wow, not even a single page was around!
421 if (!Mdl
) return NULL
;
424 // This is where the page array starts....
426 MdlPage
= (PPFN_NUMBER
)(Mdl
+ 1);
429 // Lock the PFN database
431 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
434 // Are we looking for any pages, without discriminating?
436 if ((LowPage
== 0) && (HighPage
== MmHighestPhysicalPage
))
439 // Well then, let's go shopping
441 while (PagesFound
< PageCount
)
444 // Do we have zeroed pages?
446 if (!IsListEmpty(&FreeZeroedPageListHead
))
451 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
453 else if (!IsListEmpty(&FreeUnzeroedPageListHead
))
456 // Nope, grab an unzeroed page
458 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
464 // This is not good... hopefully we have at least SOME pages
471 // Get the PFN entry for this page
473 Pfn1
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
476 // Make sure it's really free
478 ASSERT(MiIsPfnInUse(Pfn1
) == FALSE
);
479 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
482 // Allocate it and mark it
484 Pfn1
->Consumer
= MC_NPPOOL
;
485 Pfn1
->u3
.e1
.StartOfAllocation
= 1;
486 Pfn1
->u3
.e1
.EndOfAllocation
= 1;
487 Pfn1
->u3
.e2
.ReferenceCount
= 1;
488 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
489 Pfn1
->SavedSwapEntry
= 0;
492 // Decrease available pages
497 // Save it into the MDL
499 *MdlPage
++ = MiGetPfnEntryIndex(Pfn1
);
506 // You want specific range of pages. We'll do this in two runs
508 for (LookForZeroedPages
= 1; LookForZeroedPages
>= 0; LookForZeroedPages
--)
511 // Scan the range you specified
513 for (Page
= LowPage
; Page
< HighPage
; Page
++)
516 // Get the PFN entry for this page
518 Pfn1
= MiGetPfnEntry(Page
);
522 // Make sure it's free and if this is our first pass, zeroed
524 if (!MiIsPfnInUse(Pfn1
)) continue;
525 if ((Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
) != LookForZeroedPages
) continue;
530 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
533 // Now setup the page and mark it
535 Pfn1
->Consumer
= MC_NPPOOL
;
536 Pfn1
->u3
.e2
.ReferenceCount
= 1;
537 Pfn1
->u3
.e1
.StartOfAllocation
= 1;
538 Pfn1
->u3
.e1
.EndOfAllocation
= 1;
539 Pfn1
->SavedSwapEntry
= 0;
542 // If this page was unzeroed, we've consumed such a page
544 if (Pfn1
->u3
.e1
.PageLocation
!= ZeroedPageList
) UnzeroedPageCount
--;
547 // Decrease available pages
552 // Save this page into the MDL
555 if (++PagesFound
== PageCount
) break;
559 // If the first pass was enough, don't keep going, otherwise, go again
561 if (PagesFound
== PageCount
) break;
566 // Now release the PFN count
568 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
571 // We might've found less pages, but not more ;-)
573 if (PagesFound
!= PageCount
) ASSERT(PagesFound
< PageCount
);
577 // If we didn' tfind any pages at all, fail
579 DPRINT1("NO MDL PAGES!\n");
585 // Write out how many pages we found
587 Mdl
->ByteCount
= (ULONG
)(PagesFound
<< PAGE_SHIFT
);
590 // Terminate the MDL array if there's certain missing pages
592 if (PagesFound
!= PageCount
) *MdlPage
= -1;
595 // Now go back and loop over all the MDL pages
597 MdlPage
= (PPFN_NUMBER
)(Mdl
+ 1);
598 LastMdlPage
= MdlPage
+ PagesFound
;
599 while (MdlPage
< LastMdlPage
)
602 // Check if we've reached the end
605 if (Page
== (PFN_NUMBER
)-1) break;
608 // Get the PFN entry for the page and check if we should zero it out
610 Pfn1
= MiGetPfnEntry(Page
);
612 if (Pfn1
->u3
.e1
.PageLocation
!= ZeroedPageList
) MiZeroPage(Page
);
613 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
617 // We're done, mark the pages as locked (should we lock them, though???)
620 Mdl
->MdlFlags
|= MDL_PAGES_LOCKED
;
626 MmDumpPfnDatabase(VOID
)
630 PCHAR State
= "????", Type
= "Unknown";
632 ULONG Totals
[5] = {0}, FreePages
= 0;
634 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
637 // Loop the PFN database
639 for (i
= 0; i
<= MmHighestPhysicalPage
; i
++)
641 Pfn1
= MiGetPfnEntry(i
);
647 switch (Pfn1
->Consumer
)
651 Type
= "Nonpaged Pool";
661 Type
= "File System Cache";
666 Type
= "Process Working Set";
678 if (MiIsPfnInUse(Pfn1
))
681 Totals
[Pfn1
->Consumer
]++;
692 // Pretty-print the page
694 DbgPrint("0x%08p:\t%04s\t%20s\t(%02d) [%08p])\n",
698 Pfn1
->u3
.e2
.ReferenceCount
,
702 DbgPrint("Nonpaged Pool: %d pages\t[%d KB]\n", Totals
[MC_NPPOOL
], (Totals
[MC_NPPOOL
] << PAGE_SHIFT
) / 1024);
703 DbgPrint("Paged Pool: %d pages\t[%d KB]\n", Totals
[MC_PPOOL
], (Totals
[MC_PPOOL
] << PAGE_SHIFT
) / 1024);
704 DbgPrint("File System Cache: %d pages\t[%d KB]\n", Totals
[MC_CACHE
], (Totals
[MC_CACHE
] << PAGE_SHIFT
) / 1024);
705 DbgPrint("Process Working Set: %d pages\t[%d KB]\n", Totals
[MC_USER
], (Totals
[MC_USER
] << PAGE_SHIFT
) / 1024);
706 DbgPrint("System: %d pages\t[%d KB]\n", Totals
[MC_SYSTEM
], (Totals
[MC_SYSTEM
] << PAGE_SHIFT
) / 1024);
707 DbgPrint("Free: %d pages\t[%d KB]\n", FreePages
, (FreePages
<< PAGE_SHIFT
) / 1024);
709 KeLowerIrql(OldIrql
);
714 MmInitializePageList(VOID
)
717 PHYSICAL_PAGE UsedPage
;
718 PMEMORY_ALLOCATION_DESCRIPTOR Md
;
719 PLIST_ENTRY NextEntry
;
720 ULONG NrSystemPages
= 0;
722 /* Initialize the page lists */
723 InitializeListHead(&UserPageListHead
);
724 InitializeListHead(&FreeUnzeroedPageListHead
);
725 InitializeListHead(&FreeZeroedPageListHead
);
727 /* This is what a used page looks like */
728 RtlZeroMemory(&UsedPage
, sizeof(UsedPage
));
729 UsedPage
.Consumer
= MC_NPPOOL
;
730 UsedPage
.u3
.e1
.PageLocation
= ActiveAndValid
;
731 UsedPage
.u3
.e2
.ReferenceCount
= 1;
733 /* Loop the memory descriptors */
734 for (NextEntry
= KeLoaderBlock
->MemoryDescriptorListHead
.Flink
;
735 NextEntry
!= &KeLoaderBlock
->MemoryDescriptorListHead
;
736 NextEntry
= NextEntry
->Flink
)
739 /* Get the descriptor */
740 Md
= CONTAINING_RECORD(NextEntry
,
741 MEMORY_ALLOCATION_DESCRIPTOR
,
745 /* Skip bad memory */
746 if ((Md
->MemoryType
== LoaderFirmwarePermanent
) ||
747 (Md
->MemoryType
== LoaderBBTMemory
) ||
748 (Md
->MemoryType
== LoaderSpecialMemory
) ||
749 (Md
->MemoryType
== LoaderBad
))
752 // We do not build PFN entries for this
756 else if ((Md
->MemoryType
== LoaderFree
) ||
757 (Md
->MemoryType
== LoaderLoadedProgram
) ||
758 (Md
->MemoryType
== LoaderFirmwareTemporary
) ||
759 (Md
->MemoryType
== LoaderOsloaderStack
))
761 /* Loop every page part of the block */
762 for (i
= 0; i
< Md
->PageCount
; i
++)
764 /* Mark it as a free page */
765 MmPfnDatabase
[0][Md
->BasePage
+ i
].u3
.e1
.PageLocation
= FreePageList
;
766 InsertTailList(&FreeUnzeroedPageListHead
,
767 &MmPfnDatabase
[0][Md
->BasePage
+ i
].ListEntry
);
774 /* Loop every page part of the block */
775 for (i
= 0; i
< Md
->PageCount
; i
++)
777 /* Everything else is used memory */
778 MmPfnDatabase
[0][Md
->BasePage
+ i
] = UsedPage
;
784 /* Finally handle the pages describing the PFN database themselves */
785 for (i
= MxOldFreeDescriptor
.BasePage
; i
< MxFreeDescriptor
->BasePage
; i
++)
787 /* Ensure this page was not added previously */
788 ASSERT(MmPfnDatabase
[0][i
].Consumer
== 0);
790 /* Mark it as used kernel memory */
791 MmPfnDatabase
[0][i
] = UsedPage
;
795 KeInitializeEvent(&ZeroPageThreadEvent
, NotificationEvent
, TRUE
);
796 DPRINT("Pages: %x %x\n", MmAvailablePages
, NrSystemPages
);
797 MmInitializeBalancer(MmAvailablePages
, NrSystemPages
);
802 MmSetRmapListHeadPage(PFN_TYPE Pfn
, struct _MM_RMAP_ENTRY
* ListHead
)
806 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
807 MiGetPfnEntry(Pfn
)->RmapListHead
= (LONG
)ListHead
;
808 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
811 struct _MM_RMAP_ENTRY
*
813 MmGetRmapListHeadPage(PFN_TYPE Pfn
)
816 struct _MM_RMAP_ENTRY
* ListHead
;
818 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
819 ListHead
= (struct _MM_RMAP_ENTRY
*)MiGetPfnEntry(Pfn
)->RmapListHead
;
820 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
827 MmSetSavedSwapEntryPage(PFN_TYPE Pfn
, SWAPENTRY SwapEntry
)
831 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
832 MiGetPfnEntry(Pfn
)->SavedSwapEntry
= SwapEntry
;
833 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
838 MmGetSavedSwapEntryPage(PFN_TYPE Pfn
)
843 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
844 SwapEntry
= MiGetPfnEntry(Pfn
)->SavedSwapEntry
;
845 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
852 MmReferencePage(PFN_TYPE Pfn
)
856 DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
858 if (Pfn
== 0 || Pfn
> MmHighestPhysicalPage
)
863 Page
= MiGetPfnEntry(Pfn
);
866 Page
->u3
.e2
.ReferenceCount
++;
871 MmGetReferenceCountPage(PFN_TYPE Pfn
)
877 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
879 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
880 Page
= MiGetPfnEntry(Pfn
);
883 RCount
= Page
->u3
.e2
.ReferenceCount
;
885 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
891 MmIsPageInUse(PFN_TYPE Pfn
)
893 return MiIsPfnInUse(MiGetPfnEntry(Pfn
));
898 MiSetConsumer(IN PFN_TYPE Pfn
,
901 MiGetPfnEntry(Pfn
)->Consumer
= Type
;
902 MiGetPfnEntry(Pfn
)->u3
.e1
.PageLocation
= ActiveAndValid
;
907 MmDereferencePage(PFN_TYPE Pfn
)
911 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
913 Page
= MiGetPfnEntry(Pfn
);
916 Page
->u3
.e2
.ReferenceCount
--;
917 if (Page
->u3
.e2
.ReferenceCount
== 0)
920 Page
->u3
.e1
.PageLocation
= FreePageList
;
921 InsertTailList(&FreeUnzeroedPageListHead
,
924 if (UnzeroedPageCount
> 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent
))
926 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
933 MmAllocPage(ULONG Type
, SWAPENTRY SwapEntry
)
936 PLIST_ENTRY ListEntry
;
937 PPHYSICAL_PAGE PageDescriptor
;
938 BOOLEAN NeedClear
= FALSE
;
940 DPRINT("MmAllocPage()\n");
942 if (IsListEmpty(&FreeZeroedPageListHead
))
944 if (IsListEmpty(&FreeUnzeroedPageListHead
))
946 /* Check if this allocation is for the PFN DB itself */
947 if (MmNumberOfPhysicalPages
== 0)
952 DPRINT1("MmAllocPage(): Out of memory\n");
955 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
958 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
964 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
966 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
969 PageDescriptor
->Consumer
= Type
;
970 PageDescriptor
->u3
.e2
.ReferenceCount
= 1;
971 PageDescriptor
->SavedSwapEntry
= SwapEntry
;
975 PfnOffset
= PageDescriptor
- MmPfnDatabase
[0];
976 if ((NeedClear
) && (Type
!= MC_SYSTEM
))
978 MiZeroPage(PfnOffset
);
981 PageDescriptor
->u3
.e1
.PageLocation
= ActiveAndValid
;
987 MiZeroPage(PFN_TYPE Page
)
992 Irql
= KeRaiseIrqlToDpcLevel();
993 TempAddress
= MiMapPageToZeroInHyperSpace(Page
);
994 if (TempAddress
== NULL
)
996 return(STATUS_NO_MEMORY
);
998 memset(TempAddress
, 0, PAGE_SIZE
);
999 MiUnmapPagesInZeroSpace(TempAddress
, 1);
1001 return(STATUS_SUCCESS
);
1006 MmZeroPageThreadMain(PVOID Ignored
)
1010 PLIST_ENTRY ListEntry
;
1011 PPHYSICAL_PAGE PageDescriptor
;
1015 /* Free initial kernel memory */
1016 //MiFreeInitMemory();
1018 /* Set our priority to 0 */
1019 KeGetCurrentThread()->BasePriority
= 0;
1020 KeSetPriorityThread(KeGetCurrentThread(), 0);
1024 Status
= KeWaitForSingleObject(&ZeroPageThreadEvent
,
1030 if (ZeroPageThreadShouldTerminate
)
1032 DPRINT1("ZeroPageThread: Terminating\n");
1033 return STATUS_SUCCESS
;
1036 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1037 while (!IsListEmpty(&FreeUnzeroedPageListHead
))
1039 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
1040 UnzeroedPageCount
--;
1041 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
1042 /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
1043 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
1044 Pfn
= PageDescriptor
- MmPfnDatabase
[0];
1045 Status
= MiZeroPage(Pfn
);
1047 oldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1048 PageDescriptor
->u3
.e1
.PageLocation
= ZeroedPageList
;
1049 if (NT_SUCCESS(Status
))
1051 InsertHeadList(&FreeZeroedPageListHead
, ListEntry
);
1056 InsertHeadList(&FreeUnzeroedPageListHead
, ListEntry
);
1057 UnzeroedPageCount
++;
1061 DPRINT("Zeroed %d pages.\n", Count
);
1062 KeResetEvent(&ZeroPageThreadEvent
);
1063 KeReleaseQueuedSpinLock(LockQueuePfnLock
, oldIrql
);
1066 return STATUS_SUCCESS
;