xref: /reactos/ntoskrnl/mm/ARM3/pfnlist.c (revision 845faec4)
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 //    MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
258 //    memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
259 #endif
260 }
261 
262 VOID
263 NTAPI
264 MiUnlinkPageFromList(IN PMMPFN Pfn)
265 {
266     PMMPFNLIST ListHead;
267     PFN_NUMBER OldFlink, OldBlink;
268 
269     /* Make sure the PFN lock is held */
270     MI_ASSERT_PFN_LOCK_HELD();
271 
272     /* ARM3 should only call this for dead pages */
273     ASSERT(Pfn->u3.e2.ReferenceCount == 0);
274 
275     /* Transition pages are supposed to be standby/modified/nowrite */
276     ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation];
277     ASSERT(ListHead->ListName >= StandbyPageList);
278 
279     /* Check if this was standby, or modified */
280     if (ListHead == &MmStandbyPageListHead)
281     {
282         /* Should not be a ROM page */
283         ASSERT(Pfn->u3.e1.Rom == 0);
284 
285         /* Get the exact list */
286         ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority];
287 
288         /* Decrement number of available pages */
289         MiDecrementAvailablePages();
290 
291         /* Decrease transition page counter */
292         ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
293         MmTransitionSharedPages--;
294     }
295     else if (ListHead == &MmModifiedPageListHead)
296     {
297         /* Only shared memory (page-file backed) modified pages are supported */
298         ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0);
299 
300         /* Decrement the counters */
301         ListHead->Total--;
302         MmTotalPagesForPagingFile--;
303 
304         /* Pick the correct colored list */
305         ListHead = &MmModifiedPageListByColor[0];
306 
307         /* Decrease transition page counter */
308         MmTransitionSharedPages--;
309     }
310     else if (ListHead == &MmModifiedNoWritePageListHead)
311     {
312         /* List not yet supported */
313         ASSERT(FALSE);
314     }
315 
316     /* Nothing should be in progress and the list should not be empty */
317     ASSERT(Pfn->u3.e1.WriteInProgress == 0);
318     ASSERT(Pfn->u3.e1.ReadInProgress == 0);
319     ASSERT(ListHead->Total != 0);
320 
321     /* Get the forward and back pointers */
322     OldFlink = Pfn->u1.Flink;
323     OldBlink = Pfn->u2.Blink;
324 
325     /* Check if the next entry is the list head */
326     if (OldFlink != LIST_HEAD)
327     {
328         /* It is not, so set the backlink of the actual entry, to our backlink */
329         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
330     }
331     else
332     {
333         /* Set the list head's backlink instead */
334         ListHead->Blink = OldBlink;
335     }
336 
337     /* Check if the back entry is the list head */
338     if (OldBlink != LIST_HEAD)
339     {
340         /* It is not, so set the backlink of the actual entry, to our backlink */
341         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
342     }
343     else
344     {
345         /* Set the list head's backlink instead */
346         ListHead->Flink = OldFlink;
347     }
348 
349     /* ReactOS Hack */
350     Pfn->OriginalPte.u.Long = 0;
351 
352     /* We are not on a list anymore */
353     Pfn->u1.Flink = Pfn->u2.Blink = 0;
354 
355     /* Remove one entry from the list */
356     ListHead->Total--;
357 
358     ASSERT_LIST_INVARIANT(ListHead);
359 }
360 
361 PFN_NUMBER
362 NTAPI
363 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
364                     IN ULONG Color)
365 {
366     PMMPFN Pfn1;
367     PMMPFNLIST ListHead;
368     MMLISTS ListName;
369     PFN_NUMBER OldFlink, OldBlink;
370     USHORT OldColor, OldCache;
371     PMMCOLOR_TABLES ColorTable;
372 
373     /* Make sure PFN lock is held */
374     MI_ASSERT_PFN_LOCK_HELD();
375     ASSERT(Color < MmSecondaryColors);
376 
377     /* Get the PFN entry */
378     Pfn1 = MI_PFN_ELEMENT(PageIndex);
379     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
380     ASSERT(Pfn1->u3.e1.Rom == 0);
381 
382     /* Capture data for later */
383     OldColor = Pfn1->u3.e1.PageColor;
384     OldCache = Pfn1->u3.e1.CacheAttribute;
385 
386     /* Could be either on free or zero list */
387     ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
388     ASSERT_LIST_INVARIANT(ListHead);
389     ListName = ListHead->ListName;
390     ASSERT(ListName <= FreePageList);
391 
392     /* Remove a page */
393     ListHead->Total--;
394 
395     /* Get the forward and back pointers */
396     OldFlink = Pfn1->u1.Flink;
397     OldBlink = Pfn1->u2.Blink;
398 
399     /* Check if the next entry is the list head */
400     if (OldFlink != LIST_HEAD)
401     {
402         /* It is not, so set the backlink of the actual entry, to our backlink */
403         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
404     }
405     else
406     {
407         /* Set the list head's backlink instead */
408         ListHead->Blink = OldBlink;
409     }
410 
411     /* Check if the back entry is the list head */
412     if (OldBlink != LIST_HEAD)
413     {
414         /* It is not, so set the backlink of the actual entry, to our backlink */
415         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
416     }
417     else
418     {
419         /* Set the list head's backlink instead */
420         ListHead->Flink = OldFlink;
421     }
422 
423     /* We are not on a list anymore */
424     ASSERT_LIST_INVARIANT(ListHead);
425     Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
426 
427     /* Zero flags but restore color and cache */
428     Pfn1->u3.e2.ShortFlags = 0;
429     Pfn1->u3.e1.PageColor = OldColor;
430     Pfn1->u3.e1.CacheAttribute = OldCache;
431 
432     /* Get the first page on the color list */
433     ASSERT(Color < MmSecondaryColors);
434     ColorTable = &MmFreePagesByColor[ListName][Color];
435     ASSERT(ColorTable->Count >= 1);
436 
437     /* Set the forward link to whoever we were pointing to */
438     ColorTable->Flink = Pfn1->OriginalPte.u.Long;
439 
440     /* Get the first page on the color list */
441     if (ColorTable->Flink == LIST_HEAD)
442     {
443         /* This is the beginning of the list, so set the sentinel value */
444         ColorTable->Blink = (PVOID)LIST_HEAD;
445     }
446     else
447     {
448         /* The list is empty, so we are the first page */
449         MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
450     }
451 
452     /* One less page */
453     ColorTable->Count--;
454 
455     /* ReactOS Hack */
456     Pfn1->OriginalPte.u.Long = 0;
457 
458     /* Decrement number of available pages */
459     MiDecrementAvailablePages();
460 
461 #if MI_TRACE_PFNS
462     //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
463     Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
464     memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
465     //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
466     //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
467 #endif
468 
469     /* Return the page */
470     return PageIndex;
471 }
472 
473 PFN_NUMBER
474 NTAPI
475 MiRemoveAnyPage(IN ULONG Color)
476 {
477     PFN_NUMBER PageIndex;
478     PMMPFN Pfn1;
479 
480     /* Make sure PFN lock is held and we have pages */
481     MI_ASSERT_PFN_LOCK_HELD();
482     ASSERT(MmAvailablePages != 0);
483     ASSERT(Color < MmSecondaryColors);
484 
485     /* Check the colored free list */
486     PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
487     if (PageIndex == LIST_HEAD)
488     {
489         /* Check the colored zero list */
490         PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
491         if (PageIndex == LIST_HEAD)
492         {
493             /* Check the free list */
494             ASSERT_LIST_INVARIANT(&MmFreePageListHead);
495             PageIndex = MmFreePageListHead.Flink;
496             Color = PageIndex & MmSecondaryColorMask;
497             if (PageIndex == LIST_HEAD)
498             {
499                 /* Check the zero list */
500                 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
501                 PageIndex = MmZeroedPageListHead.Flink;
502                 Color = PageIndex & MmSecondaryColorMask;
503                 ASSERT(PageIndex != LIST_HEAD);
504                 if (PageIndex == LIST_HEAD)
505                 {
506                     /* FIXME: Should check the standby list */
507                     ASSERT(MmZeroedPageListHead.Total == 0);
508                 }
509             }
510         }
511     }
512 
513     /* Remove the page from its list */
514     PageIndex = MiRemovePageByColor(PageIndex, Color);
515 
516     /* Sanity checks */
517     Pfn1 = MI_PFN_ELEMENT(PageIndex);
518     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
519            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
520     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
521     ASSERT(Pfn1->u2.ShareCount == 0);
522     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
523     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
524 
525     /* Return the page */
526     return PageIndex;
527 }
528 
529 PFN_NUMBER
530 NTAPI
531 MiRemoveZeroPage(IN ULONG Color)
532 {
533     PFN_NUMBER PageIndex;
534     PMMPFN Pfn1;
535     BOOLEAN Zero = FALSE;
536 
537     /* Make sure PFN lock is held and we have pages */
538     MI_ASSERT_PFN_LOCK_HELD();
539     ASSERT(MmAvailablePages != 0);
540     ASSERT(Color < MmSecondaryColors);
541 
542     /* Check the colored zero list */
543     PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
544     if (PageIndex == LIST_HEAD)
545     {
546         /* Check the zero list */
547         ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
548         PageIndex = MmZeroedPageListHead.Flink;
549         if (PageIndex == LIST_HEAD)
550         {
551             /* This means there's no zero pages, we have to look for free ones */
552             ASSERT(MmZeroedPageListHead.Total == 0);
553             Zero = TRUE;
554 
555             /* Check the colored free list */
556             PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
557             if (PageIndex == LIST_HEAD)
558             {
559                 /* Check the free list */
560                 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
561                 PageIndex = MmFreePageListHead.Flink;
562                 Color = PageIndex & MmSecondaryColorMask;
563                 ASSERT(PageIndex != LIST_HEAD);
564                 if (PageIndex == LIST_HEAD)
565                 {
566                     /* FIXME: Should check the standby list */
567                     ASSERT(MmZeroedPageListHead.Total == 0);
568                 }
569             }
570         }
571         else
572         {
573             Color = PageIndex & MmSecondaryColorMask;
574         }
575     }
576 
577     /* Sanity checks */
578     Pfn1 = MI_PFN_ELEMENT(PageIndex);
579     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
580            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
581 
582     /* Remove the page from its list */
583     PageIndex = MiRemovePageByColor(PageIndex, Color);
584     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
585 
586     /* Zero it, if needed */
587     if (Zero) MiZeroPhysicalPage(PageIndex);
588 
589     /* Sanity checks */
590     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
591     ASSERT(Pfn1->u2.ShareCount == 0);
592     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
593     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
594 
595     /* Return the page */
596     return PageIndex;
597 }
598 
599 /* HACK for keeping legacy Mm alive */
600 extern BOOLEAN MmRosNotifyAvailablePage(PFN_NUMBER PageFrameIndex);
601 
602 VOID
603 NTAPI
604 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
605 {
606     PMMPFNLIST ListHead;
607     PFN_NUMBER LastPage;
608     PMMPFN Pfn1;
609     ULONG Color;
610     PMMPFN Blink;
611     PMMCOLOR_TABLES ColorTable;
612 
613     /* Make sure the page index is valid */
614     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
615     ASSERT((PageFrameIndex != 0) &&
616            (PageFrameIndex <= MmHighestPhysicalPage) &&
617            (PageFrameIndex >= MmLowestPhysicalPage));
618 
619     /* Get the PFN entry */
620     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
621 
622     /* Sanity checks that a right kind of page is being inserted here */
623     ASSERT(Pfn1->u4.MustBeCached == 0);
624     ASSERT(Pfn1->u3.e1.Rom != 1);
625     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
626     ASSERT(Pfn1->u4.VerifierAllocation == 0);
627     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
628 
629     /* HACK HACK HACK : Feed the page to legacy Mm */
630     if (MmRosNotifyAvailablePage(PageFrameIndex))
631     {
632         DPRINT1("Legacy Mm eating ARM3 page!.\n");
633         return;
634     }
635 
636     /* Get the free page list and increment its count */
637     ListHead = &MmFreePageListHead;
638     ASSERT_LIST_INVARIANT(ListHead);
639     ListHead->Total++;
640 
641     /* Get the last page on the list */
642     LastPage = ListHead->Blink;
643     if (LastPage != LIST_HEAD)
644     {
645         /* Link us with the previous page, so we're at the end now */
646         MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
647     }
648     else
649     {
650         /* The list is empty, so we are the first page */
651         ListHead->Flink = PageFrameIndex;
652     }
653 
654     /* Now make the list head point back to us (since we go at the end) */
655     ListHead->Blink = PageFrameIndex;
656     ASSERT_LIST_INVARIANT(ListHead);
657 
658     /* And initialize our own list pointers */
659     Pfn1->u1.Flink = LIST_HEAD;
660     Pfn1->u2.Blink = LastPage;
661 
662     /* Set the list name and default priority */
663     Pfn1->u3.e1.PageLocation = FreePageList;
664     Pfn1->u4.Priority = 3;
665 
666     /* Clear some status fields */
667     Pfn1->u4.InPageError = 0;
668     Pfn1->u4.AweAllocation = 0;
669 
670     /* Increment number of available pages */
671     MiIncrementAvailablePages();
672 
673     /* Get the page color */
674     Color = PageFrameIndex & MmSecondaryColorMask;
675 
676     /* Get the first page on the color list */
677     ColorTable = &MmFreePagesByColor[FreePageList][Color];
678     if (ColorTable->Flink == LIST_HEAD)
679     {
680         /* The list is empty, so we are the first page */
681         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
682         ColorTable->Flink = PageFrameIndex;
683     }
684     else
685     {
686         /* Get the previous page */
687         Blink = (PMMPFN)ColorTable->Blink;
688 
689         /* Make it link to us, and link back to it */
690         Blink->OriginalPte.u.Long = PageFrameIndex;
691         Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
692     }
693 
694     /* Now initialize our own list pointers */
695     ColorTable->Blink = Pfn1;
696 
697     /* This page is now the last */
698     Pfn1->OriginalPte.u.Long = LIST_HEAD;
699 
700     /* And increase the count in the colored list */
701     ColorTable->Count++;
702 
703     /* Notify zero page thread if enough pages are on the free list now */
704     if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive))
705     {
706         /* Set the event */
707         KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
708     }
709 
710 #if MI_TRACE_PFNS
711     Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
712     RtlZeroMemory(Pfn1->ProcessName, 16);
713 #endif
714 }
715 
716 VOID
717 FASTCALL
718 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
719 {
720     PMMPFNLIST ListHead;
721     PFN_NUMBER Flink;
722     PMMPFN Pfn1, Pfn2;
723 
724     /* Make sure the lock is held */
725     DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex);
726     MI_ASSERT_PFN_LOCK_HELD();
727 
728     /* Make sure the PFN is valid */
729     ASSERT((PageFrameIndex != 0) &&
730            (PageFrameIndex <= MmHighestPhysicalPage) &&
731            (PageFrameIndex >= MmLowestPhysicalPage));
732 
733     /* Grab the PFN and validate it is the right kind of PFN being inserted */
734     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
735     ASSERT(Pfn1->u4.MustBeCached == 0);
736     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
737     ASSERT(Pfn1->u3.e1.PrototypePte == 1);
738     ASSERT(Pfn1->u3.e1.Rom != 1);
739 
740     /* One more transition page on a list */
741     MmTransitionSharedPages++;
742 
743     /* Get the standby page list and increment its count */
744     ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
745     ASSERT_LIST_INVARIANT(ListHead);
746     ListHead->Total++;
747 
748     /* Make the head of the list point to this page now */
749     Flink = ListHead->Flink;
750     ListHead->Flink = PageFrameIndex;
751 
752     /* Make the page point to the previous head, and back to the list */
753     Pfn1->u1.Flink = Flink;
754     Pfn1->u2.Blink = LIST_HEAD;
755 
756     /* Was the list empty? */
757     if (Flink != LIST_HEAD)
758     {
759         /* It wasn't, so update the backlink of the previous head page */
760         Pfn2 = MI_PFN_ELEMENT(Flink);
761         Pfn2->u2.Blink = PageFrameIndex;
762     }
763     else
764     {
765         /* It was empty, so have it loop back around to this new page */
766         ListHead->Blink = PageFrameIndex;
767     }
768 
769     /* Move the page onto its new location */
770     Pfn1->u3.e1.PageLocation = StandbyPageList;
771 
772     /* Increment number of available pages */
773     MiIncrementAvailablePages();
774 }
775 
776 VOID
777 NTAPI
778 MiInsertPageInList(IN PMMPFNLIST ListHead,
779                    IN PFN_NUMBER PageFrameIndex)
780 {
781     PFN_NUMBER Flink, LastPage;
782     PMMPFN Pfn1, Pfn2;
783     MMLISTS ListName;
784     PMMCOLOR_TABLES ColorHead;
785     ULONG Color;
786 
787     /* For free pages, use MiInsertPageInFreeList */
788     ASSERT(ListHead != &MmFreePageListHead);
789 
790     /* Make sure the lock is held */
791     MI_ASSERT_PFN_LOCK_HELD();
792 
793     /* Make sure the PFN is valid */
794     ASSERT((PageFrameIndex) &&
795            (PageFrameIndex <= MmHighestPhysicalPage) &&
796            (PageFrameIndex >= MmLowestPhysicalPage));
797 
798     /* Page should be unused */
799     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
800     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
801     ASSERT(Pfn1->u3.e1.Rom != 1);
802 
803     /* Is a standby or modified page being inserted? */
804     ListName = ListHead->ListName;
805     if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
806     {
807         /* If the page is in transition, it must also be a prototype page */
808         if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
809             (Pfn1->OriginalPte.u.Soft.Transition == 1))
810         {
811             /* Crash the system on inconsistency */
812             KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
813         }
814     }
815 
816     /* Standby pages are prioritized, so we need to get the real head */
817     if (ListHead == &MmStandbyPageListHead)
818     {
819         /* Obviously the prioritized list should still have the same name */
820         ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
821         ASSERT(ListHead->ListName == ListName);
822     }
823 
824     /* Increment the list count */
825     ListHead->Total++;
826 
827     /* Is a modified page being inserted? */
828     if (ListHead == &MmModifiedPageListHead)
829     {
830         /* For now, only single-prototype pages should end up in this path */
831         DPRINT("Modified page being added: %lx\n", PageFrameIndex);
832         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
833 
834         /* Modified pages are colored when they are selected for page file */
835         ListHead = &MmModifiedPageListByColor[0];
836         ASSERT (ListHead->ListName == ListName);
837         ListHead->Total++;
838 
839         /* Increment the number of paging file modified pages */
840         MmTotalPagesForPagingFile++;
841     }
842 
843     /* Don't handle bad pages yet yet */
844     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
845 
846     /* Zero pages go to the head, all other pages go to the end */
847     if (ListName == ZeroedPageList)
848     {
849         /* Make the head of the list point to this page now */
850         Flink = ListHead->Flink;
851         ListHead->Flink = PageFrameIndex;
852 
853         /* Make the page point to the previous head, and back to the list */
854         Pfn1->u1.Flink = Flink;
855         Pfn1->u2.Blink = LIST_HEAD;
856 
857         /* Was the list empty? */
858         if (Flink != LIST_HEAD)
859         {
860             /* It wasn't, so update the backlink of the previous head page */
861             Pfn2 = MI_PFN_ELEMENT(Flink);
862             Pfn2->u2.Blink = PageFrameIndex;
863         }
864         else
865         {
866             /* It was empty, so have it loop back around to this new page */
867             ListHead->Blink = PageFrameIndex;
868         }
869     }
870     else
871     {
872         /* Get the last page on the list */
873         LastPage = ListHead->Blink;
874         if (LastPage != LIST_HEAD)
875         {
876             /* Link us with the previous page, so we're at the end now */
877             MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
878         }
879         else
880         {
881             /* The list is empty, so we are the first page */
882             ListHead->Flink = PageFrameIndex;
883         }
884 
885         /* Now make the list head point back to us (since we go at the end) */
886         ListHead->Blink = PageFrameIndex;
887         ASSERT_LIST_INVARIANT(ListHead);
888 
889         /* And initialize our own list pointers */
890         Pfn1->u1.Flink = LIST_HEAD;
891         Pfn1->u2.Blink = LastPage;
892     }
893 
894     /* Move the page onto its new location */
895     Pfn1->u3.e1.PageLocation = ListName;
896 
897     /* For zero/free pages, we also have to handle the colored lists */
898     if (ListName <= StandbyPageList)
899     {
900         /* Increment number of available pages */
901         MiIncrementAvailablePages();
902 
903         /* Sanity checks */
904         ASSERT(ListName == ZeroedPageList);
905         ASSERT(Pfn1->u4.InPageError == 0);
906 
907         /* Get the page color */
908         Color = PageFrameIndex & MmSecondaryColorMask;
909 
910         /* Get the list for this color */
911         ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
912 
913         /* Get the old head */
914         Flink = ColorHead->Flink;
915 
916         /* Make this page point back to the list, and point forwards to the old head */
917         Pfn1->OriginalPte.u.Long = Flink;
918         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
919 
920         /* Set the new head */
921         ColorHead->Flink = PageFrameIndex;
922 
923         /* Was the head empty? */
924         if (Flink != LIST_HEAD)
925         {
926             /* No, so make the old head point to this page */
927             Pfn2 = MI_PFN_ELEMENT(Flink);
928             Pfn2->u4.PteFrame = PageFrameIndex;
929         }
930         else
931         {
932             /* Yes, make it loop back to this page */
933             ColorHead->Blink = (PVOID)Pfn1;
934         }
935 
936         /* One more paged on the colored list */
937         ColorHead->Count++;
938 
939 #if MI_TRACE_PFNS
940             //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
941             Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
942             MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
943             RtlZeroMemory(Pfn1->ProcessName, 16);
944 #endif
945     }
946     else if (ListName == ModifiedPageList)
947     {
948         /* In ARM3, page must be destined for page file, and not yet written out */
949         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
950         ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
951 
952         /* One more transition page */
953         MmTransitionSharedPages++;
954 
955         /* Increment the number of per-process modified pages */
956         PsGetCurrentProcess()->ModifiedPageCount++;
957 
958         /* FIXME: Wake up modified page writer if there are not enough free pages */
959     }
960     else if (ListName == ModifiedNoWritePageList)
961     {
962         /* This list is not yet implemented */
963         ASSERT(FALSE);
964     }
965 }
966 
967 VOID
968 NTAPI
969 MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
970                 IN PMMPTE PointerPte,
971                 IN BOOLEAN Modified)
972 {
973     PMMPFN Pfn1;
974     NTSTATUS Status;
975     PMMPTE PointerPtePte;
976     MI_ASSERT_PFN_LOCK_HELD();
977 
978     /* Setup the PTE */
979     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
980     Pfn1->PteAddress = PointerPte;
981 
982     /* Check if this PFN is part of a valid address space */
983     if (PointerPte->u.Hard.Valid == 1)
984     {
985         /* Only valid from MmCreateProcessAddressSpace path */
986         ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
987 
988         /* Make this a demand zero PTE */
989         MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
990     }
991     else
992     {
993         /* Copy the PTE data */
994         Pfn1->OriginalPte = *PointerPte;
995         ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
996                  (Pfn1->OriginalPte.u.Soft.Transition == 1)));
997     }
998 
999     /* Otherwise this is a fresh page -- set it up */
1000     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1001     Pfn1->u3.e2.ReferenceCount = 1;
1002     Pfn1->u2.ShareCount = 1;
1003     Pfn1->u3.e1.PageLocation = ActiveAndValid;
1004     ASSERT(Pfn1->u3.e1.Rom == 0);
1005     Pfn1->u3.e1.Modified = Modified;
1006 
1007     /* Get the page table for the PTE */
1008     PointerPtePte = MiAddressToPte(PointerPte);
1009     if (PointerPtePte->u.Hard.Valid == 0)
1010     {
1011         /* Make sure the PDE gets paged in properly */
1012         Status = MiCheckPdeForPagedPool(PointerPte);
1013         if (!NT_SUCCESS(Status))
1014         {
1015             /* Crash */
1016             KeBugCheckEx(MEMORY_MANAGEMENT,
1017                          0x61940,
1018                          (ULONG_PTR)PointerPte,
1019                          (ULONG_PTR)PointerPtePte->u.Long,
1020                          (ULONG_PTR)MiPteToAddress(PointerPte));
1021         }
1022     }
1023 
1024     /* Get the PFN for the page table */
1025     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1026     ASSERT(PageFrameIndex != 0);
1027     Pfn1->u4.PteFrame = PageFrameIndex;
1028 
1029     /* Increase its share count so we don't get rid of it */
1030     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1031     Pfn1->u2.ShareCount++;
1032 }
1033 
1034 VOID
1035 NTAPI
1036 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
1037                                IN PMMPTE PointerPte,
1038                                IN MMPTE TempPte)
1039 {
1040     PMMPFN Pfn1;
1041     NTSTATUS Status;
1042     PMMPTE PointerPtePte;
1043     MI_ASSERT_PFN_LOCK_HELD();
1044 
1045     /* PTE must be invalid */
1046     ASSERT(PointerPte->u.Hard.Valid == 0);
1047 
1048     /* Setup the PTE */
1049     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1050     Pfn1->PteAddress = PointerPte;
1051     Pfn1->OriginalPte = DemandZeroPte;
1052 
1053     /* Otherwise this is a fresh page -- set it up */
1054     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1055     Pfn1->u3.e2.ReferenceCount++;
1056     Pfn1->u2.ShareCount++;
1057     Pfn1->u3.e1.PageLocation = ActiveAndValid;
1058     ASSERT(Pfn1->u3.e1.Rom == 0);
1059     Pfn1->u3.e1.Modified = 1;
1060 
1061     /* Get the page table for the PTE */
1062     PointerPtePte = MiAddressToPte(PointerPte);
1063     if (PointerPtePte->u.Hard.Valid == 0)
1064     {
1065         /* Make sure the PDE gets paged in properly */
1066         Status = MiCheckPdeForPagedPool(PointerPte);
1067         if (!NT_SUCCESS(Status))
1068         {
1069             /* Crash */
1070             KeBugCheckEx(MEMORY_MANAGEMENT,
1071                          0x61940,
1072                          (ULONG_PTR)PointerPte,
1073                          (ULONG_PTR)PointerPtePte->u.Long,
1074                          (ULONG_PTR)MiPteToAddress(PointerPte));
1075         }
1076     }
1077 
1078     /* Get the PFN for the page table */
1079     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1080     ASSERT(PageFrameIndex != 0);
1081     Pfn1->u4.PteFrame = PageFrameIndex;
1082 
1083     /* Increase its share count so we don't get rid of it */
1084     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1085     Pfn1->u2.ShareCount++;
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     /* Page must be in-use */
1145     if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
1146         (Pfn1->u3.e1.PageLocation != StandbyPageList))
1147     {
1148         /* Otherwise we have PFN corruption */
1149         KeBugCheckEx(PFN_LIST_CORRUPT,
1150                      0x99,
1151                      PageFrameIndex,
1152                      Pfn1->u3.e1.PageLocation,
1153                      0);
1154     }
1155 
1156     /* Page should at least have one reference */
1157     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1158 
1159     /* Check if the share count is now 0 */
1160     ASSERT(Pfn1->u2.ShareCount < 0xF000000);
1161     if (!--Pfn1->u2.ShareCount)
1162     {
1163         /* Was this a prototype PTE? */
1164         if (Pfn1->u3.e1.PrototypePte)
1165         {
1166             /* Grab the PTE address and make sure it's in prototype pool */
1167             PointerPte = Pfn1->PteAddress;
1168             ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
1169 
1170             /* The PTE that backs it should also be valdi */
1171             PointerPte = MiAddressToPte(PointerPte);
1172             ASSERT(PointerPte->u.Hard.Valid == 1);
1173 
1174             /* Get the original prototype PTE and turn it into a transition PTE */
1175             PointerPte = Pfn1->PteAddress;
1176             TempPte = *PointerPte;
1177             TempPte.u.Soft.Transition = 1;
1178             TempPte.u.Soft.Valid = 0;
1179             TempPte.u.Soft.Prototype = 0;
1180             TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
1181             MI_WRITE_INVALID_PTE(PointerPte, TempPte);
1182             DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
1183         }
1184 
1185         /* Put the page in transition */
1186         Pfn1->u3.e1.PageLocation = TransitionPage;
1187 
1188         /* PFN lock must be held */
1189         MI_ASSERT_PFN_LOCK_HELD();
1190 
1191         if (Pfn1->u3.e2.ReferenceCount == 1)
1192         {
1193             /* Is there still a PFN for this page? */
1194             if (MI_IS_PFN_DELETED(Pfn1))
1195             {
1196                 /* Clear the last reference */
1197                 Pfn1->u3.e2.ReferenceCount = 0;
1198                 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
1199 
1200                 /* Mark the page temporarily as valid, we're going to make it free soon */
1201                 Pfn1->u3.e1.PageLocation = ActiveAndValid;
1202 
1203                 /* Bring it back into the free list */
1204                 MiInsertPageInFreeList(PageFrameIndex);
1205             }
1206             else
1207             {
1208                 /* PFN not yet deleted, drop a ref count */
1209                 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
1210             }
1211         }
1212         else
1213         {
1214             /* Otherwise, just drop the reference count */
1215             InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1216         }
1217     }
1218 }
1219 
1220 VOID
1221 NTAPI
1222 MiDecrementReferenceCount(IN PMMPFN Pfn1,
1223                           IN PFN_NUMBER PageFrameIndex)
1224 {
1225     /* PFN lock must be held */
1226     MI_ASSERT_PFN_LOCK_HELD();
1227 
1228     /* Sanity checks on the page */
1229     if (PageFrameIndex > MmHighestPhysicalPage ||
1230         Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) ||
1231         Pfn1->u3.e2.ReferenceCount == 0 ||
1232         Pfn1->u3.e2.ReferenceCount >= 2500)
1233     {
1234         DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage);
1235         DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount);
1236         ASSERT(PageFrameIndex <= MmHighestPhysicalPage);
1237         ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
1238         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1239         ASSERT(Pfn1->u3.e2.ReferenceCount < 2500);
1240     }
1241 
1242     /* Dereference the page, bail out if it's still alive */
1243     InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1244     if (Pfn1->u3.e2.ReferenceCount) return;
1245 
1246     /* Nobody should still have reference to this page */
1247     if (Pfn1->u2.ShareCount != 0)
1248     {
1249         /* Otherwise something's really wrong */
1250         KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
1251     }
1252 
1253     /* And it should be lying on some page list */
1254     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1255 
1256     /* Did someone set the delete flag? */
1257     if (MI_IS_PFN_DELETED(Pfn1))
1258     {
1259         /* Insert it into the free list, there's nothing left to do */
1260         MiInsertPageInFreeList(PageFrameIndex);
1261         return;
1262     }
1263 
1264     /* Check to see which list this page should go into */
1265     if (Pfn1->u3.e1.Modified == 1)
1266     {
1267         /* Push it into the modified page list */
1268         MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
1269     }
1270     else
1271     {
1272         /* Otherwise, insert this page into the standby list */
1273         ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
1274         MiInsertStandbyListAtFront(PageFrameIndex);
1275     }
1276 }
1277 
1278 VOID
1279 NTAPI
1280 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
1281                                IN PVOID PteAddress,
1282                                IN PFN_NUMBER PteFrame)
1283 {
1284     PMMPFN Pfn1;
1285 
1286     /* Setup the PTE */
1287     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1288     Pfn1->PteAddress = PteAddress;
1289 
1290     /* Make this a software PTE */
1291     MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
1292 
1293     /* Setup the page */
1294     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1295     Pfn1->u3.e2.ReferenceCount = 1;
1296     Pfn1->u2.ShareCount = 1;
1297     Pfn1->u3.e1.PageLocation = ActiveAndValid;
1298     Pfn1->u3.e1.Modified = TRUE;
1299     Pfn1->u4.InPageError = FALSE;
1300 
1301     /* Did we get a PFN for the page table */
1302     if (PteFrame)
1303     {
1304         /* Store it */
1305         Pfn1->u4.PteFrame = PteFrame;
1306 
1307         /* Increase its share count so we don't get rid of it */
1308         Pfn1 = MI_PFN_ELEMENT(PteFrame);
1309         Pfn1->u2.ShareCount++;
1310     }
1311 }
1312 
1313 /* EOF */
1314