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 ********************************************************************/
21 MMPFNLIST MmZeroedPageListHead
= {0, ZeroedPageList
, LIST_HEAD
, LIST_HEAD
};
22 MMPFNLIST MmFreePageListHead
= {0, FreePageList
, LIST_HEAD
, LIST_HEAD
};
23 MMPFNLIST MmStandbyPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
24 MMPFNLIST MmModifiedPageListHead
= {0, ModifiedPageList
, LIST_HEAD
, LIST_HEAD
};
25 MMPFNLIST MmModifiedNoWritePageListHead
= {0, ModifiedNoWritePageList
, LIST_HEAD
, LIST_HEAD
};
26 MMPFNLIST MmBadPageListHead
= {0, BadPageList
, LIST_HEAD
, LIST_HEAD
};
27 MMPFNLIST MmRomPageListHead
= {0, StandbyPageList
, LIST_HEAD
, LIST_HEAD
};
29 PMMPFNLIST MmPageLocationList
[] =
31 &MmZeroedPageListHead
,
33 &MmStandbyPageListHead
,
34 &MmModifiedPageListHead
,
35 &MmModifiedNoWritePageListHead
,
40 /* FUNCTIONS ******************************************************************/
44 MiInsertInListTail(IN PMMPFNLIST ListHead
,
47 PFN_NUMBER OldBlink
, EntryIndex
= MiGetPfnEntryIndex(Entry
);
49 /* Get the back link */
50 OldBlink
= ListHead
->Blink
;
51 if (OldBlink
!= LIST_HEAD
)
53 /* Set the back pointer to point to us now */
54 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
58 /* Set the list to point to us */
59 ListHead
->Flink
= EntryIndex
;
62 /* Set the entry to point to the list head forwards, and the old page backwards */
63 Entry
->u1
.Flink
= LIST_HEAD
;
64 Entry
->u2
.Blink
= OldBlink
;
66 /* And now the head points back to us, since we are last */
67 ListHead
->Blink
= EntryIndex
;
73 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex
)
81 PMMCOLOR_TABLES ColorHead
;
84 /* Make sure the PFN lock is held */
85 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
87 /* Get the descriptor */
88 Pfn1
= MiGetPfnEntry(EntryIndex
);
89 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
90 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
91 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
92 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
93 ASSERT(Pfn1
->u4
.InPageError
== 0);
95 /* Use the zero list */
96 ListHead
= &MmZeroedPageListHead
;
99 /* Get the back link */
100 OldBlink
= ListHead
->Blink
;
101 if (OldBlink
!= LIST_HEAD
)
103 /* Set the back pointer to point to us now */
104 MiGetPfnEntry(OldBlink
)->u1
.Flink
= EntryIndex
;
108 /* Set the list to point to us */
109 ListHead
->Flink
= EntryIndex
;
112 /* Set the entry to point to the list head forwards, and the old page backwards */
113 Pfn1
->u1
.Flink
= LIST_HEAD
;
114 Pfn1
->u2
.Blink
= OldBlink
;
116 /* And now the head points back to us, since we are last */
117 ListHead
->Blink
= EntryIndex
;
119 /* Update the page location */
120 Pfn1
->u3
.e1
.PageLocation
= ZeroedPageList
;
122 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
123 //MmAvailablePages++;
125 /* Check if we've reached the configured low memory threshold */
126 if (MmAvailablePages
== MmLowMemoryThreshold
)
128 /* Clear the event, because now we're ABOVE the threshold */
129 KeClearEvent(MiLowMemoryEvent
);
131 else if (MmAvailablePages
== MmHighMemoryThreshold
)
133 /* Otherwise check if we reached the high threshold and signal the event */
134 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
137 /* Get the page color */
138 Color
= EntryIndex
& MmSecondaryColorMask
;
140 /* Get the first page on the color list */
141 ColorHead
= &MmFreePagesByColor
[ZeroedPageList
][Color
];
142 if (ColorHead
->Flink
== LIST_HEAD
)
144 /* The list is empty, so we are the first page */
145 Pfn1
->u4
.PteFrame
= -1;
146 ColorHead
->Flink
= EntryIndex
;
150 /* Get the previous page */
151 Blink
= (PMMPFN
)ColorHead
->Blink
;
153 /* Make it link to us */
154 Pfn1
->u4
.PteFrame
= MiGetPfnEntryIndex(Blink
);
155 Blink
->OriginalPte
.u
.Long
= EntryIndex
;
158 /* Now initialize our own list pointers */
159 ColorHead
->Blink
= Pfn1
;
160 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
162 /* And increase the count in the colored list */
169 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry
)
171 PFN_NUMBER OldFlink
, OldBlink
;
175 /* Make sure the PFN lock is held */
176 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
178 /* Make sure the PFN entry isn't in-use */
179 ASSERT(Entry
->u3
.e1
.WriteInProgress
== 0);
180 ASSERT(Entry
->u3
.e1
.ReadInProgress
== 0);
182 /* Find the list for this entry, make sure it's the free or zero list */
183 ListHead
= MmPageLocationList
[Entry
->u3
.e1
.PageLocation
];
184 ListName
= ListHead
->ListName
;
185 ASSERT(ListHead
!= NULL
);
186 ASSERT(ListName
<= FreePageList
);
188 /* Remove one count */
189 ASSERT(ListHead
->Total
!= 0);
192 /* Get the forward and back pointers */
193 OldFlink
= Entry
->u1
.Flink
;
194 OldBlink
= Entry
->u2
.Blink
;
196 /* Check if the next entry is the list head */
197 if (OldFlink
!= LIST_HEAD
)
199 /* It is not, so set the backlink of the actual entry, to our backlink */
200 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
204 /* Set the list head's backlink instead */
205 ListHead
->Blink
= OldFlink
;
208 /* Check if the back entry is the list head */
209 if (OldBlink
!= LIST_HEAD
)
211 /* It is not, so set the backlink of the actual entry, to our backlink */
212 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
216 /* Set the list head's backlink instead */
217 ListHead
->Flink
= OldFlink
;
220 /* We are not on a list anymore */
221 Entry
->u1
.Flink
= Entry
->u2
.Blink
= 0;
223 /* FIXME: Deal with color list */
225 /* See if we hit any thresholds */
226 if (MmAvailablePages
== MmHighMemoryThreshold
)
228 /* Clear the high memory event */
229 KeClearEvent(MiHighMemoryEvent
);
231 else if (MmAvailablePages
== MmLowMemoryThreshold
)
233 /* Signal the low memory event */
234 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
238 if (--MmAvailablePages
< MmMinimumFreePages
)
240 /* FIXME: Should wake up the MPW and working set manager, if we had one */
246 MiRemoveHeadList(IN PMMPFNLIST ListHead
)
248 PFN_NUMBER Entry
, Flink
;
251 /* Get the entry that's currently first on the list */
252 Entry
= ListHead
->Flink
;
253 Pfn1
= MiGetPfnEntry(Entry
);
255 /* Make the list point to the entry following the first one */
256 Flink
= Pfn1
->u1
.Flink
;
257 ListHead
->Flink
= Flink
;
259 /* Check if the next entry is actually the list head */
260 if (ListHead
->Flink
!= LIST_HEAD
)
262 /* It isn't, so therefore whoever is coming next points back to the head */
263 MiGetPfnEntry(Flink
)->u2
.Blink
= LIST_HEAD
;
267 /* Then the list is empty, so the backlink should point back to us */
268 ListHead
->Blink
= LIST_HEAD
;
271 /* We are not on a list anymore */
272 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
275 /* Return the head element */
281 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
287 PMMCOLOR_TABLES ColorHead
;
289 /* Make sure the page index is valid */
290 ASSERT((PageFrameIndex
!= 0) &&
291 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
292 (PageFrameIndex
>= MmLowestPhysicalPage
));
294 /* Get the PFN entry */
295 Pfn1
= MI_PFN_TO_PFNENTRY(PageFrameIndex
);
297 /* Sanity checks that a right kind of page is being inserted here */
298 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
299 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
300 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
301 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
302 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
304 /* Get the free page list and increment its count */
305 ListHead
= &MmFreePageListHead
;
308 /* Get the last page on the list */
309 LastPage
= ListHead
->Blink
;
310 if (LastPage
!= LIST_HEAD
)
312 /* Link us with the previous page, so we're at the end now */
313 MI_PFN_TO_PFNENTRY(LastPage
)->u1
.Flink
= PageFrameIndex
;
317 /* The list is empty, so we are the first page */
318 ListHead
->Flink
= PageFrameIndex
;
321 /* Now make the list head point back to us (since we go at the end) */
322 ListHead
->Blink
= PageFrameIndex
;
324 /* And initialize our own list pointers */
325 Pfn1
->u1
.Flink
= LIST_HEAD
;
326 Pfn1
->u2
.Blink
= LastPage
;
328 /* Set the list name and default priority */
329 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
330 Pfn1
->u4
.Priority
= 3;
332 /* Clear some status fields */
333 Pfn1
->u4
.InPageError
= 0;
334 Pfn1
->u4
.AweAllocation
= 0;
336 /* Not yet until we switch to this */
337 //MmAvailablePages++;
339 /* Check if we've reached the configured low memory threshold */
340 if (MmAvailablePages
== MmLowMemoryThreshold
)
342 /* Clear the event, because now we're ABOVE the threshold */
343 KeClearEvent(MiLowMemoryEvent
);
345 else if (MmAvailablePages
== MmHighMemoryThreshold
)
347 /* Otherwise check if we reached the high threshold and signal the event */
348 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
351 /* Get the page color */
352 Color
= PageFrameIndex
& MmSecondaryColorMask
;
354 /* Get the first page on the color list */
355 ColorHead
= &MmFreePagesByColor
[FreePageList
][Color
];
356 if (ColorHead
->Flink
== LIST_HEAD
)
358 /* The list is empty, so we are the first page */
359 Pfn1
->u4
.PteFrame
= -1;
360 ColorHead
->Flink
= PageFrameIndex
;
364 /* Get the previous page */
365 Blink
= (PMMPFN
)ColorHead
->Blink
;
367 /* Make it link to us */
368 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
369 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
372 /* Now initialize our own list pointers */
373 ColorHead
->Blink
= Pfn1
;
374 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
376 /* And increase the count in the colored list */
379 /* FIXME: Notify zero page thread if enough pages are on the free list now */