Sync up to trunk head.
[reactos.git] / ntoskrnl / mm / ARM3 / pfnlist.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::PFNLIST"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 BOOLEAN MmDynamicPfn;
22 BOOLEAN MmMirroring;
23
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};
31
32 PMMPFNLIST MmPageLocationList[] =
33 {
34 &MmZeroedPageListHead,
35 &MmFreePageListHead,
36 &MmStandbyPageListHead,
37 &MmModifiedPageListHead,
38 &MmModifiedNoWritePageListHead,
39 &MmBadPageListHead,
40 NULL,
41 NULL
42 };
43 /* FUNCTIONS ******************************************************************/
44
45 VOID
46 NTAPI
47 MiInsertInListTail(IN PMMPFNLIST ListHead,
48 IN PMMPFN Entry)
49 {
50 PFN_NUMBER OldBlink, EntryIndex = MiGetPfnEntryIndex(Entry);
51
52 /* Get the back link */
53 OldBlink = ListHead->Blink;
54 if (OldBlink != LIST_HEAD)
55 {
56 /* Set the back pointer to point to us now */
57 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
58 }
59 else
60 {
61 /* Set the list to point to us */
62 ListHead->Flink = EntryIndex;
63 }
64
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;
68
69 /* And now the head points back to us, since we are last */
70 ListHead->Blink = EntryIndex;
71 ListHead->Total++;
72 }
73
74 VOID
75 NTAPI
76 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex)
77 {
78 PFN_NUMBER OldBlink;
79 PMMPFNLIST ListHead;
80 PMMPFN Pfn1;
81 #if 0
82 PMMPFN Blink;
83 ULONG Color;
84 PMMCOLOR_TABLES ColorHead;
85 #endif
86
87 /* Make sure the PFN lock is held */
88 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
89
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);
97
98 /* Use the zero list */
99 ListHead = &MmZeroedPageListHead;
100 ListHead->Total++;
101
102 /* Get the back link */
103 OldBlink = ListHead->Blink;
104 if (OldBlink != LIST_HEAD)
105 {
106 /* Set the back pointer to point to us now */
107 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
108 }
109 else
110 {
111 /* Set the list to point to us */
112 ListHead->Flink = EntryIndex;
113 }
114
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;
118
119 /* And now the head points back to us, since we are last */
120 ListHead->Blink = EntryIndex;
121
122 /* Update the page location */
123 Pfn1->u3.e1.PageLocation = ZeroedPageList;
124
125 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
126 //MmAvailablePages++;
127
128 /* Check if we've reached the configured low memory threshold */
129 if (MmAvailablePages == MmLowMemoryThreshold)
130 {
131 /* Clear the event, because now we're ABOVE the threshold */
132 KeClearEvent(MiLowMemoryEvent);
133 }
134 else if (MmAvailablePages == MmHighMemoryThreshold)
135 {
136 /* Otherwise check if we reached the high threshold and signal the event */
137 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
138 }
139 #if 0
140 /* Get the page color */
141 Color = EntryIndex & MmSecondaryColorMask;
142
143 /* Get the first page on the color list */
144 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
145 if (ColorHead->Flink == LIST_HEAD)
146 {
147 /* The list is empty, so we are the first page */
148 Pfn1->u4.PteFrame = -1;
149 ColorHead->Flink = EntryIndex;
150 }
151 else
152 {
153 /* Get the previous page */
154 Blink = (PMMPFN)ColorHead->Blink;
155
156 /* Make it link to us */
157 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
158 Blink->OriginalPte.u.Long = EntryIndex;
159 }
160
161 /* Now initialize our own list pointers */
162 ColorHead->Blink = Pfn1;
163 Pfn1->OriginalPte.u.Long = LIST_HEAD;
164
165 /* And increase the count in the colored list */
166 ColorHead->Count++;
167 #endif
168 }
169
170 VOID
171 NTAPI
172 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
173 {
174 PFN_NUMBER OldFlink, OldBlink;
175 PMMPFNLIST ListHead;
176 MMLISTS ListName;
177
178 /* Make sure the PFN lock is held */
179 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
180
181 /* Make sure the PFN entry isn't in-use */
182 ASSERT(Entry->u3.e1.WriteInProgress == 0);
183 ASSERT(Entry->u3.e1.ReadInProgress == 0);
184
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);
190
191 /* Remove one count */
192 ASSERT(ListHead->Total != 0);
193 ListHead->Total--;
194
195 /* Get the forward and back pointers */
196 OldFlink = Entry->u1.Flink;
197 OldBlink = Entry->u2.Blink;
198
199 /* Check if the next entry is the list head */
200 if (OldFlink != LIST_HEAD)
201 {
202 /* It is not, so set the backlink of the actual entry, to our backlink */
203 MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
204 }
205 else
206 {
207 /* Set the list head's backlink instead */
208 ListHead->Blink = OldFlink;
209 }
210
211 /* Check if the back entry is the list head */
212 if (OldBlink != LIST_HEAD)
213 {
214 /* It is not, so set the backlink of the actual entry, to our backlink */
215 MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
216 }
217 else
218 {
219 /* Set the list head's backlink instead */
220 ListHead->Flink = OldFlink;
221 }
222
223 /* We are not on a list anymore */
224 Entry->u1.Flink = Entry->u2.Blink = 0;
225
226 /* FIXME: Deal with color list */
227
228 /* See if we hit any thresholds */
229 if (MmAvailablePages == MmHighMemoryThreshold)
230 {
231 /* Clear the high memory event */
232 KeClearEvent(MiHighMemoryEvent);
233 }
234 else if (MmAvailablePages == MmLowMemoryThreshold)
235 {
236 /* Signal the low memory event */
237 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
238 }
239
240 /* One less page */
241 if (--MmAvailablePages < MmMinimumFreePages)
242 {
243 /* FIXME: Should wake up the MPW and working set manager, if we had one */
244 }
245 }
246
247 PFN_NUMBER
248 NTAPI
249 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
250 IN ULONG Color)
251 {
252 PMMPFN Pfn1;
253 PMMPFNLIST ListHead;
254 MMLISTS ListName;
255 PFN_NUMBER OldFlink, OldBlink;
256 ULONG OldColor, OldCache;
257 #if 0
258 PMMCOLOR_TABLES ColorTable;
259 #endif
260 /* Make sure PFN lock is held */
261 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
262 ASSERT(Color < MmSecondaryColors);
263
264 /* Get the PFN entry */
265 Pfn1 = MiGetPfnEntry(PageIndex);
266 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
267 ASSERT(Pfn1->u3.e1.Rom == 0);
268
269 /* Capture data for later */
270 OldColor = Pfn1->u3.e1.PageColor;
271 OldCache = Pfn1->u3.e1.CacheAttribute;
272
273 /* Could be either on free or zero list */
274 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
275 ListName = ListHead->ListName;
276 ASSERT(ListName <= FreePageList);
277
278 /* Remove a page */
279 ListHead->Total--;
280
281 /* Get the forward and back pointers */
282 OldFlink = Pfn1->u1.Flink;
283 OldBlink = Pfn1->u2.Blink;
284
285 /* Check if the next entry is the list head */
286 if (OldFlink != LIST_HEAD)
287 {
288 /* It is not, so set the backlink of the actual entry, to our backlink */
289 MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
290 }
291 else
292 {
293 /* Set the list head's backlink instead */
294 ListHead->Blink = OldFlink;
295 }
296
297 /* Check if the back entry is the list head */
298 if (OldBlink != LIST_HEAD)
299 {
300 /* It is not, so set the backlink of the actual entry, to our backlink */
301 MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
302 }
303 else
304 {
305 /* Set the list head's backlink instead */
306 ListHead->Flink = OldFlink;
307 }
308
309 /* We are not on a list anymore */
310 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
311
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);
320
321 /* Set the forward link to whoever we were pointing to */
322 ColorTable->Flink = Pfn1->OriginalPte.u.Long;
323 if (ColorTable->Flink == LIST_HEAD)
324 {
325 /* This is the beginning of the list, so set the sentinel value */
326 ColorTable->Blink = LIST_HEAD;
327 }
328 else
329 {
330 /* The list is empty, so we are the first page */
331 MiGetPfnEntry(ColorTable->Flink)->u4.PteFrame = -1;
332 }
333
334 /* One more page */
335 ColorTable->Total++;
336 #endif
337 /* See if we hit any thresholds */
338 if (MmAvailablePages == MmHighMemoryThreshold)
339 {
340 /* Clear the high memory event */
341 KeClearEvent(MiHighMemoryEvent);
342 }
343 else if (MmAvailablePages == MmLowMemoryThreshold)
344 {
345 /* Signal the low memory event */
346 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
347 }
348
349 /* One less page */
350 if (--MmAvailablePages < MmMinimumFreePages)
351 {
352 /* FIXME: Should wake up the MPW and working set manager, if we had one */
353 }
354
355 /* Return the page */
356 return PageIndex;
357 }
358
359 PFN_NUMBER
360 NTAPI
361 MiRemoveAnyPage(IN ULONG Color)
362 {
363 PFN_NUMBER PageIndex;
364 PMMPFN Pfn1;
365
366 /* Make sure PFN lock is held and we have pages */
367 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
368 ASSERT(MmAvailablePages != 0);
369 ASSERT(Color < MmSecondaryColors);
370
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)
375 {
376 /* Check the colored zero list */
377 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
378 if (PageIndex == LIST_HEAD)
379 {
380 #endif
381 /* Check the free list */
382 PageIndex = MmFreePageListHead.Flink;
383 Color = PageIndex & MmSecondaryColorMask;
384 if (PageIndex == LIST_HEAD)
385 {
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)
392 {
393 /* FIXME: Should check the standby list */
394 ASSERT(MmZeroedPageListHead.Total == 0);
395 }
396 }
397 #if 0 // Enable when using ARM3 database */
398 }
399 }
400 #endif
401
402 /* Remove the page from its list */
403 PageIndex = MiRemovePageByColor(PageIndex, Color);
404
405 /* Sanity checks */
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);
411
412 /* Return the page */
413 return PageIndex;
414 }
415
416 PMMPFN
417 NTAPI
418 MiRemoveHeadList(IN PMMPFNLIST ListHead)
419 {
420 PFN_NUMBER Entry, Flink;
421 PMMPFN Pfn1;
422
423 /* Get the entry that's currently first on the list */
424 Entry = ListHead->Flink;
425 Pfn1 = MiGetPfnEntry(Entry);
426
427 /* Make the list point to the entry following the first one */
428 Flink = Pfn1->u1.Flink;
429 ListHead->Flink = Flink;
430
431 /* Check if the next entry is actually the list head */
432 if (ListHead->Flink != LIST_HEAD)
433 {
434 /* It isn't, so therefore whoever is coming next points back to the head */
435 MiGetPfnEntry(Flink)->u2.Blink = LIST_HEAD;
436 }
437 else
438 {
439 /* Then the list is empty, so the backlink should point back to us */
440 ListHead->Blink = LIST_HEAD;
441 }
442
443 /* We are not on a list anymore */
444 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
445 ListHead->Total--;
446
447 /* Return the head element */
448 return Pfn1;
449 }
450
451 VOID
452 NTAPI
453 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
454 {
455 PMMPFNLIST ListHead;
456 PFN_NUMBER LastPage;
457 PMMPFN Pfn1;
458 #if 0
459 ULONG Color;
460 PMMPFN Blink;
461 PMMCOLOR_TABLES ColorTable;
462 #endif
463 /* Make sure the page index is valid */
464 ASSERT((PageFrameIndex != 0) &&
465 (PageFrameIndex <= MmHighestPhysicalPage) &&
466 (PageFrameIndex >= MmLowestPhysicalPage));
467
468 /* Get the PFN entry */
469 Pfn1 = MiGetPfnEntry(PageFrameIndex);
470
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);
477
478 /* Get the free page list and increment its count */
479 ListHead = &MmFreePageListHead;
480 ListHead->Total++;
481
482 /* Get the last page on the list */
483 LastPage = ListHead->Blink;
484 if (LastPage != LIST_HEAD)
485 {
486 /* Link us with the previous page, so we're at the end now */
487 MiGetPfnEntry(LastPage)->u1.Flink = PageFrameIndex;
488 }
489 else
490 {
491 /* The list is empty, so we are the first page */
492 ListHead->Flink = PageFrameIndex;
493 }
494
495 /* Now make the list head point back to us (since we go at the end) */
496 ListHead->Blink = PageFrameIndex;
497
498 /* And initialize our own list pointers */
499 Pfn1->u1.Flink = LIST_HEAD;
500 Pfn1->u2.Blink = LastPage;
501
502 /* Set the list name and default priority */
503 Pfn1->u3.e1.PageLocation = FreePageList;
504 Pfn1->u4.Priority = 3;
505
506 /* Clear some status fields */
507 Pfn1->u4.InPageError = 0;
508 Pfn1->u4.AweAllocation = 0;
509
510 /* Increase available pages */
511 MmAvailablePages++;
512
513 /* Check if we've reached the configured low memory threshold */
514 if (MmAvailablePages == MmLowMemoryThreshold)
515 {
516 /* Clear the event, because now we're ABOVE the threshold */
517 KeClearEvent(MiLowMemoryEvent);
518 }
519 else if (MmAvailablePages == MmHighMemoryThreshold)
520 {
521 /* Otherwise check if we reached the high threshold and signal the event */
522 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
523 }
524
525 #if 0 // When using ARM3 PFN
526 /* Get the page color */
527 Color = PageFrameIndex & MmSecondaryColorMask;
528
529 /* Get the first page on the color list */
530 ColorTable = &MmFreePagesByColor[FreePageList][Color];
531 if (ColorTable->Flink == LIST_HEAD)
532 {
533 /* The list is empty, so we are the first page */
534 Pfn1->u4.PteFrame = -1;
535 ColorTable->Flink = PageFrameIndex;
536 }
537 else
538 {
539 /* Get the previous page */
540 Blink = (PMMPFN)ColorTable->Blink;
541
542 /* Make it link to us */
543 Pfn1->u4.PteFrame = MI_PFNENTRY_TO_PFN(Blink);
544 Blink->OriginalPte.u.Long = PageFrameIndex;
545 }
546
547 /* Now initialize our own list pointers */
548 ColorTable->Blink = Pfn1;
549 Pfn1->OriginalPte.u.Long = LIST_HEAD;
550
551 /* And increase the count in the colored list */
552 ColorTable->Count++;
553 #endif
554
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)))
558 {
559 /* This is ReactOS-specific */
560 KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
561 }
562 }
563
564 /* EOF */