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 #define MM_PTYPE(x) ((x) & 0x3)
29 typedef struct _PHYSICAL_PAGE
34 SWAPENTRY SavedSwapEntry;
37 struct _MM_RMAP_ENTRY* RmapListHead;
38 } PHYSICAL_PAGE, *PPHYSICAL_PAGE;
40 /* GLOBALS ****************************************************************/
42 static PPHYSICAL_PAGE MmPageArray;
44 static KSPIN_LOCK PageListLock;
45 static LIST_ENTRY UsedPageListHeads[MC_MAXIMUM];
46 static LIST_ENTRY FreeZeroedPageListHead;
47 static LIST_ENTRY FreeUnzeroedPageListHead;
48 static LIST_ENTRY BiosPageListHead;
50 /* FUNCTIONS *************************************************************/
53 MmTransferOwnershipPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG NewConsumer)
55 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
58 KeAcquireSpinLock(&PageListLock, &oldIrql);
59 RemoveEntryList(&MmPageArray[Start].ListEntry);
60 InsertTailList(&UsedPageListHeads[NewConsumer],
61 &MmPageArray[Start].ListEntry);
62 KeReleaseSpinLock(&PageListLock, oldIrql);
63 MiZeroPage(PhysicalAddress);
67 MmGetLRUFirstUserPage(VOID)
69 PLIST_ENTRY NextListEntry;
70 PHYSICAL_ADDRESS Next;
71 PHYSICAL_PAGE* PageDescriptor;
74 KeAcquireSpinLock(&PageListLock, &oldIrql);
75 NextListEntry = UsedPageListHeads[MC_USER].Flink;
76 if (NextListEntry == &UsedPageListHeads[MC_USER])
78 KeReleaseSpinLock(&PageListLock, oldIrql);
79 return((LARGE_INTEGER)0LL);
81 PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
82 Next.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
83 Next.QuadPart = (Next.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
84 KeReleaseSpinLock(&PageListLock, oldIrql);
89 MmGetLRUNextUserPage(PHYSICAL_ADDRESS PreviousPhysicalAddress)
91 ULONG Start = PreviousPhysicalAddress.u.LowPart / PAGE_SIZE;
92 PLIST_ENTRY NextListEntry;
93 PHYSICAL_ADDRESS Next;
94 PHYSICAL_PAGE* PageDescriptor;
97 KeAcquireSpinLock(&PageListLock, &oldIrql);
98 if (!(MmPageArray[Start].Flags & MM_PHYSICAL_PAGE_USED))
100 NextListEntry = UsedPageListHeads[MC_USER].Flink;
104 NextListEntry = MmPageArray[Start].ListEntry.Flink;
106 if (NextListEntry == &UsedPageListHeads[MC_USER])
108 KeReleaseSpinLock(&PageListLock, oldIrql);
109 return((LARGE_INTEGER)0LL);
111 PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
112 Next.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
113 Next.QuadPart = (Next.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
114 KeReleaseSpinLock(&PageListLock, oldIrql);
119 MmGetContinuousPages(ULONG NumberOfBytes,
120 PHYSICAL_ADDRESS HighestAcceptableAddress,
129 NrPages = PAGE_ROUND_UP(NumberOfBytes) / PAGE_SIZE;
131 KeAcquireSpinLock(&PageListLock, &oldIrql);
135 for (i = 0; i < (HighestAcceptableAddress.QuadPart / PAGE_SIZE); )
137 if (MM_PTYPE(MmPageArray[i].Flags) == MM_PHYSICAL_PAGE_FREE)
149 if (length == NrPages)
158 * Fast forward to the base of the next aligned region
160 i = ROUND_UP((i + 1), (Alignment / PAGE_SIZE));
163 if (start == -1 || length != NrPages)
165 KeReleaseSpinLock(&PageListLock, oldIrql);
166 return((LARGE_INTEGER)(LONGLONG)0);
168 for (i = start; i < (start + length); i++)
170 RemoveEntryList(&MmPageArray[i].ListEntry);
171 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_USED;
172 MmPageArray[i].ReferenceCount = 1;
173 MmPageArray[i].LockCount = 0;
174 MmPageArray[i].MapCount = 0;
175 MmPageArray[i].SavedSwapEntry = 0;
176 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
177 &MmPageArray[i].ListEntry);
179 KeReleaseSpinLock(&PageListLock, oldIrql);
180 return((LARGE_INTEGER)((LONGLONG)start * 4096));
184 MiParseRangeToFreeList(PADDRESS_RANGE Range)
186 ULONG i, first, last;
188 /* FIXME: Not 64-bit ready */
190 DPRINT("Range going to free list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
195 first = (Range->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE;
196 last = first + ((Range->LengthLow + PAGE_SIZE - 1) / PAGE_SIZE);
197 for (i = first; i < last; i++)
199 if (MmPageArray[i].Flags == 0)
201 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
202 MmPageArray[i].ReferenceCount = 0;
203 InsertTailList(&FreeUnzeroedPageListHead,
204 &MmPageArray[i].ListEntry);
210 MiParseRangeToBiosList(PADDRESS_RANGE Range)
212 ULONG i, first, last;
214 /* FIXME: Not 64-bit ready */
216 DPRINT("Range going to bios list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
221 first = (Range->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE;
222 last = first + ((Range->LengthLow + PAGE_SIZE - 1) / PAGE_SIZE);
223 for (i = first; i < last; i++)
225 /* Remove the page from the free list if it is there */
226 if (MmPageArray[i].Flags == MM_PHYSICAL_PAGE_FREE)
228 RemoveEntryList(&MmPageArray[i].ListEntry);
231 if (MmPageArray[i].Flags != MM_PHYSICAL_PAGE_BIOS)
233 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_BIOS;
234 MmPageArray[i].ReferenceCount = 1;
235 InsertTailList(&BiosPageListHead,
236 &MmPageArray[i].ListEntry);
242 MiParseBIOSMemoryMap(ULONG MemorySizeInPages,
243 PADDRESS_RANGE BIOSMemoryMap,
244 ULONG AddressRangeCount)
250 for (i = 0; i < AddressRangeCount; i++)
252 if (((p->BaseAddrLow + PAGE_SIZE - 1) / PAGE_SIZE) < MemorySizeInPages)
256 MiParseRangeToFreeList(p);
260 MiParseRangeToBiosList(p);
268 MmInitializePageList(PVOID FirstPhysKernelAddress,
269 PVOID LastPhysKernelAddress,
270 ULONG MemorySizeInPages,
271 ULONG LastKernelAddress,
272 PADDRESS_RANGE BIOSMemoryMap,
273 ULONG AddressRangeCount)
275 * FUNCTION: Initializes the page list with all pages free
276 * except those known to be reserved and those used by the kernel
278 * PageBuffer = Page sized buffer
279 * FirstKernelAddress = First physical address used by the kernel
280 * LastKernelAddress = Last physical address used by the kernel
287 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
288 "LastPhysKernelAddress %x, "
289 "MemorySizeInPages %x, LastKernelAddress %x)\n",
290 FirstPhysKernelAddress,
291 LastPhysKernelAddress,
295 for (i = 0; i < MC_MAXIMUM; i++)
297 InitializeListHead(&UsedPageListHeads[i]);
299 KeInitializeSpinLock(&PageListLock);
300 InitializeListHead(&FreeUnzeroedPageListHead);
301 InitializeListHead(&FreeZeroedPageListHead);
302 InitializeListHead(&BiosPageListHead);
304 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
307 PAGE_ROUND_UP((MemorySizeInPages * sizeof(PHYSICAL_PAGE))) / PAGE_SIZE;
308 MmPageArray = (PHYSICAL_PAGE *)LastKernelAddress;
310 DPRINT("Reserved %d\n", Reserved);
312 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
313 LastKernelAddress = ((ULONG)LastKernelAddress + (Reserved * PAGE_SIZE));
314 LastPhysKernelAddress = (PVOID)PAGE_ROUND_UP(LastPhysKernelAddress);
315 LastPhysKernelAddress = LastPhysKernelAddress + (Reserved * PAGE_SIZE);
317 MmStats.NrTotalPages = 0;
318 MmStats.NrSystemPages = 0;
319 MmStats.NrUserPages = 0;
320 MmStats.NrReservedPages = 0;
321 MmStats.NrFreePages = 0;
322 MmStats.NrLockedPages = 0;
324 for (i = 0; i < Reserved; i++)
326 PVOID Address = (PVOID)(ULONG)MmPageArray + (i * PAGE_SIZE);
327 if (!MmIsPagePresent(NULL, Address))
329 ULONG PhysicalAddress;
330 PhysicalAddress = (ULONG)LastPhysKernelAddress -
331 (Reserved * PAGE_SIZE) + (i * PAGE_SIZE);
333 MmCreateVirtualMappingUnsafe(NULL,
336 (PHYSICAL_ADDRESS)(LONGLONG)PhysicalAddress,
338 if (!NT_SUCCESS(Status))
340 DbgPrint("Unable to create virtual mapping\n");
344 memset((PVOID)MmPageArray + (i * PAGE_SIZE), 0, PAGE_SIZE);
348 * Page zero is reserved
350 MmPageArray[0].Flags = MM_PHYSICAL_PAGE_BIOS;
351 MmPageArray[0].ReferenceCount = 0;
352 InsertTailList(&BiosPageListHead,
353 &MmPageArray[0].ListEntry);
356 * Page one is reserved for the initial KPCR
358 MmPageArray[1].Flags = MM_PHYSICAL_PAGE_BIOS;
359 MmPageArray[1].ReferenceCount = 0;
360 InsertTailList(&BiosPageListHead,
361 &MmPageArray[1].ListEntry);
364 if ((ULONG)FirstPhysKernelAddress < 0xa0000)
366 MmStats.NrFreePages += (((ULONG)FirstPhysKernelAddress/PAGE_SIZE) - 1);
367 for (; i<((ULONG)FirstPhysKernelAddress/PAGE_SIZE); i++)
369 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
370 MmPageArray[i].ReferenceCount = 0;
371 InsertTailList(&FreeUnzeroedPageListHead,
372 &MmPageArray[i].ListEntry);
374 MmStats.NrSystemPages +=
375 ((((ULONG)LastPhysKernelAddress) / PAGE_SIZE) - i);
376 for (; i<((ULONG)LastPhysKernelAddress / PAGE_SIZE); i++)
378 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_USED;
379 MmPageArray[i].ReferenceCount = 1;
380 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
381 &MmPageArray[i].ListEntry);
383 MmStats.NrFreePages += ((0xa0000/PAGE_SIZE) - i);
384 for (; i<(0xa0000/PAGE_SIZE); i++)
386 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
387 MmPageArray[i].ReferenceCount = 0;
388 InsertTailList(&FreeUnzeroedPageListHead,
389 &MmPageArray[i].ListEntry);
391 MmStats.NrReservedPages += ((0x100000/PAGE_SIZE) - i);
392 for (; i<(0x100000 / PAGE_SIZE); i++)
394 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_BIOS;
395 MmPageArray[i].ReferenceCount = 1;
396 InsertTailList(&BiosPageListHead,
397 &MmPageArray[i].ListEntry);
402 MmStats.NrFreePages += ((0xa0000 / PAGE_SIZE) - 1);
403 for (; i<(0xa0000 / PAGE_SIZE); i++)
405 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
406 MmPageArray[i].ReferenceCount = 0;
407 InsertTailList(&FreeUnzeroedPageListHead,
408 &MmPageArray[i].ListEntry);
410 MmStats.NrReservedPages += (0x60000 / PAGE_SIZE);
411 for (; i<(0x100000 / PAGE_SIZE); i++)
413 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_BIOS;
414 MmPageArray[i].ReferenceCount = 1;
415 InsertTailList(&BiosPageListHead,
416 &MmPageArray[i].ListEntry);
418 MmStats.NrFreePages += (((ULONG)FirstPhysKernelAddress/PAGE_SIZE) - i);
419 for (; i<((ULONG)FirstPhysKernelAddress/PAGE_SIZE); i++)
421 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
422 MmPageArray[i].ReferenceCount = 0;
423 InsertTailList(&FreeUnzeroedPageListHead,
424 &MmPageArray[i].ListEntry);
426 MmStats.NrSystemPages +=
427 (((ULONG)LastPhysKernelAddress/PAGE_SIZE) - i);
428 for (; i<((ULONG)LastPhysKernelAddress/PAGE_SIZE); i++)
430 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_USED;
431 MmPageArray[i].ReferenceCount = 1;
432 InsertTailList(&UsedPageListHeads[MC_NPPOOL],
433 &MmPageArray[i].ListEntry);
437 MmStats.NrFreePages += (MemorySizeInPages - i);
438 for (; i<MemorySizeInPages; i++)
440 MmPageArray[i].Flags = MM_PHYSICAL_PAGE_FREE;
441 MmPageArray[i].ReferenceCount = 0;
442 InsertTailList(&FreeUnzeroedPageListHead,
443 &MmPageArray[i].ListEntry);
446 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
448 MiParseBIOSMemoryMap(
454 MmStats.NrTotalPages = MmStats.NrFreePages + MmStats.NrSystemPages +
455 MmStats.NrReservedPages + MmStats.NrUserPages;
456 MmInitializeBalancer(MmStats.NrFreePages);
457 return((PVOID)LastKernelAddress);
461 MmSetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG Flags)
463 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
466 KeAcquireSpinLock(&PageListLock, &oldIrql);
467 MmPageArray[Start].Flags = Flags;
468 KeReleaseSpinLock(&PageListLock, oldIrql);
472 MmSetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress,
473 struct _MM_RMAP_ENTRY* ListHead)
475 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
477 MmPageArray[Start].RmapListHead = ListHead;
480 struct _MM_RMAP_ENTRY*
481 MmGetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress)
483 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
485 return(MmPageArray[Start].RmapListHead);
489 MmMarkPageMapped(PHYSICAL_ADDRESS PhysicalAddress)
491 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
494 KeAcquireSpinLock(&PageListLock, &oldIrql);
495 MmPageArray[Start].MapCount++;
496 KeReleaseSpinLock(&PageListLock, oldIrql);
500 MmMarkPageUnmapped(PHYSICAL_ADDRESS PhysicalAddress)
502 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
505 KeAcquireSpinLock(&PageListLock, &oldIrql);
506 MmPageArray[Start].MapCount--;
507 KeReleaseSpinLock(&PageListLock, oldIrql);
511 MmGetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress)
513 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
517 KeAcquireSpinLock(&PageListLock, &oldIrql);
518 Flags = MmPageArray[Start].Flags;
519 KeReleaseSpinLock(&PageListLock, oldIrql);
526 MmSetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress,
527 SWAPENTRY SavedSwapEntry)
529 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
532 KeAcquireSpinLock(&PageListLock, &oldIrql);
533 MmPageArray[Start].SavedSwapEntry = SavedSwapEntry;
534 KeReleaseSpinLock(&PageListLock, oldIrql);
538 MmGetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress)
540 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
541 SWAPENTRY SavedSwapEntry;
544 KeAcquireSpinLock(&PageListLock, &oldIrql);
545 SavedSwapEntry = MmPageArray[Start].SavedSwapEntry;
546 KeReleaseSpinLock(&PageListLock, oldIrql);
548 return(SavedSwapEntry);
552 MmReferencePage(PHYSICAL_ADDRESS PhysicalAddress)
554 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
557 DPRINT("MmReferencePage(PhysicalAddress %x)\n", PhysicalAddress);
559 if (PhysicalAddress.u.LowPart == 0)
564 KeAcquireSpinLock(&PageListLock, &oldIrql);
566 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
568 DbgPrint("Referencing non-used page\n");
572 MmPageArray[Start].ReferenceCount++;
573 KeReleaseSpinLock(&PageListLock, oldIrql);
577 MmGetReferenceCountPage(PHYSICAL_ADDRESS PhysicalAddress)
579 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
583 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress);
585 if (PhysicalAddress.u.LowPart == 0)
590 KeAcquireSpinLock(&PageListLock, &oldIrql);
592 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
594 DbgPrint("Getting reference count for free page\n");
598 RCount = MmPageArray[Start].ReferenceCount;
600 KeReleaseSpinLock(&PageListLock, oldIrql);
605 MmIsUsablePage(PHYSICAL_ADDRESS PhysicalAddress)
607 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
609 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress);
611 if (PhysicalAddress.u.LowPart == 0)
616 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED &&
617 MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_BIOS)
626 MmDereferencePage(PHYSICAL_ADDRESS PhysicalAddress)
628 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
631 DPRINT("MmDereferencePage(PhysicalAddress %I64x)\n", PhysicalAddress);
633 if (PhysicalAddress.u.LowPart == 0)
638 KeAcquireSpinLock(&PageListLock, &oldIrql);
641 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
643 DbgPrint("Dereferencing free page\n");
647 MmPageArray[Start].ReferenceCount--;
648 if (MmPageArray[Start].ReferenceCount == 0)
650 MmStats.NrFreePages++;
651 MmStats.NrSystemPages--;
652 RemoveEntryList(&MmPageArray[Start].ListEntry);
653 if (MmPageArray[Start].RmapListHead != NULL)
655 DbgPrint("Freeing page with rmap entries.\n");
658 if (MmPageArray[Start].MapCount != 0)
660 DbgPrint("Freeing mapped page (0x%I64x count %d)\n",
661 PhysicalAddress, MmPageArray[Start].MapCount);
664 if (MmPageArray[Start].LockCount > 0)
666 DbgPrint("Freeing locked page\n");
669 if (MmPageArray[Start].SavedSwapEntry != 0)
671 DbgPrint("Freeing page with swap entry.\n");
674 if (MmPageArray[Start].Flags != MM_PHYSICAL_PAGE_USED)
676 DbgPrint("Freeing page with flags %x\n",
677 MmPageArray[Start].Flags);
680 MmPageArray[Start].Flags = MM_PHYSICAL_PAGE_FREE;
681 InsertTailList(&FreeUnzeroedPageListHead,
682 &MmPageArray[Start].ListEntry);
684 KeReleaseSpinLock(&PageListLock, oldIrql);
688 MmGetLockCountPage(PHYSICAL_ADDRESS PhysicalAddress)
690 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
694 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", PhysicalAddress);
696 if (PhysicalAddress.u.LowPart == 0)
701 KeAcquireSpinLock(&PageListLock, &oldIrql);
703 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
705 DbgPrint("Getting lock count for free page\n");
709 LockCount = MmPageArray[Start].LockCount;
710 KeReleaseSpinLock(&PageListLock, oldIrql);
716 MmLockPage(PHYSICAL_ADDRESS PhysicalAddress)
718 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
721 DPRINT("MmLockPage(PhysicalAddress %x)\n", PhysicalAddress);
723 if (PhysicalAddress.u.LowPart == 0)
728 KeAcquireSpinLock(&PageListLock, &oldIrql);
730 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
732 DbgPrint("Locking free page\n");
736 MmPageArray[Start].LockCount++;
737 KeReleaseSpinLock(&PageListLock, oldIrql);
741 MmUnlockPage(PHYSICAL_ADDRESS PhysicalAddress)
743 ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
746 DPRINT("MmUnlockPage(PhysicalAddress %llx)\n", PhysicalAddress);
748 if (PhysicalAddress.u.LowPart == 0)
753 KeAcquireSpinLock(&PageListLock, &oldIrql);
755 if (MM_PTYPE(MmPageArray[Start].Flags) != MM_PHYSICAL_PAGE_USED)
757 DbgPrint("Unlocking free page\n");
761 MmPageArray[Start].LockCount--;
762 KeReleaseSpinLock(&PageListLock, oldIrql);
766 MmAllocPage(ULONG Consumer, SWAPENTRY SavedSwapEntry)
768 PHYSICAL_ADDRESS PageOffset;
769 PLIST_ENTRY ListEntry;
770 PPHYSICAL_PAGE PageDescriptor;
772 BOOLEAN NeedClear = FALSE;
774 DPRINT("MmAllocPage()\n");
776 KeAcquireSpinLock(&PageListLock, &oldIrql);
777 if (IsListEmpty(&FreeZeroedPageListHead))
779 if (IsListEmpty(&FreeUnzeroedPageListHead))
781 DPRINT1("MmAllocPage(): Out of memory\n");
782 KeReleaseSpinLock(&PageListLock, oldIrql);
783 return((PHYSICAL_ADDRESS)0LL);
785 ListEntry = RemoveTailList(&FreeUnzeroedPageListHead);
787 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
788 KeReleaseSpinLock(&PageListLock, oldIrql);
794 ListEntry = RemoveTailList(&FreeZeroedPageListHead);
795 KeReleaseSpinLock(&PageListLock, oldIrql);
797 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
800 if (PageDescriptor->Flags != MM_PHYSICAL_PAGE_FREE)
802 DbgPrint("Got non-free page from freelist\n");
805 PageDescriptor->Flags = MM_PHYSICAL_PAGE_USED;
806 PageDescriptor->ReferenceCount = 1;
807 PageDescriptor->LockCount = 0;
808 PageDescriptor->MapCount = 0;
809 PageDescriptor->SavedSwapEntry = SavedSwapEntry;
810 ExInterlockedInsertTailList(&UsedPageListHeads[Consumer], ListEntry,
813 MmStats.NrSystemPages++;
814 MmStats.NrFreePages--;
816 PageOffset.QuadPart = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
817 PageOffset.QuadPart =
818 (PageOffset.QuadPart / sizeof(PHYSICAL_PAGE)) * PAGE_SIZE;
821 MiZeroPage(PageOffset);