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 MiRemovePageByColor(IN PFN_NUMBER PageIndex
,
255 PFN_NUMBER OldFlink
, OldBlink
;
256 ULONG OldColor
, OldCache
;
258 PMMCOLOR_TABLES ColorTable
;
260 /* Make sure PFN lock is held */
261 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
262 ASSERT(Color
< MmSecondaryColors
);
264 /* Get the PFN entry */
265 Pfn1
= MiGetPfnEntry(PageIndex
);
266 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
267 ASSERT(Pfn1
->u3
.e1
.Rom
== 0);
269 /* Capture data for later */
270 OldColor
= Pfn1
->u3
.e1
.PageColor
;
271 OldCache
= Pfn1
->u3
.e1
.CacheAttribute
;
273 /* Could be either on free or zero list */
274 ListHead
= MmPageLocationList
[Pfn1
->u3
.e1
.PageLocation
];
275 ListName
= ListHead
->ListName
;
276 ASSERT(ListName
<= FreePageList
);
281 /* Get the forward and back pointers */
282 OldFlink
= Pfn1
->u1
.Flink
;
283 OldBlink
= Pfn1
->u2
.Blink
;
285 /* Check if the next entry is the list head */
286 if (OldFlink
!= LIST_HEAD
)
288 /* It is not, so set the backlink of the actual entry, to our backlink */
289 MiGetPfnEntry(OldFlink
)->u2
.Blink
= OldBlink
;
293 /* Set the list head's backlink instead */
294 ListHead
->Blink
= OldFlink
;
297 /* Check if the back entry is the list head */
298 if (OldBlink
!= LIST_HEAD
)
300 /* It is not, so set the backlink of the actual entry, to our backlink */
301 MiGetPfnEntry(OldBlink
)->u1
.Flink
= OldFlink
;
305 /* Set the list head's backlink instead */
306 ListHead
->Flink
= OldFlink
;
309 /* We are not on a list anymore */
310 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
312 /* Zero flags but restore color and cache */
313 Pfn1
->u3
.e2
.ShortFlags
= 0;
314 Pfn1
->u3
.e1
.PageColor
= OldColor
;
315 Pfn1
->u3
.e1
.CacheAttribute
= OldCache
;
316 #if 0 // When switching to ARM3
317 /* Get the first page on the color list */
318 ColorTable
= &MmFreePagesByColor
[ListName
][Color
];
319 ASSERT(ColorTable
->Count
>= 1);
321 /* Set the forward link to whoever we were pointing to */
322 ColorTable
->Flink
= Pfn1
->OriginalPte
.u
.Long
;
323 if (ColorTable
->Flink
== LIST_HEAD
)
325 /* This is the beginning of the list, so set the sentinel value */
326 ColorTable
->Blink
= LIST_HEAD
;
330 /* The list is empty, so we are the first page */
331 MiGetPfnEntry(ColorTable
->Flink
)->u4
.PteFrame
= -1;
337 /* See if we hit any thresholds */
338 if (MmAvailablePages
== MmHighMemoryThreshold
)
340 /* Clear the high memory event */
341 KeClearEvent(MiHighMemoryEvent
);
343 else if (MmAvailablePages
== MmLowMemoryThreshold
)
345 /* Signal the low memory event */
346 KeSetEvent(MiLowMemoryEvent
, 0, FALSE
);
350 if (--MmAvailablePages
< MmMinimumFreePages
)
352 /* FIXME: Should wake up the MPW and working set manager, if we had one */
355 /* Return the page */
361 MiRemoveAnyPage(IN ULONG Color
)
363 PFN_NUMBER PageIndex
;
366 /* Make sure PFN lock is held and we have pages */
367 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
368 ASSERT(MmAvailablePages
!= 0);
369 ASSERT(Color
< MmSecondaryColors
);
371 /* Check the colored free list */
372 #if 0 // Enable when using ARM3 database */
373 PageIndex
= MmFreePagesByColor
[FreePageList
][Color
].Flink
;
374 if (PageIndex
== LIST_HEAD
)
376 /* Check the colored zero list */
377 PageIndex
= MmFreePagesByColor
[ZeroedPageList
][Color
].Flink
;
378 if (PageIndex
== LIST_HEAD
)
381 /* Check the free list */
382 PageIndex
= MmFreePageListHead
.Flink
;
383 Color
= PageIndex
& MmSecondaryColorMask
;
384 if (PageIndex
== LIST_HEAD
)
386 /* Check the zero list */
387 ASSERT(MmFreePageListHead
.Total
== 0);
388 PageIndex
= MmZeroedPageListHead
.Flink
;
389 Color
= PageIndex
& MmSecondaryColorMask
;
390 ASSERT(PageIndex
!= LIST_HEAD
);
391 if (PageIndex
== LIST_HEAD
)
393 /* FIXME: Should check the standby list */
394 ASSERT(MmZeroedPageListHead
.Total
== 0);
397 #if 0 // Enable when using ARM3 database */
402 /* Remove the page from its list */
403 PageIndex
= MiRemovePageByColor(PageIndex
, Color
);
406 Pfn1
= MiGetPfnEntry(PageIndex
);
407 ASSERT((Pfn1
->u3
.e1
.PageLocation
== FreePageList
) ||
408 (Pfn1
->u3
.e1
.PageLocation
== ZeroedPageList
));
409 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
410 ASSERT(Pfn1
->u2
.ShareCount
== 0);
412 /* Return the page */
418 MiRemoveHeadList(IN PMMPFNLIST ListHead
)
420 PFN_NUMBER Entry
, Flink
;
423 /* Get the entry that's currently first on the list */
424 Entry
= ListHead
->Flink
;
425 Pfn1
= MiGetPfnEntry(Entry
);
427 /* Make the list point to the entry following the first one */
428 Flink
= Pfn1
->u1
.Flink
;
429 ListHead
->Flink
= Flink
;
431 /* Check if the next entry is actually the list head */
432 if (ListHead
->Flink
!= LIST_HEAD
)
434 /* It isn't, so therefore whoever is coming next points back to the head */
435 MiGetPfnEntry(Flink
)->u2
.Blink
= LIST_HEAD
;
439 /* Then the list is empty, so the backlink should point back to us */
440 ListHead
->Blink
= LIST_HEAD
;
443 /* We are not on a list anymore */
444 Pfn1
->u1
.Flink
= Pfn1
->u2
.Blink
= 0;
447 /* Return the head element */
453 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex
)
461 PMMCOLOR_TABLES ColorTable
;
463 /* Make sure the page index is valid */
464 ASSERT((PageFrameIndex
!= 0) &&
465 (PageFrameIndex
<= MmHighestPhysicalPage
) &&
466 (PageFrameIndex
>= MmLowestPhysicalPage
));
468 /* Get the PFN entry */
469 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
471 /* Sanity checks that a right kind of page is being inserted here */
472 ASSERT(Pfn1
->u4
.MustBeCached
== 0);
473 ASSERT(Pfn1
->u3
.e1
.Rom
!= 1);
474 ASSERT(Pfn1
->u3
.e1
.RemovalRequested
== 0);
475 ASSERT(Pfn1
->u4
.VerifierAllocation
== 0);
476 ASSERT(Pfn1
->u3
.e2
.ReferenceCount
== 0);
478 /* Get the free page list and increment its count */
479 ListHead
= &MmFreePageListHead
;
482 /* Get the last page on the list */
483 LastPage
= ListHead
->Blink
;
484 if (LastPage
!= LIST_HEAD
)
486 /* Link us with the previous page, so we're at the end now */
487 MiGetPfnEntry(LastPage
)->u1
.Flink
= PageFrameIndex
;
491 /* The list is empty, so we are the first page */
492 ListHead
->Flink
= PageFrameIndex
;
495 /* Now make the list head point back to us (since we go at the end) */
496 ListHead
->Blink
= PageFrameIndex
;
498 /* And initialize our own list pointers */
499 Pfn1
->u1
.Flink
= LIST_HEAD
;
500 Pfn1
->u2
.Blink
= LastPage
;
502 /* Set the list name and default priority */
503 Pfn1
->u3
.e1
.PageLocation
= FreePageList
;
504 Pfn1
->u4
.Priority
= 3;
506 /* Clear some status fields */
507 Pfn1
->u4
.InPageError
= 0;
508 Pfn1
->u4
.AweAllocation
= 0;
510 /* Increase available pages */
513 /* Check if we've reached the configured low memory threshold */
514 if (MmAvailablePages
== MmLowMemoryThreshold
)
516 /* Clear the event, because now we're ABOVE the threshold */
517 KeClearEvent(MiLowMemoryEvent
);
519 else if (MmAvailablePages
== MmHighMemoryThreshold
)
521 /* Otherwise check if we reached the high threshold and signal the event */
522 KeSetEvent(MiHighMemoryEvent
, 0, FALSE
);
525 #if 0 // When using ARM3 PFN
526 /* Get the page color */
527 Color
= PageFrameIndex
& MmSecondaryColorMask
;
529 /* Get the first page on the color list */
530 ColorTable
= &MmFreePagesByColor
[FreePageList
][Color
];
531 if (ColorTable
->Flink
== LIST_HEAD
)
533 /* The list is empty, so we are the first page */
534 Pfn1
->u4
.PteFrame
= -1;
535 ColorTable
->Flink
= PageFrameIndex
;
539 /* Get the previous page */
540 Blink
= (PMMPFN
)ColorTable
->Blink
;
542 /* Make it link to us */
543 Pfn1
->u4
.PteFrame
= MI_PFNENTRY_TO_PFN(Blink
);
544 Blink
->OriginalPte
.u
.Long
= PageFrameIndex
;
547 /* Now initialize our own list pointers */
548 ColorTable
->Blink
= Pfn1
;
549 Pfn1
->OriginalPte
.u
.Long
= LIST_HEAD
;
551 /* And increase the count in the colored list */
555 /* Notify zero page thread if enough pages are on the free list now */
556 extern KEVENT ZeroPageThreadEvent
;
557 if ((MmFreePageListHead
.Total
> 8) && !(KeReadStateEvent(&ZeroPageThreadEvent
)))
559 /* This is ReactOS-specific */
560 KeSetEvent(&ZeroPageThreadEvent
, IO_NO_INCREMENT
, FALSE
);