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
);