6977f0e7fc80f97be4d9b5860d57df3ba5b36c0b
[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 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17
18 #if DBG
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 #else
29 #define ASSERT_LIST_INVARIANT(x)
30 #endif
31
32 /* GLOBALS ********************************************************************/
33
34 BOOLEAN MmDynamicPfn;
35 BOOLEAN MmMirroring;
36 ULONG MmSystemPageColor;
37
38 ULONG MmTransitionSharedPages;
39 ULONG MmTotalPagesForPagingFile;
40
41 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
42 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
43 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
44 MMPFNLIST MmStandbyPageListByPriority[8];
45 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD};
46 MMPFNLIST MmModifiedPageListByColor[1] = {{0, ModifiedPageList, LIST_HEAD, LIST_HEAD}};
47 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD};
48 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD};
49 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
50
51 PMMPFNLIST MmPageLocationList[] =
52 {
53 &MmZeroedPageListHead,
54 &MmFreePageListHead,
55 &MmStandbyPageListHead,
56 &MmModifiedPageListHead,
57 &MmModifiedNoWritePageListHead,
58 &MmBadPageListHead,
59 NULL,
60 NULL
61 };
62
63 ULONG MI_PFN_CURRENT_USAGE;
64 CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet";
65
66 /* FUNCTIONS ******************************************************************/
67
68 static
69 VOID
70 MiIncrementAvailablePages(
71 VOID)
72 {
73 /* Increment available pages */
74 MmAvailablePages++;
75
76 /* Check if we've reached the configured low memory threshold */
77 if (MmAvailablePages == MmLowMemoryThreshold)
78 {
79 /* Clear the event, because now we're ABOVE the threshold */
80 KeClearEvent(MiLowMemoryEvent);
81 }
82 else if (MmAvailablePages == MmHighMemoryThreshold)
83 {
84 /* Otherwise check if we reached the high threshold and signal the event */
85 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
86 }
87 }
88
89 static
90 VOID
91 MiDecrementAvailablePages(
92 VOID)
93 {
94 ASSERT(MmAvailablePages > 0);
95
96 /* See if we hit any thresholds */
97 if (MmAvailablePages == MmHighMemoryThreshold)
98 {
99 /* Clear the high memory event */
100 KeClearEvent(MiHighMemoryEvent);
101 }
102 else if (MmAvailablePages == MmLowMemoryThreshold)
103 {
104 /* Signal the low memory event */
105 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
106 }
107
108 /* One less page */
109 MmAvailablePages--;
110 if (MmAvailablePages < MmMinimumFreePages)
111 {
112 /* FIXME: Should wake up the MPW and working set manager, if we had one */
113
114 DPRINT1("Running low on pages: %lu remaining\n", MmAvailablePages);
115
116 /* Call RosMm and see if it can release any pages for us */
117 MmRebalanceMemoryConsumers();
118 }
119 }
120
121 VOID
122 NTAPI
123 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
124 {
125 KIRQL OldIrql;
126 PVOID VirtualAddress;
127 PEPROCESS Process = PsGetCurrentProcess();
128
129 /* Map in hyperspace, then wipe it using XMMI or MEMSET */
130 VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql);
131 ASSERT(VirtualAddress);
132 KeZeroPages(VirtualAddress, PAGE_SIZE);
133 MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql);
134 }
135
136 VOID
137 NTAPI
138 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
139 {
140 PFN_NUMBER OldFlink, OldBlink;
141 PMMPFNLIST ListHead;
142 MMLISTS ListName;
143 ULONG Color;
144 PMMCOLOR_TABLES ColorTable;
145 PMMPFN Pfn1;
146
147 /* Make sure the PFN lock is held */
148 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
149
150 /* Make sure the PFN entry isn't in-use */
151 ASSERT(Entry->u3.e1.WriteInProgress == 0);
152 ASSERT(Entry->u3.e1.ReadInProgress == 0);
153
154 /* Find the list for this entry, make sure it's the free or zero list */
155 ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
156 ListName = ListHead->ListName;
157 ASSERT(ListHead != NULL);
158 ASSERT(ListName <= FreePageList);
159 ASSERT_LIST_INVARIANT(ListHead);
160
161 /* Remove one count */
162 ASSERT(ListHead->Total != 0);
163 ListHead->Total--;
164
165 /* Get the forward and back pointers */
166 OldFlink = Entry->u1.Flink;
167 OldBlink = Entry->u2.Blink;
168
169 /* Check if the next entry is the list head */
170 if (OldFlink != LIST_HEAD)
171 {
172 /* It is not, so set the backlink of the actual entry, to our backlink */
173 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
174 }
175 else
176 {
177 /* Set the list head's backlink instead */
178 ListHead->Blink = OldBlink;
179 }
180
181 /* Check if the back entry is the list head */
182 if (OldBlink != LIST_HEAD)
183 {
184 /* It is not, so set the backlink of the actual entry, to our backlink */
185 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
186 }
187 else
188 {
189 /* Set the list head's backlink instead */
190 ListHead->Flink = OldFlink;
191 }
192
193 /* Get the page color */
194 OldBlink = MiGetPfnEntryIndex(Entry);
195 Color = OldBlink & MmSecondaryColorMask;
196
197 /* Get the first page on the color list */
198 ColorTable = &MmFreePagesByColor[ListName][Color];
199
200 /* Check if this was was actually the head */
201 OldFlink = ColorTable->Flink;
202 if (OldFlink == OldBlink)
203 {
204 /* Make the table point to the next page this page was linking to */
205 ColorTable->Flink = Entry->OriginalPte.u.Long;
206 if (ColorTable->Flink != LIST_HEAD)
207 {
208 /* And make the previous link point to the head now */
209 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
210 }
211 else
212 {
213 /* And if that page was the head, loop the list back around */
214 ColorTable->Blink = (PVOID)LIST_HEAD;
215 }
216 }
217 else
218 {
219 /* This page shouldn't be pointing back to the head */
220 ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD);
221
222 /* Make the back link point to whoever the next page is */
223 Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame);
224 Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long;
225
226 /* Check if this page was pointing to the head */
227 if (Entry->OriginalPte.u.Long != LIST_HEAD)
228 {
229 /* Make the back link point to the head */
230 Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long);
231 Pfn1->u4.PteFrame = Entry->u4.PteFrame;
232 }
233 else
234 {
235 /* Then the table is directly back pointing to this page now */
236 ColorTable->Blink = Pfn1;
237 }
238 }
239
240 /* One less colored page */
241 ASSERT(ColorTable->Count >= 1);
242 ColorTable->Count--;
243
244 /* ReactOS Hack */
245 Entry->OriginalPte.u.Long = 0;
246
247 /* We are not on a list anymore */
248 Entry->u1.Flink = Entry->u2.Blink = 0;
249 ASSERT_LIST_INVARIANT(ListHead);
250
251 /* Decrement number of available pages */
252 MiDecrementAvailablePages();
253
254 #if MI_TRACE_PFNS
255 ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
256 Entry->PfnUsage = MI_PFN_CURRENT_USAGE;
257 memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
258 // MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
259 // memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
260 #endif
261 }
262
263 VOID
264 NTAPI
265 MiUnlinkPageFromList(IN PMMPFN Pfn)
266 {
267 PMMPFNLIST ListHead;
268 PFN_NUMBER OldFlink, OldBlink;
269
270 /* Make sure the PFN lock is held */
271 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
272
273 /* ARM3 should only call this for dead pages */
274 ASSERT(Pfn->u3.e2.ReferenceCount == 0);
275
276 /* Transition pages are supposed to be standby/modified/nowrite */
277 ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation];
278 ASSERT(ListHead->ListName >= StandbyPageList);
279
280 /* Check if this was standby, or modified */
281 if (ListHead == &MmStandbyPageListHead)
282 {
283 /* Should not be a ROM page */
284 ASSERT(Pfn->u3.e1.Rom == 0);
285
286 /* Get the exact list */
287 ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority];
288
289 /* Decrement number of available pages */
290 MiDecrementAvailablePages();
291
292 /* Decrease transition page counter */
293 ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
294 MmTransitionSharedPages--;
295 }
296 else if (ListHead == &MmModifiedPageListHead)
297 {
298 /* Only shared memory (page-file backed) modified pages are supported */
299 ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0);
300
301 /* Decrement the counters */
302 ListHead->Total--;
303 MmTotalPagesForPagingFile--;
304
305 /* Pick the correct colored list */
306 ListHead = &MmModifiedPageListByColor[0];
307
308 /* Decrease transition page counter */
309 MmTransitionSharedPages--;
310 }
311 else if (ListHead == &MmModifiedNoWritePageListHead)
312 {
313 /* List not yet supported */
314 ASSERT(FALSE);
315 }
316
317 /* Nothing should be in progress and the list should not be empty */
318 ASSERT(Pfn->u3.e1.WriteInProgress == 0);
319 ASSERT(Pfn->u3.e1.ReadInProgress == 0);
320 ASSERT(ListHead->Total != 0);
321
322 /* Get the forward and back pointers */
323 OldFlink = Pfn->u1.Flink;
324 OldBlink = Pfn->u2.Blink;
325
326 /* Check if the next entry is the list head */
327 if (OldFlink != LIST_HEAD)
328 {
329 /* It is not, so set the backlink of the actual entry, to our backlink */
330 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
331 }
332 else
333 {
334 /* Set the list head's backlink instead */
335 ListHead->Blink = OldBlink;
336 }
337
338 /* Check if the back entry is the list head */
339 if (OldBlink != LIST_HEAD)
340 {
341 /* It is not, so set the backlink of the actual entry, to our backlink */
342 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
343 }
344 else
345 {
346 /* Set the list head's backlink instead */
347 ListHead->Flink = OldFlink;
348 }
349
350 /* ReactOS Hack */
351 Pfn->OriginalPte.u.Long = 0;
352
353 /* We are not on a list anymore */
354 Pfn->u1.Flink = Pfn->u2.Blink = 0;
355
356 /* Remove one entry from the list */
357 ListHead->Total--;
358
359 ASSERT_LIST_INVARIANT(ListHead);
360 }
361
362 PFN_NUMBER
363 NTAPI
364 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
365 IN ULONG Color)
366 {
367 PMMPFN Pfn1;
368 PMMPFNLIST ListHead;
369 MMLISTS ListName;
370 PFN_NUMBER OldFlink, OldBlink;
371 USHORT OldColor, OldCache;
372 PMMCOLOR_TABLES ColorTable;
373
374 /* Make sure PFN lock is held */
375 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
376 ASSERT(Color < MmSecondaryColors);
377
378 /* Get the PFN entry */
379 Pfn1 = MI_PFN_ELEMENT(PageIndex);
380 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
381 ASSERT(Pfn1->u3.e1.Rom == 0);
382
383 /* Capture data for later */
384 OldColor = Pfn1->u3.e1.PageColor;
385 OldCache = Pfn1->u3.e1.CacheAttribute;
386
387 /* Could be either on free or zero list */
388 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
389 ASSERT_LIST_INVARIANT(ListHead);
390 ListName = ListHead->ListName;
391 ASSERT(ListName <= FreePageList);
392
393 /* Remove a page */
394 ListHead->Total--;
395
396 /* Get the forward and back pointers */
397 OldFlink = Pfn1->u1.Flink;
398 OldBlink = Pfn1->u2.Blink;
399
400 /* Check if the next entry is the list head */
401 if (OldFlink != LIST_HEAD)
402 {
403 /* It is not, so set the backlink of the actual entry, to our backlink */
404 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
405 }
406 else
407 {
408 /* Set the list head's backlink instead */
409 ListHead->Blink = OldBlink;
410 }
411
412 /* Check if the back entry is the list head */
413 if (OldBlink != LIST_HEAD)
414 {
415 /* It is not, so set the backlink of the actual entry, to our backlink */
416 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
417 }
418 else
419 {
420 /* Set the list head's backlink instead */
421 ListHead->Flink = OldFlink;
422 }
423
424 /* We are not on a list anymore */
425 ASSERT_LIST_INVARIANT(ListHead);
426 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
427
428 /* Zero flags but restore color and cache */
429 Pfn1->u3.e2.ShortFlags = 0;
430 Pfn1->u3.e1.PageColor = OldColor;
431 Pfn1->u3.e1.CacheAttribute = OldCache;
432
433 /* Get the first page on the color list */
434 ASSERT(Color < MmSecondaryColors);
435 ColorTable = &MmFreePagesByColor[ListName][Color];
436 ASSERT(ColorTable->Count >= 1);
437
438 /* Set the forward link to whoever we were pointing to */
439 ColorTable->Flink = Pfn1->OriginalPte.u.Long;
440
441 /* Get the first page on the color list */
442 if (ColorTable->Flink == LIST_HEAD)
443 {
444 /* This is the beginning of the list, so set the sentinel value */
445 ColorTable->Blink = (PVOID)LIST_HEAD;
446 }
447 else
448 {
449 /* The list is empty, so we are the first page */
450 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
451 }
452
453 /* One less page */
454 ColorTable->Count--;
455
456 /* ReactOS Hack */
457 Pfn1->OriginalPte.u.Long = 0;
458
459 /* Decrement number of available pages */
460 MiDecrementAvailablePages();
461
462 #if MI_TRACE_PFNS
463 //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
464 Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
465 memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
466 //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
467 //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
468 #endif
469
470 /* Return the page */
471 return PageIndex;
472 }
473
474 PFN_NUMBER
475 NTAPI
476 MiRemoveAnyPage(IN ULONG Color)
477 {
478 PFN_NUMBER PageIndex;
479 PMMPFN Pfn1;
480
481 /* Make sure PFN lock is held and we have pages */
482 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
483 ASSERT(MmAvailablePages != 0);
484 ASSERT(Color < MmSecondaryColors);
485
486 /* Check the colored free list */
487 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
488 if (PageIndex == LIST_HEAD)
489 {
490 /* Check the colored zero list */
491 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
492 if (PageIndex == LIST_HEAD)
493 {
494 /* Check the free list */
495 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
496 PageIndex = MmFreePageListHead.Flink;
497 Color = PageIndex & MmSecondaryColorMask;
498 if (PageIndex == LIST_HEAD)
499 {
500 /* Check the zero list */
501 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
502 PageIndex = MmZeroedPageListHead.Flink;
503 Color = PageIndex & MmSecondaryColorMask;
504 ASSERT(PageIndex != LIST_HEAD);
505 if (PageIndex == LIST_HEAD)
506 {
507 /* FIXME: Should check the standby list */
508 ASSERT(MmZeroedPageListHead.Total == 0);
509 }
510 }
511 }
512 }
513
514 /* Remove the page from its list */
515 PageIndex = MiRemovePageByColor(PageIndex, Color);
516
517 /* Sanity checks */
518 Pfn1 = MI_PFN_ELEMENT(PageIndex);
519 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
520 (Pfn1->u3.e1.PageLocation == ZeroedPageList));
521 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
522 ASSERT(Pfn1->u2.ShareCount == 0);
523 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
524 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
525
526 /* Return the page */
527 return PageIndex;
528 }
529
530 PFN_NUMBER
531 NTAPI
532 MiRemoveZeroPage(IN ULONG Color)
533 {
534 PFN_NUMBER PageIndex;
535 PMMPFN Pfn1;
536 BOOLEAN Zero = FALSE;
537
538 /* Make sure PFN lock is held and we have pages */
539 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
540 ASSERT(MmAvailablePages != 0);
541 ASSERT(Color < MmSecondaryColors);
542
543 /* Check the colored zero list */
544 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
545 if (PageIndex == LIST_HEAD)
546 {
547 /* Check the zero list */
548 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
549 PageIndex = MmZeroedPageListHead.Flink;
550 if (PageIndex == LIST_HEAD)
551 {
552 /* This means there's no zero pages, we have to look for free ones */
553 ASSERT(MmZeroedPageListHead.Total == 0);
554 Zero = TRUE;
555
556 /* Check the colored free list */
557 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
558 if (PageIndex == LIST_HEAD)
559 {
560 /* Check the free list */
561 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
562 PageIndex = MmFreePageListHead.Flink;
563 Color = PageIndex & MmSecondaryColorMask;
564 ASSERT(PageIndex != LIST_HEAD);
565 if (PageIndex == LIST_HEAD)
566 {
567 /* FIXME: Should check the standby list */
568 ASSERT(MmZeroedPageListHead.Total == 0);
569 }
570 }
571 }
572 else
573 {
574 Color = PageIndex & MmSecondaryColorMask;
575 }
576 }
577
578 /* Sanity checks */
579 Pfn1 = MI_PFN_ELEMENT(PageIndex);
580 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
581 (Pfn1->u3.e1.PageLocation == ZeroedPageList));
582
583 /* Remove the page from its list */
584 PageIndex = MiRemovePageByColor(PageIndex, Color);
585 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
586
587 /* Zero it, if needed */
588 if (Zero) MiZeroPhysicalPage(PageIndex);
589
590 /* Sanity checks */
591 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
592 ASSERT(Pfn1->u2.ShareCount == 0);
593 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
594 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
595
596 /* Return the page */
597 return PageIndex;
598 }
599
600 VOID
601 NTAPI
602 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
603 {
604 PMMPFNLIST ListHead;
605 PFN_NUMBER LastPage;
606 PMMPFN Pfn1;
607 ULONG Color;
608 PMMPFN Blink;
609 PMMCOLOR_TABLES ColorTable;
610
611 /* Make sure the page index is valid */
612 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
613 ASSERT((PageFrameIndex != 0) &&
614 (PageFrameIndex <= MmHighestPhysicalPage) &&
615 (PageFrameIndex >= MmLowestPhysicalPage));
616
617 /* Get the PFN entry */
618 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
619
620 /* Sanity checks that a right kind of page is being inserted here */
621 ASSERT(Pfn1->u4.MustBeCached == 0);
622 ASSERT(Pfn1->u3.e1.Rom != 1);
623 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
624 ASSERT(Pfn1->u4.VerifierAllocation == 0);
625 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
626
627 /* Get the free page list and increment its count */
628 ListHead = &MmFreePageListHead;
629 ASSERT_LIST_INVARIANT(ListHead);
630 ListHead->Total++;
631
632 /* Get the last page on the list */
633 LastPage = ListHead->Blink;
634 if (LastPage != LIST_HEAD)
635 {
636 /* Link us with the previous page, so we're at the end now */
637 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
638 }
639 else
640 {
641 /* The list is empty, so we are the first page */
642 ListHead->Flink = PageFrameIndex;
643 }
644
645 /* Now make the list head point back to us (since we go at the end) */
646 ListHead->Blink = PageFrameIndex;
647 ASSERT_LIST_INVARIANT(ListHead);
648
649 /* And initialize our own list pointers */
650 Pfn1->u1.Flink = LIST_HEAD;
651 Pfn1->u2.Blink = LastPage;
652
653 /* Set the list name and default priority */
654 Pfn1->u3.e1.PageLocation = FreePageList;
655 Pfn1->u4.Priority = 3;
656
657 /* Clear some status fields */
658 Pfn1->u4.InPageError = 0;
659 Pfn1->u4.AweAllocation = 0;
660
661 /* Increment number of available pages */
662 MiIncrementAvailablePages();
663
664 /* Get the page color */
665 Color = PageFrameIndex & MmSecondaryColorMask;
666
667 /* Get the first page on the color list */
668 ColorTable = &MmFreePagesByColor[FreePageList][Color];
669 if (ColorTable->Flink == LIST_HEAD)
670 {
671 /* The list is empty, so we are the first page */
672 Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
673 ColorTable->Flink = PageFrameIndex;
674 }
675 else
676 {
677 /* Get the previous page */
678 Blink = (PMMPFN)ColorTable->Blink;
679
680 /* Make it link to us, and link back to it */
681 Blink->OriginalPte.u.Long = PageFrameIndex;
682 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
683 }
684
685 /* Now initialize our own list pointers */
686 ColorTable->Blink = Pfn1;
687
688 /* This page is now the last */
689 Pfn1->OriginalPte.u.Long = LIST_HEAD;
690
691 /* And increase the count in the colored list */
692 ColorTable->Count++;
693
694 /* Notify zero page thread if enough pages are on the free list now */
695 if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive))
696 {
697 /* Set the event */
698 MmZeroingPageThreadActive = TRUE;
699 KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
700 }
701
702 #if MI_TRACE_PFNS
703 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
704 RtlZeroMemory(Pfn1->ProcessName, 16);
705 #endif
706 }
707
708 VOID
709 FASTCALL
710 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
711 {
712 PMMPFNLIST ListHead;
713 PFN_NUMBER Flink;
714 PMMPFN Pfn1, Pfn2;
715
716 /* Make sure the lock is held */
717 DPRINT("Inserting page: %lx into standby list !\n", PageFrameIndex);
718 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
719
720 /* Make sure the PFN is valid */
721 ASSERT((PageFrameIndex != 0) &&
722 (PageFrameIndex <= MmHighestPhysicalPage) &&
723 (PageFrameIndex >= MmLowestPhysicalPage));
724
725 /* Grab the PFN and validate it is the right kind of PFN being inserted */
726 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
727 ASSERT(Pfn1->u4.MustBeCached == 0);
728 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
729 ASSERT(Pfn1->u3.e1.PrototypePte == 1);
730 ASSERT(Pfn1->u3.e1.Rom != 1);
731
732 /* One more transition page on a list */
733 MmTransitionSharedPages++;
734
735 /* Get the standby page list and increment its count */
736 ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
737 ASSERT_LIST_INVARIANT(ListHead);
738 ListHead->Total++;
739
740 /* Make the head of the list point to this page now */
741 Flink = ListHead->Flink;
742 ListHead->Flink = PageFrameIndex;
743
744 /* Make the page point to the previous head, and back to the list */
745 Pfn1->u1.Flink = Flink;
746 Pfn1->u2.Blink = LIST_HEAD;
747
748 /* Was the list empty? */
749 if (Flink != LIST_HEAD)
750 {
751 /* It wasn't, so update the backlink of the previous head page */
752 Pfn2 = MI_PFN_ELEMENT(Flink);
753 Pfn2->u2.Blink = PageFrameIndex;
754 }
755 else
756 {
757 /* It was empty, so have it loop back around to this new page */
758 ListHead->Blink = PageFrameIndex;
759 }
760
761 /* Move the page onto its new location */
762 Pfn1->u3.e1.PageLocation = StandbyPageList;
763
764 /* Increment number of available pages */
765 MiIncrementAvailablePages();
766 }
767
768 VOID
769 NTAPI
770 MiInsertPageInList(IN PMMPFNLIST ListHead,
771 IN PFN_NUMBER PageFrameIndex)
772 {
773 PFN_NUMBER Flink, LastPage;
774 PMMPFN Pfn1, Pfn2;
775 MMLISTS ListName;
776 PMMCOLOR_TABLES ColorHead;
777 ULONG Color;
778
779 /* For free pages, use MiInsertPageInFreeList */
780 ASSERT(ListHead != &MmFreePageListHead);
781
782 /* Make sure the lock is held */
783 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
784
785 /* Make sure the PFN is valid */
786 ASSERT((PageFrameIndex) &&
787 (PageFrameIndex <= MmHighestPhysicalPage) &&
788 (PageFrameIndex >= MmLowestPhysicalPage));
789
790 /* Page should be unused */
791 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
792 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
793 ASSERT(Pfn1->u3.e1.Rom != 1);
794
795 /* Is a standby or modified page being inserted? */
796 ListName = ListHead->ListName;
797 if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
798 {
799 /* If the page is in transition, it must also be a prototype page */
800 if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
801 (Pfn1->OriginalPte.u.Soft.Transition == 1))
802 {
803 /* Crash the system on inconsistency */
804 KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
805 }
806 }
807
808 /* Standby pages are prioritized, so we need to get the real head */
809 if (ListHead == &MmStandbyPageListHead)
810 {
811 /* Obviously the prioritized list should still have the same name */
812 ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
813 ASSERT(ListHead->ListName == ListName);
814 }
815
816 /* Increment the list count */
817 ListHead->Total++;
818
819 /* Is a modified page being inserted? */
820 if (ListHead == &MmModifiedPageListHead)
821 {
822 /* For now, only single-prototype pages should end up in this path */
823 DPRINT("Modified page being added: %lx\n", PageFrameIndex);
824 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
825
826 /* Modified pages are colored when they are selected for page file */
827 ListHead = &MmModifiedPageListByColor[0];
828 ASSERT (ListHead->ListName == ListName);
829 ListHead->Total++;
830
831 /* Increment the number of paging file modified pages */
832 MmTotalPagesForPagingFile++;
833 }
834
835 /* Don't handle bad pages yet yet */
836 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
837
838 /* Zero pages go to the head, all other pages go to the end */
839 if (ListName == ZeroedPageList)
840 {
841 /* Make the head of the list point to this page now */
842 Flink = ListHead->Flink;
843 ListHead->Flink = PageFrameIndex;
844
845 /* Make the page point to the previous head, and back to the list */
846 Pfn1->u1.Flink = Flink;
847 Pfn1->u2.Blink = LIST_HEAD;
848
849 /* Was the list empty? */
850 if (Flink != LIST_HEAD)
851 {
852 /* It wasn't, so update the backlink of the previous head page */
853 Pfn2 = MI_PFN_ELEMENT(Flink);
854 Pfn2->u2.Blink = PageFrameIndex;
855 }
856 else
857 {
858 /* It was empty, so have it loop back around to this new page */
859 ListHead->Blink = PageFrameIndex;
860 }
861 }
862 else
863 {
864 /* Get the last page on the list */
865 LastPage = ListHead->Blink;
866 if (LastPage != LIST_HEAD)
867 {
868 /* Link us with the previous page, so we're at the end now */
869 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
870 }
871 else
872 {
873 /* The list is empty, so we are the first page */
874 ListHead->Flink = PageFrameIndex;
875 }
876
877 /* Now make the list head point back to us (since we go at the end) */
878 ListHead->Blink = PageFrameIndex;
879 ASSERT_LIST_INVARIANT(ListHead);
880
881 /* And initialize our own list pointers */
882 Pfn1->u1.Flink = LIST_HEAD;
883 Pfn1->u2.Blink = LastPage;
884 }
885
886 /* Move the page onto its new location */
887 Pfn1->u3.e1.PageLocation = ListName;
888
889 /* For zero/free pages, we also have to handle the colored lists */
890 if (ListName <= StandbyPageList)
891 {
892 /* Increment number of available pages */
893 MiIncrementAvailablePages();
894
895 /* Sanity checks */
896 ASSERT(ListName == ZeroedPageList);
897 ASSERT(Pfn1->u4.InPageError == 0);
898
899 /* Get the page color */
900 Color = PageFrameIndex & MmSecondaryColorMask;
901
902 /* Get the list for this color */
903 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
904
905 /* Get the old head */
906 Flink = ColorHead->Flink;
907
908 /* Make this page point back to the list, and point forwards to the old head */
909 Pfn1->OriginalPte.u.Long = Flink;
910 Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
911
912 /* Set the new head */
913 ColorHead->Flink = PageFrameIndex;
914
915 /* Was the head empty? */
916 if (Flink != LIST_HEAD)
917 {
918 /* No, so make the old head point to this page */
919 Pfn2 = MI_PFN_ELEMENT(Flink);
920 Pfn2->u4.PteFrame = PageFrameIndex;
921 }
922 else
923 {
924 /* Yes, make it loop back to this page */
925 ColorHead->Blink = (PVOID)Pfn1;
926 }
927
928 /* One more paged on the colored list */
929 ColorHead->Count++;
930
931 #if MI_TRACE_PFNS
932 //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
933 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
934 MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
935 RtlZeroMemory(Pfn1->ProcessName, 16);
936 #endif
937 }
938 else if (ListName == ModifiedPageList)
939 {
940 /* In ARM3, page must be destined for page file, and not yet written out */
941 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
942 ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
943
944 /* One more transition page */
945 MmTransitionSharedPages++;
946
947 /* Increment the number of per-process modified pages */
948 PsGetCurrentProcess()->ModifiedPageCount++;
949
950 /* FIXME: Wake up modified page writer if there are not enough free pages */
951 }
952 else if (ListName == ModifiedNoWritePageList)
953 {
954 /* This list is not yet implemented */
955 ASSERT(FALSE);
956 }
957 }
958
959 VOID
960 NTAPI
961 MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
962 IN PMMPTE PointerPte,
963 IN BOOLEAN Modified)
964 {
965 PMMPFN Pfn1;
966 NTSTATUS Status;
967 PMMPTE PointerPtePte;
968 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
969
970 /* Setup the PTE */
971 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
972 Pfn1->PteAddress = PointerPte;
973
974 /* Check if this PFN is part of a valid address space */
975 if (PointerPte->u.Hard.Valid == 1)
976 {
977 /* Only valid from MmCreateProcessAddressSpace path */
978 ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
979
980 /* Make this a demand zero PTE */
981 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
982 }
983 else
984 {
985 /* Copy the PTE data */
986 Pfn1->OriginalPte = *PointerPte;
987 ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
988 (Pfn1->OriginalPte.u.Soft.Transition == 1)));
989 }
990
991 /* Otherwise this is a fresh page -- set it up */
992 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
993 Pfn1->u3.e2.ReferenceCount = 1;
994 Pfn1->u2.ShareCount = 1;
995 Pfn1->u3.e1.PageLocation = ActiveAndValid;
996 ASSERT(Pfn1->u3.e1.Rom == 0);
997 Pfn1->u3.e1.Modified = Modified;
998
999 /* Get the page table for the PTE */
1000 PointerPtePte = MiAddressToPte(PointerPte);
1001 if (PointerPtePte->u.Hard.Valid == 0)
1002 {
1003 /* Make sure the PDE gets paged in properly */
1004 Status = MiCheckPdeForPagedPool(PointerPte);
1005 if (!NT_SUCCESS(Status))
1006 {
1007 /* Crash */
1008 KeBugCheckEx(MEMORY_MANAGEMENT,
1009 0x61940,
1010 (ULONG_PTR)PointerPte,
1011 (ULONG_PTR)PointerPtePte->u.Long,
1012 (ULONG_PTR)MiPteToAddress(PointerPte));
1013 }
1014 }
1015
1016 /* Get the PFN for the page table */
1017 PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1018 ASSERT(PageFrameIndex != 0);
1019 Pfn1->u4.PteFrame = PageFrameIndex;
1020
1021 /* Increase its share count so we don't get rid of it */
1022 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1023 Pfn1->u2.ShareCount++;
1024 }
1025
1026 VOID
1027 NTAPI
1028 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
1029 IN PMMPTE PointerPte,
1030 IN MMPTE TempPte)
1031 {
1032 PMMPFN Pfn1;
1033 NTSTATUS Status;
1034 PMMPTE PointerPtePte;
1035 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1036
1037 /* PTE must be invalid */
1038 ASSERT(PointerPte->u.Hard.Valid == 0);
1039
1040 /* Setup the PTE */
1041 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1042 Pfn1->PteAddress = PointerPte;
1043 Pfn1->OriginalPte = DemandZeroPte;
1044
1045 /* Otherwise this is a fresh page -- set it up */
1046 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1047 Pfn1->u3.e2.ReferenceCount++;
1048 Pfn1->u2.ShareCount++;
1049 Pfn1->u3.e1.PageLocation = ActiveAndValid;
1050 ASSERT(Pfn1->u3.e1.Rom == 0);
1051 Pfn1->u3.e1.Modified = 1;
1052
1053 /* Get the page table for the PTE */
1054 PointerPtePte = MiAddressToPte(PointerPte);
1055 if (PointerPtePte->u.Hard.Valid == 0)
1056 {
1057 /* Make sure the PDE gets paged in properly */
1058 Status = MiCheckPdeForPagedPool(PointerPte);
1059 if (!NT_SUCCESS(Status))
1060 {
1061 /* Crash */
1062 KeBugCheckEx(MEMORY_MANAGEMENT,
1063 0x61940,
1064 (ULONG_PTR)PointerPte,
1065 (ULONG_PTR)PointerPtePte->u.Long,
1066 (ULONG_PTR)MiPteToAddress(PointerPte));
1067 }
1068 }
1069
1070 /* Get the PFN for the page table */
1071 PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
1072 ASSERT(PageFrameIndex != 0);
1073 Pfn1->u4.PteFrame = PageFrameIndex;
1074
1075 /* Increase its share count so we don't get rid of it */
1076 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1077 Pfn1->u2.ShareCount++;
1078
1079 /* Write valid PTE */
1080 MI_WRITE_VALID_PTE(PointerPte, TempPte);
1081 }
1082
1083 NTSTATUS
1084 NTAPI
1085 MiInitializeAndChargePfn(OUT PPFN_NUMBER PageFrameIndex,
1086 IN PMMPDE PointerPde,
1087 IN PFN_NUMBER ContainingPageFrame,
1088 IN BOOLEAN SessionAllocation)
1089 {
1090 MMPDE TempPde;
1091 KIRQL OldIrql;
1092
1093 /* Use either a global or local PDE */
1094 TempPde = SessionAllocation ? ValidKernelPdeLocal : ValidKernelPde;
1095
1096 /* Lock the PFN database */
1097 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
1098
1099 /* Make sure nobody is racing us */
1100 if (PointerPde->u.Hard.Valid == 1)
1101 {
1102 /* Return special error if that was the case */
1103 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1104 return STATUS_RETRY;
1105 }
1106
1107 /* Grab a zero page and set the PFN, then make it valid */
1108 *PageFrameIndex = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
1109 TempPde.u.Hard.PageFrameNumber = *PageFrameIndex;
1110 MI_WRITE_VALID_PDE(PointerPde, TempPde);
1111
1112 /* Initialize the PFN */
1113 MiInitializePfnForOtherProcess(*PageFrameIndex,
1114 PointerPde,
1115 ContainingPageFrame);
1116 ASSERT(MI_PFN_ELEMENT(*PageFrameIndex)->u1.WsIndex == 0);
1117
1118 /* Release the lock and return success */
1119 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
1120 return STATUS_SUCCESS;
1121 }
1122
1123 VOID
1124 NTAPI
1125 MiDecrementShareCount(IN PMMPFN Pfn1,
1126 IN PFN_NUMBER PageFrameIndex)
1127 {
1128 PMMPTE PointerPte;
1129 MMPTE TempPte;
1130
1131 ASSERT(PageFrameIndex > 0);
1132 ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
1133 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
1134 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
1135
1136 /* Page must be in-use */
1137 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
1138 (Pfn1->u3.e1.PageLocation != StandbyPageList))
1139 {
1140 /* Otherwise we have PFN corruption */
1141 KeBugCheckEx(PFN_LIST_CORRUPT,
1142 0x99,
1143 PageFrameIndex,
1144 Pfn1->u3.e1.PageLocation,
1145 0);
1146 }
1147
1148 /* Page should at least have one reference */
1149 ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1150
1151 /* Check if the share count is now 0 */
1152 ASSERT(Pfn1->u2.ShareCount < 0xF000000);
1153 if (!--Pfn1->u2.ShareCount)
1154 {
1155 /* Was this a prototype PTE? */
1156 if (Pfn1->u3.e1.PrototypePte)
1157 {
1158 /* Grab the PTE address and make sure it's in prototype pool */
1159 PointerPte = Pfn1->PteAddress;
1160 ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
1161
1162 /* The PTE that backs it should also be valdi */
1163 PointerPte = MiAddressToPte(PointerPte);
1164 ASSERT(PointerPte->u.Hard.Valid == 1);
1165
1166 /* Get the original prototype PTE and turn it into a transition PTE */
1167 PointerPte = Pfn1->PteAddress;
1168 TempPte = *PointerPte;
1169 TempPte.u.Soft.Transition = 1;
1170 TempPte.u.Soft.Valid = 0;
1171 TempPte.u.Soft.Prototype = 0;
1172 TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
1173 MI_WRITE_INVALID_PTE(PointerPte, TempPte);
1174 DPRINT("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
1175 }
1176
1177 /* Put the page in transition */
1178 Pfn1->u3.e1.PageLocation = TransitionPage;
1179
1180 /* PFN lock must be held */
1181 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1182
1183 if (Pfn1->u3.e2.ReferenceCount == 1)
1184 {
1185 /* Is there still a PFN for this page? */
1186 if (MI_IS_PFN_DELETED(Pfn1))
1187 {
1188 /* Clear the last reference */
1189 Pfn1->u3.e2.ReferenceCount = 0;
1190 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
1191
1192 /* Mark the page temporarily as valid, we're going to make it free soon */
1193 Pfn1->u3.e1.PageLocation = ActiveAndValid;
1194
1195 /* Bring it back into the free list */
1196 MiInsertPageInFreeList(PageFrameIndex);
1197 }
1198 else
1199 {
1200 /* PFN not yet deleted, drop a ref count */
1201 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
1202 }
1203 }
1204 else
1205 {
1206 /* Otherwise, just drop the reference count */
1207 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1208 }
1209 }
1210 }
1211
1212 VOID
1213 NTAPI
1214 MiDecrementReferenceCount(IN PMMPFN Pfn1,
1215 IN PFN_NUMBER PageFrameIndex)
1216 {
1217 /* PFN lock must be held */
1218 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
1219
1220 /* Sanity checks on the page */
1221 if (PageFrameIndex > MmHighestPhysicalPage ||
1222 Pfn1 != MI_PFN_ELEMENT(PageFrameIndex) ||
1223 Pfn1->u3.e2.ReferenceCount == 0 ||
1224 Pfn1->u3.e2.ReferenceCount >= 2500)
1225 {
1226 DPRINT1("PageFrameIndex=0x%lx, MmHighestPhysicalPage=0x%lx\n", PageFrameIndex, MmHighestPhysicalPage);
1227 DPRINT1("Pfn1=%p, Element=%p, RefCount=%u\n", Pfn1, MI_PFN_ELEMENT(PageFrameIndex), Pfn1->u3.e2.ReferenceCount);
1228 ASSERT(PageFrameIndex <= MmHighestPhysicalPage);
1229 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
1230 ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
1231 ASSERT(Pfn1->u3.e2.ReferenceCount < 2500);
1232 }
1233
1234 /* Dereference the page, bail out if it's still alive */
1235 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
1236 if (Pfn1->u3.e2.ReferenceCount) return;
1237
1238 /* Nobody should still have reference to this page */
1239 if (Pfn1->u2.ShareCount != 0)
1240 {
1241 /* Otherwise something's really wrong */
1242 KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
1243 }
1244
1245 /* And it should be lying on some page list */
1246 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
1247
1248 /* Did someone set the delete flag? */
1249 if (MI_IS_PFN_DELETED(Pfn1))
1250 {
1251 /* Insert it into the free list, there's nothing left to do */
1252 MiInsertPageInFreeList(PageFrameIndex);
1253 return;
1254 }
1255
1256 /* Check to see which list this page should go into */
1257 if (Pfn1->u3.e1.Modified == 1)
1258 {
1259 /* Push it into the modified page list */
1260 MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
1261 }
1262 else
1263 {
1264 /* Otherwise, insert this page into the standby list */
1265 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
1266 MiInsertStandbyListAtFront(PageFrameIndex);
1267 }
1268 }
1269
1270 VOID
1271 NTAPI
1272 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
1273 IN PVOID PteAddress,
1274 IN PFN_NUMBER PteFrame)
1275 {
1276 PMMPFN Pfn1;
1277
1278 /* Setup the PTE */
1279 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
1280 Pfn1->PteAddress = PteAddress;
1281
1282 /* Make this a software PTE */
1283 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
1284
1285 /* Setup the page */
1286 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
1287 Pfn1->u3.e2.ReferenceCount = 1;
1288 Pfn1->u2.ShareCount = 1;
1289 Pfn1->u3.e1.PageLocation = ActiveAndValid;
1290 Pfn1->u3.e1.Modified = TRUE;
1291 Pfn1->u4.InPageError = FALSE;
1292
1293 /* Did we get a PFN for the page table */
1294 if (PteFrame)
1295 {
1296 /* Store it */
1297 Pfn1->u4.PteFrame = PteFrame;
1298
1299 /* Increase its share count so we don't get rid of it */
1300 Pfn1 = MI_PFN_ELEMENT(PteFrame);
1301 Pfn1->u2.ShareCount++;
1302 }
1303 }
1304
1305 /* EOF */