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 MmZeroPageThreadMain
,
1007 if (!NT_SUCCESS(Status
))
1013 NtSetInformationThread(ZeroPageThreadHandle
,
1018 return(STATUS_SUCCESS
);