xref: /reactos/ntoskrnl/mm/ARM3/pfnlist.c (revision 98e8827a)
1 /*
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
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 #if DBG
19 #define ASSERT_LIST_INVARIANT(x) \
20 do { \
21     ASSERT(((x)->Total == 0 && \
22             (x)->Flink == LIST_HEAD && \
23             (x)->Blink == LIST_HEAD) || \
24            ((x)->Total != 0 && \
25             (x)->Flink != LIST_HEAD && \
26             (x)->Blink != LIST_HEAD)); \
27 } while (0)
28 #else
29 #define ASSERT_LIST_INVARIANT(x)
30 #endif
31 
32 /* GLOBALS ********************************************************************/
33 
34 BOOLEAN MmDynamicPfn;
35 BOOLEAN MmMirroring;
36 ULONG MmSystemPageColor;
37 
38 ULONG MmTransitionSharedPages;
39 ULONG MmTotalPagesForPagingFile;
40 
41 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
42 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
43 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
44 MMPFNLIST MmStandbyPageListByPriority[8];
45 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD};
46 MMPFNLIST MmModifiedPageListByColor[1] = {{0, ModifiedPageList, LIST_HEAD, LIST_HEAD}};
47 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD};
48 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD};
49 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
50 
51 PMMPFNLIST MmPageLocationList[] =
52 {
53     &MmZeroedPageListHead,
54     &MmFreePageListHead,
55     &MmStandbyPageListHead,
56     &MmModifiedPageListHead,
57     &MmModifiedNoWritePageListHead,
58     &MmBadPageListHead,
59     NULL,
60     NULL
61 };
62 
63 ULONG MI_PFN_CURRENT_USAGE;
64 CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet";
65 
66 /* FUNCTIONS ******************************************************************/
67 static
68 VOID
69 MiIncrementAvailablePages(
70     VOID)
71 {
72     /* Increment available pages */
73     MmAvailablePages++;
74 
75     /* Check if we've reached the configured low memory threshold */
76     if (MmAvailablePages == MmLowMemoryThreshold)
77     {
78         /* Clear the event, because now we're ABOVE the threshold */
79         KeClearEvent(MiLowMemoryEvent);
80     }
81     else if (MmAvailablePages == MmHighMemoryThreshold)
82     {
83         /* Otherwise check if we reached the high threshold and signal the event */
84         KeSetEvent(MiHighMemoryEvent, 0, FALSE);
85     }
86 }
87 
88 static
89 VOID
90 MiDecrementAvailablePages(
91     VOID)
92 {
93     ASSERT(MmAvailablePages > 0);
94 
95     /* See if we hit any thresholds */
96     if (MmAvailablePages == MmHighMemoryThreshold)
97     {
98         /* Clear the high memory event */
99         KeClearEvent(MiHighMemoryEvent);
100     }
101     else if (MmAvailablePages == MmLowMemoryThreshold)
102     {
103         /* Signal the low memory event */
104         KeSetEvent(MiLowMemoryEvent, 0, FALSE);
105     }
106 
107     /* One less page */
108     MmAvailablePages--;
109     if (MmAvailablePages < MmMinimumFreePages)
110     {
111         /* FIXME: Should wake up the MPW and working set manager, if we had one */
112 
113         DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages);
114 
115         /* Call RosMm and see if it can release any pages for us */
116         MmRebalanceMemoryConsumers();
117     }
118 }
119 
120 VOID
121 NTAPI
122 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
123 {
124     KIRQL OldIrql;
125     PVOID VirtualAddress;
126     PEPROCESS Process = PsGetCurrentProcess();
127 
128     /* Map in hyperspace, then wipe it using XMMI or MEMSET */
129     VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql);
130     ASSERT(VirtualAddress);
131     KeZeroPages(VirtualAddress, PAGE_SIZE);
132     MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql);
133 }
134 
135 VOID
136 NTAPI
137 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
138 {
139     PFN_NUMBER OldFlink, OldBlink;
140     PMMPFNLIST ListHead;
141     MMLISTS ListName;
142     ULONG Color;
143     PMMCOLOR_TABLES ColorTable;
144     PMMPFN Pfn1;
145 
146     /* Make sure the PFN lock is held */
147     MI_ASSERT_PFN_LOCK_HELD();
148 
149     /* Make sure the PFN entry isn't in-use */
150     ASSERT(Entry->u3.e1.WriteInProgress == 0);
151     ASSERT(Entry->u3.e1.ReadInProgress == 0);
152 
153     /* Find the list for this entry, make sure it's the free or zero list */
154     ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
155     ListName = ListHead->ListName;
156     ASSERT(ListHead != NULL);
157     ASSERT(ListName <= FreePageList);
158     ASSERT_LIST_INVARIANT(ListHead);
159 
160     /* Remove one count */
161     ASSERT(ListHead->Total != 0);
162     ListHead->Total--;
163 
164     /* Get the forward and back pointers */
165     OldFlink = Entry->u1.Flink;
166     OldBlink = Entry->u2.Blink;
167 
168     /* Check if the next entry is the list head */
169     if (OldFlink != LIST_HEAD)
170     {
171         /* It is not, so set the backlink of the actual entry, to our backlink */
172         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
173     }
174     else
175     {
176         /* Set the list head's backlink instead */
177         ListHead->Blink = OldBlink;
178     }
179 
180     /* Check if the back entry is the list head */
181     if (OldBlink != LIST_HEAD)
182     {
183         /* It is not, so set the backlink of the actual entry, to our backlink */
184         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
185     }
186     else
187     {
188         /* Set the list head's backlink instead */
189         ListHead->Flink = OldFlink;
190     }
191 
192     /* Get the page color */
193     OldBlink = MiGetPfnEntryIndex(Entry);
194     Color = OldBlink & MmSecondaryColorMask;
195 
196     /* Get the first page on the color list */
197     ColorTable = &MmFreePagesByColor[ListName][Color];
198 
199     /* Check if this was was actually the head */
200     OldFlink = ColorTable->Flink;
201     if (OldFlink == OldBlink)
202     {
203         /* Make the table point to the next page this page was linking to */
204         ColorTable->Flink = Entry->OriginalPte.u.Long;
205         if (ColorTable->Flink != LIST_HEAD)
206         {
207             /* And make the previous link point to the head now */
208             MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
209         }
210         else
211         {
212             /* And if that page was the head, loop the list back around */
213             ColorTable->Blink = (PVOID)LIST_HEAD;
214         }
215     }
216     else
217     {
218         /* This page shouldn't be pointing back to the head */
219         ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD);
220 
221         /* Make the back link point to whoever the next page is */
222         Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame);
223         Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long;
224 
225         /* Check if this page was pointing to the head */
226         if (Entry->OriginalPte.u.Long != LIST_HEAD)
227         {
228             /* Make the back link point to the head */
229             Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long);
230             Pfn1->u4.PteFrame = Entry->u4.PteFrame;
231         }
232         else
233         {
234             /* Then the table is directly back pointing to this page now */
235             ColorTable->Blink = Pfn1;
236         }
237     }
238 
239     /* One less colored page */
240     ASSERT(ColorTable->Count >= 1);
241     ColorTable->Count--;
242 
243     /* ReactOS Hack */
244     Entry->OriginalPte.u.Long = 0;
245 
246     /* We are not on a list anymore */
247     Entry->u1.Flink = Entry->u2.Blink = 0;
248     ASSERT_LIST_INVARIANT(ListHead);
249 
250     /* Decrement number of available pages */
251     MiDecrementAvailablePages();
252 
253 #if MI_TRACE_PFNS
254     ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
255     Entry->PfnUsage = MI_PFN_CURRENT_USAGE;
256     memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
257     Entry->CallSite = _ReturnAddress();
258     MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
259     MI_SET_PROCESS2("Not Set");
260 #endif
261 }
262 
263 VOID
264 NTAPI
265 MiUnlinkPageFromList(IN PMMPFN Pfn)
266 {
267     PMMPFNLIST ListHead;
268     PFN_NUMBER OldFlink, OldBlink;
269 
270     /* Make sure the PFN lock is held */
271     MI_ASSERT_PFN_LOCK_HELD();
272 
273     /* ARM3 should only call this for dead pages */
274     ASSERT(Pfn->u3.e2.ReferenceCount == 0);
275 
276     /* Transition pages are supposed to be standby/modified/nowrite */
277     ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation];
278     ASSERT(ListHead->ListName >= StandbyPageList);
279 
280     /* Check if this was standby, or modified */
281     if (ListHead == &MmStandbyPageListHead)
282     {
283         /* Should not be a ROM page */
284         ASSERT(Pfn->u3.e1.Rom == 0);
285 
286         /* Get the exact list */
287         ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority];
288 
289         /* Decrement number of available pages */
290         MiDecrementAvailablePages();
291 
292         /* Decrease transition page counter */
293         ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
294         MmTransitionSharedPages--;
295     }
296     else if (ListHead == &MmModifiedPageListHead)
297     {
298         /* Only shared memory (page-file backed) modified pages are supported */
299         ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0);
300 
301         /* Decrement the counters */
302         ListHead->Total--;
303         MmTotalPagesForPagingFile--;
304 
305         /* Pick the correct colored list */
306         ListHead = &MmModifiedPageListByColor[0];
307 
308         /* Decrease transition page counter */
309         MmTransitionSharedPages--;
310     }
311     else if (ListHead == &MmModifiedNoWritePageListHead)
312     {
313         /* List not yet supported */
314         ASSERT(FALSE);
315     }
316 
317     /* Nothing should be in progress and the list should not be empty */
318     ASSERT(Pfn->u3.e1.WriteInProgress == 0);
319     ASSERT(Pfn->u3.e1.ReadInProgress == 0);
320     ASSERT(ListHead->Total != 0);
321 
322     /* Get the forward and back pointers */
323     OldFlink = Pfn->u1.Flink;
324     OldBlink = Pfn->u2.Blink;
325 
326     /* Check if the next entry is the list head */
327     if (OldFlink != LIST_HEAD)
328     {
329         /* It is not, so set the backlink of the actual entry, to our backlink */
330         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
331     }
332     else
333     {
334         /* Set the list head's backlink instead */
335         ListHead->Blink = OldBlink;
336     }
337 
338     /* Check if the back entry is the list head */
339     if (OldBlink != LIST_HEAD)
340     {
341         /* It is not, so set the backlink of the actual entry, to our backlink */
342         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
343     }
344     else
345     {
346         /* Set the list head's backlink instead */
347         ListHead->Flink = OldFlink;
348     }
349 
350     /* ReactOS Hack */
351     Pfn->OriginalPte.u.Long = 0;
352 
353     /* We are not on a list anymore */
354     Pfn->u1.Flink = Pfn->u2.Blink = 0;
355 
356     /* Remove one entry from the list */
357     ListHead->Total--;
358 
359     ASSERT_LIST_INVARIANT(ListHead);
360 }
361 
362 PFN_NUMBER
363 NTAPI
364 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
365                     IN ULONG Color)
366 {
367     PMMPFN Pfn1;
368     PMMPFNLIST ListHead;
369     MMLISTS ListName;
370     PFN_NUMBER OldFlink, OldBlink;
371     USHORT OldColor, OldCache;
372     PMMCOLOR_TABLES ColorTable;
373 
374     /* Make sure PFN lock is held */
375     MI_ASSERT_PFN_LOCK_HELD();
376     ASSERT(Color < MmSecondaryColors);
377 
378     /* Get the PFN entry */
379     Pfn1 = MI_PFN_ELEMENT(PageIndex);
380     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
381     ASSERT(Pfn1->u3.e1.Rom == 0);
382 
383     /* Capture data for later */
384     OldColor = Pfn1->u3.e1.PageColor;
385     OldCache = Pfn1->u3.e1.CacheAttribute;
386 
387     /* Could be either on free or zero list */
388     ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
389     ASSERT_LIST_INVARIANT(ListHead);
390     ListName = ListHead->ListName;
391     ASSERT(ListName <= FreePageList);
392 
393     /* Remove a page */
394     ListHead->Total--;
395 
396     /* Get the forward and back pointers */
397     OldFlink = Pfn1->u1.Flink;
398     OldBlink = Pfn1->u2.Blink;
399 
400     /* Check if the next entry is the list head */
401     if (OldFlink != LIST_HEAD)
402     {
403         /* It is not, so set the backlink of the actual entry, to our backlink */
404         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
405     }
406     else
407     {
408         /* Set the list head's backlink instead */
409         ListHead->Blink = OldBlink;
410     }
411 
412     /* Check if the back entry is the list head */
413     if (OldBlink != LIST_HEAD)
414     {
415         /* It is not, so set the backlink of the actual entry, to our backlink */
416         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
417     }
418     else
419     {
420         /* Set the list head's backlink instead */
421         ListHead->Flink = OldFlink;
422     }
423 
424     /* We are not on a list anymore */
425     ASSERT_LIST_INVARIANT(ListHead);
426     Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
427 
428     /* Zero flags but restore color and cache */
429     Pfn1->u3.e2.ShortFlags = 0;
430     Pfn1->u3.e1.PageColor = OldColor;
431     Pfn1->u3.e1.CacheAttribute = OldCache;
432 
433     /* Get the first page on the color list */
434     ASSERT(Color < MmSecondaryColors);
435     ColorTable = &MmFreePagesByColor[ListName][Color];
436     ASSERT(ColorTable->Count >= 1);
437 
438     /* Set the forward link to whoever we were pointing to */
439     ColorTable->Flink = Pfn1->OriginalPte.u.Long;
440 
441     /* Get the first page on the color list */
442     if (ColorTable->Flink == LIST_HEAD)
443     {
444         /* This is the beginning of the list, so set the sentinel value */
445         ColorTable->Blink = (PVOID)LIST_HEAD;
446     }
447     else
448     {
449         /* The list is empty, so we are the first page */
450         MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
451     }
452 
453     /* One less page */
454     ColorTable->Count--;
455 
456     /* ReactOS Hack */
457     Pfn1->OriginalPte.u.Long = 0;
458 
459     /* Decrement number of available pages */
460     MiDecrementAvailablePages();
461 
462 #if MI_TRACE_PFNS
463     ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
464     Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
465     memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
466     Pfn1->CallSite = _ReturnAddress();
467     MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
468     MI_SET_PROCESS2("Not Set");
469 #endif
470 
471     /* Return the page */
472     return PageIndex;
473 }
474 
475 PFN_NUMBER
476 NTAPI
477 MiRemoveAnyPage(IN ULONG Color)
478 {
479     PFN_NUMBER PageIndex;
480     PMMPFN Pfn1;
481 
482     /* Make sure PFN lock is held and we have pages */
483     MI_ASSERT_PFN_LOCK_HELD();
484     ASSERT(MmAvailablePages != 0);
485     ASSERT(Color < MmSecondaryColors);
486 
487     /* Check the colored free list */
488     PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
489     if (PageIndex == LIST_HEAD)
490     {
491         /* Check the colored zero list */
492         PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
493         if (PageIndex == LIST_HEAD)
494         {
495             /* Check the free list */
496             ASSERT_LIST_INVARIANT(&MmFreePageListHead);
497             PageIndex = MmFreePageListHead.Flink;
498             Color = PageIndex & MmSecondaryColorMask;
499             if (PageIndex == LIST_HEAD)
500             {
501                 /* Check the zero list */
502                 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
503                 PageIndex = MmZeroedPageListHead.Flink;
504                 Color = PageIndex & MmSecondaryColorMask;
505                 ASSERT(PageIndex != LIST_HEAD);
506                 if (PageIndex == LIST_HEAD)
507                 {
508                     /* FIXME: Should check the standby list */
509                     ASSERT(MmZeroedPageListHead.Total == 0);
510                 }
511             }
512         }
513     }
514 
515     /* Remove the page from its list */
516     PageIndex = MiRemovePageByColor(PageIndex, Color);
517 
518     /* Sanity checks */
519     Pfn1 = MI_PFN_ELEMENT(PageIndex);
520     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
521            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
522     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
523     ASSERT(Pfn1->u2.ShareCount == 0);
524     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
525     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
526 
527     /* Return the page */
528     return PageIndex;
529 }
530 
531 PFN_NUMBER
532 NTAPI
533 MiRemoveZeroPage(IN ULONG Color)
534 {
535     PFN_NUMBER PageIndex;
536     PMMPFN Pfn1;
537     BOOLEAN Zero = FALSE;
538 
539     /* Make sure PFN lock is held and we have pages */
540     MI_ASSERT_PFN_LOCK_HELD();
541     ASSERT(MmAvailablePages != 0);
542     ASSERT(Color < MmSecondaryColors);
543 
544     /* Check the colored zero list */
545     PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
546     if (PageIndex == LIST_HEAD)
547     {
548         /* Check the zero list */
549         ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
550         PageIndex = MmZeroedPageListHead.Flink;
551         if (PageIndex == LIST_HEAD)
552         {
553             /* This means there's no zero pages, we have to look for free ones */
554             ASSERT(MmZeroedPageListHead.Total == 0);
555             Zero = TRUE;
556 
557             /* Check the colored free list */
558             PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
559             if (PageIndex == LIST_HEAD)
560             {
561                 /* Check the free list */
562                 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
563                 PageIndex = MmFreePageListHead.Flink;
564                 Color = PageIndex & MmSecondaryColorMask;
565                 ASSERT(PageIndex != LIST_HEAD);
566                 if (PageIndex == LIST_HEAD)
567                 {
568                     /* FIXME: Should check the standby list */
569                     ASSERT(MmZeroedPageListHead.Total == 0);
570                 }
571             }
572         }
573         else
574         {
575             Color = PageIndex & MmSecondaryColorMask;
576         }
577     }
578 
579     /* Sanity checks */
580     Pfn1 = MI_PFN_ELEMENT(PageIndex);
581     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
582            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
583 
584     /* Remove the page from its list */
585     PageIndex = MiRemovePageByColor(PageIndex, Color);
586     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
587 
588     /* Zero it, if needed */
589     if (Zero) MiZeroPhysicalPage(PageIndex);
590 
591     /* Sanity checks */
592     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
593     ASSERT(Pfn1->u2.ShareCount == 0);
594     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
595     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
596 
597     /* Return the page */
598     return PageIndex;
599 }
600 
601 VOID
602 NTAPI
603 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
604 {
605     PMMPFNLIST ListHead;
606     PFN_NUMBER LastPage;
607     PMMPFN Pfn1;
608     ULONG Color;
609     PMMPFN Blink;
610     PMMCOLOR_TABLES ColorTable;
611 
612     /* Make sure the page index is valid */
613     MI_ASSERT_PFN_LOCK_HELD();
614     ASSERT((PageFrameIndex != 0) &&
615            (PageFrameIndex <= MmHighestPhysicalPage) &&
616            (PageFrameIndex >= MmLowestPhysicalPage));
617 
618     /* Get the PFN entry */
619     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
620 
621     /* Sanity checks that a right kind of page is being inserted here */
622     ASSERT(Pfn1->u4.MustBeCached == 0);
623     ASSERT(Pfn1->u3.e1.Rom != 1);
624     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
625     ASSERT(Pfn1->u4.VerifierAllocation == 0);
626     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
627 
628     /* Get the free page list and increment its count */
629     ListHead = &MmFreePageListHead;
630     ASSERT_LIST_INVARIANT(ListHead);
631     ListHead->Total++;
632 
633     /* Get the last page on the list */
634     LastPage = ListHead->Blink;
635     if (LastPage != LIST_HEAD)
636     {
637         /* Link us with the previous page, so we're at the end now */
638         MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
639     }
640     else
641     {
642         /* The list is empty, so we are the first page */
643         ListHead->Flink = PageFrameIndex;
644     }
645 
646     /* Now make the list head point back to us (since we go at the end) */
647     ListHead->Blink = PageFrameIndex;
648     ASSERT_LIST_INVARIANT(ListHead);
649 
650     /* And initialize our own list pointers */
651     Pfn1->u1.Flink = LIST_HEAD;
652     Pfn1->u2.Blink = LastPage;
653 
654     /* Set the list name and default priority */
655     Pfn1->u3.e1.PageLocation = FreePageList;
656     Pfn1->u4.Priority = 3;
657 
658     /* Clear some status fields */
659     Pfn1->u4.InPageError = 0;
660     Pfn1->u4.AweAllocation = 0;
661 
662     /* Increment number of available pages */
663     MiIncrementAvailablePages();
664 
665     /* Get the page color */
666     Color = PageFrameIndex & MmSecondaryColorMask;
667 
668     /* Get the first page on the color list */
669     ColorTable = &MmFreePagesByColor[FreePageList][Color];
670     if (ColorTable->Flink == LIST_HEAD)
671     {
672         /* The list is empty, so we are the first page */
673         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
674         ColorTable->Flink = PageFrameIndex;
675     }
676     else
677     {
678         /* Get the previous page */
679         Blink = (PMMPFN)ColorTable->Blink;
680 
681         /* Make it link to us, and link back to it */
682         Blink->OriginalPte.u.Long = PageFrameIndex;
683         Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
684     }
685 
686     /* Now initialize our own list pointers */
687     ColorTable->Blink = Pfn1;
688 
689     /* This page is now the last */
690     Pfn1->OriginalPte.u.Long = LIST_HEAD;
691 
692     /* And increase the count in the colored list */
693     ColorTable->Count++;
694 
695     /* Notify zero page thread if enough pages are on the free list now */
696     if (ListHead->Total >= 8)
697     {
698         /* Set the event */
699         KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
700     }
701 
702 #if MI_TRACE_PFNS
703     Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
704     RtlZeroMemory(Pfn1->ProcessName, 16);
705     Pfn1->CallSite = NULL;
706 #endif
707 }
708 
709 VOID
710 FASTCALL
711 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
712 {
713     PMMPFNLIST ListHead;
714     PFN_NUMBER Flink;
715     PMMPFN Pfn1, Pfn2;
716 
717     /* Make sure the lock is held */
718     DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex);
719     MI_ASSERT_PFN_LOCK_HELD();
720 
721     /* Make sure the PFN is valid */
722     ASSERT((PageFrameIndex != 0) &&
723            (PageFrameIndex <= MmHighestPhysicalPage) &&
724            (PageFrameIndex >= MmLowestPhysicalPage));
725 
726     /* Grab the PFN and validate it is the right kind of PFN being inserted */
727     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
728     ASSERT(Pfn1->u4.MustBeCached == 0);
729     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
730     ASSERT(Pfn1->u3.e1.PrototypePte == 1);
731     ASSERT(Pfn1->u3.e1.Rom != 1);
732 
733     /* One more transition page on a list */
734     MmTransitionSharedPages++;
735 
736     /* Get the standby page list and increment its count */
737     ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
738     ASSERT_LIST_INVARIANT(ListHead);
739     ListHead->Total++;
740 
741     /* Make the head of the list point to this page now */
742     Flink = ListHead->Flink;
743     ListHead->Flink = PageFrameIndex;
744 
745     /* Make the page point to the previous head, and back to the list */
746     Pfn1->u1.Flink = Flink;
747     Pfn1->u2.Blink = LIST_HEAD;
748 
749     /* Was the list empty? */
750     if (Flink != LIST_HEAD)
751     {
752         /* It wasn't, so update the backlink of the previous head page */
753         Pfn2 = MI_PFN_ELEMENT(Flink);
754         Pfn2->u2.Blink = PageFrameIndex;
755     }
756     else
757     {
758         /* It was empty, so have it loop back around to this new page */
759         ListHead->Blink = PageFrameIndex;
760     }
761 
762     /* Move the page onto its new location */
763     Pfn1->u3.e1.PageLocation = StandbyPageList;
764 
765     /* Increment number of available pages */
766     MiIncrementAvailablePages();
767 }
768 
769 VOID
770 NTAPI
771 MiInsertPageInList(IN PMMPFNLIST ListHead,
772                    IN PFN_NUMBER PageFrameIndex)
773 {
774     PFN_NUMBER Flink, LastPage;
775     PMMPFN Pfn1, Pfn2;
776     MMLISTS ListName;
777     PMMCOLOR_TABLES ColorHead;
778     ULONG Color;
779 
780     /* For free pages, use MiInsertPageInFreeList */
781     ASSERT(ListHead != &MmFreePageListHead);
782 
783     /* Make sure the lock is held */
784     MI_ASSERT_PFN_LOCK_HELD();
785 
786     /* Make sure the PFN is valid */
787     ASSERT((PageFrameIndex) &&
788            (PageFrameIndex <= MmHighestPhysicalPage) &&
789            (PageFrameIndex >= MmLowestPhysicalPage));
790 
791     /* Page should be unused */
792     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
793     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
794     ASSERT(Pfn1->u3.e1.Rom != 1);
795 
796     /* Is a standby or modified page being inserted? */
797     ListName = ListHead->ListName;
798     if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
799     {
800         /* If the page is in transition, it must also be a prototype page */
801         if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
802             (Pfn1->OriginalPte.u.Soft.Transition == 1))
803         {
804             /* Crash the system on inconsistency */
805             KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
806         }
807     }
808 
809     /* Standby pages are prioritized, so we need to get the real head */
810     if (ListHead == &MmStandbyPageListHead)
811     {
812         /* Obviously the prioritized list should still have the same name */
813         ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
814         ASSERT(ListHead->ListName == ListName);
815     }
816 
817     /* Increment the list count */
818     ListHead->Total++;
819 
820     /* Is a modified page being inserted? */
821     if (ListHead == &MmModifiedPageListHead)
822     {
823         /* For now, only single-prototype pages should end up in this path */
824         DPRINT("Modified page being added: %lx\n", PageFrameIndex);
825         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
826 
827         /* Modified pages are colored when they are selected for page file */
828         ListHead = &MmModifiedPageListByColor[0];
829         ASSERT (ListHead->ListName == ListName);
830         ListHead->Total++;
831 
832         /* Increment the number of paging file modified pages */
833         MmTotalPagesForPagingFile++;
834     }
835 
836     /* Don't handle bad pages yet yet */
837     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
838 
839     /* Zero pages go to the head, all other pages go to the end */
840     if (ListName == ZeroedPageList)
841     {
842         /* Make the head of the list point to this page now */
843         Flink = ListHead->Flink;
844         ListHead->Flink = PageFrameIndex;
845 
846         /* Make the page point to the previous head, and back to the list */
847         Pfn1->u1.Flink = Flink;
848         Pfn1->u2.Blink = LIST_HEAD;
849 
850         /* Was the list empty? */
851         if (Flink != LIST_HEAD)
852         {
853             /* It wasn't, so update the backlink of the previous head page */
854             Pfn2 = MI_PFN_ELEMENT(Flink);
855             Pfn2->u2.Blink = PageFrameIndex;
856         }
857         else
858         {
859             /* It was empty, so have it loop back around to this new page */
860             ListHead->Blink = PageFrameIndex;
861         }
862     }
863     else
864     {
865         /* Get the last page on the list */
866         LastPage = ListHead->Blink;
867         if (LastPage != LIST_HEAD)
868         {
869             /* Link us with the previous page, so we're at the end now */
870             MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
871         }
872         else
873         {
874             /* The list is empty, so we are the first page */
875             ListHead->Flink = PageFrameIndex;
876         }
877 
878         /* Now make the list head point back to us (since we go at the end) */
879         ListHead->Blink = PageFrameIndex;
880         ASSERT_LIST_INVARIANT(ListHead);
881 
882         /* And initialize our own list pointers */
883         Pfn1->u1.Flink = LIST_HEAD;
884         Pfn1->u2.Blink = LastPage;
885     }
886 
887     /* Move the page onto its new location */
888     Pfn1->u3.e1.PageLocation = ListName;
889 
890     /* For zero/free pages, we also have to handle the colored lists */
891     if (ListName <= StandbyPageList)
892     {
893         /* Increment number of available pages */
894         MiIncrementAvailablePages();
895 
896         /* Sanity checks */
897         ASSERT(ListName == ZeroedPageList);
898         ASSERT(Pfn1->u4.InPageError == 0);
899 
900         /* Get the page color */
901         Color = PageFrameIndex & MmSecondaryColorMask;
902 
903         /* Get the list for this color */
904         ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
905 
906         /* Get the old head */
907         Flink = ColorHead->Flink;
908 
909         /* Make this page point back to the list, and point forwards to the old head */
910         Pfn1->OriginalPte.u.Long = Flink;
911         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
912 
913         /* Set the new head */
914         ColorHead->Flink = PageFrameIndex;
915 
916         /* Was the head empty? */
917         if (Flink != LIST_HEAD)
918         {
919             /* No, so make the old head point to this page */
920             Pfn2 = MI_PFN_ELEMENT(Flink);
921             Pfn2->u4.PteFrame = PageFrameIndex;
922         }
923         else
924         {
925             /* Yes, make it loop back to this page */
926             ColorHead->Blink = (PVOID)Pfn1;
927         }
928 
929         /* One more paged on the colored list */
930         ColorHead->Count++;
931 
932 #if MI_TRACE_PFNS
933             ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
934             Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
935             RtlZeroMemory(Pfn1->ProcessName, 16);
936             Pfn1->CallSite = NULL;
937 #endif
938     }
939     else if (ListName == ModifiedPageList)
940     {
941         /* In ARM3, page must be destined for page file, and not yet written out */
942         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
943         ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
944 
945         /* One more transition page */
946         MmTransitionSharedPages++;
947 
948         /* Increment the number of per-process modified pages */
949         PsGetCurrentProcess()->ModifiedPageCount++;
950 
951         /* FIXME: Wake up modified page writer if there are not enough free pages */
952     }
953     else if (ListName == ModifiedNoWritePageList)
954     {
955         /* This list is not yet implemented */
956         ASSERT(FALSE);
957     }
958 }
959 
960 VOID
961 NTAPI
962 MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
963                 IN PMMPTE PointerPte,
964                 IN BOOLEAN Modified)
965 {
966     PMMPFN Pfn1;
967     NTSTATUS Status;
968     PMMPTE PointerPtePte;
969     MI_ASSERT_PFN_LOCK_HELD();
970 
971     /* Setup the PTE */
972     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
973     Pfn1->PteAddress = PointerPte;
974 
975     DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress());
976 
977     /* Check if this PFN is part of a valid address space */
978     if (PointerPte->u.Hard.Valid == 1)
979     {
980         /* Only valid from MmCreateProcessAddressSpace path */
981         ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
982 
983         /* Make this a demand zero PTE */
984         MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
985     }
986     else
987     {
988         /* Copy the PTE data */
989         Pfn1->OriginalPte = *PointerPte;
990         ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
991                  (Pfn1->OriginalPte.u.Soft.Transition == 1)));
992     }
993 
994     /* Otherwise this is a fresh page -- set it up */
995     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
996     Pfn1->u3.e2.ReferenceCount = 1;
997     Pfn1->u2.ShareCount = 1;
998     Pfn1->u3.e1.PageLocation = ActiveAndValid;
999     ASSERT(Pfn1->u3.e1.Rom == 0);
1000     Pfn1->u3.e1.Modified = Modified;
1001 
1002     /* Get the page table for the PTE */
1003     PointerPtePte = MiAddressToPte(PointerPte);
1004     if (PointerPtePte->u.Hard.Valid == 0)
1005     {
1006         /* Make sure the PDE gets paged in properly */
1007         Status = MiCheckPdeForPagedPool(PointerPte);
1008         if (!NT_SUCCESS(Status))
1009         {
1010             /* Crash */
1011             KeBugCheckEx(MEMORY_MANAGEMENT,
1012                          0x61940,
1013                          (ULONG_PTR)PointerPte,
1014                          (ULONG_PTR)PointerPtePte->u.Long,
1015                          (ULONG_PTR)MiPteToAddress(PointerPte));
1016         }
1017     }
1018 
1019     /* Get the PFN for the page table */
1020     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1021     ASSERT(PageFrameIndex != 0);
1022     Pfn1->u4.PteFrame = PageFrameIndex;
1023 
1024     DPRINT("Incrementing share count of %lp from %p\n", PageFrameIndex, _ReturnAddress());
1025 
1026     /* Increase its share count so we don't get rid of it */
1027     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1028     Pfn1->u2.ShareCount++;
1029 }
1030 
1031 VOID
1032 NTAPI
1033 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
1034                                IN PMMPTE PointerPte,
1035                                IN MMPTE TempPte)
1036 {
1037     PMMPFN Pfn1;
1038     NTSTATUS Status;
1039     PMMPTE PointerPtePte;
1040     MI_ASSERT_PFN_LOCK_HELD();
1041 
1042     /* PTE must be invalid */
1043     ASSERT(PointerPte->u.Hard.Valid == 0);
1044 
1045     /* Setup the PTE */
1046     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1047     Pfn1->PteAddress = PointerPte;
1048     Pfn1->OriginalPte = DemandZeroPte;
1049 
1050     DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress());
1051 
1052     /* Otherwise this is a fresh page -- set it up */
1053     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1054     Pfn1->u3.e2.ReferenceCount++;
1055     Pfn1->u2.ShareCount++;
1056     Pfn1->u3.e1.PageLocation = ActiveAndValid;
1057     ASSERT(Pfn1->u3.e1.Rom == 0);
1058     Pfn1->u3.e1.Modified = 1;
1059 
1060     /* Get the page table for the PTE */
1061     PointerPtePte = MiAddressToPte(PointerPte);
1062     if (PointerPtePte->u.Hard.Valid == 0)
1063     {
1064         /* Make sure the PDE gets paged in properly */
1065         Status = MiCheckPdeForPagedPool(PointerPte);
1066         if (!NT_SUCCESS(Status))
1067         {
1068             /* Crash */
1069             KeBugCheckEx(MEMORY_MANAGEMENT,
1070                          0x61940,
1071                          (ULONG_PTR)PointerPte,
1072                          (ULONG_PTR)PointerPtePte->u.Long,
1073                          (ULONG_PTR)MiPteToAddress(PointerPte));
1074         }
1075     }
1076 
1077     /* Get the PFN for the page table */
1078     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1079     ASSERT(PageFrameIndex != 0);
1080     Pfn1->u4.PteFrame = PageFrameIndex;
1081 
1082     /* Increase its share count so we don't get rid of it */
1083     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1084     Pfn1->u2.ShareCount++;
1085     DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress());
1086 
1087     /* Write valid PTE */
1088     MI_WRITE_VALID_PTE(PointerPte, TempPte);
1089 }
1090 
1091 NTSTATUS
1092 NTAPI
1093 MiInitializeAndChargePfn(OUT PPFN_NUMBER PageFrameIndex,
1094                          IN PMMPDE PointerPde,
1095                          IN PFN_NUMBER ContainingPageFrame,
1096                          IN BOOLEAN SessionAllocation)
1097 {
1098     MMPDE TempPde;
1099     KIRQL OldIrql;
1100 
1101     /* Use either a global or local PDE */
1102     TempPde = SessionAllocation ? ValidKernelPdeLocal : ValidKernelPde;
1103 
1104     /* Lock the PFN database */
1105     OldIrql = MiAcquirePfnLock();
1106 
1107     /* Make sure nobody is racing us */
1108     if (PointerPde->u.Hard.Valid == 1)
1109     {
1110         /* Return special error if that was the case */
1111         MiReleasePfnLock(OldIrql);
1112         return STATUS_RETRY;
1113     }
1114 
1115     /* Grab a zero page and set the PFN, then make it valid */
1116     *PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
1117     TempPde.u.Hard.PageFrameNumber = *PageFrameIndex;
1118     MI_WRITE_VALID_PDE(PointerPde, TempPde);
1119 
1120     /* Initialize the PFN */
1121     MiInitializePfnForOtherProcess(*PageFrameIndex,
1122                                    PointerPde,
1123                                    ContainingPageFrame);
1124     ASSERT(MI_PFN_ELEMENT(*PageFrameIndex)->u1.WsIndex == 0);
1125 
1126     /* Release the lock and return success */
1127     MiReleasePfnLock(OldIrql);
1128     return STATUS_SUCCESS;
1129 }
1130 
1131 VOID
1132 NTAPI
1133 MiDecrementShareCount(IN PMMPFN Pfn1,
1134                       IN PFN_NUMBER PageFrameIndex)
1135 {
1136     PMMPTE PointerPte;
1137     MMPTE TempPte;
1138 
1139     ASSERT(PageFrameIndex > 0);
1140     ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
1141     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
1142     ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
1143 
1144     DPRINT("Decrementing %p from %p\n", Pfn1, _ReturnAddress());
1145 
1146     /* Page must be in-use */
1147     if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
1148         (Pfn1->u3.e1.PageLocation != StandbyPageList))
1149     {
1150         /* Otherwise we have PFN corruption */
1151         KeBugCheckEx(PFN_LIST_CORRUPT,
1152                      0x99,
1153                      PageFrameIndex,
1154                      Pfn1->u3.e1.PageLocation,
1155                      0);
1156     }
1157 
1158     /* Page should at least have one reference */
1159     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1160 
1161     /* Check if the share count is now 0 */
1162     ASSERT(Pfn1->u2.ShareCount < 0xF000000);
1163     if (!--Pfn1->u2.ShareCount)
1164     {
1165         /* Was this a prototype PTE? */
1166         if (Pfn1->u3.e1.PrototypePte)
1167         {
1168             /* Grab the PTE address and make sure it's in prototype pool */
1169             PointerPte = Pfn1->PteAddress;
1170             ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
1171 
1172             /* The PTE that backs it should also be valdi */
1173             PointerPte = MiAddressToPte(PointerPte);
1174             ASSERT(PointerPte->u.Hard.Valid == 1);
1175 
1176             /* Get the original prototype PTE and turn it into a transition PTE */
1177             PointerPte = Pfn1->PteAddress;
1178             TempPte = *PointerPte;
1179             TempPte.u.Soft.Transition = 1;
1180             TempPte.u.Soft.Valid = 0;
1181             TempPte.u.Soft.Prototype = 0;
1182             TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
1183             MI_WRITE_INVALID_PTE(PointerPte, TempPte);
1184             DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
1185         }
1186 
1187         /* Put the page in transition */
1188         Pfn1->u3.e1.PageLocation = TransitionPage;
1189 
1190         /* PFN lock must be held */
1191         MI_ASSERT_PFN_LOCK_HELD();
1192 
1193         if (Pfn1->u3.e2.ReferenceCount == 1)
1194         {
1195             /* Is there still a PFN for this page? */
1196             if (MI_IS_PFN_DELETED(Pfn1))
1197             {
1198                 /* Clear the last reference */
1199                 Pfn1->u3.e2.ReferenceCount = 0;
1200                 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
1201 
1202                 /* Mark the page temporarily as valid, we're going to make it free soon */
1203                 Pfn1->u3.e1.PageLocation = ActiveAndValid;
1204 
1205                 /* Bring it back into the free list */
1206                 MiInsertPageInFreeList(PageFrameIndex);
1207             }
1208             else
1209             {
1210                 /* PFN not yet deleted, drop a ref count */
1211                 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
1212             }
1213         }
1214         else
1215         {
1216             /* Otherwise, just drop the reference count */
1217             InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1218         }
1219     }
1220 }
1221 
1222 VOID
1223 NTAPI
1224 MiDecrementReferenceCount(IN PMMPFN Pfn1,
1225                           IN PFN_NUMBER PageFrameIndex)
1226 {
1227     /* PFN lock must be held */
1228     MI_ASSERT_PFN_LOCK_HELD();
1229 
1230     /* Sanity checks on the page */
1231     if (PageFrameIndex > MmHighestPhysicalPage ||
1232         Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) ||
1233         Pfn1->u3.e2.ReferenceCount == 0 ||
1234         Pfn1->u3.e2.ReferenceCount >= 2500)
1235     {
1236         DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage);
1237         DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount);
1238         ASSERT(PageFrameIndex <= MmHighestPhysicalPage);
1239         ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
1240         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1241         ASSERT(Pfn1->u3.e2.ReferenceCount < 2500);
1242     }
1243 
1244     /* Dereference the page, bail out if it's still alive */
1245     InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1246     if (Pfn1->u3.e2.ReferenceCount) return;
1247 
1248     /* Nobody should still have reference to this page */
1249     if (Pfn1->u2.ShareCount != 0)
1250     {
1251         /* Otherwise something's really wrong */
1252         KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
1253     }
1254 
1255     /* And it should be lying on some page list */
1256     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1257 
1258     /* Did someone set the delete flag? */
1259     if (MI_IS_PFN_DELETED(Pfn1))
1260     {
1261         /* Insert it into the free list, there's nothing left to do */
1262         MiInsertPageInFreeList(PageFrameIndex);
1263         return;
1264     }
1265 
1266     /* Check to see which list this page should go into */
1267     if (Pfn1->u3.e1.Modified == 1)
1268     {
1269         /* Push it into the modified page list */
1270         MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
1271     }
1272     else
1273     {
1274         /* Otherwise, insert this page into the standby list */
1275         ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
1276         MiInsertStandbyListAtFront(PageFrameIndex);
1277     }
1278 }
1279 
1280 VOID
1281 NTAPI
1282 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
1283                                IN PVOID PteAddress,
1284                                IN PFN_NUMBER PteFrame)
1285 {
1286     PMMPFN Pfn1;
1287 
1288     /* Setup the PTE */
1289     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1290     Pfn1->PteAddress = PteAddress;
1291 
1292     /* Make this a software PTE */
1293     MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
1294 
1295     DPRINT("Called for %p from %p\n", Pfn1, _ReturnAddress());
1296 
1297     /* Setup the page */
1298     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1299     Pfn1->u3.e2.ReferenceCount = 1;
1300     Pfn1->u2.ShareCount = 1;
1301     Pfn1->u3.e1.PageLocation = ActiveAndValid;
1302     Pfn1->u3.e1.Modified = TRUE;
1303     Pfn1->u4.InPageError = FALSE;
1304 
1305     /* Did we get a PFN for the page table */
1306     if (PteFrame)
1307     {
1308         /* Store it */
1309         Pfn1->u4.PteFrame = PteFrame;
1310 
1311         /* Increase its share count so we don't get rid of it */
1312         Pfn1 = MI_PFN_ELEMENT(PteFrame);
1313 
1314         DPRINT("Incrementing %p from %p\n", Pfn1, _ReturnAddress());
1315         Pfn1->u2.ShareCount++;
1316     }
1317 }
1318 
1319 /* EOF */
1320