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
/ PAGESIZE
;
58 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
59 RemoveEntryList(&MmPageArray
[Start
].ListEntry
);
60 InsertTailList(&UsedPageListHeads
[NewConsumer
],
61 &MmPageArray
[Start
].ListEntry
);
62 KeReleaseSpinLock(&PageListLock
, oldIrql
);
66 MmGetLRUFirstUserPage(VOID
)
68 PLIST_ENTRY NextListEntry
;
69 PHYSICAL_ADDRESS Next
;
70 PHYSICAL_PAGE
* PageDescriptor
;
73 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
74 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
75 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
77 KeReleaseSpinLock(&PageListLock
, oldIrql
);
78 return((LARGE_INTEGER
)0LL);
80 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
81 Next
.QuadPart
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
82 Next
.QuadPart
= (Next
.QuadPart
/ sizeof(PHYSICAL_PAGE
)) * PAGESIZE
;
83 KeReleaseSpinLock(&PageListLock
, oldIrql
);
88 MmGetLRUNextUserPage(PHYSICAL_ADDRESS PreviousPhysicalAddress
)
90 ULONG Start
= PreviousPhysicalAddress
.u
.LowPart
/ PAGESIZE
;
91 PLIST_ENTRY NextListEntry
;
92 PHYSICAL_ADDRESS Next
;
93 PHYSICAL_PAGE
* PageDescriptor
;
96 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
97 if (!(MmPageArray
[Start
].Flags
& MM_PHYSICAL_PAGE_USED
))
99 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
103 NextListEntry
= MmPageArray
[Start
].ListEntry
.Flink
;
105 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
107 KeReleaseSpinLock(&PageListLock
, oldIrql
);
108 return((LARGE_INTEGER
)0LL);
110 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
111 Next
.QuadPart
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
112 Next
.QuadPart
= (Next
.QuadPart
/ sizeof(PHYSICAL_PAGE
)) * PAGESIZE
;
113 KeReleaseSpinLock(&PageListLock
, oldIrql
);
118 MmGetContinuousPages(ULONG NumberOfBytes
,
119 PHYSICAL_ADDRESS HighestAcceptableAddress
,
128 NrPages
= PAGE_ROUND_UP(NumberOfBytes
) / PAGESIZE
;
130 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
134 for (i
= 0; i
< (HighestAcceptableAddress
.QuadPart
/ PAGESIZE
); )
136 if (MM_PTYPE(MmPageArray
[i
].Flags
) == MM_PHYSICAL_PAGE_FREE
)
148 if (length
== NrPages
)
157 * Fast forward to the base of the next aligned region
159 i
= ROUND_UP((i
+ 1), (Alignment
/ PAGESIZE
));
162 if (start
== -1 || length
!= NrPages
)
164 KeReleaseSpinLock(&PageListLock
, oldIrql
);
165 return((LARGE_INTEGER
)(LONGLONG
)0);
167 for (i
= start
; i
< (start
+ length
); i
++)
169 RemoveEntryList(&MmPageArray
[i
].ListEntry
);
170 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_USED
;
171 MmPageArray
[i
].ReferenceCount
= 1;
172 MmPageArray
[i
].LockCount
= 0;
173 MmPageArray
[i
].MapCount
= 0;
174 MmPageArray
[i
].SavedSwapEntry
= 0;
175 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
176 &MmPageArray
[i
].ListEntry
);
178 KeReleaseSpinLock(&PageListLock
, oldIrql
);
179 return((LARGE_INTEGER
)((LONGLONG
)start
* 4096));
183 MiParseRangeToFreeList(PADDRESS_RANGE Range
)
185 ULONG i
, first
, last
;
187 /* FIXME: Not 64-bit ready */
189 DPRINT("Range going to free list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
194 first
= (Range
->BaseAddrLow
+ PAGESIZE
- 1) / PAGESIZE
;
195 last
= first
+ ((Range
->LengthLow
+ PAGESIZE
- 1) / PAGESIZE
);
196 for (i
= first
; i
< last
; i
++)
198 if (MmPageArray
[i
].Flags
== 0)
200 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
201 MmPageArray
[i
].ReferenceCount
= 0;
202 InsertTailList(&FreeUnzeroedPageListHead
,
203 &MmPageArray
[i
].ListEntry
);
209 MiParseRangeToBiosList(PADDRESS_RANGE Range
)
211 ULONG i
, first
, last
;
213 /* FIXME: Not 64-bit ready */
215 DPRINT("Range going to bios list (Base 0x%X, Length 0x%X, Type 0x%X)\n",
220 first
= (Range
->BaseAddrLow
+ PAGESIZE
- 1) / PAGESIZE
;
221 last
= first
+ ((Range
->LengthLow
+ PAGESIZE
- 1) / PAGESIZE
);
222 for (i
= first
; i
< last
; i
++)
224 /* Remove the page from the free list if it is there */
225 if (MmPageArray
[i
].Flags
== MM_PHYSICAL_PAGE_FREE
)
227 RemoveEntryList(&MmPageArray
[i
].ListEntry
);
230 if (MmPageArray
[i
].Flags
!= MM_PHYSICAL_PAGE_BIOS
)
232 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_BIOS
;
233 MmPageArray
[i
].ReferenceCount
= 1;
234 InsertTailList(&BiosPageListHead
,
235 &MmPageArray
[i
].ListEntry
);
241 MiParseBIOSMemoryMap(ULONG MemorySizeInPages
,
242 PADDRESS_RANGE BIOSMemoryMap
,
243 ULONG AddressRangeCount
)
249 for (i
= 0; i
< AddressRangeCount
; i
++)
251 if (((p
->BaseAddrLow
+ PAGESIZE
- 1) / PAGESIZE
) < MemorySizeInPages
)
255 MiParseRangeToFreeList(p
);
259 MiParseRangeToBiosList(p
);
267 MmInitializePageList(PVOID FirstPhysKernelAddress
,
268 PVOID LastPhysKernelAddress
,
269 ULONG MemorySizeInPages
,
270 ULONG LastKernelAddress
,
271 PADDRESS_RANGE BIOSMemoryMap
,
272 ULONG AddressRangeCount
)
274 * FUNCTION: Initializes the page list with all pages free
275 * except those known to be reserved and those used by the kernel
277 * PageBuffer = Page sized buffer
278 * FirstKernelAddress = First physical address used by the kernel
279 * LastKernelAddress = Last physical address used by the kernel
286 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
287 "LastPhysKernelAddress %x, "
288 "MemorySizeInPages %x, LastKernelAddress %x)\n",
289 FirstPhysKernelAddress
,
290 LastPhysKernelAddress
,
294 for (i
= 0; i
< MC_MAXIMUM
; i
++)
296 InitializeListHead(&UsedPageListHeads
[i
]);
298 KeInitializeSpinLock(&PageListLock
);
299 InitializeListHead(&FreeUnzeroedPageListHead
);
300 InitializeListHead(&FreeZeroedPageListHead
);
301 InitializeListHead(&BiosPageListHead
);
303 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
306 PAGE_ROUND_UP((MemorySizeInPages
* sizeof(PHYSICAL_PAGE
))) / PAGESIZE
;
307 MmPageArray
= (PHYSICAL_PAGE
*)LastKernelAddress
;
309 DPRINT("Reserved %d\n", Reserved
);
311 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
312 LastKernelAddress
= ((ULONG
)LastKernelAddress
+ (Reserved
* PAGESIZE
));
313 LastPhysKernelAddress
= (PVOID
)PAGE_ROUND_UP(LastPhysKernelAddress
);
314 LastPhysKernelAddress
= LastPhysKernelAddress
+ (Reserved
* PAGESIZE
);
316 MmStats
.NrTotalPages
= 0;
317 MmStats
.NrSystemPages
= 0;
318 MmStats
.NrUserPages
= 0;
319 MmStats
.NrReservedPages
= 0;
320 MmStats
.NrFreePages
= 0;
321 MmStats
.NrLockedPages
= 0;
323 for (i
= 0; i
< Reserved
; i
++)
325 PVOID Address
= (PVOID
)(ULONG
)MmPageArray
+ (i
* PAGESIZE
);
326 if (!MmIsPagePresent(NULL
, Address
))
328 ULONG PhysicalAddress
;
329 PhysicalAddress
= (ULONG
)LastPhysKernelAddress
-
330 (Reserved
* PAGESIZE
) + (i
* PAGESIZE
);
332 MmCreateVirtualMappingUnsafe(NULL
,
335 (PHYSICAL_ADDRESS
)(LONGLONG
)PhysicalAddress
,
337 if (!NT_SUCCESS(Status
))
339 DbgPrint("Unable to create virtual mapping\n");
343 memset((PVOID
)MmPageArray
+ (i
* PAGESIZE
), 0, PAGESIZE
);
347 * Page zero is reserved
349 MmPageArray
[0].Flags
= MM_PHYSICAL_PAGE_BIOS
;
350 MmPageArray
[0].ReferenceCount
= 0;
351 InsertTailList(&BiosPageListHead
,
352 &MmPageArray
[0].ListEntry
);
355 * Page one is reserved for the initial KPCR
357 MmPageArray
[1].Flags
= MM_PHYSICAL_PAGE_BIOS
;
358 MmPageArray
[1].ReferenceCount
= 0;
359 InsertTailList(&BiosPageListHead
,
360 &MmPageArray
[1].ListEntry
);
363 if ((ULONG
)FirstPhysKernelAddress
< 0xa0000)
365 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGESIZE
) - 1);
366 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
368 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
369 MmPageArray
[i
].ReferenceCount
= 0;
370 InsertTailList(&FreeUnzeroedPageListHead
,
371 &MmPageArray
[i
].ListEntry
);
373 MmStats
.NrSystemPages
+=
374 ((((ULONG
)LastPhysKernelAddress
) / PAGESIZE
) - i
);
375 for (; i
<((ULONG
)LastPhysKernelAddress
/ PAGESIZE
); i
++)
377 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_USED
;
378 MmPageArray
[i
].ReferenceCount
= 1;
379 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
380 &MmPageArray
[i
].ListEntry
);
382 MmStats
.NrFreePages
+= ((0xa0000/PAGESIZE
) - i
);
383 for (; i
<(0xa0000/PAGESIZE
); i
++)
385 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
386 MmPageArray
[i
].ReferenceCount
= 0;
387 InsertTailList(&FreeUnzeroedPageListHead
,
388 &MmPageArray
[i
].ListEntry
);
390 MmStats
.NrReservedPages
+= ((0x100000/PAGESIZE
) - i
);
391 for (; i
<(0x100000 / PAGESIZE
); i
++)
393 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_BIOS
;
394 MmPageArray
[i
].ReferenceCount
= 1;
395 InsertTailList(&BiosPageListHead
,
396 &MmPageArray
[i
].ListEntry
);
401 MmStats
.NrFreePages
+= ((0xa0000 / PAGESIZE
) - 1);
402 for (; i
<(0xa0000 / PAGESIZE
); i
++)
404 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
405 MmPageArray
[i
].ReferenceCount
= 0;
406 InsertTailList(&FreeUnzeroedPageListHead
,
407 &MmPageArray
[i
].ListEntry
);
409 MmStats
.NrReservedPages
+= (0x60000 / PAGESIZE
);
410 for (; i
<(0x100000 / PAGESIZE
); i
++)
412 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_BIOS
;
413 MmPageArray
[i
].ReferenceCount
= 1;
414 InsertTailList(&BiosPageListHead
,
415 &MmPageArray
[i
].ListEntry
);
417 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGESIZE
) - i
);
418 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
420 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
421 MmPageArray
[i
].ReferenceCount
= 0;
422 InsertTailList(&FreeUnzeroedPageListHead
,
423 &MmPageArray
[i
].ListEntry
);
425 MmStats
.NrSystemPages
+=
426 (((ULONG
)LastPhysKernelAddress
/PAGESIZE
) - i
);
427 for (; i
<((ULONG
)LastPhysKernelAddress
/PAGESIZE
); i
++)
429 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_USED
;
430 MmPageArray
[i
].ReferenceCount
= 1;
431 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
432 &MmPageArray
[i
].ListEntry
);
436 MmStats
.NrFreePages
+= (MemorySizeInPages
- i
);
437 for (; i
<MemorySizeInPages
; i
++)
439 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
440 MmPageArray
[i
].ReferenceCount
= 0;
441 InsertTailList(&FreeUnzeroedPageListHead
,
442 &MmPageArray
[i
].ListEntry
);
445 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
447 MiParseBIOSMemoryMap(
453 MmStats
.NrTotalPages
= MmStats
.NrFreePages
+ MmStats
.NrSystemPages
+
454 MmStats
.NrReservedPages
+ MmStats
.NrUserPages
;
455 MmInitializeBalancer(MmStats
.NrFreePages
);
456 return((PVOID
)LastKernelAddress
);
460 MmSetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress
, ULONG Flags
)
462 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
465 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
466 MmPageArray
[Start
].Flags
= Flags
;
467 KeReleaseSpinLock(&PageListLock
, oldIrql
);
471 MmSetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress
,
472 struct _MM_RMAP_ENTRY
* ListHead
)
474 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
476 MmPageArray
[Start
].RmapListHead
= ListHead
;
479 struct _MM_RMAP_ENTRY
*
480 MmGetRmapListHeadPage(PHYSICAL_ADDRESS PhysicalAddress
)
482 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
484 return(MmPageArray
[Start
].RmapListHead
);
488 MmMarkPageMapped(PHYSICAL_ADDRESS PhysicalAddress
)
490 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
493 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
494 MmPageArray
[Start
].MapCount
++;
495 KeReleaseSpinLock(&PageListLock
, oldIrql
);
499 MmMarkPageUnmapped(PHYSICAL_ADDRESS PhysicalAddress
)
501 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
504 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
505 MmPageArray
[Start
].MapCount
--;
506 KeReleaseSpinLock(&PageListLock
, oldIrql
);
510 MmGetFlagsPage(PHYSICAL_ADDRESS PhysicalAddress
)
512 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
516 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
517 Flags
= MmPageArray
[Start
].Flags
;
518 KeReleaseSpinLock(&PageListLock
, oldIrql
);
525 MmSetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress
,
526 SWAPENTRY SavedSwapEntry
)
528 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
531 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
532 MmPageArray
[Start
].SavedSwapEntry
= SavedSwapEntry
;
533 KeReleaseSpinLock(&PageListLock
, oldIrql
);
537 MmGetSavedSwapEntryPage(PHYSICAL_ADDRESS PhysicalAddress
)
539 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
540 SWAPENTRY SavedSwapEntry
;
543 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
544 SavedSwapEntry
= MmPageArray
[Start
].SavedSwapEntry
;
545 KeReleaseSpinLock(&PageListLock
, oldIrql
);
547 return(SavedSwapEntry
);
551 MmReferencePage(PHYSICAL_ADDRESS PhysicalAddress
)
553 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
556 DPRINT("MmReferencePage(PhysicalAddress %x)\n", PhysicalAddress
);
558 if (PhysicalAddress
.u
.LowPart
== 0)
563 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
565 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
567 DbgPrint("Referencing non-used page\n");
571 MmPageArray
[Start
].ReferenceCount
++;
572 KeReleaseSpinLock(&PageListLock
, oldIrql
);
576 MmGetReferenceCountPage(PHYSICAL_ADDRESS PhysicalAddress
)
578 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
582 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
584 if (PhysicalAddress
.u
.LowPart
== 0)
589 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
591 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
593 DbgPrint("Getting reference count for free page\n");
597 RCount
= MmPageArray
[Start
].ReferenceCount
;
599 KeReleaseSpinLock(&PageListLock
, oldIrql
);
604 MmIsUsablePage(PHYSICAL_ADDRESS PhysicalAddress
)
606 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
608 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
610 if (PhysicalAddress
.u
.LowPart
== 0)
615 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
&&
616 MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_BIOS
)
625 MmDereferencePage(PHYSICAL_ADDRESS PhysicalAddress
)
627 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
630 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", PhysicalAddress
);
632 if (PhysicalAddress
.u
.LowPart
== 0)
637 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
640 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
642 DbgPrint("Dereferencing free page\n");
646 MmPageArray
[Start
].ReferenceCount
--;
647 if (MmPageArray
[Start
].ReferenceCount
== 0)
649 MmStats
.NrFreePages
++;
650 MmStats
.NrSystemPages
--;
651 RemoveEntryList(&MmPageArray
[Start
].ListEntry
);
652 if (MmPageArray
[Start
].RmapListHead
!= NULL
)
654 DbgPrint("Freeing page with rmap entries.\n");
657 if (MmPageArray
[Start
].MapCount
!= 0)
659 DbgPrint("Freeing mapped page (0x%x count %d)\n",
660 PhysicalAddress
, MmPageArray
[Start
].MapCount
);
663 if (MmPageArray
[Start
].LockCount
> 0)
665 DbgPrint("Freeing locked page\n");
668 if (MmPageArray
[Start
].SavedSwapEntry
!= 0)
670 DbgPrint("Freeing page with swap entry.\n");
673 if (MmPageArray
[Start
].Flags
!= MM_PHYSICAL_PAGE_USED
)
675 DbgPrint("Freeing page with flags %x\n",
676 MmPageArray
[Start
].Flags
);
679 MmPageArray
[Start
].Flags
= MM_PHYSICAL_PAGE_FREE
;
680 InsertTailList(&FreeUnzeroedPageListHead
,
681 &MmPageArray
[Start
].ListEntry
);
683 KeReleaseSpinLock(&PageListLock
, oldIrql
);
687 MmGetLockCountPage(PHYSICAL_ADDRESS PhysicalAddress
)
689 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
693 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
695 if (PhysicalAddress
.u
.LowPart
== 0)
700 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
702 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
704 DbgPrint("Getting lock count for free page\n");
708 LockCount
= MmPageArray
[Start
].LockCount
;
709 KeReleaseSpinLock(&PageListLock
, oldIrql
);
715 MmLockPage(PHYSICAL_ADDRESS PhysicalAddress
)
717 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
720 DPRINT("MmLockPage(PhysicalAddress %x)\n", PhysicalAddress
);
722 if (PhysicalAddress
.u
.LowPart
== 0)
727 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
729 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
731 DbgPrint("Locking free page\n");
735 MmPageArray
[Start
].LockCount
++;
736 KeReleaseSpinLock(&PageListLock
, oldIrql
);
740 MmUnlockPage(PHYSICAL_ADDRESS PhysicalAddress
)
742 ULONG Start
= PhysicalAddress
.u
.LowPart
/ PAGESIZE
;
745 DPRINT("MmUnlockPage(PhysicalAddress %llx)\n", PhysicalAddress
);
747 if (PhysicalAddress
.u
.LowPart
== 0)
752 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
754 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
756 DbgPrint("Unlocking free page\n");
760 MmPageArray
[Start
].LockCount
--;
761 KeReleaseSpinLock(&PageListLock
, oldIrql
);
765 MmAllocPage(ULONG Consumer
, SWAPENTRY SavedSwapEntry
)
767 PHYSICAL_ADDRESS PageOffset
;
768 PLIST_ENTRY ListEntry
;
769 PPHYSICAL_PAGE PageDescriptor
;
771 BOOLEAN NeedClear
= FALSE
;
773 DPRINT("MmAllocPage()\n");
775 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
776 if (IsListEmpty(&FreeZeroedPageListHead
))
778 if (IsListEmpty(&FreeUnzeroedPageListHead
))
780 DPRINT1("MmAllocPage(): Out of memory\n");
781 KeReleaseSpinLock(&PageListLock
, oldIrql
);
782 return((PHYSICAL_ADDRESS
)0LL);
784 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
786 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
787 KeReleaseSpinLock(&PageListLock
, oldIrql
);
793 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
794 KeReleaseSpinLock(&PageListLock
, oldIrql
);
796 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
799 if (PageDescriptor
->Flags
!= MM_PHYSICAL_PAGE_FREE
)
801 DbgPrint("Got non-free page from freelist\n");
804 PageDescriptor
->Flags
= MM_PHYSICAL_PAGE_USED
;
805 PageDescriptor
->ReferenceCount
= 1;
806 PageDescriptor
->LockCount
= 0;
807 PageDescriptor
->MapCount
= 0;
808 PageDescriptor
->SavedSwapEntry
= SavedSwapEntry
;
809 ExInterlockedInsertTailList(&UsedPageListHeads
[Consumer
], ListEntry
,
812 MmStats
.NrSystemPages
++;
813 MmStats
.NrFreePages
--;
815 PageOffset
.QuadPart
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
816 PageOffset
.QuadPart
=
817 (PageOffset
.QuadPart
/ sizeof(PHYSICAL_PAGE
)) * PAGESIZE
;
820 MiZeroPage(PageOffset
);