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"
20 #define ASSERT_LIST_INVARIANT(x) \
22 ASSERT(((x)->Total == 0 && \
23 (x)->Flink == LIST_HEAD && \
24 (x)->Blink == LIST_HEAD) || \
26 (x)->Flink != LIST_HEAD && \
27 (x)->Blink != LIST_HEAD)); \
30 #define ASSERT_LIST_INVARIANT(x)
33 /* GLOBALS ********************************************************************/
38 MMPFNLIST MmZeroedPageListHead
= {0, ZeroedPageList
, LIST_HEAD
, LIST_HEAD
};
39 MMPFNLIST MmFreePageListHead
= {0, FreePageList
, LIST_HEAD
, LIST_HEAD
};
40 MMPFNLIST MmStandbyPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
41 MMPFNLIST MmModifiedPageListHead
= {0, ModifiedPageList
, LIST_HEAD
, LIST_HEAD
};
42 MMPFNLIST MmModifiedNoWritePageListHead
= {0, ModifiedNoWritePageList
, LIST_HEAD
, LIST_HEAD
};
43 MMPFNLIST MmBadPageListHead
= {0, BadPageList
, LIST_HEAD
, LIST_HEAD
};
44 MMPFNLIST MmRomPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
46 PMMPFNLIST MmPageLocationList
[] =
48 &MmZeroedPageListHead
,
50 &MmStandbyPageListHead
,
51 &MmModifiedPageListHead
,
52 &MmModifiedNoWritePageListHead
,
57 /* FUNCTIONS ******************************************************************/
61 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex
)
65 PEPROCESS Process
= PsGetCurrentProcess();
67 /* Map in hyperspace, then wipe it using XMMI or MEMSET */
68 VirtualAddress
= MiMapPageInHyperSpace(Process
, PageFrameIndex
, &OldIrql
);
69 KeZeroPages(VirtualAddress
, PAGE_SIZE
);
70 MiUnmapPageInHyperSpace(Process
, VirtualAddress
, OldIrql
);
75 MiInsertInListTail(IN PMMPFNLIST ListHead
,
78 PFN_NUMBER OldBlink
, EntryIndex
= MiGetPfnEntryIndex(Entry
);
79 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
80 ASSERT_LIST_INVARIANT(ListHead
);
82 /* Get the back link */
83 OldBlink
= ListHead
->Blink
;
84 if (OldBlink
!= LIST_HEAD
)
86 /* Set the back pointer to point to us now */
87 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
91 /* Set the list to point to us */
92 ListHead
->Flink
= EntryIndex
;
95 /* Set the entry to point to the list head forwards, and the old page backwards */
96 Entry
->u1
.Flink
= LIST_HEAD
;
97 Entry
->u2
.Blink
= OldBlink
;
99 /* And now the head points back to us, since we are last */
100 ListHead
->Blink
= EntryIndex
;
102 ASSERT_LIST_INVARIANT(ListHead
);
107 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex
)
115 PMMCOLOR_TABLES ColorHead
;
118 /* Make sure the PFN lock is held */
119 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
121 /* Get the descriptor */
122 Pfn1
= MiGetPfnEntry(EntryIndex
);
123 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
124 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
125 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
126 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
127 ASSERT(Pfn1
->u4
.InPageError
== 0);
129 /* Use the zero list */
130 ListHead
= &MmZeroedPageListHead
;
131 ASSERT_LIST_INVARIANT(ListHead
);
134 /* Get the back link */
135 OldBlink
= ListHead
->Blink
;
136 if (OldBlink
!= LIST_HEAD
)
138 /* Set the back pointer to point to us now */
139 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
143 /* Set the list to point to us */
144 ListHead
->Flink
= EntryIndex
;
147 /* Set the entry to point to the list head forwards, and the old page backwards */
148 Pfn1
->u1
.Flink
= LIST_HEAD
;
149 Pfn1
->u2
.Blink
= OldBlink
;
151 /* And now the head points back to us, since we are last */
152 ListHead
->Blink
= EntryIndex
;
153 ASSERT_LIST_INVARIANT(ListHead
);
155 /* Update the page location */
156 Pfn1
->u3
.e1
.PageLocation
= ZeroedPageList
;
158 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
159 //MmAvailablePages++;
161 /* Check if we've reached the configured low memory threshold */
162 if (MmAvailablePages
== MmLowMemoryThreshold
)
164 /* Clear the event, because now we're ABOVE the threshold */
165 KeClearEvent(MiLowMemoryEvent
);
167 else if (MmAvailablePages
== MmHighMemoryThreshold
)
169 /* Otherwise check if we reached the high threshold and signal the event */
170 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
174 /* Get the page color */
175 Color
= EntryIndex
& MmSecondaryColorMask
;
177 /* Get the first page on the color list */
178 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
179 if (ColorHead
->Flink
== LIST_HEAD
)
181 /* The list is empty, so we are the first page */
182 Pfn1
->u4
.PteFrame
= -1;
183 ColorHead
->Flink
= EntryIndex
;
187 /* Get the previous page */
188 Blink
= (PMMPFN
)ColorHead
->Blink
;
190 /* Make it link to us */
191 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
192 Blink
->OriginalPte
.u
.Long
= EntryIndex
;
195 /* Now initialize our own list pointers */
196 ColorHead
->Blink
= Pfn1
;
197 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
199 /* And increase the count in the colored list */
206 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
208 PFN_NUMBER OldFlink
, OldBlink
;
212 /* Make sure the PFN lock is held */
213 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
215 /* Make sure the PFN entry isn't in-use */
216 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
217 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
219 /* Find the list for this entry, make sure it's the free or zero list */
220 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
221 ListName
= ListHead
->ListName
;
222 ASSERT(ListHead
!= NULL
);
223 ASSERT(ListName
<= FreePageList
);
224 ASSERT_LIST_INVARIANT(ListHead
);
226 /* Remove one count */
227 ASSERT(ListHead
->Total
!= 0);
230 /* Get the forward and back pointers */
231 OldFlink
= Entry
->u1
.Flink
;
232 OldBlink
= Entry
->u2
.Blink
;
234 /* Check if the next entry is the list head */
235 if (OldFlink
!= LIST_HEAD
)
237 /* It is not, so set the backlink of the actual entry, to our backlink */
238 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
242 /* Set the list head's backlink instead */
243 ListHead
->Blink
= OldBlink
;
246 /* Check if the back entry is the list head */
247 if (OldBlink
!= LIST_HEAD
)
249 /* It is not, so set the backlink of the actual entry, to our backlink */
250 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
254 /* Set the list head's backlink instead */
255 ListHead
->Flink
= OldFlink
;
258 /* We are not on a list anymore */
259 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
260 ASSERT_LIST_INVARIANT(ListHead
);
262 /* FIXME: Deal with color list */
264 /* See if we hit any thresholds */
265 if (MmAvailablePages
== MmHighMemoryThreshold
)
267 /* Clear the high memory event */
268 KeClearEvent(MiHighMemoryEvent
);
270 else if (MmAvailablePages
== MmLowMemoryThreshold
)
272 /* Signal the low memory event */
273 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
277 if (--MmAvailablePages
< MmMinimumFreePages
)
279 /* FIXME: Should wake up the MPW and working set manager, if we had one */
285 MiRemovePageByColor(IN PFN_NUMBER PageIndex
,
291 PFN_NUMBER OldFlink
, OldBlink
;
292 ULONG OldColor
, OldCache
;
294 PMMCOLOR_TABLES ColorTable
;
296 /* Make sure PFN lock is held */
297 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
298 ASSERT(Color
< MmSecondaryColors
);
300 /* Get the PFN entry */
301 Pfn1
= MiGetPfnEntry(PageIndex
);
302 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
303 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
305 /* Capture data for later */
306 OldColor
= Pfn1
->u3
.e1
.PageColor
;
307 OldCache
= Pfn1
->u3
.e1
.CacheAttribute
;
309 /* Could be either on free or zero list */
310 ListHead
= MmPageLocationList
[Pfn1
->u3
.e1
.PageLocation
];
311 ASSERT_LIST_INVARIANT(ListHead
);
312 ListName
= ListHead
->ListName
;
313 ASSERT(ListName
<= FreePageList
);
318 /* Get the forward and back pointers */
319 OldFlink
= Pfn1
->u1
.Flink
;
320 OldBlink
= Pfn1
->u2
.Blink
;
322 /* Check if the next entry is the list head */
323 if (OldFlink
!= LIST_HEAD
)
325 /* It is not, so set the backlink of the actual entry, to our backlink */
326 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
330 /* Set the list head's backlink instead */
331 ListHead
->Blink
= OldFlink
;
334 /* Check if the back entry is the list head */
335 if (OldBlink
!= LIST_HEAD
)
337 /* It is not, so set the backlink of the actual entry, to our backlink */
338 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
342 /* Set the list head's backlink instead */
343 ListHead
->Flink
= OldFlink
;
346 /* We are not on a list anymore */
347 ASSERT_LIST_INVARIANT(ListHead
);
348 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
350 /* Zero flags but restore color and cache */
351 Pfn1
->u3
.e2
.ShortFlags
= 0;
352 Pfn1
->u3
.e1
.PageColor
= OldColor
;
353 Pfn1
->u3
.e1
.CacheAttribute
= OldCache
;
355 #if 0 // When switching to ARM3
356 /* Get the first page on the color list */
357 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
358 ASSERT(ColorTable
->Count
>= 1);
360 /* Set the forward link to whoever we were pointing to */
361 ColorTable
->Flink
= Pfn1
->OriginalPte
.u
.Long
;
362 if (ColorTable
->Flink
== LIST_HEAD
)
364 /* This is the beginning of the list, so set the sentinel value */
365 ColorTable
->Blink
= LIST_HEAD
;
369 /* The list is empty, so we are the first page */
370 MiGetPfnEntry(ColorTable
->Flink
)->u4
.PteFrame
= -1;
376 /* See if we hit any thresholds */
377 if (MmAvailablePages
== MmHighMemoryThreshold
)
379 /* Clear the high memory event */
380 KeClearEvent(MiHighMemoryEvent
);
382 else if (MmAvailablePages
== MmLowMemoryThreshold
)
384 /* Signal the low memory event */
385 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
389 if (--MmAvailablePages
< MmMinimumFreePages
)
391 /* FIXME: Should wake up the MPW and working set manager, if we had one */
394 /* Return the page */
400 MiRemoveAnyPage(IN ULONG Color
)
402 PFN_NUMBER PageIndex
;
405 /* Make sure PFN lock is held and we have pages */
406 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
407 ASSERT(MmAvailablePages
!= 0);
408 ASSERT(Color
< MmSecondaryColors
);
410 /* Check the colored free list */
411 #if 0 // Enable when using ARM3 database */
412 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
413 if (PageIndex
== LIST_HEAD
)
415 /* Check the colored zero list */
416 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
417 if (PageIndex
== LIST_HEAD
)
420 /* Check the free list */
421 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
422 PageIndex
= MmFreePageListHead
.Flink
;
423 Color
= PageIndex
& MmSecondaryColorMask
;
424 if (PageIndex
== LIST_HEAD
)
426 /* Check the zero list */
427 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
428 PageIndex
= MmZeroedPageListHead
.Flink
;
429 Color
= PageIndex
& MmSecondaryColorMask
;
430 ASSERT(PageIndex
!= LIST_HEAD
);
431 if (PageIndex
== LIST_HEAD
)
433 /* FIXME: Should check the standby list */
434 ASSERT(MmZeroedPageListHead
.Total
== 0);
437 #if 0 // Enable when using ARM3 database */
442 /* Remove the page from its list */
443 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
446 Pfn1
= MiGetPfnEntry(PageIndex
);
447 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
448 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
449 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
450 ASSERT(Pfn1
->u2
.ShareCount
== 0);
451 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
452 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
454 /* Return the page */
460 MiRemoveZeroPage(IN ULONG Color
)
462 PFN_NUMBER PageIndex
;
466 /* Make sure PFN lock is held and we have pages */
467 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
468 ASSERT(MmAvailablePages
!= 0);
469 ASSERT(Color
< MmSecondaryColors
);
471 /* Check the colored zero list */
472 #if 0 // Enable when using ARM3 database */
473 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
474 if (PageIndex
== LIST_HEAD
)
477 /* Check the zero list */
478 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
479 PageIndex
= MmZeroedPageListHead
.Flink
;
480 Color
= PageIndex
& MmSecondaryColorMask
;
481 if (PageIndex
== LIST_HEAD
)
483 ASSERT(MmZeroedPageListHead
.Total
== 0);
485 #if 0 // Enable when using ARM3 database */
486 /* Check the colored free list */
487 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
488 if (PageIndex
== LIST_HEAD
)
491 /* Check the free list */
492 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
493 PageIndex
= MmFreePageListHead
.Flink
;
494 Color
= PageIndex
& MmSecondaryColorMask
;
495 ASSERT(PageIndex
!= LIST_HEAD
);
496 if (PageIndex
== LIST_HEAD
)
498 /* FIXME: Should check the standby list */
499 ASSERT(MmZeroedPageListHead
.Total
== 0);
501 #if 0 // Enable when using ARM3 database */
505 #if 0 // Enable when using ARM3 database */
509 Pfn1
= MiGetPfnEntry(PageIndex
);
510 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
511 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
513 /* Remove the page from its list */
514 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
515 ASSERT(Pfn1
== MiGetPfnEntry(PageIndex
));
517 /* Zero it, if needed */
518 if (Zero
) MiZeroPhysicalPage(PageIndex
);
521 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
522 ASSERT(Pfn1
->u2
.ShareCount
== 0);
523 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
524 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
526 /* Return the page */
533 MiRemoveHeadList(IN PMMPFNLIST ListHead
)
535 PFN_NUMBER Entry
, Flink
;
537 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
538 ASSERT_LIST_INVARIANT(ListHead
);
540 /* Get the entry that's currently first on the list */
541 Entry
= ListHead
->Flink
;
542 Pfn1
= MiGetPfnEntry(Entry
);
544 /* Make the list point to the entry following the first one */
545 Flink
= Pfn1
->u1
.Flink
;
546 ListHead
->Flink
= Flink
;
548 /* Check if the next entry is actually the list head */
549 if (ListHead
->Flink
!= LIST_HEAD
)
551 /* It isn't, so therefore whoever is coming next points back to the head */
552 MiGetPfnEntry(Flink
)->u2
.Blink
= LIST_HEAD
;
556 /* Then the list is empty, so the backlink should point back to us */
557 ListHead
->Blink
= LIST_HEAD
;
560 /* We are not on a list anymore */
561 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
563 ASSERT_LIST_INVARIANT(ListHead
);
565 /* Return the head element */
571 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
579 PMMCOLOR_TABLES ColorTable
;
581 /* Make sure the page index is valid */
582 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
583 ASSERT((PageFrameIndex
!= 0) &&
584 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
585 (PageFrameIndex
>= MmLowestPhysicalPage
));
587 /* Get the PFN entry */
588 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
590 /* Sanity checks that a right kind of page is being inserted here */
591 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
592 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
593 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
594 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
595 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
597 /* Get the free page list and increment its count */
598 ListHead
= &MmFreePageListHead
;
599 ASSERT_LIST_INVARIANT(ListHead
);
602 /* Get the last page on the list */
603 LastPage
= ListHead
->Blink
;
604 if (LastPage
!= LIST_HEAD
)
606 /* Link us with the previous page, so we're at the end now */
607 MiGetPfnEntry(LastPage
)->u1
.Flink
= PageFrameIndex
;
611 /* The list is empty, so we are the first page */
612 ListHead
->Flink
= PageFrameIndex
;
615 /* Now make the list head point back to us (since we go at the end) */
616 ListHead
->Blink
= PageFrameIndex
;
617 ASSERT_LIST_INVARIANT(ListHead
);
619 /* And initialize our own list pointers */
620 Pfn1
->u1
.Flink
= LIST_HEAD
;
621 Pfn1
->u2
.Blink
= LastPage
;
623 /* Set the list name and default priority */
624 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
625 Pfn1
->u4
.Priority
= 3;
627 /* Clear some status fields */
628 Pfn1
->u4
.InPageError
= 0;
629 Pfn1
->u4
.AweAllocation
= 0;
631 /* Increase available pages */
634 /* Check if we've reached the configured low memory threshold */
635 if (MmAvailablePages
== MmLowMemoryThreshold
)
637 /* Clear the event, because now we're ABOVE the threshold */
638 KeClearEvent(MiLowMemoryEvent
);
640 else if (MmAvailablePages
== MmHighMemoryThreshold
)
642 /* Otherwise check if we reached the high threshold and signal the event */
643 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
646 #if 0 // When using ARM3 PFN
647 /* Get the page color */
648 Color
= PageFrameIndex
& MmSecondaryColorMask
;
650 /* Get the first page on the color list */
651 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
652 if (ColorTable
->Flink
== LIST_HEAD
)
654 /* The list is empty, so we are the first page */
655 Pfn1
->u4
.PteFrame
= -1;
656 ColorTable
->Flink
= PageFrameIndex
;
660 /* Get the previous page */
661 Blink
= (PMMPFN
)ColorTable
->Blink
;
663 /* Make it link to us */
664 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
665 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
668 /* Now initialize our own list pointers */
669 ColorTable
->Blink
= Pfn1
;
670 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
672 /* And increase the count in the colored list */
676 /* Notify zero page thread if enough pages are on the free list now */
677 extern KEVENT ZeroPageThreadEvent
;
678 if ((MmFreePageListHead
.Total
> 8) && !(KeReadStateEvent(&ZeroPageThreadEvent
)))
680 /* This is ReactOS-specific */
681 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
687 MiInitializePfn(IN PFN_NUMBER PageFrameIndex
,
688 IN PMMPTE PointerPte
,
693 PMMPTE PointerPtePte
;
694 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
697 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
698 Pfn1
->PteAddress
= PointerPte
;
700 /* Check if this PFN is part of a valid address space */
701 if (PointerPte
->u
.Hard
.Valid
== 1)
707 /* Otherwise this is a fresh page -- set it up */
708 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
709 Pfn1
->u3
.e2
.ReferenceCount
= 1;
710 Pfn1
->u2
.ShareCount
= 1;
711 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
712 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
713 Pfn1
->u3
.e1
.Modified
= Modified
;
715 /* Get the page table for the PTE */
716 PointerPtePte
= MiAddressToPte(PointerPte
);
717 if (PointerPtePte
->u
.Hard
.Valid
== 0)
719 /* Make sure the PDE gets paged in properly */
720 Status
= MiCheckPdeForPagedPool(PointerPte
);
721 if (!NT_SUCCESS(Status
))
724 KeBugCheckEx(MEMORY_MANAGEMENT
,
726 (ULONG_PTR
)PointerPte
,
727 (ULONG_PTR
)PointerPtePte
->u
.Long
,
728 (ULONG_PTR
)MiPteToAddress(PointerPte
));
732 /* Get the PFN for the page table */
733 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
734 ASSERT(PageFrameIndex
!= 0);
735 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
737 /* Increase its share count so we don't get rid of it */
738 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
739 Pfn1
->u2
.ShareCount
++;
744 MiAllocatePfn(IN PMMPTE PointerPte
,
748 PFN_NUMBER PageFrameIndex
;
751 /* Make an empty software PTE */
752 MI_MAKE_SOFTWARE_PTE(&TempPte
, MM_READWRITE
);
754 /* Lock the PFN database */
755 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
757 /* Check if we're running low on pages */
758 if (MmAvailablePages
< 128)
760 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages
);
761 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
765 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
766 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
767 PageFrameIndex
= MiRemoveAnyPage(0);
769 /* Write the software PTE */
770 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
771 *PointerPte
= TempPte
;
772 PointerPte
->u
.Soft
.Protection
|= Protection
;
774 /* Initialize its PFN entry */
775 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
777 /* Release the PFN lock and return the page */
778 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
779 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
780 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
781 return PageFrameIndex
;
786 MiDecrementShareCount(IN PMMPFN Pfn1
,
787 IN PFN_NUMBER PageFrameIndex
)
789 ASSERT(PageFrameIndex
> 0);
790 ASSERT(MiGetPfnEntry(PageFrameIndex
) != NULL
);
791 ASSERT(Pfn1
== MiGetPfnEntry(PageFrameIndex
));
793 /* Page must be in-use */
794 if ((Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
) &&
795 (Pfn1
->u3
.e1
.PageLocation
!= StandbyPageList
))
797 /* Otherwise we have PFN corruption */
798 KeBugCheckEx(PFN_LIST_CORRUPT
,
801 Pfn1
->u3
.e1
.PageLocation
,
805 /* Check if the share count is now 0 */
806 ASSERT(Pfn1
->u2
.ShareCount
< 0xF000000);
807 if (!--Pfn1
->u2
.ShareCount
)
809 /* ReactOS does not handle these */
810 ASSERT(Pfn1
->u3
.e1
.PrototypePte
== 0);
812 /* Put the page in transition */
813 Pfn1
->u3
.e1
.PageLocation
= TransitionPage
;
815 /* PFN lock must be held */
816 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
818 /* Page should at least have one reference */
819 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
820 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
822 /* In ReactOS, this path should always be hit with a deleted PFN */
823 ASSERT(MI_IS_PFN_DELETED(Pfn1
) == TRUE
);
825 /* Clear the last reference */
826 Pfn1
->u3
.e2
.ReferenceCount
= 0;
829 * OriginalPte is used by AweReferenceCount in ReactOS, but either
830 * ways we shouldn't be seeing RMAP entries at this point
832 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
833 ASSERT(Pfn1
->OriginalPte
.u
.Long
== 0);
835 /* Mark the page temporarily as valid, we're going to make it free soon */
836 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
838 /* Bring it back into the free list */
839 MiInsertPageInFreeList(PageFrameIndex
);
843 /* Otherwise, just drop the reference count */
844 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
851 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex
,
852 IN PMMPTE PointerPte
,
853 IN PFN_NUMBER PteFrame
)
858 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
859 Pfn1
->PteAddress
= PointerPte
;
861 #if 0 // When using ARM3 PFN
862 /* Make this a software PTE */
863 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
867 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
868 Pfn1
->u3
.e2
.ReferenceCount
= 1;
869 Pfn1
->u2
.ShareCount
= 1;
870 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
871 Pfn1
->u3
.e1
.Modified
= TRUE
;
872 Pfn1
->u4
.InPageError
= FALSE
;
874 /* Did we get a PFN for the page table */
878 Pfn1
->u4
.PteFrame
= PteFrame
;
880 /* Increase its share count so we don't get rid of it */
881 Pfn1
= MiGetPfnEntry(PteFrame
);
882 Pfn1
->u2
.ShareCount
++;