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"
19 /* GLOBALS ********************************************************************/
24 MMPFNLIST MmZeroedPageListHead
= {0, ZeroedPageList
, LIST_HEAD
, LIST_HEAD
};
25 MMPFNLIST MmFreePageListHead
= {0, FreePageList
, LIST_HEAD
, LIST_HEAD
};
26 MMPFNLIST MmStandbyPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
27 MMPFNLIST MmModifiedPageListHead
= {0, ModifiedPageList
, LIST_HEAD
, LIST_HEAD
};
28 MMPFNLIST MmModifiedNoWritePageListHead
= {0, ModifiedNoWritePageList
, LIST_HEAD
, LIST_HEAD
};
29 MMPFNLIST MmBadPageListHead
= {0, BadPageList
, LIST_HEAD
, LIST_HEAD
};
30 MMPFNLIST MmRomPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
32 PMMPFNLIST MmPageLocationList
[] =
34 &MmZeroedPageListHead
,
36 &MmStandbyPageListHead
,
37 &MmModifiedPageListHead
,
38 &MmModifiedNoWritePageListHead
,
43 /* FUNCTIONS ******************************************************************/
47 MiInsertInListTail(IN PMMPFNLIST ListHead
,
50 PFN_NUMBER OldBlink
, EntryIndex
= MiGetPfnEntryIndex(Entry
);
52 /* Get the back link */
53 OldBlink
= ListHead
->Blink
;
54 if (OldBlink
!= LIST_HEAD
)
56 /* Set the back pointer to point to us now */
57 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
61 /* Set the list to point to us */
62 ListHead
->Flink
= EntryIndex
;
65 /* Set the entry to point to the list head forwards, and the old page backwards */
66 Entry
->u1
.Flink
= LIST_HEAD
;
67 Entry
->u2
.Blink
= OldBlink
;
69 /* And now the head points back to us, since we are last */
70 ListHead
->Blink
= EntryIndex
;
76 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex
)
84 PMMCOLOR_TABLES ColorHead
;
87 /* Make sure the PFN lock is held */
88 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
90 /* Get the descriptor */
91 Pfn1
= MiGetPfnEntry(EntryIndex
);
92 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
93 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
94 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
95 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
96 ASSERT(Pfn1
->u4
.InPageError
== 0);
98 /* Use the zero list */
99 ListHead
= &MmZeroedPageListHead
;
102 /* Get the back link */
103 OldBlink
= ListHead
->Blink
;
104 if (OldBlink
!= LIST_HEAD
)
106 /* Set the back pointer to point to us now */
107 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
111 /* Set the list to point to us */
112 ListHead
->Flink
= EntryIndex
;
115 /* Set the entry to point to the list head forwards, and the old page backwards */
116 Pfn1
->u1
.Flink
= LIST_HEAD
;
117 Pfn1
->u2
.Blink
= OldBlink
;
119 /* And now the head points back to us, since we are last */
120 ListHead
->Blink
= EntryIndex
;
122 /* Update the page location */
123 Pfn1
->u3
.e1
.PageLocation
= ZeroedPageList
;
125 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
126 //MmAvailablePages++;
128 /* Check if we've reached the configured low memory threshold */
129 if (MmAvailablePages
== MmLowMemoryThreshold
)
131 /* Clear the event, because now we're ABOVE the threshold */
132 KeClearEvent(MiLowMemoryEvent
);
134 else if (MmAvailablePages
== MmHighMemoryThreshold
)
136 /* Otherwise check if we reached the high threshold and signal the event */
137 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
140 /* Get the page color */
141 Color
= EntryIndex
& MmSecondaryColorMask
;
143 /* Get the first page on the color list */
144 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
145 if (ColorHead
->Flink
== LIST_HEAD
)
147 /* The list is empty, so we are the first page */
148 Pfn1
->u4
.PteFrame
= -1;
149 ColorHead
->Flink
= EntryIndex
;
153 /* Get the previous page */
154 Blink
= (PMMPFN
)ColorHead
->Blink
;
156 /* Make it link to us */
157 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
158 Blink
->OriginalPte
.u
.Long
= EntryIndex
;
161 /* Now initialize our own list pointers */
162 ColorHead
->Blink
= Pfn1
;
163 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
165 /* And increase the count in the colored list */
172 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
174 PFN_NUMBER OldFlink
, OldBlink
;
178 /* Make sure the PFN lock is held */
179 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
181 /* Make sure the PFN entry isn't in-use */
182 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
183 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
185 /* Find the list for this entry, make sure it's the free or zero list */
186 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
187 ListName
= ListHead
->ListName
;
188 ASSERT(ListHead
!= NULL
);
189 ASSERT(ListName
<= FreePageList
);
191 /* Remove one count */
192 ASSERT(ListHead
->Total
!= 0);
195 /* Get the forward and back pointers */
196 OldFlink
= Entry
->u1
.Flink
;
197 OldBlink
= Entry
->u2
.Blink
;
199 /* Check if the next entry is the list head */
200 if (OldFlink
!= LIST_HEAD
)
202 /* It is not, so set the backlink of the actual entry, to our backlink */
203 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
207 /* Set the list head's backlink instead */
208 ListHead
->Blink
= OldFlink
;
211 /* Check if the back entry is the list head */
212 if (OldBlink
!= LIST_HEAD
)
214 /* It is not, so set the backlink of the actual entry, to our backlink */
215 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
219 /* Set the list head's backlink instead */
220 ListHead
->Flink
= OldFlink
;
223 /* We are not on a list anymore */
224 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
226 /* FIXME: Deal with color list */
228 /* See if we hit any thresholds */
229 if (MmAvailablePages
== MmHighMemoryThreshold
)
231 /* Clear the high memory event */
232 KeClearEvent(MiHighMemoryEvent
);
234 else if (MmAvailablePages
== MmLowMemoryThreshold
)
236 /* Signal the low memory event */
237 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
241 if (--MmAvailablePages
< MmMinimumFreePages
)
243 /* FIXME: Should wake up the MPW and working set manager, if we had one */
249 MiRemoveHeadList(IN PMMPFNLIST ListHead
)
251 PFN_NUMBER Entry
, Flink
;
254 /* Get the entry that's currently first on the list */
255 Entry
= ListHead
->Flink
;
256 Pfn1
= MiGetPfnEntry(Entry
);
258 /* Make the list point to the entry following the first one */
259 Flink
= Pfn1
->u1
.Flink
;
260 ListHead
->Flink
= Flink
;
262 /* Check if the next entry is actually the list head */
263 if (ListHead
->Flink
!= LIST_HEAD
)
265 /* It isn't, so therefore whoever is coming next points back to the head */
266 MiGetPfnEntry(Flink
)->u2
.Blink
= LIST_HEAD
;
270 /* Then the list is empty, so the backlink should point back to us */
271 ListHead
->Blink
= LIST_HEAD
;
274 /* We are not on a list anymore */
275 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
278 /* Return the head element */
284 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
290 PMMCOLOR_TABLES ColorHead
;
292 /* Make sure the page index is valid */
293 ASSERT((PageFrameIndex
!= 0) &&
294 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
295 (PageFrameIndex
>= MmLowestPhysicalPage
));
297 /* Get the PFN entry */
298 Pfn1
= MI_PFN_TO_PFNENTRY(PageFrameIndex
);
300 /* Sanity checks that a right kind of page is being inserted here */
301 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
302 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
303 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
304 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
305 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
307 /* Get the free page list and increment its count */
308 ListHead
= &MmFreePageListHead
;
311 /* Get the last page on the list */
312 LastPage
= ListHead
->Blink
;
313 if (LastPage
!= LIST_HEAD
)
315 /* Link us with the previous page, so we're at the end now */
316 MI_PFN_TO_PFNENTRY(LastPage
)->u1
.Flink
= PageFrameIndex
;
320 /* The list is empty, so we are the first page */
321 ListHead
->Flink
= PageFrameIndex
;
324 /* Now make the list head point back to us (since we go at the end) */
325 ListHead
->Blink
= PageFrameIndex
;
327 /* And initialize our own list pointers */
328 Pfn1
->u1
.Flink
= LIST_HEAD
;
329 Pfn1
->u2
.Blink
= LastPage
;
331 /* Set the list name and default priority */
332 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
333 Pfn1
->u4
.Priority
= 3;
335 /* Clear some status fields */
336 Pfn1
->u4
.InPageError
= 0;
337 Pfn1
->u4
.AweAllocation
= 0;
339 /* Not yet until we switch to this */
340 //MmAvailablePages++;
342 /* Check if we've reached the configured low memory threshold */
343 if (MmAvailablePages
== MmLowMemoryThreshold
)
345 /* Clear the event, because now we're ABOVE the threshold */
346 KeClearEvent(MiLowMemoryEvent
);
348 else if (MmAvailablePages
== MmHighMemoryThreshold
)
350 /* Otherwise check if we reached the high threshold and signal the event */
351 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
354 /* Get the page color */
355 Color
= PageFrameIndex
& MmSecondaryColorMask
;
357 /* Get the first page on the color list */
358 ColorHead
= &MmFreePagesByColor
[FreePageList
][Color
];
359 if (ColorHead
->Flink
== LIST_HEAD
)
361 /* The list is empty, so we are the first page */
362 Pfn1
->u4
.PteFrame
= -1;
363 ColorHead
->Flink
= PageFrameIndex
;
367 /* Get the previous page */
368 Blink
= (PMMPFN
)ColorHead
->Blink
;
370 /* Make it link to us */
371 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
372 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
375 /* Now initialize our own list pointers */
376 ColorHead
->Blink
= Pfn1
;
377 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
379 /* And increase the count in the colored list */
382 /* FIXME: Notify zero page thread if enough pages are on the free list now */