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