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 * PROGRAMMER: David Welch (welch@cwcom.net)
9 * 18/08/98: Added a fix from Robert Bergkvist
12 /* INCLUDES ****************************************************************/
16 #include <internal/debug.h>
18 /* TYPES *******************************************************************/
20 #define MM_PHYSICAL_PAGE_FREE (0x1)
21 #define MM_PHYSICAL_PAGE_USED (0x2)
22 #define MM_PHYSICAL_PAGE_BIOS (0x3)
24 typedef struct _PHYSICAL_PAGE
40 SWAPENTRY SavedSwapEntry
;
43 struct _MM_RMAP_ENTRY
* RmapListHead
;
45 PHYSICAL_PAGE
, *PPHYSICAL_PAGE
;
48 /* GLOBALS ****************************************************************/
50 static PPHYSICAL_PAGE MmPageArray
;
51 ULONG MmPageArraySize
;
53 static KSPIN_LOCK PageListLock
;
54 static LIST_ENTRY UsedPageListHeads
[MC_MAXIMUM
];
55 static LIST_ENTRY FreeZeroedPageListHead
;
56 static LIST_ENTRY FreeUnzeroedPageListHead
;
57 static LIST_ENTRY BiosPageListHead
;
59 static HANDLE ZeroPageThreadHandle
;
60 static CLIENT_ID ZeroPageThreadId
;
61 static KEVENT ZeroPageThreadEvent
;
63 static ULONG UnzeroedPageCount
= 0;
65 /* FUNCTIONS *************************************************************/
68 MmTransferOwnershipPage(PFN_TYPE Pfn
, ULONG NewConsumer
)
72 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
73 if (MmPageArray
[Pfn
].MapCount
!= 0)
75 DbgPrint("Transfering mapped page.\n");
78 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
80 DPRINT1("Type: %d\n", MmPageArray
[Pfn
].Flags
.Type
);
83 if (MmPageArray
[Pfn
].ReferenceCount
!= 1)
85 DPRINT1("ReferenceCount: %d\n", MmPageArray
[Pfn
].ReferenceCount
);
88 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
89 InsertTailList(&UsedPageListHeads
[NewConsumer
],
90 &MmPageArray
[Pfn
].ListEntry
);
91 MmPageArray
[Pfn
].Flags
.Consumer
= NewConsumer
;
92 KeReleaseSpinLock(&PageListLock
, oldIrql
);
97 MmGetLRUFirstUserPage(VOID
)
99 PLIST_ENTRY NextListEntry
;
100 PHYSICAL_PAGE
* PageDescriptor
;
103 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
104 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
105 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
107 KeReleaseSpinLock(&PageListLock
, oldIrql
);
110 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
111 KeReleaseSpinLock(&PageListLock
, oldIrql
);
112 return PageDescriptor
- MmPageArray
;
116 MmSetLRULastPage(PFN_TYPE Pfn
)
120 ASSERT(Pfn
< MmPageArraySize
);
121 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
122 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_USED
&&
123 MmPageArray
[Pfn
].Flags
.Consumer
== MC_USER
)
125 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
126 InsertTailList(&UsedPageListHeads
[MC_USER
],
127 &MmPageArray
[Pfn
].ListEntry
);
129 KeReleaseSpinLock(&PageListLock
, oldIrql
);
133 MmGetLRUNextUserPage(PFN_TYPE PreviousPfn
)
135 PLIST_ENTRY NextListEntry
;
136 PHYSICAL_PAGE
* PageDescriptor
;
139 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
140 if (MmPageArray
[PreviousPfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
||
141 MmPageArray
[PreviousPfn
].Flags
.Consumer
!= MC_USER
)
143 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
147 NextListEntry
= MmPageArray
[PreviousPfn
].ListEntry
.Flink
;
149 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
151 KeReleaseSpinLock(&PageListLock
, oldIrql
);
154 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
155 KeReleaseSpinLock(&PageListLock
, oldIrql
);
156 return PageDescriptor
- MmPageArray
;
160 MmGetContinuousPages(ULONG NumberOfBytes
,
161 PHYSICAL_ADDRESS LowestAcceptableAddress
,
162 PHYSICAL_ADDRESS HighestAcceptableAddress
,
171 NrPages
= PAGE_ROUND_UP(NumberOfBytes
) / PAGE_SIZE
;
173 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
177 for (i
= (LowestAcceptableAddress
.QuadPart
/ PAGE_SIZE
); i
< (HighestAcceptableAddress
.QuadPart
/ PAGE_SIZE
); )
179 if (MmPageArray
[i
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
191 if (length
== NrPages
)
200 * Fast forward to the base of the next aligned region
202 i
= ROUND_UP((i
+ 1), (Alignment
/ PAGE_SIZE
));
205 if (start
== -1 || length
!= NrPages
)
207 KeReleaseSpinLock(&PageListLock
, oldIrql
);
210 for (i
= start
; i
< (start
+ length
); i
++)
212 RemoveEntryList(&MmPageArray
[i
].ListEntry
);
213 if (MmPageArray
[i
].Flags
.Zero
== 0)
217 MmStats
.NrFreePages
--;
218 MmStats
.NrSystemPages
++;
219 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
220 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
221 MmPageArray
[i
].ReferenceCount
= 1;
222 MmPageArray
[i
].LockCount
= 0;
223 MmPageArray
[i
].MapCount
= 0;
224 MmPageArray
[i
].SavedSwapEntry
= 0;
225 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
226 &MmPageArray
[i
].ListEntry
);
228 KeReleaseSpinLock(&PageListLock
, oldIrql
);
229 for (i
= start
; i
< (start
+ length
); i
++)
231 if (MmPageArray
[i
].Flags
.Zero
== 0)
237 MmPageArray
[i
].Flags
.Zero
= 0;
246 MiIsPfnRam(PADDRESS_RANGE BIOSMemoryMap
,
247 ULONG AddressRangeCount
,
251 LARGE_INTEGER BaseAddress
;
252 LARGE_INTEGER EndAddress
;
254 if (BIOSMemoryMap
!= NULL
&& AddressRangeCount
> 0)
257 for (i
= 0; i
< AddressRangeCount
; i
++)
259 BaseAddress
.u
.LowPart
= BIOSMemoryMap
[i
].BaseAddrLow
;
260 BaseAddress
.u
.HighPart
= BIOSMemoryMap
[i
].BaseAddrHigh
;
261 EndAddress
.u
.LowPart
= BIOSMemoryMap
[i
].LengthLow
;
262 EndAddress
.u
.HighPart
= BIOSMemoryMap
[i
].LengthHigh
;
263 EndAddress
.QuadPart
+= BaseAddress
.QuadPart
;
264 BaseAddress
.QuadPart
= PAGE_ROUND_DOWN(BaseAddress
.QuadPart
);
265 EndAddress
.QuadPart
= PAGE_ROUND_UP(EndAddress
.QuadPart
);
267 if ((BaseAddress
.QuadPart
>> PAGE_SHIFT
) <= Pfn
&&
268 Pfn
< (EndAddress
.QuadPart
>> PAGE_SHIFT
))
270 if (BIOSMemoryMap
[i
].Type
== 1)
287 MmInitializePageList(PVOID FirstPhysKernelAddress
,
288 PVOID LastPhysKernelAddress
,
289 ULONG MemorySizeInPages
,
290 ULONG LastKernelAddress
,
291 PADDRESS_RANGE BIOSMemoryMap
,
292 ULONG AddressRangeCount
)
294 * FUNCTION: Initializes the page list with all pages free
295 * except those known to be reserved and those used by the kernel
297 * FirstKernelAddress = First physical address used by the kernel
298 * LastKernelAddress = Last physical address used by the kernel
305 PFN_TYPE FirstUninitializedPage
;
307 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
308 "LastPhysKernelAddress %x, "
309 "MemorySizeInPages %x, LastKernelAddress %x)\n",
310 FirstPhysKernelAddress
,
311 LastPhysKernelAddress
,
315 for (i
= 0; i
< MC_MAXIMUM
; i
++)
317 InitializeListHead(&UsedPageListHeads
[i
]);
319 KeInitializeSpinLock(&PageListLock
);
320 InitializeListHead(&FreeUnzeroedPageListHead
);
321 InitializeListHead(&FreeZeroedPageListHead
);
322 InitializeListHead(&BiosPageListHead
);
324 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
326 MmPageArraySize
= MemorySizeInPages
;
328 PAGE_ROUND_UP((MmPageArraySize
* sizeof(PHYSICAL_PAGE
))) / PAGE_SIZE
;
329 MmPageArray
= (PHYSICAL_PAGE
*)LastKernelAddress
;
331 DPRINT("Reserved %d\n", Reserved
);
333 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
334 LastKernelAddress
= ((ULONG
)LastKernelAddress
+ (Reserved
* PAGE_SIZE
));
335 LastPhysKernelAddress
= (PVOID
)PAGE_ROUND_UP(LastPhysKernelAddress
);
336 LastPhysKernelAddress
= (char*)LastPhysKernelAddress
+ (Reserved
* PAGE_SIZE
);
338 MmStats
.NrTotalPages
= 0;
339 MmStats
.NrSystemPages
= 0;
340 MmStats
.NrUserPages
= 0;
341 MmStats
.NrReservedPages
= 0;
342 MmStats
.NrFreePages
= 0;
343 MmStats
.NrLockedPages
= 0;
345 /* Preinitialize the Balancer because we need some pages for pte's */
346 MmInitializeBalancer(MemorySizeInPages
, 0);
348 FirstUninitializedPage
= (ULONG_PTR
)LastPhysKernelAddress
/ PAGE_SIZE
;
349 LastPage
= MmPageArraySize
;
350 for (i
= 0; i
< Reserved
; i
++)
352 PVOID Address
= (char*)(ULONG
)MmPageArray
+ (i
* PAGE_SIZE
);
354 if (!MmIsPagePresent(NULL
, Address
))
358 while (Pfn
== 0 && LastPage
> FirstUninitializedPage
)
360 /* Allocate the page from the upper end of the RAM */
361 if (MiIsPfnRam(BIOSMemoryMap
, AddressRangeCount
, --LastPage
))
368 Pfn
= MmAllocPage(MC_NPPOOL
, 0);
374 Status
= MmCreateVirtualMappingForKernel(Address
,
378 if (!NT_SUCCESS(Status
))
380 DbgPrint("Unable to create virtual mapping\n");
384 memset(Address
, 0, PAGE_SIZE
);
386 start
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MmPageArray
) / sizeof(PHYSICAL_PAGE
);
387 end
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MmPageArray
+ PAGE_SIZE
) / sizeof(PHYSICAL_PAGE
);
389 for (j
= start
; j
< end
&& j
< LastPage
; j
++)
391 if (MiIsPfnRam(BIOSMemoryMap
, AddressRangeCount
, j
))
396 * Page zero is reserved
398 MmPageArray
[0].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
399 MmPageArray
[0].Flags
.Consumer
= MC_NPPOOL
;
400 MmPageArray
[0].Flags
.Zero
= 0;
401 MmPageArray
[0].ReferenceCount
= 0;
402 InsertTailList(&BiosPageListHead
,
403 &MmPageArray
[0].ListEntry
);
404 MmStats
.NrReservedPages
++;
410 * Page one is reserved for the initial KPCR
412 MmPageArray
[1].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
413 MmPageArray
[1].Flags
.Consumer
= MC_NPPOOL
;
414 MmPageArray
[1].Flags
.Zero
= 0;
415 MmPageArray
[1].ReferenceCount
= 0;
416 InsertTailList(&BiosPageListHead
,
417 &MmPageArray
[1].ListEntry
);
418 MmStats
.NrReservedPages
++;
420 else if (j
>= 0xa0000 / PAGE_SIZE
&& j
< 0x100000 / PAGE_SIZE
)
422 MmPageArray
[j
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
423 MmPageArray
[j
].Flags
.Zero
= 0;
424 MmPageArray
[j
].Flags
.Consumer
= MC_NPPOOL
;
425 MmPageArray
[j
].ReferenceCount
= 1;
426 InsertTailList(&BiosPageListHead
,
427 &MmPageArray
[j
].ListEntry
);
428 MmStats
.NrReservedPages
++;
430 else if (j
>= (ULONG
)FirstPhysKernelAddress
/PAGE_SIZE
&&
431 j
< (ULONG
)LastPhysKernelAddress
/PAGE_SIZE
)
433 MmPageArray
[j
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
434 MmPageArray
[j
].Flags
.Zero
= 0;
435 MmPageArray
[j
].Flags
.Consumer
= MC_NPPOOL
;
436 MmPageArray
[j
].ReferenceCount
= 1;
437 MmPageArray
[j
].MapCount
= 1;
438 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
439 &MmPageArray
[j
].ListEntry
);
440 MmStats
.NrSystemPages
++;
444 MmPageArray
[j
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
445 MmPageArray
[j
].Flags
.Zero
= 0;
446 MmPageArray
[j
].ReferenceCount
= 0;
447 InsertTailList(&FreeUnzeroedPageListHead
,
448 &MmPageArray
[j
].ListEntry
);
450 MmStats
.NrFreePages
++;
455 MmPageArray
[j
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
456 MmPageArray
[j
].Flags
.Consumer
= MC_NPPOOL
;
457 MmPageArray
[j
].Flags
.Zero
= 0;
458 MmPageArray
[j
].ReferenceCount
= 0;
459 InsertTailList(&BiosPageListHead
,
460 &MmPageArray
[j
].ListEntry
);
461 MmStats
.NrReservedPages
++;
464 FirstUninitializedPage
= j
;
468 /* Add the pages from the upper end to the list */
469 for (i
= LastPage
; i
< MmPageArraySize
; i
++)
471 if (MiIsPfnRam(BIOSMemoryMap
, AddressRangeCount
, i
))
473 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
474 MmPageArray
[i
].Flags
.Zero
= 0;
475 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
476 MmPageArray
[i
].ReferenceCount
= 1;
477 MmPageArray
[i
].MapCount
= 1;
478 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
479 &MmPageArray
[i
].ListEntry
);
480 MmStats
.NrSystemPages
++;
484 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
485 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
486 MmPageArray
[i
].Flags
.Zero
= 0;
487 MmPageArray
[i
].ReferenceCount
= 0;
488 InsertTailList(&BiosPageListHead
,
489 &MmPageArray
[i
].ListEntry
);
490 MmStats
.NrReservedPages
++;
496 KeInitializeEvent(&ZeroPageThreadEvent
, NotificationEvent
, TRUE
);
498 MmStats
.NrTotalPages
= MmStats
.NrFreePages
+ MmStats
.NrSystemPages
+
499 MmStats
.NrReservedPages
+ MmStats
.NrUserPages
;
500 MmInitializeBalancer(MmStats
.NrFreePages
, MmStats
.NrSystemPages
+ MmStats
.NrReservedPages
);
501 return((PVOID
)LastKernelAddress
);
505 MmSetFlagsPage(PFN_TYPE Pfn
, ULONG Flags
)
509 ASSERT(Pfn
< MmPageArraySize
);
510 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
511 MmPageArray
[Pfn
].AllFlags
= Flags
;
512 KeReleaseSpinLock(&PageListLock
, oldIrql
);
516 MmSetRmapListHeadPage(PFN_TYPE Pfn
, struct _MM_RMAP_ENTRY
* ListHead
)
518 MmPageArray
[Pfn
].RmapListHead
= ListHead
;
521 struct _MM_RMAP_ENTRY
*
522 MmGetRmapListHeadPage(PFN_TYPE Pfn
)
524 return(MmPageArray
[Pfn
].RmapListHead
);
528 MmMarkPageMapped(PFN_TYPE Pfn
)
532 if (Pfn
< MmPageArraySize
)
534 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
535 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
537 DbgPrint("Mapping non-used page\n");
540 MmPageArray
[Pfn
].MapCount
++;
541 KeReleaseSpinLock(&PageListLock
, oldIrql
);
546 MmMarkPageUnmapped(PFN_TYPE Pfn
)
550 if (Pfn
< MmPageArraySize
)
552 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
553 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
555 DbgPrint("Unmapping non-used page\n");
558 if (MmPageArray
[Pfn
].MapCount
== 0)
560 DbgPrint("Unmapping not mapped page\n");
563 MmPageArray
[Pfn
].MapCount
--;
564 KeReleaseSpinLock(&PageListLock
, oldIrql
);
569 MmGetFlagsPage(PFN_TYPE Pfn
)
574 ASSERT(Pfn
< MmPageArraySize
);
575 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
576 Flags
= MmPageArray
[Pfn
].AllFlags
;
577 KeReleaseSpinLock(&PageListLock
, oldIrql
);
584 MmSetSavedSwapEntryPage(PFN_TYPE Pfn
, SWAPENTRY SavedSwapEntry
)
588 ASSERT(Pfn
< MmPageArraySize
);
589 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
590 MmPageArray
[Pfn
].SavedSwapEntry
= SavedSwapEntry
;
591 KeReleaseSpinLock(&PageListLock
, oldIrql
);
595 MmGetSavedSwapEntryPage(PFN_TYPE Pfn
)
597 SWAPENTRY SavedSwapEntry
;
600 ASSERT(Pfn
< MmPageArraySize
);
601 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
602 SavedSwapEntry
= MmPageArray
[Pfn
].SavedSwapEntry
;
603 KeReleaseSpinLock(&PageListLock
, oldIrql
);
605 return(SavedSwapEntry
);
609 MmReferencePage(PFN_TYPE Pfn
)
613 DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
615 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
620 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
622 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
624 DbgPrint("Referencing non-used page\n");
628 MmPageArray
[Pfn
].ReferenceCount
++;
629 KeReleaseSpinLock(&PageListLock
, oldIrql
);
633 MmGetReferenceCountPage(PFN_TYPE Pfn
)
638 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
640 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
645 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
647 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
649 DbgPrint("Getting reference count for free page\n");
653 RCount
= MmPageArray
[Pfn
].ReferenceCount
;
655 KeReleaseSpinLock(&PageListLock
, oldIrql
);
660 MmIsUsablePage(PFN_TYPE Pfn
)
663 DPRINT("MmIsUsablePage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
665 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
670 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
&&
671 MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_BIOS
)
680 MmDereferencePage(PFN_TYPE Pfn
)
684 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
686 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
691 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
693 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
695 DbgPrint("Dereferencing free page\n");
698 if (MmPageArray
[Pfn
].ReferenceCount
== 0)
700 DbgPrint("Derefrencing page with reference count 0\n");
704 MmPageArray
[Pfn
].ReferenceCount
--;
705 if (MmPageArray
[Pfn
].ReferenceCount
== 0)
707 MmStats
.NrFreePages
++;
708 MmStats
.NrSystemPages
--;
709 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
710 if (MmPageArray
[Pfn
].RmapListHead
!= NULL
)
712 DbgPrint("Freeing page with rmap entries.\n");
715 if (MmPageArray
[Pfn
].MapCount
!= 0)
717 DbgPrint("Freeing mapped page (0x%x count %d)\n",
718 Pfn
<< PAGE_SHIFT
, MmPageArray
[Pfn
].MapCount
);
721 if (MmPageArray
[Pfn
].LockCount
> 0)
723 DbgPrint("Freeing locked page\n");
726 if (MmPageArray
[Pfn
].SavedSwapEntry
!= 0)
728 DbgPrint("Freeing page with swap entry.\n");
731 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
733 DbgPrint("Freeing page with flags %x\n",
734 MmPageArray
[Pfn
].Flags
.Type
);
737 MmPageArray
[Pfn
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
738 MmPageArray
[Pfn
].Flags
.Consumer
= MC_MAXIMUM
;
739 InsertTailList(&FreeUnzeroedPageListHead
,
740 &MmPageArray
[Pfn
].ListEntry
);
742 if (UnzeroedPageCount
> 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent
))
744 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
747 KeReleaseSpinLock(&PageListLock
, oldIrql
);
751 MmGetLockCountPage(PFN_TYPE Pfn
)
756 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
758 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
763 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
765 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
767 DbgPrint("Getting lock count for free page\n");
771 LockCount
= MmPageArray
[Pfn
].LockCount
;
772 KeReleaseSpinLock(&PageListLock
, oldIrql
);
778 MmLockPage(PFN_TYPE Pfn
)
782 DPRINT("MmLockPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
784 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
789 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
791 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
793 DbgPrint("Locking free page\n");
797 MmPageArray
[Pfn
].LockCount
++;
798 KeReleaseSpinLock(&PageListLock
, oldIrql
);
802 MmUnlockPage(PFN_TYPE Pfn
)
806 DPRINT("MmUnlockPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
808 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
813 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
815 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
817 DbgPrint("Unlocking free page\n");
821 MmPageArray
[Pfn
].LockCount
--;
822 KeReleaseSpinLock(&PageListLock
, oldIrql
);
826 MmAllocPage(ULONG Consumer
, SWAPENTRY SavedSwapEntry
)
829 PLIST_ENTRY ListEntry
;
830 PPHYSICAL_PAGE PageDescriptor
;
832 BOOLEAN NeedClear
= FALSE
;
834 DPRINT("MmAllocPage()\n");
836 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
837 if (IsListEmpty(&FreeZeroedPageListHead
))
839 if (IsListEmpty(&FreeUnzeroedPageListHead
))
841 DPRINT1("MmAllocPage(): Out of memory\n");
842 KeReleaseSpinLock(&PageListLock
, oldIrql
);
845 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
848 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
854 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
856 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
859 if (PageDescriptor
->Flags
.Type
!= MM_PHYSICAL_PAGE_FREE
)
861 DbgPrint("Got non-free page from freelist\n");
864 if (PageDescriptor
->MapCount
!= 0)
866 DbgPrint("Got mapped page from freelist\n");
869 if (PageDescriptor
->ReferenceCount
!= 0)
871 DPRINT1("%d\n", PageDescriptor
->ReferenceCount
);
874 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
875 PageDescriptor
->Flags
.Consumer
= Consumer
;
876 PageDescriptor
->ReferenceCount
= 1;
877 PageDescriptor
->LockCount
= 0;
878 PageDescriptor
->MapCount
= 0;
879 PageDescriptor
->SavedSwapEntry
= SavedSwapEntry
;
880 InsertTailList(&UsedPageListHeads
[Consumer
], ListEntry
);
882 MmStats
.NrSystemPages
++;
883 MmStats
.NrFreePages
--;
885 KeReleaseSpinLock(&PageListLock
, oldIrql
);
887 PfnOffset
= PageDescriptor
- MmPageArray
;
890 MiZeroPage(PfnOffset
);
892 if (PageDescriptor
->MapCount
!= 0)
894 DbgPrint("Returning mapped page.\n");
902 MmZeroPageThreadMain(PVOID Ignored
)
906 PLIST_ENTRY ListEntry
;
907 PPHYSICAL_PAGE PageDescriptor
;
909 static PVOID Address
= NULL
;
914 Status
= KeWaitForSingleObject(&ZeroPageThreadEvent
,
919 if (!NT_SUCCESS(Status
))
921 DbgPrint("ZeroPageThread: Wait failed\n");
923 return(STATUS_UNSUCCESSFUL
);
927 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
928 while (!IsListEmpty(&FreeUnzeroedPageListHead
))
930 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
932 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
933 /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
934 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
935 KeReleaseSpinLock(&PageListLock
, oldIrql
);
937 Pfn
= PageDescriptor
- MmPageArray
;
940 Address
= ExAllocatePageWithPhysPage(Pfn
);
944 Status
= MmCreateVirtualMapping(NULL
,
946 PAGE_READWRITE
| PAGE_SYSTEM
,
949 if (!NT_SUCCESS(Status
))
951 DbgPrint("Unable to create virtual mapping\n");
955 memset(Address
, 0, PAGE_SIZE
);
956 MmDeleteVirtualMapping(NULL
, (PVOID
)Address
, FALSE
, NULL
, NULL
);
957 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
958 if (PageDescriptor
->MapCount
!= 0)
960 DbgPrint("Mapped page on freelist.\n");
963 PageDescriptor
->Flags
.Zero
= 1;
964 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
965 InsertHeadList(&FreeZeroedPageListHead
, ListEntry
);
967 DPRINT("Zeroed %d pages.\n", Count
);
968 KeResetEvent(&ZeroPageThreadEvent
);
969 KeReleaseSpinLock(&PageListLock
, oldIrql
);
973 NTSTATUS INIT_FUNCTION
974 MmInitZeroPageThread(VOID
)
979 Status
= PsCreateSystemThread(&ZeroPageThreadHandle
,
984 (PKSTART_ROUTINE
) MmZeroPageThreadMain
,
986 if (!NT_SUCCESS(Status
))
992 NtSetInformationThread(ZeroPageThreadHandle
,
997 return(STATUS_SUCCESS
);