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 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
19 #define ASSERT_LIST_INVARIANT(x) \
21 ASSERT(((x)->Total == 0 && \
22 (x)->Flink == LIST_HEAD && \
23 (x)->Blink == LIST_HEAD) || \
25 (x)->Flink != LIST_HEAD && \
26 (x)->Blink != LIST_HEAD)); \
29 #define ASSERT_LIST_INVARIANT(x)
32 /* GLOBALS ********************************************************************/
36 ULONG MmSystemPageColor
;
38 ULONG MmTransitionSharedPages
;
39 ULONG MmTotalPagesForPagingFile
;
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
};
51 PMMPFNLIST MmPageLocationList
[] =
53 &MmZeroedPageListHead
,
55 &MmStandbyPageListHead
,
56 &MmModifiedPageListHead
,
57 &MmModifiedNoWritePageListHead
,
63 ULONG MI_PFN_CURRENT_USAGE
;
64 CHAR MI_PFN_CURRENT_PROCESS_NAME
[16] = "None yet";
66 /* FUNCTIONS ******************************************************************/
70 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex
)
74 PEPROCESS Process
= PsGetCurrentProcess();
76 /* Map in hyperspace, then wipe it using XMMI or MEMSET */
77 VirtualAddress
= MiMapPageInHyperSpace(Process
, PageFrameIndex
, &OldIrql
);
78 ASSERT(VirtualAddress
);
79 KeZeroPages(VirtualAddress
, PAGE_SIZE
);
80 MiUnmapPageInHyperSpace(Process
, VirtualAddress
, OldIrql
);
85 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
87 PFN_NUMBER OldFlink
, OldBlink
;
91 PMMCOLOR_TABLES ColorTable
;
94 /* Make sure the PFN lock is held */
95 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
97 /* Make sure the PFN entry isn't in-use */
98 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
99 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
101 /* Find the list for this entry, make sure it's the free or zero list */
102 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
103 ListName
= ListHead
->ListName
;
104 ASSERT(ListHead
!= NULL
);
105 ASSERT(ListName
<= FreePageList
);
106 ASSERT_LIST_INVARIANT(ListHead
);
108 /* Remove one count */
109 ASSERT(ListHead
->Total
!= 0);
112 /* Get the forward and back pointers */
113 OldFlink
= Entry
->u1
.Flink
;
114 OldBlink
= Entry
->u2
.Blink
;
116 /* Check if the next entry is the list head */
117 if (OldFlink
!= LIST_HEAD
)
119 /* It is not, so set the backlink of the actual entry, to our backlink */
120 MI_PFN_ELEMENT(OldFlink
)->u2
.Blink
= OldBlink
;
124 /* Set the list head's backlink instead */
125 ListHead
->Blink
= OldBlink
;
128 /* Check if the back entry is the list head */
129 if (OldBlink
!= LIST_HEAD
)
131 /* It is not, so set the backlink of the actual entry, to our backlink */
132 MI_PFN_ELEMENT(OldBlink
)->u1
.Flink
= OldFlink
;
136 /* Set the list head's backlink instead */
137 ListHead
->Flink
= OldFlink
;
140 /* Get the page color */
141 OldBlink
= MiGetPfnEntryIndex(Entry
);
142 Color
= OldBlink
& MmSecondaryColorMask
;
144 /* Get the first page on the color list */
145 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
147 /* Check if this was was actually the head */
148 OldFlink
= ColorTable
->Flink
;
149 if (OldFlink
== OldBlink
)
151 /* Make the table point to the next page this page was linking to */
152 ColorTable
->Flink
= Entry
->OriginalPte
.u
.Long
;
153 if (ColorTable
->Flink
!= LIST_HEAD
)
155 /* And make the previous link point to the head now */
156 MI_PFN_ELEMENT(ColorTable
->Flink
)->u4
.PteFrame
= COLORED_LIST_HEAD
;
160 /* And if that page was the head, loop the list back around */
161 ColorTable
->Blink
= (PVOID
)LIST_HEAD
;
166 /* This page shouldn't be pointing back to the head */
167 ASSERT(Entry
->u4
.PteFrame
!= COLORED_LIST_HEAD
);
169 /* Make the back link point to whoever the next page is */
170 Pfn1
= MI_PFN_ELEMENT(Entry
->u4
.PteFrame
);
171 Pfn1
->OriginalPte
.u
.Long
= Entry
->OriginalPte
.u
.Long
;
173 /* Check if this page was pointing to the head */
174 if (Entry
->OriginalPte
.u
.Long
!= LIST_HEAD
)
176 /* Make the back link point to the head */
177 Pfn1
= MI_PFN_ELEMENT(Entry
->OriginalPte
.u
.Long
);
178 Pfn1
->u4
.PteFrame
= Entry
->u4
.PteFrame
;
182 /* Then the table is directly back pointing to this page now */
183 ColorTable
->Blink
= Pfn1
;
187 /* One less colored page */
188 ASSERT(ColorTable
->Count
>= 1);
192 Entry
->OriginalPte
.u
.Long
= 0;
194 /* We are not on a list anymore */
195 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
196 ASSERT_LIST_INVARIANT(ListHead
);
198 /* See if we hit any thresholds */
199 if (MmAvailablePages
== MmHighMemoryThreshold
)
201 /* Clear the high memory event */
202 KeClearEvent(MiHighMemoryEvent
);
204 else if (MmAvailablePages
== MmLowMemoryThreshold
)
206 /* Signal the low memory event */
207 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
211 if (--MmAvailablePages
< MmMinimumFreePages
)
213 /* FIXME: Should wake up the MPW and working set manager, if we had one */
215 DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages
);
217 /* Call RosMm and see if it can release any pages for us */
218 MmRebalanceMemoryConsumers();
222 ASSERT(MI_PFN_CURRENT_USAGE
!= MI_USAGE_NOT_SET
);
223 Entry
->PfnUsage
= MI_PFN_CURRENT_USAGE
;
224 memcpy(Entry
->ProcessName
, MI_PFN_CURRENT_PROCESS_NAME
, 16);
225 // MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
226 // memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
232 MiUnlinkPageFromList(IN PMMPFN Pfn
)
235 PFN_NUMBER OldFlink
, OldBlink
;
237 /* Make sure the PFN lock is held */
238 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
240 /* ARM3 should only call this for dead pages */
241 ASSERT(Pfn
->u3
.e2
.ReferenceCount
== 0);
243 /* Transition pages are supposed to be standby/modified/nowrite */
244 ListHead
= MmPageLocationList
[Pfn
->u3
.e1
.PageLocation
];
245 ASSERT(ListHead
->ListName
>= StandbyPageList
);
247 /* Check if this was standby, or modified */
248 if (ListHead
== &MmStandbyPageListHead
)
250 /* Should not be a ROM page */
251 ASSERT(Pfn
->u3
.e1
.Rom
== 0);
253 /* Get the exact list */
254 ListHead
= &MmStandbyPageListByPriority
[Pfn
->u4
.Priority
];
256 /* See if we hit any thresholds */
257 if (MmAvailablePages
== MmHighMemoryThreshold
)
259 /* Clear the high memory event */
260 KeClearEvent(MiHighMemoryEvent
);
262 else if (MmAvailablePages
== MmLowMemoryThreshold
)
264 /* Signal the low memory event */
265 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
268 /* Decrease transition page counter */
269 ASSERT(Pfn
->u3
.e1
.PrototypePte
== 1); /* Only supported ARM3 case */
270 MmTransitionSharedPages
--;
273 if (--MmAvailablePages
< MmMinimumFreePages
)
275 /* FIXME: Should wake up the MPW and working set manager, if we had one */
276 DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages
);
278 /* Call RosMm and see if it can release any pages for us */
279 MmRebalanceMemoryConsumers();
282 else if (ListHead
== &MmModifiedPageListHead
)
284 /* Only shared memory (page-file backed) modified pages are supported */
285 ASSERT(Pfn
->OriginalPte
.u
.Soft
.Prototype
== 0);
287 /* Decrement the counters */
289 MmTotalPagesForPagingFile
--;
291 /* Pick the correct colored list */
292 ListHead
= &MmModifiedPageListByColor
[0];
294 /* Decrease transition page counter */
295 MmTransitionSharedPages
--;
297 else if (ListHead
== &MmModifiedNoWritePageListHead
)
299 /* List not yet supported */
303 /* Nothing should be in progress and the list should not be empty */
304 ASSERT(Pfn
->u3
.e1
.WriteInProgress
== 0);
305 ASSERT(Pfn
->u3
.e1
.ReadInProgress
== 0);
306 ASSERT(ListHead
->Total
!= 0);
308 /* Get the forward and back pointers */
309 OldFlink
= Pfn
->u1
.Flink
;
310 OldBlink
= Pfn
->u2
.Blink
;
312 /* Check if the next entry is the list head */
313 if (OldFlink
!= LIST_HEAD
)
315 /* It is not, so set the backlink of the actual entry, to our backlink */
316 MI_PFN_ELEMENT(OldFlink
)->u2
.Blink
= OldBlink
;
320 /* Set the list head's backlink instead */
321 ListHead
->Blink
= OldBlink
;
324 /* Check if the back entry is the list head */
325 if (OldBlink
!= LIST_HEAD
)
327 /* It is not, so set the backlink of the actual entry, to our backlink */
328 MI_PFN_ELEMENT(OldBlink
)->u1
.Flink
= OldFlink
;
332 /* Set the list head's backlink instead */
333 ListHead
->Flink
= OldFlink
;
337 Pfn
->OriginalPte
.u
.Long
= 0;
339 /* We are not on a list anymore */
340 Pfn
->u1
.Flink
= Pfn
->u2
.Blink
= 0;
342 /* Remove one entry from the list */
345 ASSERT_LIST_INVARIANT(ListHead
);
350 MiRemovePageByColor(IN PFN_NUMBER PageIndex
,
356 PFN_NUMBER OldFlink
, OldBlink
;
357 USHORT OldColor
, OldCache
;
358 PMMCOLOR_TABLES ColorTable
;
360 /* Make sure PFN lock is held */
361 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
362 ASSERT(Color
< MmSecondaryColors
);
364 /* Get the PFN entry */
365 Pfn1
= MI_PFN_ELEMENT(PageIndex
);
366 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
367 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
369 /* Capture data for later */
370 OldColor
= Pfn1
->u3
.e1
.PageColor
;
371 OldCache
= Pfn1
->u3
.e1
.CacheAttribute
;
373 /* Could be either on free or zero list */
374 ListHead
= MmPageLocationList
[Pfn1
->u3
.e1
.PageLocation
];
375 ASSERT_LIST_INVARIANT(ListHead
);
376 ListName
= ListHead
->ListName
;
377 ASSERT(ListName
<= FreePageList
);
382 /* Get the forward and back pointers */
383 OldFlink
= Pfn1
->u1
.Flink
;
384 OldBlink
= Pfn1
->u2
.Blink
;
386 /* Check if the next entry is the list head */
387 if (OldFlink
!= LIST_HEAD
)
389 /* It is not, so set the backlink of the actual entry, to our backlink */
390 MI_PFN_ELEMENT(OldFlink
)->u2
.Blink
= OldBlink
;
394 /* Set the list head's backlink instead */
395 ListHead
->Blink
= OldBlink
;
398 /* Check if the back entry is the list head */
399 if (OldBlink
!= LIST_HEAD
)
401 /* It is not, so set the backlink of the actual entry, to our backlink */
402 MI_PFN_ELEMENT(OldBlink
)->u1
.Flink
= OldFlink
;
406 /* Set the list head's backlink instead */
407 ListHead
->Flink
= OldFlink
;
410 /* We are not on a list anymore */
411 ASSERT_LIST_INVARIANT(ListHead
);
412 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
414 /* Zero flags but restore color and cache */
415 Pfn1
->u3
.e2
.ShortFlags
= 0;
416 Pfn1
->u3
.e1
.PageColor
= OldColor
;
417 Pfn1
->u3
.e1
.CacheAttribute
= OldCache
;
419 /* Get the first page on the color list */
420 ASSERT(Color
< MmSecondaryColors
);
421 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
422 ASSERT(ColorTable
->Count
>= 1);
424 /* Set the forward link to whoever we were pointing to */
425 ColorTable
->Flink
= Pfn1
->OriginalPte
.u
.Long
;
427 /* Get the first page on the color list */
428 if (ColorTable
->Flink
== LIST_HEAD
)
430 /* This is the beginning of the list, so set the sentinel value */
431 ColorTable
->Blink
= (PVOID
)LIST_HEAD
;
435 /* The list is empty, so we are the first page */
436 MI_PFN_ELEMENT(ColorTable
->Flink
)->u4
.PteFrame
= COLORED_LIST_HEAD
;
443 Pfn1
->OriginalPte
.u
.Long
= 0;
445 /* See if we hit any thresholds */
446 if (MmAvailablePages
== MmHighMemoryThreshold
)
448 /* Clear the high memory event */
449 KeClearEvent(MiHighMemoryEvent
);
451 else if (MmAvailablePages
== MmLowMemoryThreshold
)
453 /* Signal the low memory event */
454 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
458 if (--MmAvailablePages
< MmMinimumFreePages
)
460 /* FIXME: Should wake up the MPW and working set manager, if we had one */
462 DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages
);
464 /* Call RosMm and see if it can release any pages for us */
465 MmRebalanceMemoryConsumers();
469 //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
470 Pfn1
->PfnUsage
= MI_PFN_CURRENT_USAGE
;
471 memcpy(Pfn1
->ProcessName
, MI_PFN_CURRENT_PROCESS_NAME
, 16);
472 //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
473 //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
476 /* Return the page */
482 MiRemoveAnyPage(IN ULONG Color
)
484 PFN_NUMBER PageIndex
;
487 /* Make sure PFN lock is held and we have pages */
488 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
489 ASSERT(MmAvailablePages
!= 0);
490 ASSERT(Color
< MmSecondaryColors
);
492 /* Check the colored free list */
493 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
494 if (PageIndex
== LIST_HEAD
)
496 /* Check the colored zero list */
497 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
498 if (PageIndex
== LIST_HEAD
)
500 /* Check the free list */
501 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
502 PageIndex
= MmFreePageListHead
.Flink
;
503 Color
= PageIndex
& MmSecondaryColorMask
;
504 if (PageIndex
== LIST_HEAD
)
506 /* Check the zero list */
507 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
508 PageIndex
= MmZeroedPageListHead
.Flink
;
509 Color
= PageIndex
& MmSecondaryColorMask
;
510 ASSERT(PageIndex
!= LIST_HEAD
);
511 if (PageIndex
== LIST_HEAD
)
513 /* FIXME: Should check the standby list */
514 ASSERT(MmZeroedPageListHead
.Total
== 0);
520 /* Remove the page from its list */
521 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
524 Pfn1
= MI_PFN_ELEMENT(PageIndex
);
525 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
526 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
527 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
528 ASSERT(Pfn1
->u2
.ShareCount
== 0);
529 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
530 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
532 /* Return the page */
538 MiRemoveZeroPage(IN ULONG Color
)
540 PFN_NUMBER PageIndex
;
542 BOOLEAN Zero
= FALSE
;
544 /* Make sure PFN lock is held and we have pages */
545 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
546 ASSERT(MmAvailablePages
!= 0);
547 ASSERT(Color
< MmSecondaryColors
);
549 /* Check the colored zero list */
550 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
551 if (PageIndex
== LIST_HEAD
)
553 /* Check the zero list */
554 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
555 PageIndex
= MmZeroedPageListHead
.Flink
;
556 if (PageIndex
== LIST_HEAD
)
558 /* This means there's no zero pages, we have to look for free ones */
559 ASSERT(MmZeroedPageListHead
.Total
== 0);
562 /* Check the colored free list */
563 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
564 if (PageIndex
== LIST_HEAD
)
566 /* Check the free list */
567 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
568 PageIndex
= MmFreePageListHead
.Flink
;
569 Color
= PageIndex
& MmSecondaryColorMask
;
570 ASSERT(PageIndex
!= LIST_HEAD
);
571 if (PageIndex
== LIST_HEAD
)
573 /* FIXME: Should check the standby list */
574 ASSERT(MmZeroedPageListHead
.Total
== 0);
580 Color
= PageIndex
& MmSecondaryColorMask
;
585 Pfn1
= MI_PFN_ELEMENT(PageIndex
);
586 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
587 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
589 /* Remove the page from its list */
590 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
591 ASSERT(Pfn1
== MI_PFN_ELEMENT(PageIndex
));
593 /* Zero it, if needed */
594 if (Zero
) MiZeroPhysicalPage(PageIndex
);
597 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
598 ASSERT(Pfn1
->u2
.ShareCount
== 0);
599 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
600 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
602 /* Return the page */
608 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
615 PMMCOLOR_TABLES ColorTable
;
617 /* Make sure the page index is valid */
618 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
619 ASSERT((PageFrameIndex
!= 0) &&
620 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
621 (PageFrameIndex
>= MmLowestPhysicalPage
));
623 /* Get the PFN entry */
624 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
626 /* Sanity checks that a right kind of page is being inserted here */
627 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
628 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
629 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
630 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
631 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
633 /* Get the free page list and increment its count */
634 ListHead
= &MmFreePageListHead
;
635 ASSERT_LIST_INVARIANT(ListHead
);
638 /* Get the last page on the list */
639 LastPage
= ListHead
->Blink
;
640 if (LastPage
!= LIST_HEAD
)
642 /* Link us with the previous page, so we're at the end now */
643 MI_PFN_ELEMENT(LastPage
)->u1
.Flink
= PageFrameIndex
;
647 /* The list is empty, so we are the first page */
648 ListHead
->Flink
= PageFrameIndex
;
651 /* Now make the list head point back to us (since we go at the end) */
652 ListHead
->Blink
= PageFrameIndex
;
653 ASSERT_LIST_INVARIANT(ListHead
);
655 /* And initialize our own list pointers */
656 Pfn1
->u1
.Flink
= LIST_HEAD
;
657 Pfn1
->u2
.Blink
= LastPage
;
659 /* Set the list name and default priority */
660 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
661 Pfn1
->u4
.Priority
= 3;
663 /* Clear some status fields */
664 Pfn1
->u4
.InPageError
= 0;
665 Pfn1
->u4
.AweAllocation
= 0;
667 /* Increase available pages */
670 /* Check if we've reached the configured low memory threshold */
671 if (MmAvailablePages
== MmLowMemoryThreshold
)
673 /* Clear the event, because now we're ABOVE the threshold */
674 KeClearEvent(MiLowMemoryEvent
);
676 else if (MmAvailablePages
== MmHighMemoryThreshold
)
678 /* Otherwise check if we reached the high threshold and signal the event */
679 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
682 /* Get the page color */
683 Color
= PageFrameIndex
& MmSecondaryColorMask
;
685 /* Get the first page on the color list */
686 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
687 if (ColorTable
->Flink
== LIST_HEAD
)
689 /* The list is empty, so we are the first page */
690 Pfn1
->u4
.PteFrame
= COLORED_LIST_HEAD
;
691 ColorTable
->Flink
= PageFrameIndex
;
695 /* Get the previous page */
696 Blink
= (PMMPFN
)ColorTable
->Blink
;
698 /* Make it link to us, and link back to it */
699 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
700 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
703 /* Now initialize our own list pointers */
704 ColorTable
->Blink
= Pfn1
;
706 /* This page is now the last */
707 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
709 /* And increase the count in the colored list */
712 /* Notify zero page thread if enough pages are on the free list now */
713 if ((ListHead
->Total
>= 8) && !(MmZeroingPageThreadActive
))
716 MmZeroingPageThreadActive
= TRUE
;
717 KeSetEvent(&MmZeroingPageEvent
, IO_NO_INCREMENT
, FALSE
);
721 Pfn1
->PfnUsage
= MI_USAGE_FREE_PAGE
;
722 RtlZeroMemory(Pfn1
->ProcessName
, 16);
728 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex
)
734 /* Make sure the lock is held */
735 DPRINT1("Inserting page: %lx into standby list !\n", PageFrameIndex
);
736 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
738 /* Make sure the PFN is valid */
739 ASSERT((PageFrameIndex
!= 0) &&
740 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
741 (PageFrameIndex
>= MmLowestPhysicalPage
));
743 /* Grab the PFN and validate it is the right kind of PFN being inserted */
744 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
745 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
746 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
747 ASSERT(Pfn1
->u3
.e1
.PrototypePte
== 1);
748 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
750 /* One more transition page on a list */
751 MmTransitionSharedPages
++;
753 /* Get the standby page list and increment its count */
754 ListHead
= &MmStandbyPageListByPriority
[Pfn1
->u4
.Priority
];
755 ASSERT_LIST_INVARIANT(ListHead
);
758 /* Make the head of the list point to this page now */
759 Flink
= ListHead
->Flink
;
760 ListHead
->Flink
= PageFrameIndex
;
762 /* Make the page point to the previous head, and back to the list */
763 Pfn1
->u1
.Flink
= Flink
;
764 Pfn1
->u2
.Blink
= LIST_HEAD
;
766 /* Was the list empty? */
767 if (Flink
!= LIST_HEAD
)
769 /* It wasn't, so update the backlink of the previous head page */
770 Pfn2
= MI_PFN_ELEMENT(Flink
);
771 Pfn2
->u2
.Blink
= PageFrameIndex
;
775 /* It was empty, so have it loop back around to this new page */
776 ListHead
->Blink
= PageFrameIndex
;
779 /* Move the page onto its new location */
780 Pfn1
->u3
.e1
.PageLocation
= StandbyPageList
;
782 /* One more page on the system */
785 /* Check if we've reached the configured low memory threshold */
786 if (MmAvailablePages
== MmLowMemoryThreshold
)
788 /* Clear the event, because now we're ABOVE the threshold */
789 KeClearEvent(MiLowMemoryEvent
);
791 else if (MmAvailablePages
== MmHighMemoryThreshold
)
793 /* Otherwise check if we reached the high threshold and signal the event */
794 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
800 MiInsertPageInList(IN PMMPFNLIST ListHead
,
801 IN PFN_NUMBER PageFrameIndex
)
803 PFN_NUMBER Flink
, LastPage
;
806 PMMCOLOR_TABLES ColorHead
;
809 /* For free pages, use MiInsertPageInFreeList */
810 ASSERT(ListHead
!= &MmFreePageListHead
);
812 /* Make sure the lock is held */
813 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
815 /* Make sure the PFN is valid */
816 ASSERT((PageFrameIndex
) &&
817 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
818 (PageFrameIndex
>= MmLowestPhysicalPage
));
820 /* Page should be unused */
821 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
822 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
823 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
825 /* Is a standby or modified page being inserted? */
826 ListName
= ListHead
->ListName
;
827 if ((ListName
== StandbyPageList
) || (ListName
== ModifiedPageList
))
829 /* If the page is in transition, it must also be a prototype page */
830 if ((Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0) &&
831 (Pfn1
->OriginalPte
.u
.Soft
.Transition
== 1))
833 /* Crash the system on inconsistency */
834 KeBugCheckEx(MEMORY_MANAGEMENT
, 0x8888, 0, 0, 0);
838 /* Standby pages are prioritized, so we need to get the real head */
839 if (ListHead
== &MmStandbyPageListHead
)
841 /* Obviously the prioritized list should still have the same name */
842 ListHead
= &MmStandbyPageListByPriority
[Pfn1
->u4
.Priority
];
843 ASSERT(ListHead
->ListName
== ListName
);
846 /* Increment the list count */
849 /* Is a modified page being inserted? */
850 if (ListHead
== &MmModifiedPageListHead
)
852 /* For now, only single-prototype pages should end up in this path */
853 DPRINT("Modified page being added: %lx\n", PageFrameIndex
);
854 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
856 /* Modified pages are colored when they are selected for page file */
857 ListHead
= &MmModifiedPageListByColor
[0];
858 ASSERT (ListHead
->ListName
== ListName
);
861 /* Increment the number of paging file modified pages */
862 MmTotalPagesForPagingFile
++;
865 /* Don't handle bad pages yet yet */
866 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
868 /* Zero pages go to the head, all other pages go to the end */
869 if (ListName
== ZeroedPageList
)
871 /* Make the head of the list point to this page now */
872 Flink
= ListHead
->Flink
;
873 ListHead
->Flink
= PageFrameIndex
;
875 /* Make the page point to the previous head, and back to the list */
876 Pfn1
->u1
.Flink
= Flink
;
877 Pfn1
->u2
.Blink
= LIST_HEAD
;
879 /* Was the list empty? */
880 if (Flink
!= LIST_HEAD
)
882 /* It wasn't, so update the backlink of the previous head page */
883 Pfn2
= MI_PFN_ELEMENT(Flink
);
884 Pfn2
->u2
.Blink
= PageFrameIndex
;
888 /* It was empty, so have it loop back around to this new page */
889 ListHead
->Blink
= PageFrameIndex
;
894 /* Get the last page on the list */
895 LastPage
= ListHead
->Blink
;
896 if (LastPage
!= LIST_HEAD
)
898 /* Link us with the previous page, so we're at the end now */
899 MI_PFN_ELEMENT(LastPage
)->u1
.Flink
= PageFrameIndex
;
903 /* The list is empty, so we are the first page */
904 ListHead
->Flink
= PageFrameIndex
;
907 /* Now make the list head point back to us (since we go at the end) */
908 ListHead
->Blink
= PageFrameIndex
;
909 ASSERT_LIST_INVARIANT(ListHead
);
911 /* And initialize our own list pointers */
912 Pfn1
->u1
.Flink
= LIST_HEAD
;
913 Pfn1
->u2
.Blink
= LastPage
;
916 /* Move the page onto its new location */
917 Pfn1
->u3
.e1
.PageLocation
= ListName
;
919 /* For zero/free pages, we also have to handle the colored lists */
920 if (ListName
<= StandbyPageList
)
922 /* One more page on the system */
925 /* Check if we've reached the configured low memory threshold */
926 if (MmAvailablePages
== MmLowMemoryThreshold
)
928 /* Clear the event, because now we're ABOVE the threshold */
929 KeClearEvent(MiLowMemoryEvent
);
931 else if (MmAvailablePages
== MmHighMemoryThreshold
)
933 /* Otherwise check if we reached the high threshold and signal the event */
934 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
938 ASSERT(ListName
== ZeroedPageList
);
939 ASSERT(Pfn1
->u4
.InPageError
== 0);
941 /* Get the page color */
942 Color
= PageFrameIndex
& MmSecondaryColorMask
;
944 /* Get the list for this color */
945 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
947 /* Get the old head */
948 Flink
= ColorHead
->Flink
;
950 /* Make this page point back to the list, and point forwards to the old head */
951 Pfn1
->OriginalPte
.u
.Long
= Flink
;
952 Pfn1
->u4
.PteFrame
= COLORED_LIST_HEAD
;
954 /* Set the new head */
955 ColorHead
->Flink
= PageFrameIndex
;
957 /* Was the head empty? */
958 if (Flink
!= LIST_HEAD
)
960 /* No, so make the old head point to this page */
961 Pfn2
= MI_PFN_ELEMENT(Flink
);
962 Pfn2
->u4
.PteFrame
= PageFrameIndex
;
966 /* Yes, make it loop back to this page */
967 ColorHead
->Blink
= (PVOID
)Pfn1
;
970 /* One more paged on the colored list */
974 //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
975 Pfn1
->PfnUsage
= MI_USAGE_FREE_PAGE
;
976 MI_PFN_CURRENT_USAGE
= MI_USAGE_NOT_SET
;
977 RtlZeroMemory(Pfn1
->ProcessName
, 16);
980 else if (ListName
== ModifiedPageList
)
982 /* In ARM3, page must be destined for page file, and not yet written out */
983 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
984 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.PageFileHigh
== 0);
986 /* One more transition page */
987 MmTransitionSharedPages
++;
989 /* Increment the number of per-process modified pages */
990 PsGetCurrentProcess()->ModifiedPageCount
++;
992 /* FIXME: Wake up modified page writer if there are not enough free pages */
994 else if (ListName
== ModifiedNoWritePageList
)
996 /* This list is not yet implemented */
1003 MiInitializePfn(IN PFN_NUMBER PageFrameIndex
,
1004 IN PMMPTE PointerPte
,
1005 IN BOOLEAN Modified
)
1009 PMMPTE PointerPtePte
;
1010 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1013 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
1014 Pfn1
->PteAddress
= PointerPte
;
1016 /* Check if this PFN is part of a valid address space */
1017 if (PointerPte
->u
.Hard
.Valid
== 1)
1019 /* Only valid from MmCreateProcessAddressSpace path */
1020 ASSERT(PsGetCurrentProcess()->Vm
.WorkingSetSize
== 0);
1022 /* Make this a demand zero PTE */
1023 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
1027 /* Copy the PTE data */
1028 Pfn1
->OriginalPte
= *PointerPte
;
1029 ASSERT(!((Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0) &&
1030 (Pfn1
->OriginalPte
.u
.Soft
.Transition
== 1)));
1033 /* Otherwise this is a fresh page -- set it up */
1034 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
1035 Pfn1
->u3
.e2
.ReferenceCount
= 1;
1036 Pfn1
->u2
.ShareCount
= 1;
1037 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
1038 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1039 Pfn1
->u3
.e1
.Modified
= Modified
;
1041 /* Get the page table for the PTE */
1042 PointerPtePte
= MiAddressToPte(PointerPte
);
1043 if (PointerPtePte
->u
.Hard
.Valid
== 0)
1045 /* Make sure the PDE gets paged in properly */
1046 Status
= MiCheckPdeForPagedPool(PointerPte
);
1047 if (!NT_SUCCESS(Status
))
1050 KeBugCheckEx(MEMORY_MANAGEMENT
,
1052 (ULONG_PTR
)PointerPte
,
1053 (ULONG_PTR
)PointerPtePte
->u
.Long
,
1054 (ULONG_PTR
)MiPteToAddress(PointerPte
));
1058 /* Get the PFN for the page table */
1059 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
1060 ASSERT(PageFrameIndex
!= 0);
1061 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
1063 /* Increase its share count so we don't get rid of it */
1064 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
1065 Pfn1
->u2
.ShareCount
++;
1070 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex
,
1071 IN PMMPTE PointerPte
,
1076 PMMPTE PointerPtePte
;
1077 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1079 /* PTE must be invalid */
1080 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1083 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
1084 Pfn1
->PteAddress
= PointerPte
;
1085 Pfn1
->OriginalPte
= DemandZeroPte
;
1087 /* Otherwise this is a fresh page -- set it up */
1088 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
1089 Pfn1
->u3
.e2
.ReferenceCount
++;
1090 Pfn1
->u2
.ShareCount
++;
1091 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
1092 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
1093 Pfn1
->u3
.e1
.Modified
= 1;
1095 /* Get the page table for the PTE */
1096 PointerPtePte
= MiAddressToPte(PointerPte
);
1097 if (PointerPtePte
->u
.Hard
.Valid
== 0)
1099 /* Make sure the PDE gets paged in properly */
1100 Status
= MiCheckPdeForPagedPool(PointerPte
);
1101 if (!NT_SUCCESS(Status
))
1104 KeBugCheckEx(MEMORY_MANAGEMENT
,
1106 (ULONG_PTR
)PointerPte
,
1107 (ULONG_PTR
)PointerPtePte
->u
.Long
,
1108 (ULONG_PTR
)MiPteToAddress(PointerPte
));
1112 /* Get the PFN for the page table */
1113 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
1114 ASSERT(PageFrameIndex
!= 0);
1115 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
1117 /* Increase its share count so we don't get rid of it */
1118 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
1119 Pfn1
->u2
.ShareCount
++;
1121 /* Write valid PTE */
1122 MI_WRITE_VALID_PTE(PointerPte
, TempPte
);
1127 MiInitializeAndChargePfn(OUT PPFN_NUMBER PageFrameIndex
,
1128 IN PMMPTE PointerPde
,
1129 IN PFN_NUMBER ContainingPageFrame
,
1130 IN BOOLEAN SessionAllocation
)
1135 /* Use either a global or local PDE */
1136 TempPte
= SessionAllocation
? ValidKernelPdeLocal
: ValidKernelPde
;
1138 /* Lock the PFN database */
1139 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1141 /* Make sure nobody is racing us */
1142 if (PointerPde
->u
.Hard
.Valid
== 1)
1144 /* Return special error if that was the case */
1145 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1146 return STATUS_RETRY
;
1149 /* Grab a zero page and set the PFN, then make it valid */
1150 *PageFrameIndex
= MiRemoveZeroPage(MI_GET_NEXT_COLOR());
1151 TempPte
.u
.Hard
.PageFrameNumber
= *PageFrameIndex
;
1152 MI_WRITE_VALID_PTE(PointerPde
, TempPte
);
1154 /* Initialize the PFN */
1155 MiInitializePfnForOtherProcess(*PageFrameIndex
,
1157 ContainingPageFrame
);
1158 ASSERT(MI_PFN_ELEMENT(*PageFrameIndex
)->u1
.WsIndex
== 0);
1160 /* Release the lock and return success */
1161 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1162 return STATUS_SUCCESS
;
1167 MiAllocatePfn(IN PMMPTE PointerPte
,
1168 IN ULONG Protection
)
1171 PFN_NUMBER PageFrameIndex
;
1174 /* Sanity check that we aren't passed a valid PTE */
1175 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
1177 /* Make an empty software PTE */
1178 MI_MAKE_SOFTWARE_PTE(&TempPte
, MM_READWRITE
);
1180 /* Lock the PFN database */
1181 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1183 /* Check if we're running low on pages */
1184 if (MmAvailablePages
< 128)
1186 DPRINT1("Warning, running low on memory: %lu pages left\n", MmAvailablePages
);
1188 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
1190 /* Call RosMm and see if it can release any pages for us */
1191 MmRebalanceMemoryConsumers();
1195 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
1196 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
1197 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
1199 /* Write the software PTE */
1200 MI_WRITE_INVALID_PTE(PointerPte
, TempPte
);
1201 PointerPte
->u
.Soft
.Protection
|= Protection
;
1203 /* Initialize its PFN entry */
1204 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
1206 /* Release the PFN lock and return the page */
1207 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
1208 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
1209 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1210 return PageFrameIndex
;
1215 MiDecrementShareCount(IN PMMPFN Pfn1
,
1216 IN PFN_NUMBER PageFrameIndex
)
1221 ASSERT(PageFrameIndex
> 0);
1222 ASSERT(MI_PFN_ELEMENT(PageFrameIndex
) != NULL
);
1223 ASSERT(Pfn1
== MI_PFN_ELEMENT(PageFrameIndex
));
1224 ASSERT(MI_IS_ROS_PFN(Pfn1
) == FALSE
);
1226 /* Page must be in-use */
1227 if ((Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
) &&
1228 (Pfn1
->u3
.e1
.PageLocation
!= StandbyPageList
))
1230 /* Otherwise we have PFN corruption */
1231 KeBugCheckEx(PFN_LIST_CORRUPT
,
1234 Pfn1
->u3
.e1
.PageLocation
,
1238 /* Page should at least have one reference */
1239 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
1241 /* Check if the share count is now 0 */
1242 ASSERT(Pfn1
->u2
.ShareCount
< 0xF000000);
1243 if (!--Pfn1
->u2
.ShareCount
)
1245 /* Was this a prototype PTE? */
1246 if (Pfn1
->u3
.e1
.PrototypePte
)
1248 /* Grab the PTE address and make sure it's in prototype pool */
1249 PointerPte
= Pfn1
->PteAddress
;
1250 ASSERT((PointerPte
>= (PMMPTE
)MmPagedPoolStart
) && (PointerPte
<= (PMMPTE
)MmPagedPoolEnd
));
1252 /* The PTE that backs it should also be valdi */
1253 PointerPte
= MiAddressToPte(PointerPte
);
1254 ASSERT(PointerPte
->u
.Hard
.Valid
== 1);
1256 /* Get the original prototype PTE and turn it into a transition PTE */
1257 PointerPte
= Pfn1
->PteAddress
;
1258 TempPte
= *PointerPte
;
1259 TempPte
.u
.Soft
.Transition
= 1;
1260 TempPte
.u
.Soft
.Valid
= 0;
1261 TempPte
.u
.Soft
.Prototype
= 0;
1262 TempPte
.u
.Soft
.Protection
= Pfn1
->OriginalPte
.u
.Soft
.Protection
;
1263 MI_WRITE_INVALID_PTE(PointerPte
, TempPte
);
1264 DPRINT1("Marking PTE: %p as transition (%p - %lx)\n", PointerPte
, Pfn1
, MiGetPfnEntryIndex(Pfn1
));
1267 /* Put the page in transition */
1268 Pfn1
->u3
.e1
.PageLocation
= TransitionPage
;
1270 /* PFN lock must be held */
1271 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1273 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
1275 /* Is there still a PFN for this page? */
1276 if (MI_IS_PFN_DELETED(Pfn1
) == TRUE
)
1278 /* Clear the last reference */
1279 Pfn1
->u3
.e2
.ReferenceCount
= 0;
1280 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
1282 /* Mark the page temporarily as valid, we're going to make it free soon */
1283 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
1285 /* Bring it back into the free list */
1286 MiInsertPageInFreeList(PageFrameIndex
);
1290 /* PFN not yet deleted, drop a ref count */
1291 MiDecrementReferenceCount(Pfn1
, PageFrameIndex
);
1296 /* Otherwise, just drop the reference count */
1297 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
1304 MiDecrementReferenceCount(IN PMMPFN Pfn1
,
1305 IN PFN_NUMBER PageFrameIndex
)
1307 /* PFN lock must be held */
1308 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
1310 /* Sanity checks on the page */
1311 if (PageFrameIndex
> MmHighestPhysicalPage
||
1312 Pfn1
!= MI_PFN_ELEMENT(PageFrameIndex
) ||
1313 Pfn1
->u3
.e2
.ReferenceCount
== 0 ||
1314 Pfn1
->u3
.e2
.ReferenceCount
>= 2500)
1316 DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex
, MmHighestPhysicalPage
);
1317 DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1
, MI_PFN_ELEMENT(PageFrameIndex
), Pfn1
->u3
.e2
.ReferenceCount
);
1318 ASSERT(PageFrameIndex
<= MmHighestPhysicalPage
);
1319 ASSERT(Pfn1
== MI_PFN_ELEMENT(PageFrameIndex
));
1320 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
1321 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
< 2500);
1324 /* Dereference the page, bail out if it's still alive */
1325 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
1326 if (Pfn1
->u3
.e2
.ReferenceCount
) return;
1328 /* Nobody should still have reference to this page */
1329 if (Pfn1
->u2
.ShareCount
!= 0)
1331 /* Otherwise something's really wrong */
1332 KeBugCheckEx(PFN_LIST_CORRUPT
, 7, PageFrameIndex
, Pfn1
->u2
.ShareCount
, 0);
1335 /* And it should be lying on some page list */
1336 ASSERT(Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
);
1338 /* Did someone set the delete flag? */
1339 if (MI_IS_PFN_DELETED(Pfn1
))
1341 /* Insert it into the free list, there's nothing left to do */
1342 MiInsertPageInFreeList(PageFrameIndex
);
1346 /* Check to see which list this page should go into */
1347 if (Pfn1
->u3
.e1
.Modified
== 1)
1349 /* Push it into the modified page list */
1350 MiInsertPageInList(&MmModifiedPageListHead
, PageFrameIndex
);
1354 /* Otherwise, insert this page into the standby list */
1355 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
1356 MiInsertStandbyListAtFront(PageFrameIndex
);
1362 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex
,
1363 IN PMMPTE PointerPte
,
1364 IN PFN_NUMBER PteFrame
)
1369 Pfn1
= MI_PFN_ELEMENT(PageFrameIndex
);
1370 Pfn1
->PteAddress
= PointerPte
;
1372 /* Make this a software PTE */
1373 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
1375 /* Setup the page */
1376 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
1377 Pfn1
->u3
.e2
.ReferenceCount
= 1;
1378 Pfn1
->u2
.ShareCount
= 1;
1379 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
1380 Pfn1
->u3
.e1
.Modified
= TRUE
;
1381 Pfn1
->u4
.InPageError
= FALSE
;
1383 /* Did we get a PFN for the page table */
1387 Pfn1
->u4
.PteFrame
= PteFrame
;
1389 /* Increase its share count so we don't get rid of it */
1390 Pfn1
= MI_PFN_ELEMENT(PteFrame
);
1391 Pfn1
->u2
.ShareCount
++;