42b090da5572345a99d9c4a791ea31c5e2d2154d
[reactos.git] / reactos / 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 #define ASSERT_LIST_INVARIANT(x) \
20 do { \
21 ASSERT(((x)->Total == 0 && \
22 (x)->Flink == LIST_HEAD && \
23 (x)->Blink == LIST_HEAD) || \
24 ((x)->Total != 0 && \
25 (x)->Flink != LIST_HEAD && \
26 (x)->Blink != LIST_HEAD)); \
27 } while (0)
28
29 /* GLOBALS ********************************************************************/
30
31 BOOLEAN MmDynamicPfn;
32 BOOLEAN MmMirroring;
33
34 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
35 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
36 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
37 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD};
38 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD};
39 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD};
40 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
41
42 PMMPFNLIST MmPageLocationList[] =
43 {
44 &MmZeroedPageListHead,
45 &MmFreePageListHead,
46 &MmStandbyPageListHead,
47 &MmModifiedPageListHead,
48 &MmModifiedNoWritePageListHead,
49 &MmBadPageListHead,
50 NULL,
51 NULL
52 };
53 /* FUNCTIONS ******************************************************************/
54
55 VOID
56 NTAPI
57 MiInsertInListTail(IN PMMPFNLIST ListHead,
58 IN PMMPFN Entry)
59 {
60 PFN_NUMBER OldBlink, EntryIndex = MiGetPfnEntryIndex(Entry);
61
62 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
63 ASSERT_LIST_INVARIANT(ListHead);
64
65 /* Get the back link */
66 OldBlink = ListHead->Blink;
67 if (OldBlink != LIST_HEAD)
68 {
69 /* Set the back pointer to point to us now */
70 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
71 }
72 else
73 {
74 /* Set the list to point to us */
75 ListHead->Flink = EntryIndex;
76 }
77
78 /* Set the entry to point to the list head forwards, and the old page backwards */
79 Entry->u1.Flink = LIST_HEAD;
80 Entry->u2.Blink = OldBlink;
81
82 /* And now the head points back to us, since we are last */
83 ListHead->Blink = EntryIndex;
84 ListHead->Total++;
85 ASSERT_LIST_INVARIANT(ListHead);
86 }
87
88 VOID
89 NTAPI
90 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex)
91 {
92 PFN_NUMBER OldBlink;
93 PMMPFNLIST ListHead;
94 PMMPFN Pfn1;
95 #if 0
96 PMMPFN Blink;
97 ULONG Color;
98 PMMCOLOR_TABLES ColorHead;
99 #endif
100
101 /* Make sure the PFN lock is held */
102 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
103
104 /* Get the descriptor */
105 Pfn1 = MiGetPfnEntry(EntryIndex);
106 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
107 ASSERT(Pfn1->u4.MustBeCached == 0);
108 ASSERT(Pfn1->u3.e1.Rom == 0);
109 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
110 ASSERT(Pfn1->u4.InPageError == 0);
111
112 /* Use the zero list */
113 ListHead = &MmZeroedPageListHead;
114 ASSERT_LIST_INVARIANT(ListHead);
115 ListHead->Total++;
116
117 /* Get the back link */
118 OldBlink = ListHead->Blink;
119 if (OldBlink != LIST_HEAD)
120 {
121 /* Set the back pointer to point to us now */
122 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
123 }
124 else
125 {
126 /* Set the list to point to us */
127 ListHead->Flink = EntryIndex;
128 }
129
130 /* Set the entry to point to the list head forwards, and the old page backwards */
131 Pfn1->u1.Flink = LIST_HEAD;
132 Pfn1->u2.Blink = OldBlink;
133
134 /* And now the head points back to us, since we are last */
135 ListHead->Blink = EntryIndex;
136
137 /* Update the page location */
138 Pfn1->u3.e1.PageLocation = ZeroedPageList;
139
140 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
141 //MmAvailablePages++;
142
143 /* Check if we've reached the configured low memory threshold */
144 if (MmAvailablePages == MmLowMemoryThreshold)
145 {
146 /* Clear the event, because now we're ABOVE the threshold */
147 KeClearEvent(MiLowMemoryEvent);
148 }
149 else if (MmAvailablePages == MmHighMemoryThreshold)
150 {
151 /* Otherwise check if we reached the high threshold and signal the event */
152 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
153 }
154
155 ASSERT_LIST_INVARIANT(ListHead);
156
157 #if 0
158 /* Get the page color */
159 Color = EntryIndex & MmSecondaryColorMask;
160
161 /* Get the first page on the color list */
162 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
163 if (ColorHead->Flink == LIST_HEAD)
164 {
165 /* The list is empty, so we are the first page */
166 Pfn1->u4.PteFrame = -1;
167 ColorHead->Flink = EntryIndex;
168 }
169 else
170 {
171 /* Get the previous page */
172 Blink = (PMMPFN)ColorHead->Blink;
173
174 /* Make it link to us */
175 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
176 Blink->OriginalPte.u.Long = EntryIndex;
177 }
178
179 /* Now initialize our own list pointers */
180 ColorHead->Blink = Pfn1;
181 Pfn1->OriginalPte.u.Long = LIST_HEAD;
182
183 /* And increase the count in the colored list */
184 ColorHead->Count++;
185 #endif
186 }
187
188 VOID
189 NTAPI
190 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
191 {
192 PFN_NUMBER OldFlink, OldBlink;
193 PMMPFNLIST ListHead;
194 MMLISTS ListName;
195
196 /* Make sure the PFN lock is held */
197 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
198
199 /* Make sure the PFN entry isn't in-use */
200 ASSERT(Entry->u3.e1.WriteInProgress == 0);
201 ASSERT(Entry->u3.e1.ReadInProgress == 0);
202
203 /* Find the list for this entry, make sure it's the free or zero list */
204 ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
205 ListName = ListHead->ListName;
206 ASSERT(ListHead != NULL);
207 ASSERT(ListName <= FreePageList);
208 ASSERT_LIST_INVARIANT(ListHead);
209
210 /* Remove one count */
211 ASSERT(ListHead->Total != 0);
212 ListHead->Total--;
213
214 /* Get the forward and back pointers */
215 OldFlink = Entry->u1.Flink;
216 OldBlink = Entry->u2.Blink;
217
218 /* Check if the next entry is the list head */
219 if (OldFlink != LIST_HEAD)
220 {
221 /* It is not, so set the backlink of the actual entry, to our backlink */
222 MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
223 }
224 else
225 {
226 /* Set the list head's backlink instead */
227 ListHead->Blink = OldBlink;
228 }
229
230 /* Check if the back entry is the list head */
231 if (OldBlink != LIST_HEAD)
232 {
233 /* It is not, so set the backlink of the actual entry, to our backlink */
234 MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
235 }
236 else
237 {
238 /* Set the list head's backlink instead */
239 ListHead->Flink = OldFlink;
240 }
241
242 /* We are not on a list anymore */
243 Entry->u1.Flink = Entry->u2.Blink = 0;
244 ASSERT_LIST_INVARIANT(ListHead);
245
246 /* FIXME: Deal with color list */
247
248 /* See if we hit any thresholds */
249 if (MmAvailablePages == MmHighMemoryThreshold)
250 {
251 /* Clear the high memory event */
252 KeClearEvent(MiHighMemoryEvent);
253 }
254 else if (MmAvailablePages == MmLowMemoryThreshold)
255 {
256 /* Signal the low memory event */
257 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
258 }
259
260 /* One less page */
261 if (--MmAvailablePages < MmMinimumFreePages)
262 {
263 /* FIXME: Should wake up the MPW and working set manager, if we had one */
264 }
265 }
266
267 PFN_NUMBER
268 NTAPI
269 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
270 IN ULONG Color)
271 {
272 PMMPFN Pfn1;
273 PMMPFNLIST ListHead;
274 MMLISTS ListName;
275 PFN_NUMBER OldFlink, OldBlink;
276 ULONG OldColor, OldCache;
277 #if 0
278 PMMCOLOR_TABLES ColorTable;
279 #endif
280 /* Make sure PFN lock is held */
281 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
282 ASSERT(Color < MmSecondaryColors);
283
284 /* Get the PFN entry */
285 Pfn1 = MiGetPfnEntry(PageIndex);
286 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
287 ASSERT(Pfn1->u3.e1.Rom == 0);
288
289 /* Capture data for later */
290 OldColor = Pfn1->u3.e1.PageColor;
291 OldCache = Pfn1->u3.e1.CacheAttribute;
292
293 /* Could be either on free or zero list */
294 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
295 ASSERT_LIST_INVARIANT(ListHead);
296 ListName = ListHead->ListName;
297 ASSERT(ListName <= FreePageList);
298
299 /* Remove a page */
300 ListHead->Total--;
301
302 /* Get the forward and back pointers */
303 OldFlink = Pfn1->u1.Flink;
304 OldBlink = Pfn1->u2.Blink;
305
306 /* Check if the next entry is the list head */
307 if (OldFlink != LIST_HEAD)
308 {
309 /* It is not, so set the backlink of the actual entry, to our backlink */
310 MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
311 }
312 else
313 {
314 /* Set the list head's backlink instead */
315 ListHead->Blink = OldFlink;
316 }
317
318 /* Check if the back entry is the list head */
319 if (OldBlink != LIST_HEAD)
320 {
321 /* It is not, so set the backlink of the actual entry, to our backlink */
322 MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
323 }
324 else
325 {
326 /* Set the list head's backlink instead */
327 ListHead->Flink = OldFlink;
328 }
329
330 /* We are not on a list anymore */
331 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
332
333 /* Zero flags but restore color and cache */
334 Pfn1->u3.e2.ShortFlags = 0;
335 Pfn1->u3.e1.PageColor = OldColor;
336 Pfn1->u3.e1.CacheAttribute = OldCache;
337
338 ASSERT_LIST_INVARIANT(ListHead);
339
340 #if 0 // When switching to ARM3
341 /* Get the first page on the color list */
342 ColorTable = &MmFreePagesByColor[ListName][Color];
343 ASSERT(ColorTable->Count >= 1);
344
345 /* Set the forward link to whoever we were pointing to */
346 ColorTable->Flink = Pfn1->OriginalPte.u.Long;
347 if (ColorTable->Flink == LIST_HEAD)
348 {
349 /* This is the beginning of the list, so set the sentinel value */
350 ColorTable->Blink = LIST_HEAD;
351 }
352 else
353 {
354 /* The list is empty, so we are the first page */
355 MiGetPfnEntry(ColorTable->Flink)->u4.PteFrame = -1;
356 }
357
358 /* One more page */
359 ColorTable->Total++;
360 #endif
361 /* See if we hit any thresholds */
362 if (MmAvailablePages == MmHighMemoryThreshold)
363 {
364 /* Clear the high memory event */
365 KeClearEvent(MiHighMemoryEvent);
366 }
367 else if (MmAvailablePages == MmLowMemoryThreshold)
368 {
369 /* Signal the low memory event */
370 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
371 }
372
373 /* One less page */
374 if (--MmAvailablePages < MmMinimumFreePages)
375 {
376 /* FIXME: Should wake up the MPW and working set manager, if we had one */
377 }
378
379 /* Return the page */
380 return PageIndex;
381 }
382
383 PFN_NUMBER
384 NTAPI
385 MiRemoveAnyPage(IN ULONG Color)
386 {
387 PFN_NUMBER PageIndex;
388 PMMPFN Pfn1;
389
390 /* Make sure PFN lock is held and we have pages */
391 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
392 ASSERT(MmAvailablePages != 0);
393 ASSERT(Color < MmSecondaryColors);
394
395 /* Check the colored free list */
396 #if 0 // Enable when using ARM3 database */
397 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
398 if (PageIndex == LIST_HEAD)
399 {
400 /* Check the colored zero list */
401 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
402 if (PageIndex == LIST_HEAD)
403 {
404 #endif
405 /* Check the free list */
406 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
407 PageIndex = MmFreePageListHead.Flink;
408 Color = PageIndex & MmSecondaryColorMask;
409 if (PageIndex == LIST_HEAD)
410 {
411 /* Check the zero list */
412 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
413 PageIndex = MmZeroedPageListHead.Flink;
414 Color = PageIndex & MmSecondaryColorMask;
415 ASSERT(PageIndex != LIST_HEAD);
416 if (PageIndex == LIST_HEAD)
417 {
418 /* FIXME: Should check the standby list */
419 ASSERT(MmZeroedPageListHead.Total == 0);
420 }
421 }
422 #if 0 // Enable when using ARM3 database */
423 }
424 }
425 #endif
426
427 /* Remove the page from its list */
428 PageIndex = MiRemovePageByColor(PageIndex, Color);
429
430 /* Sanity checks */
431 Pfn1 = MiGetPfnEntry(PageIndex);
432 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
433 (Pfn1->u3.e1.PageLocation == ZeroedPageList));
434 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
435 ASSERT(Pfn1->u2.ShareCount == 0);
436
437 /* Return the page */
438 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
439 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
440
441 return PageIndex;
442 }
443
444 PMMPFN
445 NTAPI
446 MiRemoveHeadList(IN PMMPFNLIST ListHead)
447 {
448 PFN_NUMBER Entry, Flink;
449 PMMPFN Pfn1;
450
451 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
452 ASSERT_LIST_INVARIANT(ListHead);
453
454 /* Get the entry that's currently first on the list */
455 Entry = ListHead->Flink;
456 Pfn1 = MiGetPfnEntry(Entry);
457
458 /* Make the list point to the entry following the first one */
459 Flink = Pfn1->u1.Flink;
460 ListHead->Flink = Flink;
461
462 /* Check if the next entry is actually the list head */
463 if (ListHead->Flink != LIST_HEAD)
464 {
465 /* It isn't, so therefore whoever is coming next points back to the head */
466 MiGetPfnEntry(Flink)->u2.Blink = LIST_HEAD;
467 }
468 else
469 {
470 /* Then the list is empty, so the backlink should point back to us */
471 ListHead->Blink = LIST_HEAD;
472 }
473
474 /* We are not on a list anymore */
475 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
476 ListHead->Total--;
477
478 ASSERT_LIST_INVARIANT(ListHead);
479
480 /* Return the head element */
481 return Pfn1;
482 }
483
484 VOID
485 NTAPI
486 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
487 {
488 PMMPFNLIST ListHead;
489 PFN_NUMBER LastPage;
490 PMMPFN Pfn1;
491 #if 0
492 ULONG Color;
493 PMMPFN Blink;
494 PMMCOLOR_TABLES ColorTable;
495 #endif
496 /* Make sure the page index is valid */
497 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
498 ASSERT((PageFrameIndex != 0) &&
499 (PageFrameIndex <= MmHighestPhysicalPage) &&
500 (PageFrameIndex >= MmLowestPhysicalPage));
501
502 /* Get the PFN entry */
503 Pfn1 = MiGetPfnEntry(PageFrameIndex);
504
505 /* Sanity checks that a right kind of page is being inserted here */
506 ASSERT(Pfn1->u4.MustBeCached == 0);
507 ASSERT(Pfn1->u3.e1.Rom != 1);
508 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
509 ASSERT(Pfn1->u4.VerifierAllocation == 0);
510 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
511
512 /* Get the free page list and increment its count */
513 ListHead = &MmFreePageListHead;
514 ASSERT_LIST_INVARIANT(ListHead);
515 ListHead->Total++;
516
517 /* Get the last page on the list */
518 LastPage = ListHead->Blink;
519 if (LastPage != LIST_HEAD)
520 {
521 /* Link us with the previous page, so we're at the end now */
522 MiGetPfnEntry(LastPage)->u1.Flink = PageFrameIndex;
523 }
524 else
525 {
526 /* The list is empty, so we are the first page */
527 ListHead->Flink = PageFrameIndex;
528 }
529
530 /* Now make the list head point back to us (since we go at the end) */
531 ListHead->Blink = PageFrameIndex;
532
533 /* And initialize our own list pointers */
534 Pfn1->u1.Flink = LIST_HEAD;
535 Pfn1->u2.Blink = LastPage;
536
537 /* Set the list name and default priority */
538 Pfn1->u3.e1.PageLocation = FreePageList;
539 Pfn1->u4.Priority = 3;
540
541 /* Clear some status fields */
542 Pfn1->u4.InPageError = 0;
543 Pfn1->u4.AweAllocation = 0;
544
545 /* Increase available pages */
546 MmAvailablePages++;
547
548 /* Check if we've reached the configured low memory threshold */
549 if (MmAvailablePages == MmLowMemoryThreshold)
550 {
551 /* Clear the event, because now we're ABOVE the threshold */
552 KeClearEvent(MiLowMemoryEvent);
553 }
554 else if (MmAvailablePages == MmHighMemoryThreshold)
555 {
556 /* Otherwise check if we reached the high threshold and signal the event */
557 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
558 }
559
560 ASSERT_LIST_INVARIANT(ListHead);
561
562 #if 0 // When using ARM3 PFN
563 /* Get the page color */
564 Color = PageFrameIndex & MmSecondaryColorMask;
565
566 /* Get the first page on the color list */
567 ColorTable = &MmFreePagesByColor[FreePageList][Color];
568 if (ColorTable->Flink == LIST_HEAD)
569 {
570 /* The list is empty, so we are the first page */
571 Pfn1->u4.PteFrame = -1;
572 ColorTable->Flink = PageFrameIndex;
573 }
574 else
575 {
576 /* Get the previous page */
577 Blink = (PMMPFN)ColorTable->Blink;
578
579 /* Make it link to us */
580 Pfn1->u4.PteFrame = MI_PFNENTRY_TO_PFN(Blink);
581 Blink->OriginalPte.u.Long = PageFrameIndex;
582 }
583
584 /* Now initialize our own list pointers */
585 ColorTable->Blink = Pfn1;
586 Pfn1->OriginalPte.u.Long = LIST_HEAD;
587
588 /* And increase the count in the colored list */
589 ColorTable->Count++;
590 #endif
591
592 /* Notify zero page thread if enough pages are on the free list now */
593 extern KEVENT ZeroPageThreadEvent;
594 if ((MmFreePageListHead.Total > 8) && !(KeReadStateEvent(&ZeroPageThreadEvent)))
595 {
596 /* This is ReactOS-specific */
597 KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
598 }
599 }
600
601 VOID
602 NTAPI
603 MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
604 IN PMMPTE PointerPte,
605 IN BOOLEAN Modified)
606 {
607 PMMPFN Pfn1;
608 NTSTATUS Status;
609 PMMPTE PointerPtePte;
610 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
611
612 /* Setup the PTE */
613 Pfn1 = MiGetPfnEntry(PageFrameIndex);
614 Pfn1->PteAddress = PointerPte;
615
616 /* Check if this PFN is part of a valid address space */
617 if (PointerPte->u.Hard.Valid == 1)
618 {
619 /* FIXME: TODO */
620 ASSERT(FALSE);
621 }
622
623 /* Otherwise this is a fresh page -- set it up */
624 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
625 Pfn1->u3.e2.ReferenceCount = 1;
626 Pfn1->u2.ShareCount = 1;
627 Pfn1->u3.e1.PageLocation = ActiveAndValid;
628 ASSERT(Pfn1->u3.e1.Rom == 0);
629 Pfn1->u3.e1.Modified = Modified;
630
631 /* Get the page table for the PTE */
632 PointerPtePte = MiAddressToPte(PointerPte);
633 if (PointerPtePte->u.Hard.Valid == 0)
634 {
635 /* Make sure the PDE gets paged in properly */
636 Status = MiCheckPdeForPagedPool(PointerPte);
637 if (!NT_SUCCESS(Status))
638 {
639 /* Crash */
640 KeBugCheckEx(MEMORY_MANAGEMENT,
641 0x61940,
642 (ULONG_PTR)PointerPte,
643 (ULONG_PTR)PointerPtePte->u.Long,
644 (ULONG_PTR)MiPteToAddress(PointerPte));
645 }
646 }
647
648 /* Get the PFN for the page table */
649 PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
650 ASSERT(PageFrameIndex != 0);
651 Pfn1->u4.PteFrame = PageFrameIndex;
652
653 /* Increase its share count so we don't get rid of it */
654 Pfn1 = MiGetPfnEntry(PageFrameIndex);
655 Pfn1->u2.ShareCount++;
656 }
657
658 PFN_NUMBER
659 NTAPI
660 MiAllocatePfn(IN PMMPTE PointerPte,
661 IN ULONG Protection)
662 {
663 KIRQL OldIrql;
664 PFN_NUMBER PageFrameIndex;
665 MMPTE TempPte;
666
667 /* Make an empty software PTE */
668 MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
669
670 /* Lock the PFN database */
671 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
672
673 /* Check if we're running low on pages */
674 if (MmAvailablePages < 128)
675 {
676 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages);
677 //MiEnsureAvailablePageOrWait(NULL, OldIrql);
678 }
679
680 /* Grab a page */
681 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
682 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
683 PageFrameIndex = MiRemoveAnyPage(0);
684
685 /* Write the software PTE */
686 ASSERT(PointerPte->u.Hard.Valid == 0);
687 *PointerPte = TempPte;
688 PointerPte->u.Soft.Protection |= Protection;
689
690 /* Initialize its PFN entry */
691 MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
692
693 /* Release the PFN lock and return the page */
694 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
695 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
696 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
697 return PageFrameIndex;
698 }
699
700 VOID
701 NTAPI
702 MiDecrementShareCount(IN PMMPFN Pfn1,
703 IN PFN_NUMBER PageFrameIndex)
704 {
705 ASSERT(PageFrameIndex > 0);
706 ASSERT(MiGetPfnEntry(PageFrameIndex) != NULL);
707 ASSERT(Pfn1 == MiGetPfnEntry(PageFrameIndex));
708
709 /* Page must be in-use */
710 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
711 (Pfn1->u3.e1.PageLocation != StandbyPageList))
712 {
713 /* Otherwise we have PFN corruption */
714 KeBugCheckEx(PFN_LIST_CORRUPT,
715 0x99,
716 PageFrameIndex,
717 Pfn1->u3.e1.PageLocation,
718 0);
719 }
720
721 /* Check if the share count is now 0 */
722 ASSERT(Pfn1->u2.ShareCount < 0xF000000);
723 if (!--Pfn1->u2.ShareCount)
724 {
725 /* ReactOS does not handle these */
726 ASSERT(Pfn1->u3.e1.PrototypePte == 0);
727
728 /* Put the page in transition */
729 Pfn1->u3.e1.PageLocation = TransitionPage;
730
731 /* PFN lock must be held */
732 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
733
734 /* Page should at least have one reference */
735 ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
736 if (Pfn1->u3.e2.ReferenceCount == 1)
737 {
738 /* In ReactOS, this path should always be hit with a deleted PFN */
739 ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
740
741 /* Clear the last reference */
742 Pfn1->u3.e2.ReferenceCount = 0;
743
744 /*
745 * OriginalPte is used by AweReferenceCount in ReactOS, but either
746 * ways we shouldn't be seeing RMAP entries at this point
747 */
748 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
749 ASSERT(Pfn1->OriginalPte.u.Long == 0);
750
751 /* Mark the page temporarily as valid, we're going to make it free soon */
752 Pfn1->u3.e1.PageLocation = ActiveAndValid;
753
754 /* Bring it back into the free list */
755 MiInsertPageInFreeList(PageFrameIndex);
756 }
757 else
758 {
759 /* Otherwise, just drop the reference count */
760 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
761 }
762 }
763 }
764
765 /* EOF */