2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/pfnlist.c
5 * PURPOSE: ARM Memory Manager PFN List Manipulation
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::PFNLIST"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 #define ASSERT_LIST_INVARIANT(x) \
21 ASSERT(((x)->Total == 0 && \
22 (x)->Flink == LIST_HEAD && \
23 (x)->Blink == LIST_HEAD) || \
25 (x)->Flink != LIST_HEAD && \
26 (x)->Blink != LIST_HEAD)); \
29 /* GLOBALS ********************************************************************/
34 MMPFNLIST MmZeroedPageListHead
= {0, ZeroedPageList
, LIST_HEAD
, LIST_HEAD
};
35 MMPFNLIST MmFreePageListHead
= {0, FreePageList
, LIST_HEAD
, LIST_HEAD
};
36 MMPFNLIST MmStandbyPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
37 MMPFNLIST MmModifiedPageListHead
= {0, ModifiedPageList
, LIST_HEAD
, LIST_HEAD
};
38 MMPFNLIST MmModifiedNoWritePageListHead
= {0, ModifiedNoWritePageList
, LIST_HEAD
, LIST_HEAD
};
39 MMPFNLIST MmBadPageListHead
= {0, BadPageList
, LIST_HEAD
, LIST_HEAD
};
40 MMPFNLIST MmRomPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
42 PMMPFNLIST MmPageLocationList
[] =
44 &MmZeroedPageListHead
,
46 &MmStandbyPageListHead
,
47 &MmModifiedPageListHead
,
48 &MmModifiedNoWritePageListHead
,
53 /* FUNCTIONS ******************************************************************/
57 MiInsertInListTail(IN PMMPFNLIST ListHead
,
60 PFN_NUMBER OldBlink
, EntryIndex
= MiGetPfnEntryIndex(Entry
);
62 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
63 ASSERT_LIST_INVARIANT(ListHead
);
65 /* Get the back link */
66 OldBlink
= ListHead
->Blink
;
67 if (OldBlink
!= LIST_HEAD
)
69 /* Set the back pointer to point to us now */
70 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
74 /* Set the list to point to us */
75 ListHead
->Flink
= EntryIndex
;
78 /* Set the entry to point to the list head forwards, and the old page backwards */
79 Entry
->u1
.Flink
= LIST_HEAD
;
80 Entry
->u2
.Blink
= OldBlink
;
82 /* And now the head points back to us, since we are last */
83 ListHead
->Blink
= EntryIndex
;
85 ASSERT_LIST_INVARIANT(ListHead
);
90 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex
)
98 PMMCOLOR_TABLES ColorHead
;
101 /* Make sure the PFN lock is held */
102 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
104 /* Get the descriptor */
105 Pfn1
= MiGetPfnEntry(EntryIndex
);
106 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
107 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
108 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
109 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
110 ASSERT(Pfn1
->u4
.InPageError
== 0);
112 /* Use the zero list */
113 ListHead
= &MmZeroedPageListHead
;
114 ASSERT_LIST_INVARIANT(ListHead
);
117 /* Get the back link */
118 OldBlink
= ListHead
->Blink
;
119 if (OldBlink
!= LIST_HEAD
)
121 /* Set the back pointer to point to us now */
122 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
126 /* Set the list to point to us */
127 ListHead
->Flink
= EntryIndex
;
130 /* Set the entry to point to the list head forwards, and the old page backwards */
131 Pfn1
->u1
.Flink
= LIST_HEAD
;
132 Pfn1
->u2
.Blink
= OldBlink
;
134 /* And now the head points back to us, since we are last */
135 ListHead
->Blink
= EntryIndex
;
137 /* Update the page location */
138 Pfn1
->u3
.e1
.PageLocation
= ZeroedPageList
;
140 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
141 //MmAvailablePages++;
143 /* Check if we've reached the configured low memory threshold */
144 if (MmAvailablePages
== MmLowMemoryThreshold
)
146 /* Clear the event, because now we're ABOVE the threshold */
147 KeClearEvent(MiLowMemoryEvent
);
149 else if (MmAvailablePages
== MmHighMemoryThreshold
)
151 /* Otherwise check if we reached the high threshold and signal the event */
152 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
155 ASSERT_LIST_INVARIANT(ListHead
);
158 /* Get the page color */
159 Color
= EntryIndex
& MmSecondaryColorMask
;
161 /* Get the first page on the color list */
162 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
163 if (ColorHead
->Flink
== LIST_HEAD
)
165 /* The list is empty, so we are the first page */
166 Pfn1
->u4
.PteFrame
= -1;
167 ColorHead
->Flink
= EntryIndex
;
171 /* Get the previous page */
172 Blink
= (PMMPFN
)ColorHead
->Blink
;
174 /* Make it link to us */
175 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
176 Blink
->OriginalPte
.u
.Long
= EntryIndex
;
179 /* Now initialize our own list pointers */
180 ColorHead
->Blink
= Pfn1
;
181 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
183 /* And increase the count in the colored list */
190 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
192 PFN_NUMBER OldFlink
, OldBlink
;
196 /* Make sure the PFN lock is held */
197 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
199 /* Make sure the PFN entry isn't in-use */
200 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
201 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
203 /* Find the list for this entry, make sure it's the free or zero list */
204 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
205 ListName
= ListHead
->ListName
;
206 ASSERT(ListHead
!= NULL
);
207 ASSERT(ListName
<= FreePageList
);
208 ASSERT_LIST_INVARIANT(ListHead
);
210 /* Remove one count */
211 ASSERT(ListHead
->Total
!= 0);
214 /* Get the forward and back pointers */
215 OldFlink
= Entry
->u1
.Flink
;
216 OldBlink
= Entry
->u2
.Blink
;
218 /* Check if the next entry is the list head */
219 if (OldFlink
!= LIST_HEAD
)
221 /* It is not, so set the backlink of the actual entry, to our backlink */
222 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
226 /* Set the list head's backlink instead */
227 ListHead
->Blink
= OldBlink
;
230 /* Check if the back entry is the list head */
231 if (OldBlink
!= LIST_HEAD
)
233 /* It is not, so set the backlink of the actual entry, to our backlink */
234 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
238 /* Set the list head's backlink instead */
239 ListHead
->Flink
= OldFlink
;
242 /* We are not on a list anymore */
243 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
244 ASSERT_LIST_INVARIANT(ListHead
);
246 /* FIXME: Deal with color list */
248 /* See if we hit any thresholds */
249 if (MmAvailablePages
== MmHighMemoryThreshold
)
251 /* Clear the high memory event */
252 KeClearEvent(MiHighMemoryEvent
);
254 else if (MmAvailablePages
== MmLowMemoryThreshold
)
256 /* Signal the low memory event */
257 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
261 if (--MmAvailablePages
< MmMinimumFreePages
)
263 /* FIXME: Should wake up the MPW and working set manager, if we had one */
269 MiRemovePageByColor(IN PFN_NUMBER PageIndex
,
275 PFN_NUMBER OldFlink
, OldBlink
;
276 ULONG OldColor
, OldCache
;
278 PMMCOLOR_TABLES ColorTable
;
280 /* Make sure PFN lock is held */
281 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
282 ASSERT(Color
< MmSecondaryColors
);
284 /* Get the PFN entry */
285 Pfn1
= MiGetPfnEntry(PageIndex
);
286 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
287 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
289 /* Capture data for later */
290 OldColor
= Pfn1
->u3
.e1
.PageColor
;
291 OldCache
= Pfn1
->u3
.e1
.CacheAttribute
;
293 /* Could be either on free or zero list */
294 ListHead
= MmPageLocationList
[Pfn1
->u3
.e1
.PageLocation
];
295 ASSERT_LIST_INVARIANT(ListHead
);
296 ListName
= ListHead
->ListName
;
297 ASSERT(ListName
<= FreePageList
);
302 /* Get the forward and back pointers */
303 OldFlink
= Pfn1
->u1
.Flink
;
304 OldBlink
= Pfn1
->u2
.Blink
;
306 /* Check if the next entry is the list head */
307 if (OldFlink
!= LIST_HEAD
)
309 /* It is not, so set the backlink of the actual entry, to our backlink */
310 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
314 /* Set the list head's backlink instead */
315 ListHead
->Blink
= OldFlink
;
318 /* Check if the back entry is the list head */
319 if (OldBlink
!= LIST_HEAD
)
321 /* It is not, so set the backlink of the actual entry, to our backlink */
322 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
326 /* Set the list head's backlink instead */
327 ListHead
->Flink
= OldFlink
;
330 /* We are not on a list anymore */
331 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
333 /* Zero flags but restore color and cache */
334 Pfn1
->u3
.e2
.ShortFlags
= 0;
335 Pfn1
->u3
.e1
.PageColor
= OldColor
;
336 Pfn1
->u3
.e1
.CacheAttribute
= OldCache
;
338 ASSERT_LIST_INVARIANT(ListHead
);
340 #if 0 // When switching to ARM3
341 /* Get the first page on the color list */
342 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
343 ASSERT(ColorTable
->Count
>= 1);
345 /* Set the forward link to whoever we were pointing to */
346 ColorTable
->Flink
= Pfn1
->OriginalPte
.u
.Long
;
347 if (ColorTable
->Flink
== LIST_HEAD
)
349 /* This is the beginning of the list, so set the sentinel value */
350 ColorTable
->Blink
= LIST_HEAD
;
354 /* The list is empty, so we are the first page */
355 MiGetPfnEntry(ColorTable
->Flink
)->u4
.PteFrame
= -1;
361 /* See if we hit any thresholds */
362 if (MmAvailablePages
== MmHighMemoryThreshold
)
364 /* Clear the high memory event */
365 KeClearEvent(MiHighMemoryEvent
);
367 else if (MmAvailablePages
== MmLowMemoryThreshold
)
369 /* Signal the low memory event */
370 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
374 if (--MmAvailablePages
< MmMinimumFreePages
)
376 /* FIXME: Should wake up the MPW and working set manager, if we had one */
379 /* Return the page */
385 MiRemoveAnyPage(IN ULONG Color
)
387 PFN_NUMBER PageIndex
;
390 /* Make sure PFN lock is held and we have pages */
391 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
392 ASSERT(MmAvailablePages
!= 0);
393 ASSERT(Color
< MmSecondaryColors
);
395 /* Check the colored free list */
396 #if 0 // Enable when using ARM3 database */
397 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
398 if (PageIndex
== LIST_HEAD
)
400 /* Check the colored zero list */
401 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
402 if (PageIndex
== LIST_HEAD
)
405 /* Check the free list */
406 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
407 PageIndex
= MmFreePageListHead
.Flink
;
408 Color
= PageIndex
& MmSecondaryColorMask
;
409 if (PageIndex
== LIST_HEAD
)
411 /* Check the zero list */
412 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
413 PageIndex
= MmZeroedPageListHead
.Flink
;
414 Color
= PageIndex
& MmSecondaryColorMask
;
415 ASSERT(PageIndex
!= LIST_HEAD
);
416 if (PageIndex
== LIST_HEAD
)
418 /* FIXME: Should check the standby list */
419 ASSERT(MmZeroedPageListHead
.Total
== 0);
422 #if 0 // Enable when using ARM3 database */
427 /* Remove the page from its list */
428 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
431 Pfn1
= MiGetPfnEntry(PageIndex
);
432 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
433 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
434 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
435 ASSERT(Pfn1
->u2
.ShareCount
== 0);
437 /* Return the page */
438 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
439 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
446 MiRemoveHeadList(IN PMMPFNLIST ListHead
)
448 PFN_NUMBER Entry
, Flink
;
451 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
452 ASSERT_LIST_INVARIANT(ListHead
);
454 /* Get the entry that's currently first on the list */
455 Entry
= ListHead
->Flink
;
456 Pfn1
= MiGetPfnEntry(Entry
);
458 /* Make the list point to the entry following the first one */
459 Flink
= Pfn1
->u1
.Flink
;
460 ListHead
->Flink
= Flink
;
462 /* Check if the next entry is actually the list head */
463 if (ListHead
->Flink
!= LIST_HEAD
)
465 /* It isn't, so therefore whoever is coming next points back to the head */
466 MiGetPfnEntry(Flink
)->u2
.Blink
= LIST_HEAD
;
470 /* Then the list is empty, so the backlink should point back to us */
471 ListHead
->Blink
= LIST_HEAD
;
474 /* We are not on a list anymore */
475 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
478 ASSERT_LIST_INVARIANT(ListHead
);
480 /* Return the head element */
486 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
494 PMMCOLOR_TABLES ColorTable
;
496 /* Make sure the page index is valid */
497 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
498 ASSERT((PageFrameIndex
!= 0) &&
499 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
500 (PageFrameIndex
>= MmLowestPhysicalPage
));
502 /* Get the PFN entry */
503 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
505 /* Sanity checks that a right kind of page is being inserted here */
506 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
507 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
508 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
509 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
510 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
512 /* Get the free page list and increment its count */
513 ListHead
= &MmFreePageListHead
;
514 ASSERT_LIST_INVARIANT(ListHead
);
517 /* Get the last page on the list */
518 LastPage
= ListHead
->Blink
;
519 if (LastPage
!= LIST_HEAD
)
521 /* Link us with the previous page, so we're at the end now */
522 MiGetPfnEntry(LastPage
)->u1
.Flink
= PageFrameIndex
;
526 /* The list is empty, so we are the first page */
527 ListHead
->Flink
= PageFrameIndex
;
530 /* Now make the list head point back to us (since we go at the end) */
531 ListHead
->Blink
= PageFrameIndex
;
533 /* And initialize our own list pointers */
534 Pfn1
->u1
.Flink
= LIST_HEAD
;
535 Pfn1
->u2
.Blink
= LastPage
;
537 /* Set the list name and default priority */
538 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
539 Pfn1
->u4
.Priority
= 3;
541 /* Clear some status fields */
542 Pfn1
->u4
.InPageError
= 0;
543 Pfn1
->u4
.AweAllocation
= 0;
545 /* Increase available pages */
548 /* Check if we've reached the configured low memory threshold */
549 if (MmAvailablePages
== MmLowMemoryThreshold
)
551 /* Clear the event, because now we're ABOVE the threshold */
552 KeClearEvent(MiLowMemoryEvent
);
554 else if (MmAvailablePages
== MmHighMemoryThreshold
)
556 /* Otherwise check if we reached the high threshold and signal the event */
557 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
560 ASSERT_LIST_INVARIANT(ListHead
);
562 #if 0 // When using ARM3 PFN
563 /* Get the page color */
564 Color
= PageFrameIndex
& MmSecondaryColorMask
;
566 /* Get the first page on the color list */
567 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
568 if (ColorTable
->Flink
== LIST_HEAD
)
570 /* The list is empty, so we are the first page */
571 Pfn1
->u4
.PteFrame
= -1;
572 ColorTable
->Flink
= PageFrameIndex
;
576 /* Get the previous page */
577 Blink
= (PMMPFN
)ColorTable
->Blink
;
579 /* Make it link to us */
580 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
581 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
584 /* Now initialize our own list pointers */
585 ColorTable
->Blink
= Pfn1
;
586 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
588 /* And increase the count in the colored list */
592 /* Notify zero page thread if enough pages are on the free list now */
593 extern KEVENT ZeroPageThreadEvent
;
594 if ((MmFreePageListHead
.Total
> 8) && !(KeReadStateEvent(&ZeroPageThreadEvent
)))
596 /* This is ReactOS-specific */
597 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
603 MiInitializePfn(IN PFN_NUMBER PageFrameIndex
,
604 IN PMMPTE PointerPte
,
609 PMMPTE PointerPtePte
;
610 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
613 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
614 Pfn1
->PteAddress
= PointerPte
;
616 /* Check if this PFN is part of a valid address space */
617 if (PointerPte
->u
.Hard
.Valid
== 1)
623 /* Otherwise this is a fresh page -- set it up */
624 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
625 Pfn1
->u3
.e2
.ReferenceCount
= 1;
626 Pfn1
->u2
.ShareCount
= 1;
627 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
628 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
629 Pfn1
->u3
.e1
.Modified
= Modified
;
631 /* Get the page table for the PTE */
632 PointerPtePte
= MiAddressToPte(PointerPte
);
633 if (PointerPtePte
->u
.Hard
.Valid
== 0)
635 /* Make sure the PDE gets paged in properly */
636 Status
= MiCheckPdeForPagedPool(PointerPte
);
637 if (!NT_SUCCESS(Status
))
640 KeBugCheckEx(MEMORY_MANAGEMENT
,
642 (ULONG_PTR
)PointerPte
,
643 (ULONG_PTR
)PointerPtePte
->u
.Long
,
644 (ULONG_PTR
)MiPteToAddress(PointerPte
));
648 /* Get the PFN for the page table */
649 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
650 ASSERT(PageFrameIndex
!= 0);
651 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
653 /* Increase its share count so we don't get rid of it */
654 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
655 Pfn1
->u2
.ShareCount
++;
660 MiAllocatePfn(IN PMMPTE PointerPte
,
664 PFN_NUMBER PageFrameIndex
;
667 /* Make an empty software PTE */
668 MI_MAKE_SOFTWARE_PTE(&TempPte
, MM_READWRITE
);
670 /* Lock the PFN database */
671 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
673 /* Check if we're running low on pages */
674 if (MmAvailablePages
< 128)
676 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages
);
677 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
681 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
682 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
683 PageFrameIndex
= MiRemoveAnyPage(0);
685 /* Write the software PTE */
686 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
687 *PointerPte
= TempPte
;
688 PointerPte
->u
.Soft
.Protection
|= Protection
;
690 /* Initialize its PFN entry */
691 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
693 /* Release the PFN lock and return the page */
694 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
695 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
696 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
697 return PageFrameIndex
;
702 MiDecrementShareCount(IN PMMPFN Pfn1
,
703 IN PFN_NUMBER PageFrameIndex
)
705 ASSERT(PageFrameIndex
> 0);
706 ASSERT(MiGetPfnEntry(PageFrameIndex
) != NULL
);
707 ASSERT(Pfn1
== MiGetPfnEntry(PageFrameIndex
));
709 /* Page must be in-use */
710 if ((Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
) &&
711 (Pfn1
->u3
.e1
.PageLocation
!= StandbyPageList
))
713 /* Otherwise we have PFN corruption */
714 KeBugCheckEx(PFN_LIST_CORRUPT
,
717 Pfn1
->u3
.e1
.PageLocation
,
721 /* Check if the share count is now 0 */
722 ASSERT(Pfn1
->u2
.ShareCount
< 0xF000000);
723 if (!--Pfn1
->u2
.ShareCount
)
725 /* ReactOS does not handle these */
726 ASSERT(Pfn1
->u3
.e1
.PrototypePte
== 0);
728 /* Put the page in transition */
729 Pfn1
->u3
.e1
.PageLocation
= TransitionPage
;
731 /* PFN lock must be held */
732 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
734 /* Page should at least have one reference */
735 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
736 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
738 /* In ReactOS, this path should always be hit with a deleted PFN */
739 ASSERT(MI_IS_PFN_DELETED(Pfn1
) == TRUE
);
741 /* Clear the last reference */
742 Pfn1
->u3
.e2
.ReferenceCount
= 0;
745 * OriginalPte is used by AweReferenceCount in ReactOS, but either
746 * ways we shouldn't be seeing RMAP entries at this point
748 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
749 ASSERT(Pfn1
->OriginalPte
.u
.Long
== 0);
751 /* Mark the page temporarily as valid, we're going to make it free soon */
752 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
754 /* Bring it back into the free list */
755 MiInsertPageInFreeList(PageFrameIndex
);
759 /* Otherwise, just drop the reference count */
760 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);