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 ****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/mm.h>
16 #include <internal/ntoskrnl.h>
19 #include <internal/debug.h>
21 /* TYPES *******************************************************************/
23 #define MM_PHYSICAL_PAGE_FREE (0x1)
24 #define MM_PHYSICAL_PAGE_USED (0x2)
25 #define MM_PHYSICAL_PAGE_BIOS (0x3)
27 typedef struct _PHYSICAL_PAGE
43 SWAPENTRY SavedSwapEntry
;
46 struct _MM_RMAP_ENTRY
* RmapListHead
;
48 PHYSICAL_PAGE
, *PPHYSICAL_PAGE
;
51 /* GLOBALS ****************************************************************/
53 static PPHYSICAL_PAGE MmPageArray
;
54 ULONG MmPageArraySize
;
56 static KSPIN_LOCK PageListLock
;
57 static LIST_ENTRY UsedPageListHeads
[MC_MAXIMUM
];
58 static LIST_ENTRY FreeZeroedPageListHead
;
59 static LIST_ENTRY FreeUnzeroedPageListHead
;
60 static LIST_ENTRY BiosPageListHead
;
62 static HANDLE ZeroPageThreadHandle
;
63 static CLIENT_ID ZeroPageThreadId
;
64 static KEVENT ZeroPageThreadEvent
;
66 static ULONG UnzeroedPageCount
= 0;
68 /* FUNCTIONS *************************************************************/
71 MmTransferOwnershipPage(PFN_TYPE Pfn
, ULONG NewConsumer
)
75 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
76 if (MmPageArray
[Pfn
].MapCount
!= 0)
78 DbgPrint("Transfering mapped page.\n");
81 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
83 DPRINT1("Type: %d\n", MmPageArray
[Pfn
].Flags
.Type
);
86 if (MmPageArray
[Pfn
].ReferenceCount
!= 1)
88 DPRINT1("ReferenceCount: %d\n", MmPageArray
[Pfn
].ReferenceCount
);
91 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
92 InsertTailList(&UsedPageListHeads
[NewConsumer
],
93 &MmPageArray
[Pfn
].ListEntry
);
94 MmPageArray
[Pfn
].Flags
.Consumer
= NewConsumer
;
95 KeReleaseSpinLock(&PageListLock
, oldIrql
);
100 MmGetLRUFirstUserPage(VOID
)
102 PLIST_ENTRY NextListEntry
;
103 PHYSICAL_PAGE
* PageDescriptor
;
106 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
107 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
108 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
110 KeReleaseSpinLock(&PageListLock
, oldIrql
);
113 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
114 KeReleaseSpinLock(&PageListLock
, oldIrql
);
115 return PageDescriptor
- MmPageArray
;
119 MmSetLRULastPage(PFN_TYPE Pfn
)
123 assert (Pfn
< MmPageArraySize
);
124 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
125 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_USED
&&
126 MmPageArray
[Pfn
].Flags
.Consumer
== MC_USER
)
128 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
129 InsertTailList(&UsedPageListHeads
[MC_USER
],
130 &MmPageArray
[Pfn
].ListEntry
);
132 KeReleaseSpinLock(&PageListLock
, oldIrql
);
136 MmGetLRUNextUserPage(PFN_TYPE PreviousPfn
)
138 PLIST_ENTRY NextListEntry
;
139 PHYSICAL_PAGE
* PageDescriptor
;
142 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
143 if (MmPageArray
[PreviousPfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
||
144 MmPageArray
[PreviousPfn
].Flags
.Consumer
!= MC_USER
)
146 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
150 NextListEntry
= MmPageArray
[PreviousPfn
].ListEntry
.Flink
;
152 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
154 KeReleaseSpinLock(&PageListLock
, oldIrql
);
157 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
158 KeReleaseSpinLock(&PageListLock
, oldIrql
);
159 return PageDescriptor
- MmPageArray
;
163 MmGetContinuousPages(ULONG NumberOfBytes
,
164 PHYSICAL_ADDRESS LowestAcceptableAddress
,
165 PHYSICAL_ADDRESS HighestAcceptableAddress
,
174 NrPages
= PAGE_ROUND_UP(NumberOfBytes
) / PAGE_SIZE
;
176 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
180 for (i
= (LowestAcceptableAddress
.QuadPart
/ PAGE_SIZE
); i
< (HighestAcceptableAddress
.QuadPart
/ PAGE_SIZE
); )
182 if (MmPageArray
[i
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
194 if (length
== NrPages
)
203 * Fast forward to the base of the next aligned region
205 i
= ROUND_UP((i
+ 1), (Alignment
/ PAGE_SIZE
));
208 if (start
== -1 || length
!= NrPages
)
210 KeReleaseSpinLock(&PageListLock
, oldIrql
);
213 for (i
= start
; i
< (start
+ length
); i
++)
215 RemoveEntryList(&MmPageArray
[i
].ListEntry
);
216 if (MmPageArray
[i
].Flags
.Zero
== 0)
220 MmStats
.NrFreePages
--;
221 MmStats
.NrSystemPages
++;
222 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
223 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
224 MmPageArray
[i
].ReferenceCount
= 1;
225 MmPageArray
[i
].LockCount
= 0;
226 MmPageArray
[i
].MapCount
= 0;
227 MmPageArray
[i
].SavedSwapEntry
= 0;
228 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
229 &MmPageArray
[i
].ListEntry
);
231 KeReleaseSpinLock(&PageListLock
, oldIrql
);
232 for (i
= start
; i
< (start
+ length
); i
++)
234 if (MmPageArray
[i
].Flags
.Zero
== 0)
240 MmPageArray
[i
].Flags
.Zero
= 0;
248 MiParseRangeToFreeList(PADDRESS_RANGE Range
)
250 ULONG i
, first
, last
;
252 /* FIXME: Not 64-bit ready */
254 DPRINT("Range going to free list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
259 first
= (Range
->BaseAddrLow
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
260 last
= first
+ ((Range
->LengthLow
+ PAGE_SIZE
- 1) / PAGE_SIZE
);
261 for (i
= first
; i
< last
&& i
< MmPageArraySize
; i
++)
263 if (MmPageArray
[i
].Flags
.Type
== 0)
265 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
266 MmPageArray
[i
].Flags
.Zero
= 0;
267 MmPageArray
[i
].ReferenceCount
= 0;
268 InsertTailList(&FreeUnzeroedPageListHead
,
269 &MmPageArray
[i
].ListEntry
);
270 MmStats
.NrFreePages
++;
277 MiParseRangeToBiosList(PADDRESS_RANGE Range
)
279 ULONG i
, first
, last
;
281 /* FIXME: Not 64-bit ready */
283 DPRINT("Range going to bios list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
288 first
= (Range
->BaseAddrLow
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
289 last
= first
+ ((Range
->LengthLow
+ PAGE_SIZE
- 1) / PAGE_SIZE
);
290 for (i
= first
; i
< last
&& i
< MmPageArraySize
; i
++)
292 /* Remove the page from the free list if it is there */
293 if (MmPageArray
[i
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
295 RemoveEntryList(&MmPageArray
[i
].ListEntry
);
297 MmStats
.NrFreePages
--;
301 if (MmPageArray
[i
].Flags
.Type
!= MM_PHYSICAL_PAGE_BIOS
)
303 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
304 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
305 MmPageArray
[i
].ReferenceCount
= 1;
306 InsertTailList(&BiosPageListHead
,
307 &MmPageArray
[i
].ListEntry
);
308 MmStats
.NrSystemPages
++;
314 MiParseBIOSMemoryMap(PADDRESS_RANGE BIOSMemoryMap
,
315 ULONG AddressRangeCount
)
321 for (i
= 0; i
< AddressRangeCount
; i
++, p
++)
325 MiParseRangeToFreeList(p
);
329 MiParseRangeToBiosList(p
);
335 MmInitializePageList(PVOID FirstPhysKernelAddress
,
336 PVOID LastPhysKernelAddress
,
337 ULONG MemorySizeInPages
,
338 ULONG LastKernelAddress
,
339 PADDRESS_RANGE BIOSMemoryMap
,
340 ULONG AddressRangeCount
)
342 * FUNCTION: Initializes the page list with all pages free
343 * except those known to be reserved and those used by the kernel
345 * PageBuffer = Page sized buffer
346 * FirstKernelAddress = First physical address used by the kernel
347 * LastKernelAddress = Last physical address used by the kernel
354 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
355 "LastPhysKernelAddress %x, "
356 "MemorySizeInPages %x, LastKernelAddress %x)\n",
357 FirstPhysKernelAddress
,
358 LastPhysKernelAddress
,
362 for (i
= 0; i
< MC_MAXIMUM
; i
++)
364 InitializeListHead(&UsedPageListHeads
[i
]);
366 KeInitializeSpinLock(&PageListLock
);
367 InitializeListHead(&FreeUnzeroedPageListHead
);
368 InitializeListHead(&FreeZeroedPageListHead
);
369 InitializeListHead(&BiosPageListHead
);
371 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
373 MmPageArraySize
= MemorySizeInPages
;
375 PAGE_ROUND_UP((MmPageArraySize
* sizeof(PHYSICAL_PAGE
))) / PAGE_SIZE
;
376 MmPageArray
= (PHYSICAL_PAGE
*)LastKernelAddress
;
378 DPRINT("Reserved %d\n", Reserved
);
380 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
381 LastKernelAddress
= ((ULONG
)LastKernelAddress
+ (Reserved
* PAGE_SIZE
));
382 LastPhysKernelAddress
= (PVOID
)PAGE_ROUND_UP(LastPhysKernelAddress
);
383 LastPhysKernelAddress
= (char*)LastPhysKernelAddress
+ (Reserved
* PAGE_SIZE
);
385 MmStats
.NrTotalPages
= 0;
386 MmStats
.NrSystemPages
= 0;
387 MmStats
.NrUserPages
= 0;
388 MmStats
.NrReservedPages
= 0;
389 MmStats
.NrFreePages
= 0;
390 MmStats
.NrLockedPages
= 0;
392 for (i
= 0; i
< Reserved
; i
++)
394 PVOID Address
= (char*)(ULONG
)MmPageArray
+ (i
* PAGE_SIZE
);
395 if (!MmIsPagePresent(NULL
, Address
))
397 ULONG Pfn
= ((ULONG_PTR
)LastPhysKernelAddress
>> PAGE_SHIFT
) - Reserved
+ i
;
399 MmCreateVirtualMappingUnsafe(NULL
,
404 if (!NT_SUCCESS(Status
))
406 DbgPrint("Unable to create virtual mapping\n");
410 memset((char*)MmPageArray
+ (i
* PAGE_SIZE
), 0, PAGE_SIZE
);
415 * Page zero is reserved
417 MmPageArray
[0].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
418 MmPageArray
[0].Flags
.Consumer
= MC_NPPOOL
;
419 MmPageArray
[0].Flags
.Zero
= 0;
420 MmPageArray
[0].ReferenceCount
= 0;
421 InsertTailList(&BiosPageListHead
,
422 &MmPageArray
[0].ListEntry
);
425 * Page one is reserved for the initial KPCR
427 MmPageArray
[1].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
428 MmPageArray
[1].Flags
.Consumer
= MC_NPPOOL
;
429 MmPageArray
[1].Flags
.Zero
= 0;
430 MmPageArray
[1].ReferenceCount
= 0;
431 InsertTailList(&BiosPageListHead
,
432 &MmPageArray
[1].ListEntry
);
435 if ((ULONG
)FirstPhysKernelAddress
< 0xa0000)
437 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGE_SIZE
) - 2);
438 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGE_SIZE
); i
++)
440 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
441 MmPageArray
[i
].Flags
.Zero
= 0;
442 MmPageArray
[i
].ReferenceCount
= 0;
443 InsertTailList(&FreeUnzeroedPageListHead
,
444 &MmPageArray
[i
].ListEntry
);
447 MmStats
.NrSystemPages
+=
448 ((((ULONG
)LastPhysKernelAddress
) / PAGE_SIZE
) - i
);
449 for (; i
<((ULONG
)LastPhysKernelAddress
/ PAGE_SIZE
); i
++)
451 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
452 MmPageArray
[i
].Flags
.Zero
= 0;
453 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
454 MmPageArray
[i
].ReferenceCount
= 1;
455 MmPageArray
[i
].MapCount
= 1;
456 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
457 &MmPageArray
[i
].ListEntry
);
459 MmStats
.NrFreePages
+= ((0xa0000/PAGE_SIZE
) - i
);
460 for (; i
<(0xa0000/PAGE_SIZE
); i
++)
462 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
463 MmPageArray
[i
].Flags
.Zero
= 0;
464 MmPageArray
[i
].ReferenceCount
= 0;
465 InsertTailList(&FreeUnzeroedPageListHead
,
466 &MmPageArray
[i
].ListEntry
);
469 MmStats
.NrReservedPages
+= ((0x100000/PAGE_SIZE
) - i
);
470 for (; i
<(0x100000 / PAGE_SIZE
); i
++)
472 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
473 MmPageArray
[i
].Flags
.Zero
= 0;
474 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
475 MmPageArray
[i
].ReferenceCount
= 1;
476 InsertTailList(&BiosPageListHead
,
477 &MmPageArray
[i
].ListEntry
);
482 MmStats
.NrFreePages
+= ((0xa0000 / PAGE_SIZE
) - 2);
483 for (; i
<(0xa0000 / PAGE_SIZE
); i
++)
485 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
486 MmPageArray
[i
].Flags
.Zero
= 0;
487 MmPageArray
[i
].ReferenceCount
= 0;
488 InsertTailList(&FreeUnzeroedPageListHead
,
489 &MmPageArray
[i
].ListEntry
);
492 MmStats
.NrReservedPages
+= (0x60000 / PAGE_SIZE
);
493 for (; i
<(0x100000 / PAGE_SIZE
); i
++)
495 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_BIOS
;
496 MmPageArray
[i
].Flags
.Zero
= 0;
497 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
498 MmPageArray
[i
].ReferenceCount
= 1;
499 InsertTailList(&BiosPageListHead
,
500 &MmPageArray
[i
].ListEntry
);
502 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGE_SIZE
) - i
);
503 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGE_SIZE
); i
++)
505 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
506 MmPageArray
[i
].Flags
.Zero
= 0;
507 MmPageArray
[i
].ReferenceCount
= 0;
508 InsertTailList(&FreeUnzeroedPageListHead
,
509 &MmPageArray
[i
].ListEntry
);
512 MmStats
.NrSystemPages
+=
513 (((ULONG
)LastPhysKernelAddress
/PAGE_SIZE
) - i
);
514 for (; i
<((ULONG
)LastPhysKernelAddress
/PAGE_SIZE
); i
++)
516 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
517 MmPageArray
[i
].Flags
.Zero
= 0;
518 MmPageArray
[i
].Flags
.Consumer
= MC_NPPOOL
;
519 MmPageArray
[i
].ReferenceCount
= 1;
520 MmPageArray
[i
].MapCount
= 1;
521 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
522 &MmPageArray
[i
].ListEntry
);
526 MmStats
.NrFreePages
+= (MemorySizeInPages
- i
);
527 for (; i
<MemorySizeInPages
; i
++)
529 MmPageArray
[i
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
530 MmPageArray
[i
].Flags
.Zero
= 0;
531 MmPageArray
[i
].ReferenceCount
= 0;
532 InsertTailList(&FreeUnzeroedPageListHead
,
533 &MmPageArray
[i
].ListEntry
);
537 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
539 MiParseBIOSMemoryMap(
544 KeInitializeEvent(&ZeroPageThreadEvent
, NotificationEvent
, TRUE
);
546 MmStats
.NrTotalPages
= MmStats
.NrFreePages
+ MmStats
.NrSystemPages
+
547 MmStats
.NrReservedPages
+ MmStats
.NrUserPages
;
548 MmInitializeBalancer(MmStats
.NrFreePages
, MmStats
.NrSystemPages
+ MmStats
.NrReservedPages
);
549 return((PVOID
)LastKernelAddress
);
553 MmSetFlagsPage(PFN_TYPE Pfn
, ULONG Flags
)
557 assert (Pfn
< MmPageArraySize
);
558 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
559 MmPageArray
[Pfn
].AllFlags
= Flags
;
560 KeReleaseSpinLock(&PageListLock
, oldIrql
);
564 MmSetRmapListHeadPage(PFN_TYPE Pfn
, struct _MM_RMAP_ENTRY
* ListHead
)
566 MmPageArray
[Pfn
].RmapListHead
= ListHead
;
569 struct _MM_RMAP_ENTRY
*
570 MmGetRmapListHeadPage(PFN_TYPE Pfn
)
572 return(MmPageArray
[Pfn
].RmapListHead
);
576 MmMarkPageMapped(PFN_TYPE Pfn
)
580 if (Pfn
< MmPageArraySize
)
582 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
583 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
585 DbgPrint("Mapping non-used page\n");
588 MmPageArray
[Pfn
].MapCount
++;
589 KeReleaseSpinLock(&PageListLock
, oldIrql
);
594 MmMarkPageUnmapped(PFN_TYPE Pfn
)
598 if (Pfn
< MmPageArraySize
)
600 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
601 if (MmPageArray
[Pfn
].Flags
.Type
== MM_PHYSICAL_PAGE_FREE
)
603 DbgPrint("Unmapping non-used page\n");
606 if (MmPageArray
[Pfn
].MapCount
== 0)
608 DbgPrint("Unmapping not mapped page\n");
611 MmPageArray
[Pfn
].MapCount
--;
612 KeReleaseSpinLock(&PageListLock
, oldIrql
);
617 MmGetFlagsPage(PFN_TYPE Pfn
)
622 assert (Pfn
< MmPageArraySize
);
623 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
624 Flags
= MmPageArray
[Pfn
].AllFlags
;
625 KeReleaseSpinLock(&PageListLock
, oldIrql
);
632 MmSetSavedSwapEntryPage(PFN_TYPE Pfn
, SWAPENTRY SavedSwapEntry
)
636 assert (Pfn
< MmPageArraySize
);
637 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
638 MmPageArray
[Pfn
].SavedSwapEntry
= SavedSwapEntry
;
639 KeReleaseSpinLock(&PageListLock
, oldIrql
);
643 MmGetSavedSwapEntryPage(PFN_TYPE Pfn
)
645 SWAPENTRY SavedSwapEntry
;
648 assert (Pfn
< MmPageArraySize
);
649 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
650 SavedSwapEntry
= MmPageArray
[Pfn
].SavedSwapEntry
;
651 KeReleaseSpinLock(&PageListLock
, oldIrql
);
653 return(SavedSwapEntry
);
657 MmReferencePage(PFN_TYPE Pfn
)
661 DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
663 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
668 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
670 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
672 DbgPrint("Referencing non-used page\n");
676 MmPageArray
[Pfn
].ReferenceCount
++;
677 KeReleaseSpinLock(&PageListLock
, oldIrql
);
681 MmGetReferenceCountPage(PFN_TYPE Pfn
)
686 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
688 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
693 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
695 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
697 DbgPrint("Getting reference count for free page\n");
701 RCount
= MmPageArray
[Pfn
].ReferenceCount
;
703 KeReleaseSpinLock(&PageListLock
, oldIrql
);
708 MmIsUsablePage(PFN_TYPE Pfn
)
711 DPRINT("MmIsUsablePage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
713 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
718 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
&&
719 MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_BIOS
)
728 MmDereferencePage(PFN_TYPE Pfn
)
732 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
734 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
739 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
741 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
743 DbgPrint("Dereferencing free page\n");
746 if (MmPageArray
[Pfn
].ReferenceCount
== 0)
748 DbgPrint("Derefrencing page with reference count 0\n");
752 MmPageArray
[Pfn
].ReferenceCount
--;
753 if (MmPageArray
[Pfn
].ReferenceCount
== 0)
755 MmStats
.NrFreePages
++;
756 MmStats
.NrSystemPages
--;
757 RemoveEntryList(&MmPageArray
[Pfn
].ListEntry
);
758 if (MmPageArray
[Pfn
].RmapListHead
!= NULL
)
760 DbgPrint("Freeing page with rmap entries.\n");
763 if (MmPageArray
[Pfn
].MapCount
!= 0)
765 DbgPrint("Freeing mapped page (0x%x count %d)\n",
766 Pfn
<< PAGE_SHIFT
, MmPageArray
[Pfn
].MapCount
);
769 if (MmPageArray
[Pfn
].LockCount
> 0)
771 DbgPrint("Freeing locked page\n");
774 if (MmPageArray
[Pfn
].SavedSwapEntry
!= 0)
776 DbgPrint("Freeing page with swap entry.\n");
779 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
781 DbgPrint("Freeing page with flags %x\n",
782 MmPageArray
[Pfn
].Flags
.Type
);
785 MmPageArray
[Pfn
].Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
786 MmPageArray
[Pfn
].Flags
.Consumer
= MC_MAXIMUM
;
787 InsertTailList(&FreeUnzeroedPageListHead
,
788 &MmPageArray
[Pfn
].ListEntry
);
790 if (UnzeroedPageCount
> 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent
))
792 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
795 KeReleaseSpinLock(&PageListLock
, oldIrql
);
799 MmGetLockCountPage(PFN_TYPE Pfn
)
804 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
806 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
811 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
813 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
815 DbgPrint("Getting lock count for free page\n");
819 LockCount
= MmPageArray
[Pfn
].LockCount
;
820 KeReleaseSpinLock(&PageListLock
, oldIrql
);
826 MmLockPage(PFN_TYPE Pfn
)
830 DPRINT("MmLockPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
832 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
837 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
839 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
841 DbgPrint("Locking free page\n");
845 MmPageArray
[Pfn
].LockCount
++;
846 KeReleaseSpinLock(&PageListLock
, oldIrql
);
850 MmUnlockPage(PFN_TYPE Pfn
)
854 DPRINT("MmUnlockPage(PhysicalAddress %x)\n", Pfn
<< PAGE_SHIFT
);
856 if (Pfn
== 0 || Pfn
>= MmPageArraySize
)
861 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
863 if (MmPageArray
[Pfn
].Flags
.Type
!= MM_PHYSICAL_PAGE_USED
)
865 DbgPrint("Unlocking free page\n");
869 MmPageArray
[Pfn
].LockCount
--;
870 KeReleaseSpinLock(&PageListLock
, oldIrql
);
874 MmAllocPage(ULONG Consumer
, SWAPENTRY SavedSwapEntry
)
877 PLIST_ENTRY ListEntry
;
878 PPHYSICAL_PAGE PageDescriptor
;
880 BOOLEAN NeedClear
= FALSE
;
882 DPRINT("MmAllocPage()\n");
884 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
885 if (IsListEmpty(&FreeZeroedPageListHead
))
887 if (IsListEmpty(&FreeUnzeroedPageListHead
))
889 DPRINT1("MmAllocPage(): Out of memory\n");
890 KeReleaseSpinLock(&PageListLock
, oldIrql
);
893 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
896 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
902 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
904 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
907 if (PageDescriptor
->Flags
.Type
!= MM_PHYSICAL_PAGE_FREE
)
909 DbgPrint("Got non-free page from freelist\n");
912 if (PageDescriptor
->MapCount
!= 0)
914 DbgPrint("Got mapped page from freelist\n");
917 if (PageDescriptor
->ReferenceCount
!= 0)
919 DPRINT1("%d\n", PageDescriptor
->ReferenceCount
);
922 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
923 PageDescriptor
->Flags
.Consumer
= Consumer
;
924 PageDescriptor
->ReferenceCount
= 1;
925 PageDescriptor
->LockCount
= 0;
926 PageDescriptor
->MapCount
= 0;
927 PageDescriptor
->SavedSwapEntry
= SavedSwapEntry
;
928 InsertTailList(&UsedPageListHeads
[Consumer
], ListEntry
);
930 MmStats
.NrSystemPages
++;
931 MmStats
.NrFreePages
--;
933 KeReleaseSpinLock(&PageListLock
, oldIrql
);
935 PfnOffset
= PageDescriptor
- MmPageArray
;
938 MiZeroPage(PfnOffset
);
940 if (PageDescriptor
->MapCount
!= 0)
942 DbgPrint("Returning mapped page.\n");
950 MmZeroPageThreadMain(PVOID Ignored
)
954 PLIST_ENTRY ListEntry
;
955 PPHYSICAL_PAGE PageDescriptor
;
957 static PVOID Address
= NULL
;
962 Status
= KeWaitForSingleObject(&ZeroPageThreadEvent
,
967 if (!NT_SUCCESS(Status
))
969 DbgPrint("ZeroPageThread: Wait failed\n");
971 return(STATUS_UNSUCCESSFUL
);
975 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
976 while (!IsListEmpty(&FreeUnzeroedPageListHead
))
978 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
980 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
981 /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
982 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_USED
;
983 KeReleaseSpinLock(&PageListLock
, oldIrql
);
985 Pfn
= PageDescriptor
- MmPageArray
;
988 Address
= ExAllocatePageWithPhysPage(Pfn
);
992 Status
= MmCreateVirtualMapping(NULL
,
994 PAGE_READWRITE
| PAGE_SYSTEM
,
997 if (!NT_SUCCESS(Status
))
999 DbgPrint("Unable to create virtual mapping\n");
1003 memset(Address
, 0, PAGE_SIZE
);
1004 MmDeleteVirtualMapping(NULL
, (PVOID
)Address
, FALSE
, NULL
, NULL
);
1005 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
1006 if (PageDescriptor
->MapCount
!= 0)
1008 DbgPrint("Mapped page on freelist.\n");
1011 PageDescriptor
->Flags
.Zero
= 1;
1012 PageDescriptor
->Flags
.Type
= MM_PHYSICAL_PAGE_FREE
;
1013 InsertHeadList(&FreeZeroedPageListHead
, ListEntry
);
1015 DPRINT("Zeroed %d pages.\n", Count
);
1016 KeResetEvent(&ZeroPageThreadEvent
);
1017 KeReleaseSpinLock(&PageListLock
, oldIrql
);
1021 NTSTATUS INIT_FUNCTION
1022 MmInitZeroPageThread(VOID
)
1027 Status
= PsCreateSystemThread(&ZeroPageThreadHandle
,
1032 (PKSTART_ROUTINE
) MmZeroPageThreadMain
,
1034 if (!NT_SUCCESS(Status
))
1040 NtSetInformationThread(ZeroPageThreadHandle
,
1045 return(STATUS_SUCCESS
);