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(PVOID PhysicalAddress
, ULONG NewConsumer
)
55 ULONG Start
= (ULONG
)PhysicalAddress
/ 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
;
70 PHYSICAL_PAGE
* PageDescriptor
;
73 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
74 NextListEntry
= UsedPageListHeads
[MC_USER
].Flink
;
75 if (NextListEntry
== &UsedPageListHeads
[MC_USER
])
77 KeReleaseSpinLock(&PageListLock
, oldIrql
);
80 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
81 Next
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
82 Next
= (Next
/ sizeof(PHYSICAL_PAGE
)) * PAGESIZE
;
83 KeReleaseSpinLock(&PageListLock
, oldIrql
);
88 MmGetLRUNextUserPage(PVOID PreviousPhysicalAddress
)
90 ULONG Start
= (ULONG
)PreviousPhysicalAddress
/ PAGESIZE
;
91 PLIST_ENTRY NextListEntry
;
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
);
110 PageDescriptor
= CONTAINING_RECORD(NextListEntry
, PHYSICAL_PAGE
, ListEntry
);
111 Next
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
112 Next
= (Next
/ 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
);
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((PVOID
)(start
* 4096));
182 VOID
MiParseRangeToFreeList(
183 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
);
208 VOID
MiParseRangeToBiosList(
209 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
);
240 VOID
MiParseBIOSMemoryMap(
241 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 if (!MmIsPagePresent(NULL
,
326 (PVOID
)((ULONG
)MmPageArray
+ (i
* PAGESIZE
))))
329 MmCreateVirtualMappingUnsafe(NULL
,
330 (PVOID
)((ULONG
)MmPageArray
+
333 (ULONG
)(LastPhysKernelAddress
334 - (Reserved
* PAGESIZE
) + (i
* PAGESIZE
)),
336 if (!NT_SUCCESS(Status
))
338 DbgPrint("Unable to create virtual mapping\n");
342 memset((PVOID
)MmPageArray
+ (i
* PAGESIZE
), 0, PAGESIZE
);
346 * Page zero is reserved
348 MmPageArray
[0].Flags
= MM_PHYSICAL_PAGE_BIOS
;
349 MmPageArray
[0].ReferenceCount
= 0;
350 InsertTailList(&BiosPageListHead
,
351 &MmPageArray
[0].ListEntry
);
354 * Page one is reserved for the initial KPCR
356 MmPageArray
[1].Flags
= MM_PHYSICAL_PAGE_BIOS
;
357 MmPageArray
[1].ReferenceCount
= 0;
358 InsertTailList(&BiosPageListHead
,
359 &MmPageArray
[1].ListEntry
);
362 if ((ULONG
)FirstPhysKernelAddress
< 0xa0000)
364 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGESIZE
) - 1);
365 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
367 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
368 MmPageArray
[i
].ReferenceCount
= 0;
369 InsertTailList(&FreeUnzeroedPageListHead
,
370 &MmPageArray
[i
].ListEntry
);
372 MmStats
.NrSystemPages
+=
373 ((((ULONG
)LastPhysKernelAddress
) / PAGESIZE
) - i
);
374 for (; i
<((ULONG
)LastPhysKernelAddress
/ PAGESIZE
); i
++)
376 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_USED
;
377 MmPageArray
[i
].ReferenceCount
= 1;
378 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
379 &MmPageArray
[i
].ListEntry
);
381 MmStats
.NrFreePages
+= ((0xa0000/PAGESIZE
) - i
);
382 for (; i
<(0xa0000/PAGESIZE
); i
++)
384 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
385 MmPageArray
[i
].ReferenceCount
= 0;
386 InsertTailList(&FreeUnzeroedPageListHead
,
387 &MmPageArray
[i
].ListEntry
);
389 MmStats
.NrReservedPages
+= ((0x100000/PAGESIZE
) - i
);
390 for (; i
<(0x100000 / PAGESIZE
); i
++)
392 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_BIOS
;
393 MmPageArray
[i
].ReferenceCount
= 1;
394 InsertTailList(&BiosPageListHead
,
395 &MmPageArray
[i
].ListEntry
);
400 MmStats
.NrFreePages
+= ((0xa0000 / PAGESIZE
) - 1);
401 for (; i
<(0xa0000 / PAGESIZE
); i
++)
403 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
404 MmPageArray
[i
].ReferenceCount
= 0;
405 InsertTailList(&FreeUnzeroedPageListHead
,
406 &MmPageArray
[i
].ListEntry
);
408 MmStats
.NrReservedPages
+= (0x60000 / PAGESIZE
);
409 for (; i
<(0x100000 / PAGESIZE
); i
++)
411 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_BIOS
;
412 MmPageArray
[i
].ReferenceCount
= 1;
413 InsertTailList(&BiosPageListHead
,
414 &MmPageArray
[i
].ListEntry
);
416 MmStats
.NrFreePages
+= (((ULONG
)FirstPhysKernelAddress
/PAGESIZE
) - i
);
417 for (; i
<((ULONG
)FirstPhysKernelAddress
/PAGESIZE
); i
++)
419 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
420 MmPageArray
[i
].ReferenceCount
= 0;
421 InsertTailList(&FreeUnzeroedPageListHead
,
422 &MmPageArray
[i
].ListEntry
);
424 MmStats
.NrSystemPages
+=
425 (((ULONG
)LastPhysKernelAddress
/PAGESIZE
) - i
);
426 for (; i
<((ULONG
)LastPhysKernelAddress
/PAGESIZE
); i
++)
428 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_USED
;
429 MmPageArray
[i
].ReferenceCount
= 1;
430 InsertTailList(&UsedPageListHeads
[MC_NPPOOL
],
431 &MmPageArray
[i
].ListEntry
);
435 MmStats
.NrFreePages
+= (MemorySizeInPages
- i
);
436 for (; i
<MemorySizeInPages
; i
++)
438 MmPageArray
[i
].Flags
= MM_PHYSICAL_PAGE_FREE
;
439 MmPageArray
[i
].ReferenceCount
= 0;
440 InsertTailList(&FreeUnzeroedPageListHead
,
441 &MmPageArray
[i
].ListEntry
);
444 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
446 MiParseBIOSMemoryMap(
452 MmStats
.NrTotalPages
= MmStats
.NrFreePages
+ MmStats
.NrSystemPages
+
453 MmStats
.NrReservedPages
+ MmStats
.NrUserPages
;
454 MmInitializeBalancer(MmStats
.NrFreePages
);
455 return((PVOID
)LastKernelAddress
);
458 VOID
MmSetFlagsPage(PVOID PhysicalAddress
,
461 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
464 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
465 MmPageArray
[Start
].Flags
= Flags
;
466 KeReleaseSpinLock(&PageListLock
, oldIrql
);
470 MmSetRmapListHeadPage(PVOID PhysicalAddress
, struct _MM_RMAP_ENTRY
* ListHead
)
472 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
474 MmPageArray
[Start
].RmapListHead
= ListHead
;
477 struct _MM_RMAP_ENTRY
*
478 MmGetRmapListHeadPage(PVOID PhysicalAddress
)
480 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
482 return(MmPageArray
[Start
].RmapListHead
);
486 MmMarkPageMapped(PVOID PhysicalAddress
)
488 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
491 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
492 MmPageArray
[Start
].MapCount
++;
493 KeReleaseSpinLock(&PageListLock
, oldIrql
);
497 MmMarkPageUnmapped(PVOID PhysicalAddress
)
499 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
502 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
503 MmPageArray
[Start
].MapCount
--;
504 KeReleaseSpinLock(&PageListLock
, oldIrql
);
507 ULONG
MmGetFlagsPage(PVOID PhysicalAddress
)
509 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
513 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
514 Flags
= MmPageArray
[Start
].Flags
;
515 KeReleaseSpinLock(&PageListLock
, oldIrql
);
521 VOID
MmSetSavedSwapEntryPage(PVOID PhysicalAddress
,
522 SWAPENTRY SavedSwapEntry
)
524 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
527 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
528 MmPageArray
[Start
].SavedSwapEntry
= SavedSwapEntry
;
529 KeReleaseSpinLock(&PageListLock
, oldIrql
);
533 MmGetSavedSwapEntryPage(PVOID PhysicalAddress
)
535 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
536 SWAPENTRY SavedSwapEntry
;
539 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
540 SavedSwapEntry
= MmPageArray
[Start
].SavedSwapEntry
;
541 KeReleaseSpinLock(&PageListLock
, oldIrql
);
543 return(SavedSwapEntry
);
546 VOID
MmReferencePage(PVOID PhysicalAddress
)
548 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
551 DPRINT("MmReferencePage(PhysicalAddress %x)\n", PhysicalAddress
);
553 if (((ULONG
)PhysicalAddress
) == 0)
558 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
560 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
562 DbgPrint("Referencing non-used page\n");
566 MmPageArray
[Start
].ReferenceCount
++;
567 KeReleaseSpinLock(&PageListLock
, oldIrql
);
571 MmGetReferenceCountPage(PVOID PhysicalAddress
)
573 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
577 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
579 if (((ULONG
)PhysicalAddress
) == 0)
584 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
586 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
588 DbgPrint("Getting reference count for free page\n");
592 RCount
= MmPageArray
[Start
].ReferenceCount
;
594 KeReleaseSpinLock(&PageListLock
, oldIrql
);
599 MmIsUsablePage(PVOID PhysicalAddress
)
601 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
603 DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
605 if (((ULONG
)PhysicalAddress
) == 0)
610 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
&&
611 MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_BIOS
)
620 VOID
MmDereferencePage(PVOID PhysicalAddress
)
622 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
625 DPRINT("MmDereferencePage(PhysicalAddress %x)\n", PhysicalAddress
);
627 if (((ULONG
)PhysicalAddress
) == 0)
632 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
635 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
637 DbgPrint("Dereferencing free page\n");
641 MmPageArray
[Start
].ReferenceCount
--;
642 if (MmPageArray
[Start
].ReferenceCount
== 0)
644 MmStats
.NrFreePages
++;
645 MmStats
.NrSystemPages
--;
646 RemoveEntryList(&MmPageArray
[Start
].ListEntry
);
647 if (MmPageArray
[Start
].RmapListHead
!= NULL
)
649 DbgPrint("Freeing page with rmap entries.\n");
652 if (MmPageArray
[Start
].MapCount
!= 0)
654 DbgPrint("Freeing mapped page (0x%x count %d)\n",
655 PhysicalAddress
, MmPageArray
[Start
].MapCount
);
658 if (MmPageArray
[Start
].LockCount
> 0)
660 DbgPrint("Freeing locked page\n");
663 if (MmPageArray
[Start
].SavedSwapEntry
!= 0)
665 DbgPrint("Freeing page with swap entry.\n");
668 if (MmPageArray
[Start
].Flags
!= MM_PHYSICAL_PAGE_USED
)
670 DbgPrint("Freeing page with flags %x\n",
671 MmPageArray
[Start
].Flags
);
674 MmPageArray
[Start
].Flags
= MM_PHYSICAL_PAGE_FREE
;
675 InsertTailList(&FreeUnzeroedPageListHead
,
676 &MmPageArray
[Start
].ListEntry
);
678 KeReleaseSpinLock(&PageListLock
, oldIrql
);
681 ULONG
MmGetLockCountPage(PVOID PhysicalAddress
)
683 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
687 DPRINT("MmGetLockCountPage(PhysicalAddress %x)\n", PhysicalAddress
);
689 if (((ULONG
)PhysicalAddress
) == 0)
694 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
696 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
698 DbgPrint("Getting lock count for free page\n");
702 LockCount
= MmPageArray
[Start
].LockCount
;
703 KeReleaseSpinLock(&PageListLock
, oldIrql
);
708 VOID
MmLockPage(PVOID PhysicalAddress
)
710 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
713 DPRINT("MmLockPage(PhysicalAddress %x)\n", PhysicalAddress
);
715 if (((ULONG
)PhysicalAddress
) == 0)
720 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
722 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
724 DbgPrint("Locking free page\n");
728 MmPageArray
[Start
].LockCount
++;
729 KeReleaseSpinLock(&PageListLock
, oldIrql
);
732 VOID
MmUnlockPage(PVOID PhysicalAddress
)
734 ULONG Start
= (ULONG
)PhysicalAddress
/ PAGESIZE
;
737 DPRINT("MmUnlockPage(PhysicalAddress %x)\n", PhysicalAddress
);
739 if (((ULONG
)PhysicalAddress
) == 0)
744 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
746 if (MM_PTYPE(MmPageArray
[Start
].Flags
) != MM_PHYSICAL_PAGE_USED
)
748 DbgPrint("Unlocking free page\n");
752 MmPageArray
[Start
].LockCount
--;
753 KeReleaseSpinLock(&PageListLock
, oldIrql
);
758 MmAllocPage(ULONG Consumer
, SWAPENTRY SavedSwapEntry
)
761 PLIST_ENTRY ListEntry
;
762 PPHYSICAL_PAGE PageDescriptor
;
764 BOOLEAN NeedClear
= FALSE
;
766 if (SavedSwapEntry
== 0x17)
771 DPRINT("MmAllocPage()\n");
773 KeAcquireSpinLock(&PageListLock
, &oldIrql
);
774 if (IsListEmpty(&FreeZeroedPageListHead
))
776 if (IsListEmpty(&FreeUnzeroedPageListHead
))
778 DPRINT1("MmAllocPage(): Out of memory\n");
779 KeReleaseSpinLock(&PageListLock
, oldIrql
);
782 ListEntry
= RemoveTailList(&FreeUnzeroedPageListHead
);
784 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
785 KeReleaseSpinLock(&PageListLock
, oldIrql
);
791 ListEntry
= RemoveTailList(&FreeZeroedPageListHead
);
792 KeReleaseSpinLock(&PageListLock
, oldIrql
);
794 PageDescriptor
= CONTAINING_RECORD(ListEntry
, PHYSICAL_PAGE
, ListEntry
);
797 if (PageDescriptor
->Flags
!= MM_PHYSICAL_PAGE_FREE
)
799 DbgPrint("Got non-free page from freelist\n");
802 PageDescriptor
->Flags
= MM_PHYSICAL_PAGE_USED
;
803 PageDescriptor
->ReferenceCount
= 1;
804 PageDescriptor
->LockCount
= 0;
805 PageDescriptor
->MapCount
= 0;
806 PageDescriptor
->SavedSwapEntry
= SavedSwapEntry
;
807 ExInterlockedInsertTailList(&UsedPageListHeads
[Consumer
], ListEntry
,
810 MmStats
.NrSystemPages
++;
811 MmStats
.NrFreePages
--;
813 offset
= (ULONG
)((ULONG
)PageDescriptor
- (ULONG
)MmPageArray
);
814 offset
= (offset
/ sizeof(PHYSICAL_PAGE
)) * PAGESIZE
;
819 DPRINT("MmAllocPage() = %x\n",offset
);
820 return((PVOID
)offset
);