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