2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/pfnlist.c
5 * PURPOSE: ARM Memory Manager PFN List Manipulation
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::PFNLIST"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
20 #define ASSERT_LIST_INVARIANT(x) \
22 ASSERT(((x)->Total == 0 && \
23 (x)->Flink == LIST_HEAD && \
24 (x)->Blink == LIST_HEAD) || \
26 (x)->Flink != LIST_HEAD && \
27 (x)->Blink != LIST_HEAD)); \
30 #define ASSERT_LIST_INVARIANT(x)
33 /* GLOBALS ********************************************************************/
37 ULONG MmSystemPageColor
;
39 MMPFNLIST MmZeroedPageListHead
= {0, ZeroedPageList
, LIST_HEAD
, LIST_HEAD
};
40 MMPFNLIST MmFreePageListHead
= {0, FreePageList
, LIST_HEAD
, LIST_HEAD
};
41 MMPFNLIST MmStandbyPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
42 MMPFNLIST MmModifiedPageListHead
= {0, ModifiedPageList
, LIST_HEAD
, LIST_HEAD
};
43 MMPFNLIST MmModifiedNoWritePageListHead
= {0, ModifiedNoWritePageList
, LIST_HEAD
, LIST_HEAD
};
44 MMPFNLIST MmBadPageListHead
= {0, BadPageList
, LIST_HEAD
, LIST_HEAD
};
45 MMPFNLIST MmRomPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
47 PMMPFNLIST MmPageLocationList
[] =
49 &MmZeroedPageListHead
,
51 &MmStandbyPageListHead
,
52 &MmModifiedPageListHead
,
53 &MmModifiedNoWritePageListHead
,
58 /* FUNCTIONS ******************************************************************/
62 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex
)
66 PEPROCESS Process
= PsGetCurrentProcess();
68 /* Map in hyperspace, then wipe it using XMMI or MEMSET */
69 VirtualAddress
= MiMapPageInHyperSpace(Process
, PageFrameIndex
, &OldIrql
);
70 ASSERT(VirtualAddress
);
71 KeZeroPages(VirtualAddress
, PAGE_SIZE
);
72 MiUnmapPageInHyperSpace(Process
, VirtualAddress
, OldIrql
);
77 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
79 PFN_NUMBER OldFlink
, OldBlink
;
83 PMMCOLOR_TABLES ColorTable
;
86 /* Make sure the PFN lock is held */
87 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
89 /* Make sure the PFN entry isn't in-use */
90 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
91 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
93 /* Find the list for this entry, make sure it's the free or zero list */
94 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
95 ListName
= ListHead
->ListName
;
96 ASSERT(ListHead
!= NULL
);
97 ASSERT(ListName
<= FreePageList
);
98 ASSERT_LIST_INVARIANT(ListHead
);
100 /* Remove one count */
101 ASSERT(ListHead
->Total
!= 0);
104 /* Get the forward and back pointers */
105 OldFlink
= Entry
->u1
.Flink
;
106 OldBlink
= Entry
->u2
.Blink
;
108 /* Check if the next entry is the list head */
109 if (OldFlink
!= LIST_HEAD
)
111 /* It is not, so set the backlink of the actual entry, to our backlink */
112 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
116 /* Set the list head's backlink instead */
117 ListHead
->Blink
= OldBlink
;
120 /* Check if the back entry is the list head */
121 if (OldBlink
!= LIST_HEAD
)
123 /* It is not, so set the backlink of the actual entry, to our backlink */
124 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
128 /* Set the list head's backlink instead */
129 ListHead
->Flink
= OldFlink
;
132 /* Get the page color */
133 OldBlink
= MiGetPfnEntryIndex(Entry
);
134 Color
= OldBlink
& MmSecondaryColorMask
;
136 /* Get the first page on the color list */
137 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
139 /* Check if this was was actually the head */
140 OldFlink
= ColorTable
->Flink
;
141 if (OldFlink
== OldBlink
)
143 /* Make the table point to the next page this page was linking to */
144 ColorTable
->Flink
= Entry
->OriginalPte
.u
.Long
;
145 if (ColorTable
->Flink
!= LIST_HEAD
)
147 /* And make the previous link point to the head now */
148 MiGetPfnEntry(ColorTable
->Flink
)->u4
.PteFrame
= COLORED_LIST_HEAD
;
152 /* And if that page was the head, loop the list back around */
153 ColorTable
->Blink
= (PVOID
)LIST_HEAD
;
158 /* This page shouldn't be pointing back to the head */
159 ASSERT(Entry
->u4
.PteFrame
!= COLORED_LIST_HEAD
);
161 /* Make the back link point to whoever the next page is */
162 Pfn1
= MiGetPfnEntry(Entry
->u4
.PteFrame
);
163 Pfn1
->OriginalPte
.u
.Long
= Entry
->OriginalPte
.u
.Long
;
165 /* Check if this page was pointing to the head */
166 if (Entry
->OriginalPte
.u
.Long
!= LIST_HEAD
)
168 /* Make the back link point to the head */
169 Pfn1
= MiGetPfnEntry(Entry
->OriginalPte
.u
.Long
);
170 Pfn1
->u4
.PteFrame
= Entry
->u4
.PteFrame
;
174 /* Then the table is directly back pointing to this page now */
175 ColorTable
->Blink
= Pfn1
;
179 /* One less colored page */
180 ASSERT(ColorTable
->Count
>= 1);
184 Entry
->OriginalPte
.u
.Long
= 0;
186 /* We are not on a list anymore */
187 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
188 ASSERT_LIST_INVARIANT(ListHead
);
190 /* See if we hit any thresholds */
191 if (MmAvailablePages
== MmHighMemoryThreshold
)
193 /* Clear the high memory event */
194 KeClearEvent(MiHighMemoryEvent
);
196 else if (MmAvailablePages
== MmLowMemoryThreshold
)
198 /* Signal the low memory event */
199 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
203 if (--MmAvailablePages
< MmMinimumFreePages
)
205 /* FIXME: Should wake up the MPW and working set manager, if we had one */
211 MiRemovePageByColor(IN PFN_NUMBER PageIndex
,
217 PFN_NUMBER OldFlink
, OldBlink
;
218 ULONG OldColor
, OldCache
;
219 PMMCOLOR_TABLES ColorTable
;
221 /* Make sure PFN lock is held */
222 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
223 ASSERT(Color
< MmSecondaryColors
);
225 /* Get the PFN entry */
226 Pfn1
= MiGetPfnEntry(PageIndex
);
227 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
228 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
230 /* Capture data for later */
231 OldColor
= Pfn1
->u3
.e1
.PageColor
;
232 OldCache
= Pfn1
->u3
.e1
.CacheAttribute
;
234 /* Could be either on free or zero list */
235 ListHead
= MmPageLocationList
[Pfn1
->u3
.e1
.PageLocation
];
236 ASSERT_LIST_INVARIANT(ListHead
);
237 ListName
= ListHead
->ListName
;
238 ASSERT(ListName
<= FreePageList
);
243 /* Get the forward and back pointers */
244 OldFlink
= Pfn1
->u1
.Flink
;
245 OldBlink
= Pfn1
->u2
.Blink
;
247 /* Check if the next entry is the list head */
248 if (OldFlink
!= LIST_HEAD
)
250 /* It is not, so set the backlink of the actual entry, to our backlink */
251 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
255 /* Set the list head's backlink instead */
256 ListHead
->Blink
= OldFlink
;
259 /* Check if the back entry is the list head */
260 if (OldBlink
!= LIST_HEAD
)
262 /* It is not, so set the backlink of the actual entry, to our backlink */
263 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
267 /* Set the list head's backlink instead */
268 ListHead
->Flink
= OldFlink
;
271 /* We are not on a list anymore */
272 ASSERT_LIST_INVARIANT(ListHead
);
273 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
275 /* Zero flags but restore color and cache */
276 Pfn1
->u3
.e2
.ShortFlags
= 0;
277 Pfn1
->u3
.e1
.PageColor
= OldColor
;
278 Pfn1
->u3
.e1
.CacheAttribute
= OldCache
;
280 /* Get the first page on the color list */
281 ASSERT(Color
< MmSecondaryColors
);
282 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
283 ASSERT(ColorTable
->Count
>= 1);
285 /* Set the forward link to whoever we were pointing to */
286 ColorTable
->Flink
= Pfn1
->OriginalPte
.u
.Long
;
288 /* Get the first page on the color list */
289 if (ColorTable
->Flink
== LIST_HEAD
)
291 /* This is the beginning of the list, so set the sentinel value */
292 ColorTable
->Blink
= (PVOID
)LIST_HEAD
;
296 /* The list is empty, so we are the first page */
297 MiGetPfnEntry(ColorTable
->Flink
)->u4
.PteFrame
= COLORED_LIST_HEAD
;
304 Pfn1
->OriginalPte
.u
.Long
= 0;
306 /* See if we hit any thresholds */
307 if (MmAvailablePages
== MmHighMemoryThreshold
)
309 /* Clear the high memory event */
310 KeClearEvent(MiHighMemoryEvent
);
312 else if (MmAvailablePages
== MmLowMemoryThreshold
)
314 /* Signal the low memory event */
315 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
319 if (--MmAvailablePages
< MmMinimumFreePages
)
321 /* FIXME: Should wake up the MPW and working set manager, if we had one */
324 /* Return the page */
330 MiRemoveAnyPage(IN ULONG Color
)
332 PFN_NUMBER PageIndex
;
335 /* Make sure PFN lock is held and we have pages */
336 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
337 ASSERT(MmAvailablePages
!= 0);
338 ASSERT(Color
< MmSecondaryColors
);
340 /* Check the colored free list */
341 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
342 DPRINT1("Found free page: %lx\n", PageIndex
);
343 if (PageIndex
== LIST_HEAD
)
345 /* Check the colored zero list */
346 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
347 DPRINT1("Found zero page: %lx\n", PageIndex
);
348 if (PageIndex
== LIST_HEAD
)
351 /* Check the free list */
352 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
353 PageIndex
= MmFreePageListHead
.Flink
;
354 Color
= PageIndex
& MmSecondaryColorMask
;
355 if (PageIndex
== LIST_HEAD
)
357 /* Check the zero list */
358 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
359 PageIndex
= MmZeroedPageListHead
.Flink
;
360 Color
= PageIndex
& MmSecondaryColorMask
;
361 ASSERT(PageIndex
!= LIST_HEAD
);
362 if (PageIndex
== LIST_HEAD
)
364 /* FIXME: Should check the standby list */
365 ASSERT(MmZeroedPageListHead
.Total
== 0);
372 /* Remove the page from its list */
373 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
376 Pfn1
= MiGetPfnEntry(PageIndex
);
377 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
378 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
379 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
380 ASSERT(Pfn1
->u2
.ShareCount
== 0);
381 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
382 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
384 /* Return the page */
390 MiRemoveZeroPage(IN ULONG Color
)
392 PFN_NUMBER PageIndex
;
396 /* Make sure PFN lock is held and we have pages */
397 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
398 ASSERT(MmAvailablePages
!= 0);
399 ASSERT(Color
< MmSecondaryColors
);
401 /* Check the colored zero list */
403 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
404 if (PageIndex
== LIST_HEAD
)
407 /* Check the zero list */
408 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
409 PageIndex
= MmZeroedPageListHead
.Flink
;
410 Color
= PageIndex
& MmSecondaryColorMask
;
411 if (PageIndex
== LIST_HEAD
)
413 /* This means there's no zero pages, we have to look for free ones */
414 ASSERT(MmZeroedPageListHead
.Total
== 0);
417 /* Check the colored free list */
418 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
419 if (PageIndex
== LIST_HEAD
)
422 /* Check the free list */
423 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
424 PageIndex
= MmFreePageListHead
.Flink
;
425 Color
= PageIndex
& MmSecondaryColorMask
;
426 ASSERT(PageIndex
!= LIST_HEAD
);
427 if (PageIndex
== LIST_HEAD
)
429 /* FIXME: Should check the standby list */
430 ASSERT(MmZeroedPageListHead
.Total
== 0);
441 Pfn1
= MiGetPfnEntry(PageIndex
);
442 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
443 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
445 /* Remove the page from its list */
446 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
447 ASSERT(Pfn1
== MiGetPfnEntry(PageIndex
));
449 /* Zero it, if needed */
450 if (Zero
) MiZeroPhysicalPage(PageIndex
);
453 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
454 ASSERT(Pfn1
->u2
.ShareCount
== 0);
455 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
456 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
458 /* Return the page */
464 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
471 PMMCOLOR_TABLES ColorTable
;
473 /* Make sure the page index is valid */
474 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL
);
475 ASSERT((PageFrameIndex
!= 0) &&
476 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
477 (PageFrameIndex
>= MmLowestPhysicalPage
));
479 /* Get the PFN entry */
480 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
482 /* Sanity checks that a right kind of page is being inserted here */
483 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
484 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
485 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
486 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
487 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
489 /* Get the free page list and increment its count */
490 ListHead
= &MmFreePageListHead
;
491 ASSERT_LIST_INVARIANT(ListHead
);
494 /* Get the last page on the list */
495 LastPage
= ListHead
->Blink
;
496 if (LastPage
!= LIST_HEAD
)
498 /* Link us with the previous page, so we're at the end now */
499 MiGetPfnEntry(LastPage
)->u1
.Flink
= PageFrameIndex
;
503 /* The list is empty, so we are the first page */
504 ListHead
->Flink
= PageFrameIndex
;
507 /* Now make the list head point back to us (since we go at the end) */
508 ListHead
->Blink
= PageFrameIndex
;
509 ASSERT_LIST_INVARIANT(ListHead
);
511 /* And initialize our own list pointers */
512 Pfn1
->u1
.Flink
= LIST_HEAD
;
513 Pfn1
->u2
.Blink
= LastPage
;
515 /* Set the list name and default priority */
516 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
517 Pfn1
->u4
.Priority
= 3;
519 /* Clear some status fields */
520 Pfn1
->u4
.InPageError
= 0;
521 Pfn1
->u4
.AweAllocation
= 0;
523 /* Increase available pages */
526 /* Check if we've reached the configured low memory threshold */
527 if (MmAvailablePages
== MmLowMemoryThreshold
)
529 /* Clear the event, because now we're ABOVE the threshold */
530 KeClearEvent(MiLowMemoryEvent
);
532 else if (MmAvailablePages
== MmHighMemoryThreshold
)
534 /* Otherwise check if we reached the high threshold and signal the event */
535 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
538 /* Get the page color */
539 Color
= PageFrameIndex
& MmSecondaryColorMask
;
541 /* Get the first page on the color list */
542 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
543 if (ColorTable
->Flink
== LIST_HEAD
)
545 /* The list is empty, so we are the first page */
546 Pfn1
->u4
.PteFrame
= COLORED_LIST_HEAD
;
547 ColorTable
->Flink
= PageFrameIndex
;
551 /* Get the previous page */
552 Blink
= (PMMPFN
)ColorTable
->Blink
;
554 /* Make it link to us */
555 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
557 /* If there is an original pte, it should be an old link, NOT a ReactOS RMAP */
558 ASSERT(Blink
->u4
.AweAllocation
== FALSE
);
559 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
562 /* Now initialize our own list pointers */
563 ColorTable
->Blink
= Pfn1
;
565 /* If there is an original pte, it should be an old link, NOT a ReactOS RMAP */
566 ASSERT(Pfn1
->u4
.AweAllocation
== FALSE
);
567 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
569 /* And increase the count in the colored list */
572 /* Notify zero page thread if enough pages are on the free list now */
573 if ((ListHead
->Total
>= 8) && !(MmZeroingPageThreadActive
))
576 MmZeroingPageThreadActive
= TRUE
;
577 KeSetEvent(&MmZeroingPageEvent
, IO_NO_INCREMENT
, FALSE
);
581 /* Note: This function is hardcoded only for the zeroed page list, for now */
584 MiInsertPageInList(IN PMMPFNLIST ListHead
,
585 IN PFN_NUMBER PageFrameIndex
)
590 PMMCOLOR_TABLES ColorHead
;
593 /* For free pages, use MiInsertPageInFreeList */
594 ASSERT(ListHead
!= &MmFreePageListHead
);
596 /* Make sure the lock is held */
597 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
599 /* Make sure the PFN is valid */
600 ASSERT((PageFrameIndex
) &&
601 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
602 (PageFrameIndex
>= MmLowestPhysicalPage
));
604 /* Page should be unused */
605 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
606 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
607 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
609 /* Only used for zero pages in ReactOS */
610 ListName
= ListHead
->ListName
;
611 ASSERT(ListName
== ZeroedPageList
);
614 /* Don't handle bad pages yet yet */
615 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
617 /* Make the head of the list point to this page now */
618 Flink
= ListHead
->Flink
;
619 ListHead
->Flink
= PageFrameIndex
;
621 /* Make the page point to the previous head, and back to the list */
622 Pfn1
->u1
.Flink
= Flink
;
623 Pfn1
->u2
.Blink
= LIST_HEAD
;
625 /* Was the list empty? */
626 if (Flink
!= LIST_HEAD
)
628 /* It wasn't, so update the backlink of the previous head page */
629 Pfn2
= MiGetPfnEntry(Flink
);
630 Pfn2
->u2
.Blink
= PageFrameIndex
;
634 /* It was empty, so have it loop back around to this new page */
635 ListHead
->Blink
= PageFrameIndex
;
638 /* Move the page onto its new location */
639 Pfn1
->u3
.e1
.PageLocation
= ListName
;
641 /* One more page on the system */
644 /* Check if we've reached the configured low memory threshold */
645 if (MmAvailablePages
== MmLowMemoryThreshold
)
647 /* Clear the event, because now we're ABOVE the threshold */
648 KeClearEvent(MiLowMemoryEvent
);
650 else if (MmAvailablePages
== MmHighMemoryThreshold
)
652 /* Otherwise check if we reached the high threshold and signal the event */
653 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
657 ASSERT(ListName
== ZeroedPageList
);
658 ASSERT(Pfn1
->u4
.InPageError
== 0);
660 /* Get the page color */
661 Color
= PageFrameIndex
& MmSecondaryColorMask
;
663 /* Get the list for this color */
664 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
666 /* Get the old head */
667 Flink
= ColorHead
->Flink
;
669 /* If there is an original pte, it should be an old link, NOT a ReactOS RMAP */
670 ASSERT(Pfn1
->u4
.AweAllocation
== FALSE
);
672 /* Make this page point back to the list, and point forwards to the old head */
673 Pfn1
->OriginalPte
.u
.Long
= Flink
;
674 Pfn1
->u4
.PteFrame
= COLORED_LIST_HEAD
;
676 /* Set the new head */
677 ColorHead
->Flink
= PageFrameIndex
;
679 /* Was the head empty? */
680 if (Flink
!= LIST_HEAD
)
682 /* No, so make the old head point to this page */
683 Pfn2
= MiGetPfnEntry(Flink
);
684 Pfn2
->u4
.PteFrame
= PageFrameIndex
;
688 /* Yes, make it loop back to this page */
689 ColorHead
->Blink
= (PVOID
)Pfn1
;
692 /* One more paged on the colored list */
698 MiInitializePfn(IN PFN_NUMBER PageFrameIndex
,
699 IN PMMPTE PointerPte
,
704 PMMPTE PointerPtePte
;
705 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
708 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
709 Pfn1
->PteAddress
= PointerPte
;
711 /* Check if this PFN is part of a valid address space */
712 if (PointerPte
->u
.Hard
.Valid
== 1)
714 /* Only valid from MmCreateProcessAddressSpace path */
715 ASSERT(PsGetCurrentProcess()->Vm
.WorkingSetSize
== 0);
717 /* Make this a demand zero PTE */
718 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
722 /* Copy the PTE data */
723 Pfn1
->OriginalPte
= *PointerPte
;
724 ASSERT(!((Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0) &&
725 (Pfn1
->OriginalPte
.u
.Soft
.Transition
== 1)));
728 /* Otherwise this is a fresh page -- set it up */
729 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
730 Pfn1
->u3
.e2
.ReferenceCount
= 1;
731 Pfn1
->u2
.ShareCount
= 1;
732 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
733 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
734 Pfn1
->u3
.e1
.Modified
= Modified
;
736 /* Get the page table for the PTE */
737 PointerPtePte
= MiAddressToPte(PointerPte
);
738 if (PointerPtePte
->u
.Hard
.Valid
== 0)
740 /* Make sure the PDE gets paged in properly */
741 Status
= MiCheckPdeForPagedPool(PointerPte
);
742 if (!NT_SUCCESS(Status
))
745 KeBugCheckEx(MEMORY_MANAGEMENT
,
747 (ULONG_PTR
)PointerPte
,
748 (ULONG_PTR
)PointerPtePte
->u
.Long
,
749 (ULONG_PTR
)MiPteToAddress(PointerPte
));
753 /* Get the PFN for the page table */
754 PageFrameIndex
= PFN_FROM_PTE(PointerPtePte
);
755 ASSERT(PageFrameIndex
!= 0);
756 Pfn1
->u4
.PteFrame
= PageFrameIndex
;
758 /* Increase its share count so we don't get rid of it */
759 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
760 Pfn1
->u2
.ShareCount
++;
765 MiAllocatePfn(IN PMMPTE PointerPte
,
769 PFN_NUMBER PageFrameIndex
;
772 /* Sanity check that we aren't passed a valid PTE */
773 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
775 /* Make an empty software PTE */
776 MI_MAKE_SOFTWARE_PTE(&TempPte
, MM_READWRITE
);
778 /* Lock the PFN database */
779 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
781 /* Check if we're running low on pages */
782 if (MmAvailablePages
< 128)
784 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages
);
785 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
789 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
790 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
791 PageFrameIndex
= MiRemoveAnyPage(MI_GET_NEXT_COLOR());
793 /* Write the software PTE */
794 MI_WRITE_INVALID_PTE(PointerPte
, TempPte
);
795 PointerPte
->u
.Soft
.Protection
|= Protection
;
797 /* Initialize its PFN entry */
798 MiInitializePfn(PageFrameIndex
, PointerPte
, TRUE
);
800 /* Release the PFN lock and return the page */
801 ASSERT_LIST_INVARIANT(&MmFreePageListHead
);
802 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead
);
803 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
804 return PageFrameIndex
;
809 MiDecrementShareCount(IN PMMPFN Pfn1
,
810 IN PFN_NUMBER PageFrameIndex
)
812 ASSERT(PageFrameIndex
> 0);
813 ASSERT(MiGetPfnEntry(PageFrameIndex
) != NULL
);
814 ASSERT(Pfn1
== MiGetPfnEntry(PageFrameIndex
));
815 ASSERT(MI_IS_ROS_PFN(Pfn1
) == FALSE
);
817 /* Page must be in-use */
818 if ((Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
) &&
819 (Pfn1
->u3
.e1
.PageLocation
!= StandbyPageList
))
821 /* Otherwise we have PFN corruption */
822 KeBugCheckEx(PFN_LIST_CORRUPT
,
825 Pfn1
->u3
.e1
.PageLocation
,
829 /* Check if the share count is now 0 */
830 ASSERT(Pfn1
->u2
.ShareCount
< 0xF000000);
831 if (!--Pfn1
->u2
.ShareCount
)
833 /* ReactOS does not handle these */
834 ASSERT(Pfn1
->u3
.e1
.PrototypePte
== 0);
836 /* Put the page in transition */
837 Pfn1
->u3
.e1
.PageLocation
= TransitionPage
;
839 /* PFN lock must be held */
840 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
842 /* Page should at least have one reference */
843 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
844 if (Pfn1
->u3
.e2
.ReferenceCount
== 1)
846 /* In ReactOS, this path should always be hit with a deleted PFN */
847 ASSERT(MI_IS_PFN_DELETED(Pfn1
) == TRUE
);
849 /* Clear the last reference */
850 Pfn1
->u3
.e2
.ReferenceCount
= 0;
853 * OriginalPte is used by AweReferenceCount in ReactOS, but either
854 * ways we shouldn't be seeing RMAP entries at this point
856 ASSERT(Pfn1
->OriginalPte
.u
.Soft
.Prototype
== 0);
857 ASSERT(Pfn1
->u4
.AweAllocation
== FALSE
);
859 /* Mark the page temporarily as valid, we're going to make it free soon */
860 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
862 /* Bring it back into the free list */
863 MiInsertPageInFreeList(PageFrameIndex
);
867 /* Otherwise, just drop the reference count */
868 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
875 MiDecrementReferenceCount(IN PMMPFN Pfn1
,
876 IN PFN_NUMBER PageFrameIndex
)
878 /* PFN lock must be held */
879 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
881 /* Sanity checks on the page */
882 ASSERT(PageFrameIndex
< MmHighestPhysicalPage
);
883 ASSERT(Pfn1
== MiGetPfnEntry(PageFrameIndex
));
884 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
!= 0);
886 /* Dereference the page, bail out if it's still alive */
887 InterlockedDecrement16((PSHORT
)&Pfn1
->u3
.e2
.ReferenceCount
);
888 if (Pfn1
->u3
.e2
.ReferenceCount
) return;
890 /* Nobody should still have reference to this page */
891 if (Pfn1
->u2
.ShareCount
!= 0)
893 /* Otherwise something's really wrong */
894 KeBugCheckEx(PFN_LIST_CORRUPT
, 7, PageFrameIndex
, Pfn1
->u2
.ShareCount
, 0);
897 /* And it should be lying on some page list */
898 ASSERT(Pfn1
->u3
.e1
.PageLocation
!= ActiveAndValid
);
900 /* Did someone set the delete flag? */
901 if (MI_IS_PFN_DELETED(Pfn1
))
903 /* Insert it into the free list, there's nothing left to do */
904 MiInsertPageInFreeList(PageFrameIndex
);
908 /* We don't have a modified list yet */
909 ASSERT(Pfn1
->u3
.e1
.Modified
== 0);
910 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
912 /* FIXME: Normally it would go on the standby list, but we're pushing it on the free list */
913 MiInsertPageInFreeList(PageFrameIndex
);
918 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex
,
919 IN PMMPTE PointerPte
,
920 IN PFN_NUMBER PteFrame
)
925 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
926 Pfn1
->PteAddress
= PointerPte
;
928 /* Make this a software PTE */
929 MI_MAKE_SOFTWARE_PTE(&Pfn1
->OriginalPte
, MM_READWRITE
);
932 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
933 Pfn1
->u3
.e2
.ReferenceCount
= 1;
934 Pfn1
->u2
.ShareCount
= 1;
935 Pfn1
->u3
.e1
.PageLocation
= ActiveAndValid
;
936 Pfn1
->u3
.e1
.Modified
= TRUE
;
937 Pfn1
->u4
.InPageError
= FALSE
;
939 /* Did we get a PFN for the page table */
943 Pfn1
->u4
.PteFrame
= PteFrame
;
945 /* Increase its share count so we don't get rid of it */
946 Pfn1
= MiGetPfnEntry(PteFrame
);
947 Pfn1
->u2
.ShareCount
++;