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
41 SWAPENTRY SavedSwapEntry;
44 struct _MM_RMAP_ENTRY* RmapListHead;
45 } PHYSICAL_PAGE, *PPHYSICAL_PAGE;
47 /* GLOBALS ****************************************************************/
49 static PPHYSICAL_PAGE MmPageArray;
50 static ULONG MmPageArraySize;
52 static KSPIN_LOCK PageListLock;
53 static LIST_ENTRY UsedPageListHeads[MC_MAXIMUM];
54 static LIST_ENTRY FreeZeroedPageListHead;
55 static LIST_ENTRY FreeUnzeroedPageListHead;
56 static LIST_ENTRY BiosPageListHead;
58 static HANDLE ZeroPageThreadHandle;
59 static CLIENT_ID ZeroPageThreadId;
60 static KEVENT ZeroPageThreadEvent;
62 static ULONG UnzeroedPageCount = 0;
64 /* FUNCTIONS *************************************************************/
67 MmTransferOwnershipPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG NewConsumer)
69 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
72 KeAcquireSpinLock(&PageListLock, &oldIrql);
73 if (MmPageArray[Start].MapCount != 0)
75 DbgPrint("Transfering mapped page.\n");
78 RemoveEntryList(&MmPageArray[Start].ListEntry);
79 InsertTailList(&UsedPageListHeads[NewConsumer],
80 &MmPageArray[Start].ListEntry);
81 MmPageArray[Start].Flags.Consumer = NewConsumer;
82 KeReleaseSpinLock(&PageListLock, oldIrql);
83 MiZeroPage(PhysicalAddress);
87 MmGetLRUFirstUserPage(VOID)
89 PLIST_ENTRY NextListEntry;
90 PHYSICAL_ADDRESS Next;
91 PHYSICAL_PAGE* PageDescriptor;
94 KeAcquireSpinLock(&PageListLock, &oldIrql);
95 NextListEntry = UsedPageListHeads[MC_USER].Flink;
96 if (NextListEntry == &UsedPageListHeads[MC_USER])
98 KeReleaseSpinLock(&PageListLock, oldIrql);
99 return((LARGE_INTEGER)0LL);
101 PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
102 Next.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
103 Next.QuadPart = (Next.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
104 KeReleaseSpinLock(&PageListLock, oldIrql);
109 MmSetLRULastPage(PHYSICAL_ADDRESS PhysicalAddress)
111 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
114 KeAcquireSpinLock(&PageListLock, &oldIrql);
115 if (MmPageArray[Start].Flags.Type == MM_PHYSICAL_PAGE_USED &&
116 MmPageArray[Start].Flags.Consumer == MC_USER)
118 RemoveEntryList(&MmPageArray[Start].ListEntry);
119 InsertTailList(&UsedPageListHeads[MC_USER],
120 &MmPageArray[Start].ListEntry);
122 KeReleaseSpinLock(&PageListLock, oldIrql);
126 MmGetLRUNextUserPage(PHYSICAL_ADDRESS PreviousPhysicalAddress)
128 ULONG Start = PreviousPhysicalAddress.u.LowPart / PAGE_SIZE;
129 PLIST_ENTRY NextListEntry;
130 PHYSICAL_ADDRESS Next;
131 PHYSICAL_PAGE* PageDescriptor;
134 KeAcquireSpinLock(&PageListLock, &oldIrql);
135 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED ||
136 MmPageArray[Start].Flags.Consumer != MC_USER)
138 NextListEntry = UsedPageListHeads[MC_USER].Flink;
142 NextListEntry = MmPageArray[Start].ListEntry.Flink;
144 if (NextListEntry == &UsedPageListHeads[MC_USER])
146 KeReleaseSpinLock(&PageListLock, oldIrql);
147 return((LARGE_INTEGER)0LL);
149 PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
150 Next.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
151 Next.QuadPart = (Next.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
152 KeReleaseSpinLock(&PageListLock, oldIrql);
157 MmGetContinuousPages(ULONG NumberOfBytes,
158 PHYSICAL_ADDRESS HighestAcceptableAddress,
167 NrPages = PAGE_ROUND_UP(NumberOfBytes) / PAGE_SIZE;
169 KeAcquireSpinLock(&PageListLock, &oldIrql);
173 for (i = 0; i < (HighestAcceptableAddress.QuadPart / PAGE_SIZE); )
175 if (MmPageArray[i].Flags.Type == MM_PHYSICAL_PAGE_FREE)
187 if (length == NrPages)
196 * Fast forward to the base of the next aligned region
198 i = ROUND_UP((i + 1), (Alignment / PAGE_SIZE));
201 if (start == -1 || length != NrPages)
203 KeReleaseSpinLock(&PageListLock, oldIrql);
204 return((LARGE_INTEGER)(LONGLONG)0);
206 for (i = start; i < (start + length); i++)
208 RemoveEntryList(&MmPageArray[i].ListEntry);
209 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_USED;
210 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
211 MmPageArray[i].ReferenceCount = 1;
212 MmPageArray[i].LockCount = 0;
213 MmPageArray[i].MapCount = 0;
214 MmPageArray[i].SavedSwapEntry = 0;
215 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
216 &MmPageArray[i].ListEntry);
218 KeReleaseSpinLock(&PageListLock, oldIrql);
219 return((LARGE_INTEGER)((LONGLONG)start * PAGE_SIZE));
223 MiParseRangeToFreeList(PADDRESS_RANGE Range)
225 ULONG i, first, last;
227 /* FIXME: Not 64-bit ready */
229 DPRINT("Range going to free list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
234 first = (Range->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE;
235 last = first + ((Range->LengthLow + PAGE_SIZE - 1) / PAGE_SIZE);
236 for (i = first; i < last; i++)
238 if (MmPageArray[i].Flags.Type == 0)
240 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
241 MmPageArray[i].ReferenceCount = 0;
242 InsertTailList(&FreeUnzeroedPageListHead,
243 &MmPageArray[i].ListEntry);
250 MiParseRangeToBiosList(PADDRESS_RANGE Range)
252 ULONG i, first, last;
254 /* FIXME: Not 64-bit ready */
256 DPRINT("Range going to bios list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
261 first = (Range->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE;
262 last = first + ((Range->LengthLow + PAGE_SIZE - 1) / PAGE_SIZE);
263 for (i = first; i < last; i++)
265 /* Remove the page from the free list if it is there */
266 if (MmPageArray[i].Flags.Type == MM_PHYSICAL_PAGE_FREE)
268 RemoveEntryList(&MmPageArray[i].ListEntry);
271 if (MmPageArray[i].Flags.Type != MM_PHYSICAL_PAGE_BIOS)
273 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_BIOS;
274 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
275 MmPageArray[i].ReferenceCount = 1;
276 InsertTailList(&BiosPageListHead,
277 &MmPageArray[i].ListEntry);
283 MiParseBIOSMemoryMap(ULONG MemorySizeInPages,
284 PADDRESS_RANGE BIOSMemoryMap,
285 ULONG AddressRangeCount)
291 for (i = 0; i < AddressRangeCount; i++)
293 if (((p->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE) < MemorySizeInPages)
297 MiParseRangeToFreeList(p);
301 MiParseRangeToBiosList(p);
309 MmInitializePageList(PVOID FirstPhysKernelAddress,
310 PVOID LastPhysKernelAddress,
311 ULONG MemorySizeInPages,
312 ULONG LastKernelAddress,
313 PADDRESS_RANGE BIOSMemoryMap,
314 ULONG AddressRangeCount)
316 * FUNCTION: Initializes the page list with all pages free
317 * except those known to be reserved and those used by the kernel
319 * PageBuffer = Page sized buffer
320 * FirstKernelAddress = First physical address used by the kernel
321 * LastKernelAddress = Last physical address used by the kernel
328 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
329 "LastPhysKernelAddress %x, "
330 "MemorySizeInPages %x, LastKernelAddress %x)\n",
331 FirstPhysKernelAddress,
332 LastPhysKernelAddress,
336 for (i = 0; i < MC_MAXIMUM; i++)
338 InitializeListHead(&UsedPageListHeads[i]);
340 KeInitializeSpinLock(&PageListLock);
341 InitializeListHead(&FreeUnzeroedPageListHead);
342 InitializeListHead(&FreeZeroedPageListHead);
343 InitializeListHead(&BiosPageListHead);
345 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
347 MmPageArraySize = MemorySizeInPages;
349 PAGE_ROUND_UP((MmPageArraySize * sizeof(PHYSICAL_PAGE))) / PAGE_SIZE;
350 MmPageArray = (PHYSICAL_PAGE *)LastKernelAddress;
352 DPRINT("Reserved %d\n", Reserved);
354 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
355 LastKernelAddress = ((ULONG)LastKernelAddress + (Reserved * PAGE_SIZE));
356 LastPhysKernelAddress = (PVOID)PAGE_ROUND_UP(LastPhysKernelAddress);
357 LastPhysKernelAddress = LastPhysKernelAddress + (Reserved * PAGE_SIZE);
359 MmStats.NrTotalPages = 0;
360 MmStats.NrSystemPages = 0;
361 MmStats.NrUserPages = 0;
362 MmStats.NrReservedPages = 0;
363 MmStats.NrFreePages = 0;
364 MmStats.NrLockedPages = 0;
366 for (i = 0; i < Reserved; i++)
368 PVOID Address = (PVOID)(ULONG)MmPageArray + (i * PAGE_SIZE);
369 if (!MmIsPagePresent(NULL, Address))
371 ULONG PhysicalAddress;
372 PhysicalAddress = (ULONG)LastPhysKernelAddress -
373 (Reserved * PAGE_SIZE) + (i * PAGE_SIZE);
375 MmCreateVirtualMappingUnsafe(NULL,
378 (PHYSICAL_ADDRESS)(LONGLONG)PhysicalAddress,
380 if (!NT_SUCCESS(Status))
382 DbgPrint("Unable to create virtual mapping\n");
386 memset((PVOID)MmPageArray + (i * PAGE_SIZE), 0, PAGE_SIZE);
391 * Page zero is reserved
393 MmPageArray[0].Flags.Type = MM_PHYSICAL_PAGE_BIOS;
394 MmPageArray[0].Flags.Consumer = MC_NPPOOL;
395 MmPageArray[0].ReferenceCount = 0;
396 InsertTailList(&BiosPageListHead,
397 &MmPageArray[0].ListEntry);
400 * Page one is reserved for the initial KPCR
402 MmPageArray[1].Flags.Type = MM_PHYSICAL_PAGE_BIOS;
403 MmPageArray[1].Flags.Consumer = MC_NPPOOL;
404 MmPageArray[1].ReferenceCount = 0;
405 InsertTailList(&BiosPageListHead,
406 &MmPageArray[1].ListEntry);
409 if ((ULONG)FirstPhysKernelAddress < 0xa0000)
411 MmStats.NrFreePages += (((ULONG)FirstPhysKernelAddress/PAGE_SIZE) - 2);
412 for (; i<((ULONG)FirstPhysKernelAddress/PAGE_SIZE); i++)
414 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
415 MmPageArray[i].ReferenceCount = 0;
416 InsertTailList(&FreeUnzeroedPageListHead,
417 &MmPageArray[i].ListEntry);
420 MmStats.NrSystemPages +=
421 ((((ULONG)LastPhysKernelAddress) / PAGE_SIZE) - i);
422 for (; i<((ULONG)LastPhysKernelAddress / PAGE_SIZE); i++)
424 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_USED;
425 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
426 MmPageArray[i].ReferenceCount = 1;
427 MmPageArray[i].MapCount = 1;
428 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
429 &MmPageArray[i].ListEntry);
431 MmStats.NrFreePages += ((0xa0000/PAGE_SIZE) - i);
432 for (; i<(0xa0000/PAGE_SIZE); i++)
434 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
435 MmPageArray[i].ReferenceCount = 0;
436 InsertTailList(&FreeUnzeroedPageListHead,
437 &MmPageArray[i].ListEntry);
440 MmStats.NrReservedPages += ((0x100000/PAGE_SIZE) - i);
441 for (; i<(0x100000 / PAGE_SIZE); i++)
443 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_BIOS;
444 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
445 MmPageArray[i].ReferenceCount = 1;
446 InsertTailList(&BiosPageListHead,
447 &MmPageArray[i].ListEntry);
452 MmStats.NrFreePages += ((0xa0000 / PAGE_SIZE) - 2);
453 for (; i<(0xa0000 / PAGE_SIZE); i++)
455 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
456 MmPageArray[i].ReferenceCount = 0;
457 InsertTailList(&FreeUnzeroedPageListHead,
458 &MmPageArray[i].ListEntry);
461 MmStats.NrReservedPages += (0x60000 / PAGE_SIZE);
462 for (; i<(0x100000 / PAGE_SIZE); i++)
464 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_BIOS;
465 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
466 MmPageArray[i].ReferenceCount = 1;
467 InsertTailList(&BiosPageListHead,
468 &MmPageArray[i].ListEntry);
470 MmStats.NrFreePages += (((ULONG)FirstPhysKernelAddress/PAGE_SIZE) - i);
471 for (; i<((ULONG)FirstPhysKernelAddress/PAGE_SIZE); i++)
473 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
474 MmPageArray[i].ReferenceCount = 0;
475 InsertTailList(&FreeUnzeroedPageListHead,
476 &MmPageArray[i].ListEntry);
479 MmStats.NrSystemPages +=
480 (((ULONG)LastPhysKernelAddress/PAGE_SIZE) - i);
481 for (; i<((ULONG)LastPhysKernelAddress/PAGE_SIZE); i++)
483 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_USED;
484 MmPageArray[i].Flags.Consumer = MC_NPPOOL;
485 MmPageArray[i].ReferenceCount = 1;
486 MmPageArray[i].MapCount = 1;
487 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
488 &MmPageArray[i].ListEntry);
492 MmStats.NrFreePages += (MemorySizeInPages - i);
493 for (; i<MemorySizeInPages; i++)
495 MmPageArray[i].Flags.Type = MM_PHYSICAL_PAGE_FREE;
496 MmPageArray[i].ReferenceCount = 0;
497 InsertTailList(&FreeUnzeroedPageListHead,
498 &MmPageArray[i].ListEntry);
502 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
504 MiParseBIOSMemoryMap(
510 KeInitializeEvent(&ZeroPageThreadEvent, NotificationEvent, TRUE);
513 MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages +
514 MmStats.NrReservedPages + MmStats.NrUserPages;
515 MmInitializeBalancer(MmStats.NrFreePages);
516 return((PVOID)LastKernelAddress);
520 MmSetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG Flags)
522 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
525 KeAcquireSpinLock(&PageListLock, &oldIrql);
526 MmPageArray[Start].AllFlags = Flags;
527 KeReleaseSpinLock(&PageListLock, oldIrql);
531 MmSetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress,
532 struct _MM_RMAP_ENTRY* ListHead)
534 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
536 MmPageArray[Start].RmapListHead = ListHead;
539 struct _MM_RMAP_ENTRY*
540 MmGetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress)
542 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
544 return(MmPageArray[Start].RmapListHead);
548 MmMarkPageMapped(PHYSICAL_ADDRESS PhysicalAddress)
550 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
553 if (Start < MmPageArraySize)
555 KeAcquireSpinLock(&PageListLock, &oldIrql);
556 if (MmPageArray[Start].Flags.Type == MM_PHYSICAL_PAGE_FREE)
558 DbgPrint("Mapping non-used page\n");
561 MmPageArray[Start].MapCount++;
562 KeReleaseSpinLock(&PageListLock, oldIrql);
567 MmMarkPageUnmapped(PHYSICAL_ADDRESS PhysicalAddress)
569 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
572 if (Start < MmPageArraySize)
574 KeAcquireSpinLock(&PageListLock, &oldIrql);
575 if (MmPageArray[Start].Flags.Type == MM_PHYSICAL_PAGE_FREE)
577 DbgPrint("Unmapping non-used page\n");
580 if (MmPageArray[Start].MapCount == 0)
582 DbgPrint("Unmapping not mapped page\n");
585 MmPageArray[Start].MapCount--;
586 KeReleaseSpinLock(&PageListLock, oldIrql);
591 MmGetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress)
593 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
597 KeAcquireSpinLock(&PageListLock, &oldIrql);
598 Flags = MmPageArray[Start].AllFlags;
599 KeReleaseSpinLock(&PageListLock, oldIrql);
606 MmSetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress,
607 SWAPENTRY SavedSwapEntry)
609 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
612 KeAcquireSpinLock(&PageListLock, &oldIrql);
613 MmPageArray[Start].SavedSwapEntry = SavedSwapEntry;
614 KeReleaseSpinLock(&PageListLock, oldIrql);
618 MmGetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress)
620 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
621 SWAPENTRY SavedSwapEntry;
624 KeAcquireSpinLock(&PageListLock, &oldIrql);
625 SavedSwapEntry = MmPageArray[Start].SavedSwapEntry;
626 KeReleaseSpinLock(&PageListLock, oldIrql);
628 return(SavedSwapEntry);
632 MmReferencePage(PHYSICAL_ADDRESS PhysicalAddress)
634 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
637 DPRINT("MmReferencePage(PhysicalAddress %x)\n", PhysicalAddress);
639 if (PhysicalAddress.u.LowPart == 0)
644 KeAcquireSpinLock(&PageListLock, &oldIrql);
646 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
648 DbgPrint("Referencing non-used page\n");
652 MmPageArray[Start].ReferenceCount++;
653 KeReleaseSpinLock(&PageListLock, oldIrql);
657 MmGetReferenceCountPage(PHYSICAL_ADDRESS PhysicalAddress)
659 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
663 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress);
665 if (PhysicalAddress.u.LowPart == 0)
670 KeAcquireSpinLock(&PageListLock, &oldIrql);
672 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
674 DbgPrint("Getting reference count for free page\n");
678 RCount = MmPageArray[Start].ReferenceCount;
680 KeReleaseSpinLock(&PageListLock, oldIrql);
685 MmIsUsablePage(PHYSICAL_ADDRESS PhysicalAddress)
687 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
689 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress);
691 if (PhysicalAddress.u.LowPart == 0)
696 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED &&
697 MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_BIOS)
706 MmDereferencePage(PHYSICAL_ADDRESS PhysicalAddress)
708 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
711 DPRINT("MmDereferencePage(PhysicalAddress %I64x)\n", PhysicalAddress);
713 if (PhysicalAddress.u.LowPart == 0)
718 KeAcquireSpinLock(&PageListLock, &oldIrql);
721 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
723 DbgPrint("Dereferencing free page\n");
727 MmPageArray[Start].ReferenceCount--;
728 if (MmPageArray[Start].ReferenceCount == 0)
730 MmStats.NrFreePages++;
731 MmStats.NrSystemPages--;
732 RemoveEntryList(&MmPageArray[Start].ListEntry);
733 if (MmPageArray[Start].RmapListHead != NULL)
735 DbgPrint("Freeing page with rmap entries.\n");
738 if (MmPageArray[Start].MapCount != 0)
740 DbgPrint("Freeing mapped page (0x%I64x count %d)\n",
741 PhysicalAddress, MmPageArray[Start].MapCount);
744 if (MmPageArray[Start].LockCount > 0)
746 DbgPrint("Freeing locked page\n");
749 if (MmPageArray[Start].SavedSwapEntry != 0)
751 DbgPrint("Freeing page with swap entry.\n");
754 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
756 DbgPrint("Freeing page with flags %x\n",
757 MmPageArray[Start].Flags.Type);
760 MmPageArray[Start].Flags.Type = MM_PHYSICAL_PAGE_FREE;
761 InsertTailList(&FreeUnzeroedPageListHead,
762 &MmPageArray[Start].ListEntry);
764 if (UnzeroedPageCount > 8 && 0 == KeReadStateEvent(&ZeroPageThreadEvent))
766 KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
769 KeReleaseSpinLock(&PageListLock, oldIrql);
773 MmGetLockCountPage(PHYSICAL_ADDRESS PhysicalAddress)
775 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
779 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", PhysicalAddress);
781 if (PhysicalAddress.u.LowPart == 0)
786 KeAcquireSpinLock(&PageListLock, &oldIrql);
788 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
790 DbgPrint("Getting lock count for free page\n");
794 LockCount = MmPageArray[Start].LockCount;
795 KeReleaseSpinLock(&PageListLock, oldIrql);
801 MmLockPage(PHYSICAL_ADDRESS PhysicalAddress)
803 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
806 DPRINT("MmLockPage(PhysicalAddress %x)\n", PhysicalAddress);
808 if (PhysicalAddress.u.LowPart == 0)
813 KeAcquireSpinLock(&PageListLock, &oldIrql);
815 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
817 DbgPrint("Locking free page\n");
821 MmPageArray[Start].LockCount++;
822 KeReleaseSpinLock(&PageListLock, oldIrql);
826 MmUnlockPage(PHYSICAL_ADDRESS PhysicalAddress)
828 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
831 DPRINT("MmUnlockPage(PhysicalAddress %llx)\n", PhysicalAddress);
833 if (PhysicalAddress.u.LowPart == 0)
838 KeAcquireSpinLock(&PageListLock, &oldIrql);
840 if (MmPageArray[Start].Flags.Type != MM_PHYSICAL_PAGE_USED)
842 DbgPrint("Unlocking free page\n");
846 MmPageArray[Start].LockCount--;
847 KeReleaseSpinLock(&PageListLock, oldIrql);
851 MmAllocPage(ULONG Consumer, SWAPENTRY SavedSwapEntry)
853 PHYSICAL_ADDRESS PageOffset;
854 PLIST_ENTRY ListEntry;
855 PPHYSICAL_PAGE PageDescriptor;
857 BOOLEAN NeedClear = FALSE;
859 DPRINT("MmAllocPage()\n");
861 KeAcquireSpinLock(&PageListLock, &oldIrql);
862 if (IsListEmpty(&FreeZeroedPageListHead))
864 if (IsListEmpty(&FreeUnzeroedPageListHead))
866 DPRINT1("MmAllocPage(): Out of memory\n");
867 KeReleaseSpinLock(&PageListLock, oldIrql);
868 return((PHYSICAL_ADDRESS)0LL);
870 ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
873 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
879 ListEntry = RemoveTailList(&FreeZeroedPageListHead);
881 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
884 if (PageDescriptor->Flags.Type != MM_PHYSICAL_PAGE_FREE)
886 DbgPrint("Got non-free page from freelist\n");
889 if (PageDescriptor->MapCount != 0)
891 DbgPrint("Got mapped page from freelist\n");
894 PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_USED;
895 PageDescriptor->Flags.Consumer = Consumer;
896 PageDescriptor->ReferenceCount = 1;
897 PageDescriptor->LockCount = 0;
898 PageDescriptor->MapCount = 0;
899 PageDescriptor->SavedSwapEntry = SavedSwapEntry;
900 InsertTailList(&UsedPageListHeads[Consumer], ListEntry);
902 MmStats.NrSystemPages++;
903 MmStats.NrFreePages--;
905 KeReleaseSpinLock(&PageListLock, oldIrql);
907 PageOffset.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
908 PageOffset.QuadPart =
909 (PageOffset.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
912 MiZeroPage(PageOffset);
914 if (PageDescriptor->MapCount != 0)
916 DbgPrint("Returning mapped page.\n");
924 MmZeroPageThreadMain(PVOID Ignored)
928 PLIST_ENTRY ListEntry;
929 PPHYSICAL_PAGE PageDescriptor;
930 PHYSICAL_ADDRESS PhysPage;
931 static PVOID Address = NULL;
936 Status = KeWaitForSingleObject(&ZeroPageThreadEvent,
941 if (!NT_SUCCESS(Status))
943 DbgPrint("ZeroPageThread: Wait failed\n");
945 return(STATUS_UNSUCCESSFUL);
949 KeAcquireSpinLock(&PageListLock, &oldIrql);
950 while (!IsListEmpty(&FreeUnzeroedPageListHead))
952 ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
954 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
955 /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
956 PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_USED;
957 KeReleaseSpinLock(&PageListLock, oldIrql);
959 PhysPage.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
960 PhysPage.QuadPart = (PhysPage.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
963 Address = ExAllocatePageWithPhysPage(PhysPage);
967 Status = MmCreateVirtualMapping(NULL,
969 PAGE_READWRITE | PAGE_SYSTEM,
972 if (!NT_SUCCESS(Status))
974 DbgPrint("Unable to create virtual mapping\n");
978 memset(Address, 0, PAGE_SIZE);
979 MmDeleteVirtualMapping(NULL, (PVOID)Address, FALSE, NULL, NULL);
980 KeAcquireSpinLock(&PageListLock, &oldIrql);
981 if (PageDescriptor->MapCount != 0)
983 DbgPrint("Mapped page on freelist.\n");
986 PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_FREE;
987 InsertHeadList(&FreeZeroedPageListHead, ListEntry);
989 DPRINT("Zeroed %d pages.\n", Count);
990 KeResetEvent(&ZeroPageThreadEvent);
991 KeReleaseSpinLock(&PageListLock, oldIrql);
995 NTSTATUS MmInitZeroPageThread(VOID)
1000 Status = PsCreateSystemThread(&ZeroPageThreadHandle,
1005 (PKSTART_ROUTINE) MmZeroPageThreadMain,
1007 if (!NT_SUCCESS(Status))
1013 NtSetInformationThread(ZeroPageThreadHandle,
1018 return(STATUS_SUCCESS);