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 */
569 extern KEVENT ZeroPageThreadEvent
;
573 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
581 PMMCOLOR_TABLES ColorTable
;
583 /* Make sure the page index is valid */
584 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
585 ASSERT((PageFrameIndex
!= 0) &&
586 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
587 (PageFrameIndex
>= MmLowestPhysicalPage
));
589 /* Get the PFN entry */
590 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
592 /* Sanity checks that a right kind of page is being inserted here */
593 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
594 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
595 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
596 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
597 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
599 /* Get the free page list and increment its count */
600 ListHead
= &MmFreePageListHead
;
601 ASSERT_LIST_INVARIANT(ListHead
);
604 /* Get the last page on the list */
605 LastPage
= ListHead
->Blink
;
606 if (LastPage
!= LIST_HEAD
)
608 /* Link us with the previous page, so we're at the end now */
609 MiGetPfnEntry(LastPage
)->u1
.Flink
= PageFrameIndex
;
613 /* The list is empty, so we are the first page */
614 ListHead
->Flink
= PageFrameIndex
;
617 /* Now make the list head point back to us (since we go at the end) */
618 ListHead
->Blink
= PageFrameIndex
;
619 ASSERT_LIST_INVARIANT(ListHead
);
621 /* And initialize our own list pointers */
622 Pfn1
->u1
.Flink
= LIST_HEAD
;
623 Pfn1
->u2
.Blink
= LastPage
;
625 /* Set the list name and default priority */
626 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
627 Pfn1
->u4
.Priority
= 3;
629 /* Clear some status fields */
630 Pfn1
->u4
.InPageError
= 0;
631 Pfn1
->u4
.AweAllocation
= 0;
633 /* Increase available pages */
636 /* Check if we've reached the configured low memory threshold */
637 if (MmAvailablePages
== MmLowMemoryThreshold
)
639 /* Clear the event, because now we're ABOVE the threshold */
640 KeClearEvent(MiLowMemoryEvent
);
642 else if (MmAvailablePages
== MmHighMemoryThreshold
)
644 /* Otherwise check if we reached the high threshold and signal the event */
645 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
648 #if 0 // When using ARM3 PFN
649 /* Get the page color */
650 Color
= PageFrameIndex
& MmSecondaryColorMask
;
652 /* Get the first page on the color list */
653 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
654 if (ColorTable
->Flink
== LIST_HEAD
)
656 /* The list is empty, so we are the first page */
657 Pfn1
->u4
.PteFrame
= -1;
658 ColorTable
->Flink
= PageFrameIndex
;
662 /* Get the previous page */
663 Blink
= (PMMPFN
)ColorTable
->Blink
;
665 /* Make it link to us */
666 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
667 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
670 /* Now initialize our own list pointers */
671 ColorTable
->Blink
= Pfn1
;
672 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
674 /* And increase the count in the colored list */
678 /* Notify zero page thread if enough pages are on the free list now */
679 if ((MmFreePageListHead
.Total
> 8) && !(KeReadStateEvent(&ZeroPageThreadEvent
)))
681 /* This is ReactOS-specific */
682 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);
688 MiInitializePfn(IN PFN_NUMBER PageFrameIndex
,
689 IN PMMPTE PointerPte
,
694 PMMPTE PointerPtePte
;
695 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
698 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
699 Pfn1
->PteAddress
= PointerPte
;
701 /* Check if this PFN is part of a valid address space */
702 if (PointerPte
->u
.Hard
.Valid
== 1)
704 /* Only valid from MmCreateProcessAddressSpace path */
705 ASSERT(PsGetCurrentProcess()->Vm
.WorkingSetSize
== 0);
708 /* Otherwise this is a fresh page -- set it up */
709 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
710 Pfn1
->u3
.e2
.ReferenceCount
= 1;
711 Pfn1
->u2
.ShareCount
= 1;
712 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
713 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
714 Pfn1
->u3
.e1
.Modified
= Modified
;
716 /* Get the page table for the PTE */
717 PointerPtePte
= MiAddressToPte(PointerPte
);
718 if (PointerPtePte
->u
.Hard
.Valid
== 0)
720 /* Make sure the PDE gets paged in properly */
721 Status
= MiCheckPdeForPagedPool(PointerPte
);
722 if (!NT_SUCCESS(Status
))
725 KeBugCheckEx(MEMORY_MANAGEMENT
,
727 (ULONG_PTR
)PointerPte
,
728 (ULONG_PTR
)PointerPtePte
->u
.Long
,
729 (ULONG_PTR
)MiPteToAddress(PointerPte
));
733 /* Get the PFN for the page table */
734 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
735 ASSERT(PageFrameIndex
!= 0);
736 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
738 /* Increase its share count so we don't get rid of it */
739 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
740 Pfn1
->u2
.ShareCount
++;
745 MiAllocatePfn(IN PMMPTE PointerPte
,
749 PFN_NUMBER PageFrameIndex
;
752 /* Sanity check that we aren't passed a valid PTE */
753 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
755 /* Make an empty software PTE */
756 MI_MAKE_SOFTWARE_PTE(&TempPte
, MM_READWRITE
);
758 /* Lock the PFN database */
759 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
761 /* Check if we're running low on pages */
762 if (MmAvailablePages
< 128)
764 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages
);
765 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
769 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
770 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
771 PageFrameIndex
= MiRemoveAnyPage(0);
773 /* Write the software PTE */
774 MI_WRITE_INVALID_PTE(PointerPte
, TempPte
);
775 PointerPte
->u
.Soft
.Protection
|= Protection
;
777 /* Initialize its PFN entry */
778 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
780 /* Release the PFN lock and return the page */
781 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
782 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
783 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
784 return PageFrameIndex
;
789 MiDecrementShareCount(IN PMMPFN Pfn1
,
790 IN PFN_NUMBER PageFrameIndex
)
792 ASSERT(PageFrameIndex
> 0);
793 ASSERT(MiGetPfnEntry(PageFrameIndex
) != NULL
);
794 ASSERT(Pfn1
== MiGetPfnEntry(PageFrameIndex
));
796 /* Page must be in-use */
797 if ((Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
) &&
798 (Pfn1
->u3
.e1
.PageLocation
!= StandbyPageList
))
800 /* Otherwise we have PFN corruption */
801 KeBugCheckEx(PFN_LIST_CORRUPT
,
804 Pfn1
->u3
.e1
.PageLocation
,
808 /* Check if the share count is now 0 */
809 ASSERT(Pfn1
->u2
.ShareCount
< 0xF000000);
810 if (!--Pfn1
->u2
.ShareCount
)
812 /* ReactOS does not handle these */
813 ASSERT(Pfn1
->u3
.e1
.PrototypePte
== 0);
815 /* Put the page in transition */
816 Pfn1
->u3
.e1
.PageLocation
= TransitionPage
;
818 /* PFN lock must be held */
819 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
821 /* Page should at least have one reference */
822 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
823 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
825 /* In ReactOS, this path should always be hit with a deleted PFN */
826 ASSERT(MI_IS_PFN_DELETED(Pfn1
) == TRUE
);
828 /* Clear the last reference */
829 Pfn1
->u3
.e2
.ReferenceCount
= 0;
832 * OriginalPte is used by AweReferenceCount in ReactOS, but either
833 * ways we shouldn't be seeing RMAP entries at this point
835 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
836 ASSERT(Pfn1
->OriginalPte
.u
.Long
== 0);
838 /* Mark the page temporarily as valid, we're going to make it free soon */
839 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
841 /* Bring it back into the free list */
842 MiInsertPageInFreeList(PageFrameIndex
);
846 /* Otherwise, just drop the reference count */
847 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
854 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex
,
855 IN PMMPTE PointerPte
,
856 IN PFN_NUMBER PteFrame
)
861 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
862 Pfn1
->PteAddress
= PointerPte
;
864 #if 0 // When using ARM3 PFN
865 /* Make this a software PTE */
866 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
870 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
871 Pfn1
->u3
.e2
.ReferenceCount
= 1;
872 Pfn1
->u2
.ShareCount
= 1;
873 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
874 Pfn1
->u3
.e1
.Modified
= TRUE
;
875 Pfn1
->u4
.InPageError
= FALSE
;
877 /* Did we get a PFN for the page table */
881 Pfn1
->u4
.PteFrame
= PteFrame
;
883 /* Increase its share count so we don't get rid of it */
884 Pfn1
= MiGetPfnEntry(PteFrame
);
885 Pfn1
->u2
.ShareCount
++;