ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pfnlist.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/mm/ARM3/pfnlist.c
00005  * PURPOSE:         ARM Memory Manager PFN List Manipulation
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #define MODULE_INVOLVED_IN_ARM3
00016 #include "../ARM3/miarm.h"
00017 
00018 #if DBG
00019 #define ASSERT_LIST_INVARIANT(x) \
00020 do { \
00021     ASSERT(((x)->Total == 0 && \
00022             (x)->Flink == LIST_HEAD && \
00023             (x)->Blink == LIST_HEAD) || \
00024            ((x)->Total != 0 && \
00025             (x)->Flink != LIST_HEAD && \
00026             (x)->Blink != LIST_HEAD)); \
00027 } while (0)
00028 #else
00029 #define ASSERT_LIST_INVARIANT(x)
00030 #endif
00031 
00032 /* GLOBALS ********************************************************************/
00033 
00034 BOOLEAN MmDynamicPfn;
00035 BOOLEAN MmMirroring;
00036 ULONG MmSystemPageColor;
00037 
00038 ULONG MmTransitionSharedPages;
00039 ULONG MmTotalPagesForPagingFile;
00040 
00041 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
00042 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
00043 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
00044 MMPFNLIST MmStandbyPageListByPriority[8];
00045 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD};
00046 MMPFNLIST MmModifiedPageListByColor[1] = {{0, ModifiedPageList, LIST_HEAD, LIST_HEAD}};
00047 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD};
00048 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD};
00049 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
00050 
00051 PMMPFNLIST MmPageLocationList[] =
00052 {
00053     &MmZeroedPageListHead,
00054     &MmFreePageListHead,
00055     &MmStandbyPageListHead,
00056     &MmModifiedPageListHead,
00057     &MmModifiedNoWritePageListHead,
00058     &MmBadPageListHead,
00059     NULL,
00060     NULL
00061 };
00062 
00063 ULONG MI_PFN_CURRENT_USAGE;
00064 CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet";
00065 
00066 /* FUNCTIONS ******************************************************************/
00067 
00068 VOID
00069 NTAPI
00070 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
00071 {
00072     KIRQL OldIrql;
00073     PVOID VirtualAddress;
00074     PEPROCESS Process = PsGetCurrentProcess();
00075 
00076     /* Map in hyperspace, then wipe it using XMMI or MEMSET */
00077     VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql);
00078     ASSERT(VirtualAddress);
00079     KeZeroPages(VirtualAddress, PAGE_SIZE);
00080     MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql);
00081 }
00082 
00083 VOID
00084 NTAPI
00085 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
00086 {
00087     PFN_NUMBER OldFlink, OldBlink;
00088     PMMPFNLIST ListHead;
00089     MMLISTS ListName;
00090     ULONG Color;
00091     PMMCOLOR_TABLES ColorTable;
00092     PMMPFN Pfn1;
00093 
00094     /* Make sure the PFN lock is held */
00095     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00096 
00097     /* Make sure the PFN entry isn't in-use */
00098     ASSERT(Entry->u3.e1.WriteInProgress == 0);
00099     ASSERT(Entry->u3.e1.ReadInProgress == 0);
00100 
00101     /* Find the list for this entry, make sure it's the free or zero list */
00102     ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
00103     ListName = ListHead->ListName;
00104     ASSERT(ListHead != NULL);
00105     ASSERT(ListName <= FreePageList);
00106     ASSERT_LIST_INVARIANT(ListHead);
00107 
00108     /* Remove one count */
00109     ASSERT(ListHead->Total != 0);
00110     ListHead->Total--;
00111 
00112     /* Get the forward and back pointers */
00113     OldFlink = Entry->u1.Flink;
00114     OldBlink = Entry->u2.Blink;
00115 
00116     /* Check if the next entry is the list head */
00117     if (OldFlink != LIST_HEAD)
00118     {
00119         /* It is not, so set the backlink of the actual entry, to our backlink */
00120         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
00121     }
00122     else
00123     {
00124         /* Set the list head's backlink instead */
00125         ListHead->Blink = OldBlink;
00126     }
00127 
00128     /* Check if the back entry is the list head */
00129     if (OldBlink != LIST_HEAD)
00130     {
00131         /* It is not, so set the backlink of the actual entry, to our backlink */
00132         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
00133     }
00134     else
00135     {
00136         /* Set the list head's backlink instead */
00137         ListHead->Flink = OldFlink;
00138     }
00139 
00140     /* Get the page color */
00141     OldBlink = MiGetPfnEntryIndex(Entry);
00142     Color = OldBlink & MmSecondaryColorMask;
00143 
00144     /* Get the first page on the color list */
00145     ColorTable = &MmFreePagesByColor[ListName][Color];
00146 
00147     /* Check if this was was actually the head */
00148     OldFlink = ColorTable->Flink;
00149     if (OldFlink == OldBlink)
00150     {
00151         /* Make the table point to the next page this page was linking to */
00152         ColorTable->Flink = Entry->OriginalPte.u.Long;
00153         if (ColorTable->Flink != LIST_HEAD)
00154         {
00155             /* And make the previous link point to the head now */
00156             MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
00157         }
00158         else
00159         {
00160             /* And if that page was the head, loop the list back around */
00161             ColorTable->Blink = (PVOID)LIST_HEAD;
00162         }
00163     }
00164     else
00165     {
00166         /* This page shouldn't be pointing back to the head */
00167         ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD);
00168 
00169         /* Make the back link point to whoever the next page is */
00170         Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame);
00171         Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long;
00172 
00173         /* Check if this page was pointing to the head */
00174         if (Entry->OriginalPte.u.Long != LIST_HEAD)
00175         {
00176             /* Make the back link point to the head */
00177             Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long);
00178             Pfn1->u4.PteFrame = Entry->u4.PteFrame;
00179         }
00180         else
00181         {
00182             /* Then the table is directly back pointing to this page now */
00183             ColorTable->Blink = Pfn1;
00184         }
00185     }
00186 
00187     /* One less colored page */
00188     ASSERT(ColorTable->Count >= 1);
00189     ColorTable->Count--;
00190 
00191     /* ReactOS Hack */
00192     Entry->OriginalPte.u.Long = 0;
00193 
00194     /* We are not on a list anymore */
00195     Entry->u1.Flink = Entry->u2.Blink = 0;
00196     ASSERT_LIST_INVARIANT(ListHead);
00197 
00198     /* See if we hit any thresholds */
00199     if (MmAvailablePages == MmHighMemoryThreshold)
00200     {
00201         /* Clear the high memory event */
00202         KeClearEvent(MiHighMemoryEvent);
00203     }
00204     else if (MmAvailablePages == MmLowMemoryThreshold)
00205     {
00206         /* Signal the low memory event */
00207         KeSetEvent(MiLowMemoryEvent, 0, FALSE);
00208     }
00209 
00210     /* One less page */
00211     if (--MmAvailablePages < MmMinimumFreePages)
00212     {
00213         /* FIXME: Should wake up the MPW and working set manager, if we had one */
00214 
00215         DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages);
00216 
00217         /* Call RosMm and see if it can release any pages for us */
00218         MmRebalanceMemoryConsumers();
00219     }
00220 
00221 #if MI_TRACE_PFNS
00222     ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
00223     Entry->PfnUsage = MI_PFN_CURRENT_USAGE;
00224     memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
00225 //    MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
00226 //    memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
00227 #endif
00228 }
00229 
00230 VOID
00231 NTAPI
00232 MiUnlinkPageFromList(IN PMMPFN Pfn)
00233 {
00234     PMMPFNLIST ListHead;
00235     PFN_NUMBER OldFlink, OldBlink;
00236 
00237     /* Make sure the PFN lock is held */
00238     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00239 
00240     /* ARM3 should only call this for dead pages */
00241     ASSERT(Pfn->u3.e2.ReferenceCount == 0);
00242 
00243     /* Transition pages are supposed to be standby/modified/nowrite */
00244     ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation];
00245     ASSERT(ListHead->ListName >= StandbyPageList);
00246 
00247     /* Check if this was standby, or modified */
00248     if (ListHead == &MmStandbyPageListHead)
00249     {
00250         /* Should not be a ROM page */
00251         ASSERT(Pfn->u3.e1.Rom == 0);
00252 
00253         /* Get the exact list */
00254         ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority];
00255 
00256         /* See if we hit any thresholds */
00257         if (MmAvailablePages == MmHighMemoryThreshold)
00258         {
00259             /* Clear the high memory event */
00260             KeClearEvent(MiHighMemoryEvent);
00261         }
00262         else if (MmAvailablePages == MmLowMemoryThreshold)
00263         {
00264             /* Signal the low memory event */
00265             KeSetEvent(MiLowMemoryEvent, 0, FALSE);
00266         }
00267 
00268         /* Decrease transition page counter */
00269         ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
00270         MmTransitionSharedPages--;
00271 
00272         /* One less page */
00273         if (--MmAvailablePages < MmMinimumFreePages)
00274         {
00275             /* FIXME: Should wake up the MPW and working set manager, if we had one */
00276             DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages);
00277 
00278             /* Call RosMm and see if it can release any pages for us */
00279             MmRebalanceMemoryConsumers();
00280         }
00281     }
00282     else if (ListHead == &MmModifiedPageListHead)
00283     {
00284         /* Only shared memory (page-file backed) modified pages are supported */
00285         ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0);
00286 
00287         /* Decrement the counters */
00288         ListHead->Total--;
00289         MmTotalPagesForPagingFile--;
00290 
00291         /* Pick the correct colored list */
00292         ListHead = &MmModifiedPageListByColor[0];
00293 
00294         /* Decrease transition page counter */
00295         ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
00296         MmTransitionSharedPages--;
00297     }
00298     else if (ListHead == &MmModifiedNoWritePageListHead)
00299     {
00300         /* List not yet supported */
00301         ASSERT(FALSE);
00302     }
00303 
00304     /* Nothing should be in progress and the list should not be empty */
00305     ASSERT(Pfn->u3.e1.WriteInProgress == 0);
00306     ASSERT(Pfn->u3.e1.ReadInProgress == 0);
00307     ASSERT(ListHead->Total != 0);
00308 
00309     /* Get the forward and back pointers */
00310     OldFlink = Pfn->u1.Flink;
00311     OldBlink = Pfn->u2.Blink;
00312 
00313     /* Check if the next entry is the list head */
00314     if (OldFlink != LIST_HEAD)
00315     {
00316         /* It is not, so set the backlink of the actual entry, to our backlink */
00317         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
00318     }
00319     else
00320     {
00321         /* Set the list head's backlink instead */
00322         ListHead->Blink = OldBlink;
00323     }
00324 
00325     /* Check if the back entry is the list head */
00326     if (OldBlink != LIST_HEAD)
00327     {
00328         /* It is not, so set the backlink of the actual entry, to our backlink */
00329         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
00330     }
00331     else
00332     {
00333         /* Set the list head's backlink instead */
00334         ListHead->Flink = OldFlink;
00335     }
00336 
00337     /* ReactOS Hack */
00338     Pfn->OriginalPte.u.Long = 0;
00339 
00340     /* We are not on a list anymore */
00341     Pfn->u1.Flink = Pfn->u2.Blink = 0;
00342     ASSERT_LIST_INVARIANT(ListHead);
00343 
00344     /* Remove one entry from the list */
00345     ListHead->Total--;
00346 }
00347 
00348 PFN_NUMBER
00349 NTAPI
00350 MiRemovePageByColor(IN PFN_NUMBER PageIndex,
00351                     IN ULONG Color)
00352 {
00353     PMMPFN Pfn1;
00354     PMMPFNLIST ListHead;
00355     MMLISTS ListName;
00356     PFN_NUMBER OldFlink, OldBlink;
00357     USHORT OldColor, OldCache;
00358     PMMCOLOR_TABLES ColorTable;
00359 
00360     /* Make sure PFN lock is held */
00361     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00362     ASSERT(Color < MmSecondaryColors);
00363 
00364     /* Get the PFN entry */
00365     Pfn1 = MI_PFN_ELEMENT(PageIndex);
00366     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
00367     ASSERT(Pfn1->u3.e1.Rom == 0);
00368 
00369     /* Capture data for later */
00370     OldColor = Pfn1->u3.e1.PageColor;
00371     OldCache = Pfn1->u3.e1.CacheAttribute;
00372 
00373     /* Could be either on free or zero list */
00374     ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
00375     ASSERT_LIST_INVARIANT(ListHead);
00376     ListName = ListHead->ListName;
00377     ASSERT(ListName <= FreePageList);
00378 
00379     /* Remove a page */
00380     ListHead->Total--;
00381 
00382     /* Get the forward and back pointers */
00383     OldFlink = Pfn1->u1.Flink;
00384     OldBlink = Pfn1->u2.Blink;
00385 
00386     /* Check if the next entry is the list head */
00387     if (OldFlink != LIST_HEAD)
00388     {
00389         /* It is not, so set the backlink of the actual entry, to our backlink */
00390         MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
00391     }
00392     else
00393     {
00394         /* Set the list head's backlink instead */
00395         ListHead->Blink = OldBlink;
00396     }
00397 
00398     /* Check if the back entry is the list head */
00399     if (OldBlink != LIST_HEAD)
00400     {
00401         /* It is not, so set the backlink of the actual entry, to our backlink */
00402         MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
00403     }
00404     else
00405     {
00406         /* Set the list head's backlink instead */
00407         ListHead->Flink = OldFlink;
00408     }
00409 
00410     /* We are not on a list anymore */
00411     ASSERT_LIST_INVARIANT(ListHead);
00412     Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
00413 
00414     /* Zero flags but restore color and cache */
00415     Pfn1->u3.e2.ShortFlags = 0;
00416     Pfn1->u3.e1.PageColor = OldColor;
00417     Pfn1->u3.e1.CacheAttribute = OldCache;
00418 
00419     /* Get the first page on the color list */
00420     ASSERT(Color < MmSecondaryColors);
00421     ColorTable = &MmFreePagesByColor[ListName][Color];
00422     ASSERT(ColorTable->Count >= 1);
00423 
00424     /* Set the forward link to whoever we were pointing to */
00425     ColorTable->Flink = Pfn1->OriginalPte.u.Long;
00426 
00427     /* Get the first page on the color list */
00428     if (ColorTable->Flink == LIST_HEAD)
00429     {
00430         /* This is the beginning of the list, so set the sentinel value */
00431         ColorTable->Blink = (PVOID)LIST_HEAD;
00432     }
00433     else
00434     {
00435         /* The list is empty, so we are the first page */
00436         MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
00437     }
00438 
00439     /* One less page */
00440     ColorTable->Count--;
00441 
00442     /* ReactOS Hack */
00443     Pfn1->OriginalPte.u.Long = 0;
00444 
00445     /* See if we hit any thresholds */
00446     if (MmAvailablePages == MmHighMemoryThreshold)
00447     {
00448         /* Clear the high memory event */
00449         KeClearEvent(MiHighMemoryEvent);
00450     }
00451     else if (MmAvailablePages == MmLowMemoryThreshold)
00452     {
00453         /* Signal the low memory event */
00454         KeSetEvent(MiLowMemoryEvent, 0, FALSE);
00455     }
00456 
00457     /* One less page */
00458     if (--MmAvailablePages < MmMinimumFreePages)
00459     {
00460         /* FIXME: Should wake up the MPW and working set manager, if we had one */
00461 
00462         DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages);
00463 
00464         /* Call RosMm and see if it can release any pages for us */
00465         MmRebalanceMemoryConsumers();
00466     }
00467 
00468 #if MI_TRACE_PFNS
00469     //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
00470     Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
00471     memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
00472     //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
00473     //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
00474 #endif
00475 
00476     /* Return the page */
00477     return PageIndex;
00478 }
00479 
00480 PFN_NUMBER
00481 NTAPI
00482 MiRemoveAnyPage(IN ULONG Color)
00483 {
00484     PFN_NUMBER PageIndex;
00485     PMMPFN Pfn1;
00486 
00487     /* Make sure PFN lock is held and we have pages */
00488     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00489     ASSERT(MmAvailablePages != 0);
00490     ASSERT(Color < MmSecondaryColors);
00491 
00492     /* Check the colored free list */
00493     PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
00494     if (PageIndex == LIST_HEAD)
00495     {
00496         /* Check the colored zero list */
00497         PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
00498         if (PageIndex == LIST_HEAD)
00499         {
00500             /* Check the free list */
00501             ASSERT_LIST_INVARIANT(&MmFreePageListHead);
00502             PageIndex = MmFreePageListHead.Flink;
00503             Color = PageIndex & MmSecondaryColorMask;
00504             if (PageIndex == LIST_HEAD)
00505             {
00506                 /* Check the zero list */
00507                 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
00508                 PageIndex = MmZeroedPageListHead.Flink;
00509                 Color = PageIndex & MmSecondaryColorMask;
00510                 ASSERT(PageIndex != LIST_HEAD);
00511                 if (PageIndex == LIST_HEAD)
00512                 {
00513                     /* FIXME: Should check the standby list */
00514                     ASSERT(MmZeroedPageListHead.Total == 0);
00515                 }
00516             }
00517         }
00518     }
00519 
00520     /* Remove the page from its list */
00521     PageIndex = MiRemovePageByColor(PageIndex, Color);
00522 
00523     /* Sanity checks */
00524     Pfn1 = MI_PFN_ELEMENT(PageIndex);
00525     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
00526            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
00527     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00528     ASSERT(Pfn1->u2.ShareCount == 0);
00529     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
00530     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
00531 
00532     /* Return the page */
00533     return PageIndex;
00534 }
00535 
00536 PFN_NUMBER
00537 NTAPI
00538 MiRemoveZeroPage(IN ULONG Color)
00539 {
00540     PFN_NUMBER PageIndex;
00541     PMMPFN Pfn1;
00542     BOOLEAN Zero = FALSE;
00543 
00544     /* Make sure PFN lock is held and we have pages */
00545     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00546     ASSERT(MmAvailablePages != 0);
00547     ASSERT(Color < MmSecondaryColors);
00548 
00549     /* Check the colored zero list */
00550     PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
00551     if (PageIndex == LIST_HEAD)
00552     {
00553         /* Check the zero list */
00554         ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
00555         PageIndex = MmZeroedPageListHead.Flink;
00556         if (PageIndex == LIST_HEAD)
00557         {
00558             /* This means there's no zero pages, we have to look for free ones */
00559             ASSERT(MmZeroedPageListHead.Total == 0);
00560             Zero = TRUE;
00561 
00562             /* Check the colored free list */
00563             PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
00564             if (PageIndex == LIST_HEAD)
00565             {
00566                 /* Check the free list */
00567                 ASSERT_LIST_INVARIANT(&MmFreePageListHead);
00568                 PageIndex = MmFreePageListHead.Flink;
00569                 Color = PageIndex & MmSecondaryColorMask;
00570                 ASSERT(PageIndex != LIST_HEAD);
00571                 if (PageIndex == LIST_HEAD)
00572                 {
00573                     /* FIXME: Should check the standby list */
00574                     ASSERT(MmZeroedPageListHead.Total == 0);
00575                 }
00576             }
00577         }
00578         else
00579         {
00580             Color = PageIndex & MmSecondaryColorMask;
00581         }
00582     }
00583 
00584     /* Sanity checks */
00585     Pfn1 = MI_PFN_ELEMENT(PageIndex);
00586     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
00587            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
00588 
00589     /* Remove the page from its list */
00590     PageIndex = MiRemovePageByColor(PageIndex, Color);
00591     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
00592 
00593     /* Zero it, if needed */
00594     if (Zero) MiZeroPhysicalPage(PageIndex);
00595 
00596     /* Sanity checks */
00597     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00598     ASSERT(Pfn1->u2.ShareCount == 0);
00599     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
00600     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
00601 
00602     /* Return the page */
00603     return PageIndex;
00604 }
00605 
00606 VOID
00607 NTAPI
00608 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
00609 {
00610     PMMPFNLIST ListHead;
00611     PFN_NUMBER LastPage;
00612     PMMPFN Pfn1;
00613     ULONG Color;
00614     PMMPFN Blink;
00615     PMMCOLOR_TABLES ColorTable;
00616 
00617     /* Make sure the page index is valid */
00618     ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
00619     ASSERT((PageFrameIndex != 0) &&
00620            (PageFrameIndex <= MmHighestPhysicalPage) &&
00621            (PageFrameIndex >= MmLowestPhysicalPage));
00622 
00623     /* Get the PFN entry */
00624     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
00625 
00626     /* Sanity checks that a right kind of page is being inserted here */
00627     ASSERT(Pfn1->u4.MustBeCached == 0);
00628     ASSERT(Pfn1->u3.e1.Rom != 1);
00629     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
00630     ASSERT(Pfn1->u4.VerifierAllocation == 0);
00631     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00632 
00633     /* Get the free page list and increment its count */
00634     ListHead = &MmFreePageListHead;
00635     ASSERT_LIST_INVARIANT(ListHead);
00636     ListHead->Total++;
00637 
00638     /* Get the last page on the list */
00639     LastPage = ListHead->Blink;
00640     if (LastPage != LIST_HEAD)
00641     {
00642         /* Link us with the previous page, so we're at the end now */
00643         MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
00644     }
00645     else
00646     {
00647         /* The list is empty, so we are the first page */
00648         ListHead->Flink = PageFrameIndex;
00649     }
00650 
00651     /* Now make the list head point back to us (since we go at the end) */
00652     ListHead->Blink = PageFrameIndex;
00653     ASSERT_LIST_INVARIANT(ListHead);
00654 
00655     /* And initialize our own list pointers */
00656     Pfn1->u1.Flink = LIST_HEAD;
00657     Pfn1->u2.Blink = LastPage;
00658 
00659     /* Set the list name and default priority */
00660     Pfn1->u3.e1.PageLocation = FreePageList;
00661     Pfn1->u4.Priority = 3;
00662 
00663     /* Clear some status fields */
00664     Pfn1->u4.InPageError = 0;
00665     Pfn1->u4.AweAllocation = 0;
00666 
00667     /* Increase available pages */
00668     MmAvailablePages++;
00669 
00670     /* Check if we've reached the configured low memory threshold */
00671     if (MmAvailablePages == MmLowMemoryThreshold)
00672     {
00673         /* Clear the event, because now we're ABOVE the threshold */
00674         KeClearEvent(MiLowMemoryEvent);
00675     }
00676     else if (MmAvailablePages == MmHighMemoryThreshold)
00677     {
00678         /* Otherwise check if we reached the high threshold and signal the event */
00679         KeSetEvent(MiHighMemoryEvent, 0, FALSE);
00680     }
00681 
00682     /* Get the page color */
00683     Color = PageFrameIndex & MmSecondaryColorMask;
00684 
00685     /* Get the first page on the color list */
00686     ColorTable = &MmFreePagesByColor[FreePageList][Color];
00687     if (ColorTable->Flink == LIST_HEAD)
00688     {
00689         /* The list is empty, so we are the first page */
00690         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
00691         ColorTable->Flink = PageFrameIndex;
00692     }
00693     else
00694     {
00695         /* Get the previous page */
00696         Blink = (PMMPFN)ColorTable->Blink;
00697 
00698         /* Make it link to us, and link back to it */
00699         Blink->OriginalPte.u.Long = PageFrameIndex;
00700         Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
00701     }
00702 
00703     /* Now initialize our own list pointers */
00704     ColorTable->Blink = Pfn1;
00705 
00706     /* This page is now the last */
00707     Pfn1->OriginalPte.u.Long = LIST_HEAD;
00708 
00709     /* And increase the count in the colored list */
00710     ColorTable->Count++;
00711 
00712     /* Notify zero page thread if enough pages are on the free list now */
00713     if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive))
00714     {
00715         /* Set the event */
00716         MmZeroingPageThreadActive = TRUE;
00717         KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
00718     }
00719 
00720 #if MI_TRACE_PFNS
00721     Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
00722     RtlZeroMemory(Pfn1->ProcessName, 16);
00723 #endif
00724 }
00725 
00726 VOID
00727 FASTCALL
00728 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
00729 {
00730     PMMPFNLIST ListHead;
00731     PFN_NUMBER Flink;
00732     PMMPFN Pfn1, Pfn2;
00733 
00734     /* Make sure the lock is held */
00735     DPRINT1("Inserting page: %lx into standby list !\n", PageFrameIndex);
00736     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00737 
00738     /* Make sure the PFN is valid */
00739     ASSERT((PageFrameIndex != 0) &&
00740            (PageFrameIndex <= MmHighestPhysicalPage) &&
00741            (PageFrameIndex >= MmLowestPhysicalPage));
00742 
00743     /* Grab the PFN and validate it is the right kind of PFN being inserted */
00744     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
00745     ASSERT(Pfn1->u4.MustBeCached == 0);
00746     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00747     ASSERT(Pfn1->u3.e1.PrototypePte == 1);
00748     ASSERT(Pfn1->u3.e1.Rom != 1);
00749 
00750     /* One more transition page on a list */
00751     MmTransitionSharedPages++;
00752 
00753     /* Get the standby page list and increment its count */
00754     ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
00755     ASSERT_LIST_INVARIANT(ListHead);
00756     ListHead->Total++;
00757 
00758     /* Make the head of the list point to this page now */
00759     Flink = ListHead->Flink;
00760     ListHead->Flink = PageFrameIndex;
00761 
00762     /* Make the page point to the previous head, and back to the list */
00763     Pfn1->u1.Flink = Flink;
00764     Pfn1->u2.Blink = LIST_HEAD;
00765 
00766     /* Was the list empty? */
00767     if (Flink != LIST_HEAD)
00768     {
00769         /* It wasn't, so update the backlink of the previous head page */
00770         Pfn2 = MI_PFN_ELEMENT(Flink);
00771         Pfn2->u2.Blink = PageFrameIndex;
00772     }
00773     else
00774     {
00775         /* It was empty, so have it loop back around to this new page */
00776         ListHead->Blink = PageFrameIndex;
00777     }
00778 
00779     /* Move the page onto its new location */
00780     Pfn1->u3.e1.PageLocation = StandbyPageList;
00781 
00782     /* One more page on the system */
00783     MmAvailablePages++;
00784 
00785     /* Check if we've reached the configured low memory threshold */
00786     if (MmAvailablePages == MmLowMemoryThreshold)
00787     {
00788         /* Clear the event, because now we're ABOVE the threshold */
00789         KeClearEvent(MiLowMemoryEvent);
00790     }
00791     else if (MmAvailablePages == MmHighMemoryThreshold)
00792     {
00793         /* Otherwise check if we reached the high threshold and signal the event */
00794         KeSetEvent(MiHighMemoryEvent, 0, FALSE);
00795     }
00796 }
00797 
00798 VOID
00799 NTAPI
00800 MiInsertPageInList(IN PMMPFNLIST ListHead,
00801                    IN PFN_NUMBER PageFrameIndex)
00802 {
00803     PFN_NUMBER Flink, LastPage;
00804     PMMPFN Pfn1, Pfn2;
00805     MMLISTS ListName;
00806     PMMCOLOR_TABLES ColorHead;
00807     ULONG Color;
00808 
00809     /* For free pages, use MiInsertPageInFreeList */
00810     ASSERT(ListHead != &MmFreePageListHead);
00811 
00812     /* Make sure the lock is held */
00813     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00814 
00815     /* Make sure the PFN is valid */
00816     ASSERT((PageFrameIndex) &&
00817            (PageFrameIndex <= MmHighestPhysicalPage) &&
00818            (PageFrameIndex >= MmLowestPhysicalPage));
00819 
00820     /* Page should be unused */
00821     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
00822     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00823     ASSERT(Pfn1->u3.e1.Rom != 1);
00824 
00825     /* Is a standby or modified page being inserted? */
00826     ListName = ListHead->ListName;
00827     if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
00828     {
00829         /* If the page is in transition, it must also be a prototype page */
00830         if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
00831             (Pfn1->OriginalPte.u.Soft.Transition == 1))
00832         {
00833             /* Crash the system on inconsistency */
00834             KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
00835         }
00836     }
00837 
00838     /* Standby pages are prioritized, so we need to get the real head */
00839     if (ListHead == &MmStandbyPageListHead)
00840     {
00841         /* Obviously the prioritized list should still have the same name */
00842         ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
00843         ASSERT(ListHead->ListName == ListName);
00844     }
00845 
00846     /* Increment the list count */
00847     ListHead->Total++;
00848 
00849     /* Is a modified page being inserted? */
00850     if (ListHead == &MmModifiedPageListHead)
00851     {
00852         /* For now, only single-prototype pages should end up in this path */
00853         DPRINT1("Modified page being added: %lx\n", PageFrameIndex);
00854         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
00855 
00856         /* Modified pages are colored when they are selected for page file */
00857         ListHead = &MmModifiedPageListByColor[0];
00858         ASSERT (ListHead->ListName == ListName);
00859         ListHead->Total++;
00860 
00861         /* Increment the number of paging file modified pages */
00862         MmTotalPagesForPagingFile++;
00863     }
00864 
00865     /* Don't handle bad pages yet yet */
00866     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
00867 
00868     /* Zero pages go to the head, all other pages go to the end */
00869     if (ListName == ZeroedPageList)
00870     {
00871         /* Make the head of the list point to this page now */
00872         Flink = ListHead->Flink;
00873         ListHead->Flink = PageFrameIndex;
00874 
00875         /* Make the page point to the previous head, and back to the list */
00876         Pfn1->u1.Flink = Flink;
00877         Pfn1->u2.Blink = LIST_HEAD;
00878 
00879         /* Was the list empty? */
00880         if (Flink != LIST_HEAD)
00881         {
00882             /* It wasn't, so update the backlink of the previous head page */
00883             Pfn2 = MI_PFN_ELEMENT(Flink);
00884             Pfn2->u2.Blink = PageFrameIndex;
00885         }
00886         else
00887         {
00888             /* It was empty, so have it loop back around to this new page */
00889             ListHead->Blink = PageFrameIndex;
00890         }
00891     }
00892     else
00893     {
00894         /* Get the last page on the list */
00895         LastPage = ListHead->Blink;
00896         if (LastPage != LIST_HEAD)
00897         {
00898             /* Link us with the previous page, so we're at the end now */
00899             MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
00900         }
00901         else
00902         {
00903             /* The list is empty, so we are the first page */
00904             ListHead->Flink = PageFrameIndex;
00905         }
00906 
00907         /* Now make the list head point back to us (since we go at the end) */
00908         ListHead->Blink = PageFrameIndex;
00909         ASSERT_LIST_INVARIANT(ListHead);
00910 
00911         /* And initialize our own list pointers */
00912         Pfn1->u1.Flink = LIST_HEAD;
00913         Pfn1->u2.Blink = LastPage;
00914     }
00915 
00916     /* Move the page onto its new location */
00917     Pfn1->u3.e1.PageLocation = ListName;
00918 
00919     /* For zero/free pages, we also have to handle the colored lists */
00920     if (ListName <= StandbyPageList)
00921     {
00922         /* One more page on the system */
00923         MmAvailablePages++;
00924 
00925         /* Check if we've reached the configured low memory threshold */
00926         if (MmAvailablePages == MmLowMemoryThreshold)
00927         {
00928             /* Clear the event, because now we're ABOVE the threshold */
00929             KeClearEvent(MiLowMemoryEvent);
00930         }
00931         else if (MmAvailablePages == MmHighMemoryThreshold)
00932         {
00933             /* Otherwise check if we reached the high threshold and signal the event */
00934             KeSetEvent(MiHighMemoryEvent, 0, FALSE);
00935         }
00936 
00937         /* Sanity checks */
00938         ASSERT(ListName == ZeroedPageList);
00939         ASSERT(Pfn1->u4.InPageError == 0);
00940 
00941         /* Get the page color */
00942         Color = PageFrameIndex & MmSecondaryColorMask;
00943 
00944         /* Get the list for this color */
00945         ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
00946 
00947         /* Get the old head */
00948         Flink = ColorHead->Flink;
00949 
00950         /* Make this page point back to the list, and point forwards to the old head */
00951         Pfn1->OriginalPte.u.Long = Flink;
00952         Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
00953 
00954         /* Set the new head */
00955         ColorHead->Flink = PageFrameIndex;
00956 
00957         /* Was the head empty? */
00958         if (Flink != LIST_HEAD)
00959         {
00960             /* No, so make the old head point to this page */
00961             Pfn2 = MI_PFN_ELEMENT(Flink);
00962             Pfn2->u4.PteFrame = PageFrameIndex;
00963         }
00964         else
00965         {
00966             /* Yes, make it loop back to this page */
00967             ColorHead->Blink = (PVOID)Pfn1;
00968         }
00969 
00970         /* One more paged on the colored list */
00971         ColorHead->Count++;
00972 
00973 #if MI_TRACE_PFNS
00974             //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
00975             Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
00976             MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
00977             RtlZeroMemory(Pfn1->ProcessName, 16);
00978 #endif
00979     }
00980     else if (ListName == ModifiedPageList)
00981     {
00982         /* In ARM3, page must be destined for page file, and not yet written out */
00983         ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
00984         ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
00985 
00986         /* One more transition page */
00987         ASSERT(Pfn1->u3.e1.PrototypePte == 1);
00988         MmTransitionSharedPages++;
00989 
00990         /* Increment the number of per-process modified pages */
00991         PsGetCurrentProcess()->ModifiedPageCount++;
00992 
00993         /* FIXME: Wake up modified page writer if there are not enough free pages */
00994     }
00995     else if (ListName == ModifiedNoWritePageList)
00996     {
00997         /* This list is not yet implemented */
00998         ASSERT(FALSE);
00999     }
01000 }
01001 
01002 VOID
01003 NTAPI
01004 MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
01005                 IN PMMPTE PointerPte,
01006                 IN BOOLEAN Modified)
01007 {
01008     PMMPFN Pfn1;
01009     NTSTATUS Status;
01010     PMMPTE PointerPtePte;
01011     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01012 
01013     /* Setup the PTE */
01014     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
01015     Pfn1->PteAddress = PointerPte;
01016 
01017     /* Check if this PFN is part of a valid address space */
01018     if (PointerPte->u.Hard.Valid == 1)
01019     {
01020         /* Only valid from MmCreateProcessAddressSpace path */
01021         ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
01022 
01023         /* Make this a demand zero PTE */
01024         MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
01025     }
01026     else
01027     {
01028         /* Copy the PTE data */
01029         Pfn1->OriginalPte = *PointerPte;
01030         ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
01031                  (Pfn1->OriginalPte.u.Soft.Transition == 1)));
01032     }
01033 
01034     /* Otherwise this is a fresh page -- set it up */
01035     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
01036     Pfn1->u3.e2.ReferenceCount = 1;
01037     Pfn1->u2.ShareCount = 1;
01038     Pfn1->u3.e1.PageLocation = ActiveAndValid;
01039     ASSERT(Pfn1->u3.e1.Rom == 0);
01040     Pfn1->u3.e1.Modified = Modified;
01041 
01042     /* Get the page table for the PTE */
01043     PointerPtePte = MiAddressToPte(PointerPte);
01044     if (PointerPtePte->u.Hard.Valid == 0)
01045     {
01046         /* Make sure the PDE gets paged in properly */
01047         Status = MiCheckPdeForPagedPool(PointerPte);
01048         if (!NT_SUCCESS(Status))
01049         {
01050             /* Crash */
01051             KeBugCheckEx(MEMORY_MANAGEMENT,
01052                          0x61940,
01053                          (ULONG_PTR)PointerPte,
01054                          (ULONG_PTR)PointerPtePte->u.Long,
01055                          (ULONG_PTR)MiPteToAddress(PointerPte));
01056         }
01057     }
01058 
01059     /* Get the PFN for the page table */
01060     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
01061     ASSERT(PageFrameIndex != 0);
01062     Pfn1->u4.PteFrame = PageFrameIndex;
01063 
01064     /* Increase its share count so we don't get rid of it */
01065     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
01066     Pfn1->u2.ShareCount++;
01067 }
01068 
01069 VOID
01070 NTAPI
01071 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
01072                                IN PMMPTE PointerPte,
01073                                IN MMPTE TempPte)
01074 {
01075     PMMPFN Pfn1;
01076     NTSTATUS Status;
01077     PMMPTE PointerPtePte;
01078     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01079 
01080     /* PTE must be invalid */
01081     ASSERT(PointerPte->u.Hard.Valid == 0);
01082 
01083     /* Setup the PTE */
01084     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
01085     Pfn1->PteAddress = PointerPte;
01086     Pfn1->OriginalPte = DemandZeroPte;
01087 
01088     /* Otherwise this is a fresh page -- set it up */
01089     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
01090     Pfn1->u3.e2.ReferenceCount++;
01091     Pfn1->u2.ShareCount++;
01092     Pfn1->u3.e1.PageLocation = ActiveAndValid;
01093     ASSERT(Pfn1->u3.e1.Rom == 0);
01094     Pfn1->u3.e1.Modified = 1;
01095 
01096     /* Get the page table for the PTE */
01097     PointerPtePte = MiAddressToPte(PointerPte);
01098     if (PointerPtePte->u.Hard.Valid == 0)
01099     {
01100         /* Make sure the PDE gets paged in properly */
01101         Status = MiCheckPdeForPagedPool(PointerPte);
01102         if (!NT_SUCCESS(Status))
01103         {
01104             /* Crash */
01105             KeBugCheckEx(MEMORY_MANAGEMENT,
01106                          0x61940,
01107                          (ULONG_PTR)PointerPte,
01108                          (ULONG_PTR)PointerPtePte->u.Long,
01109                          (ULONG_PTR)MiPteToAddress(PointerPte));
01110         }
01111     }
01112 
01113     /* Get the PFN for the page table */
01114     PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
01115     ASSERT(PageFrameIndex != 0);
01116     Pfn1->u4.PteFrame = PageFrameIndex;
01117 
01118     /* Increase its share count so we don't get rid of it */
01119     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
01120     Pfn1->u2.ShareCount++;
01121 
01122     /* Write valid PTE */
01123     MI_WRITE_VALID_PTE(PointerPte, TempPte);
01124 }
01125 
01126 
01127 PFN_NUMBER
01128 NTAPI
01129 MiAllocatePfn(IN PMMPTE PointerPte,
01130               IN ULONG Protection)
01131 {
01132     KIRQL OldIrql;
01133     PFN_NUMBER PageFrameIndex;
01134     MMPTE TempPte;
01135 
01136     /* Sanity check that we aren't passed a valid PTE */
01137     ASSERT(PointerPte->u.Hard.Valid == 0);
01138 
01139     /* Make an empty software PTE */
01140     MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
01141 
01142     /* Lock the PFN database */
01143     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01144 
01145     /* Check if we're running low on pages */
01146     if (MmAvailablePages < 128)
01147     {
01148         DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages);
01149 
01150         //MiEnsureAvailablePageOrWait(NULL, OldIrql);
01151 
01152         /* Call RosMm and see if it can release any pages for us */
01153         MmRebalanceMemoryConsumers();
01154     }
01155 
01156     /* Grab a page */
01157     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
01158     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
01159     PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
01160 
01161     /* Write the software PTE */
01162     MI_WRITE_INVALID_PTE(PointerPte, TempPte);
01163     PointerPte->u.Soft.Protection |= Protection;
01164 
01165     /* Initialize its PFN entry */
01166     MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
01167 
01168     /* Release the PFN lock and return the page */
01169     ASSERT_LIST_INVARIANT(&MmFreePageListHead);
01170     ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
01171     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01172     return PageFrameIndex;
01173 }
01174 
01175 VOID
01176 NTAPI
01177 MiDecrementShareCount(IN PMMPFN Pfn1,
01178                       IN PFN_NUMBER PageFrameIndex)
01179 {
01180     PMMPTE PointerPte;
01181     MMPTE TempPte;
01182 
01183     ASSERT(PageFrameIndex > 0);
01184     ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
01185     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
01186     ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
01187 
01188     /* Page must be in-use */
01189     if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
01190         (Pfn1->u3.e1.PageLocation != StandbyPageList))
01191     {
01192         /* Otherwise we have PFN corruption */
01193         KeBugCheckEx(PFN_LIST_CORRUPT,
01194                      0x99,
01195                      PageFrameIndex,
01196                      Pfn1->u3.e1.PageLocation,
01197                      0);
01198     }
01199 
01200     /* Check if the share count is now 0 */
01201     ASSERT(Pfn1->u2.ShareCount < 0xF000000);
01202     if (!--Pfn1->u2.ShareCount)
01203     {
01204         /* Was this a prototype PTE? */
01205         if (Pfn1->u3.e1.PrototypePte)
01206         {
01207             /* Grab the PTE address and make sure it's in prototype pool */
01208             PointerPte = Pfn1->PteAddress;
01209             ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
01210 
01211             /* The PTE that backs it should also be valdi */
01212             PointerPte = MiAddressToPte(PointerPte);
01213             ASSERT(PointerPte->u.Hard.Valid == 1);
01214 
01215             /* Get the original prototype PTE and turn it into a transition PTE */
01216             PointerPte = Pfn1->PteAddress;
01217             TempPte = *PointerPte;
01218             TempPte.u.Soft.Transition = 1;
01219             TempPte.u.Soft.Valid = 0;
01220             TempPte.u.Soft.Prototype = 0;
01221             TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
01222             MI_WRITE_INVALID_PTE(PointerPte, TempPte);
01223             DPRINT1("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
01224         }
01225 
01226         /* Put the page in transition */
01227         Pfn1->u3.e1.PageLocation = TransitionPage;
01228 
01229         /* PFN lock must be held */
01230         ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01231 
01232         /* Page should at least have one reference */
01233         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
01234         if (Pfn1->u3.e2.ReferenceCount == 1)
01235         {
01236             /* Is there still a PFN for this page? */
01237             if (MI_IS_PFN_DELETED(Pfn1) == TRUE)
01238             {
01239                 /* Clear the last reference */
01240                 Pfn1->u3.e2.ReferenceCount = 0;
01241                 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
01242 
01243                 /* Mark the page temporarily as valid, we're going to make it free soon */
01244                 Pfn1->u3.e1.PageLocation = ActiveAndValid;
01245 
01246                 /* Bring it back into the free list */
01247                 MiInsertPageInFreeList(PageFrameIndex);
01248             }
01249             else
01250             {
01251                 /* PFN not yet deleted, drop a ref count */
01252                 MiDecrementReferenceCount(Pfn1, PageFrameIndex);
01253             }
01254         }
01255         else
01256         {
01257             /* Otherwise, just drop the reference count */
01258             InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
01259         }
01260     }
01261 }
01262 
01263 VOID
01264 NTAPI
01265 MiDecrementReferenceCount(IN PMMPFN Pfn1,
01266                           IN PFN_NUMBER PageFrameIndex)
01267 {
01268     /* PFN lock must be held */
01269     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
01270 
01271     /* Sanity checks on the page */
01272     ASSERT(PageFrameIndex < MmHighestPhysicalPage);
01273     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
01274     ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
01275 
01276     /* Dereference the page, bail out if it's still alive */
01277     InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
01278     if (Pfn1->u3.e2.ReferenceCount) return;
01279 
01280     /* Nobody should still have reference to this page */
01281     if (Pfn1->u2.ShareCount != 0)
01282     {
01283         /* Otherwise something's really wrong */
01284         KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
01285     }
01286 
01287     /* And it should be lying on some page list */
01288     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
01289 
01290     /* Did someone set the delete flag? */
01291     if (MI_IS_PFN_DELETED(Pfn1))
01292     {
01293         /* Insert it into the free list, there's nothing left to do */
01294         MiInsertPageInFreeList(PageFrameIndex);
01295         return;
01296     }
01297 
01298     /* Check to see which list this page should go into */
01299     ASSERT(FALSE);
01300     if (Pfn1->u3.e1.Modified == 1)
01301     {
01302         /* Push it into the modified page list */
01303         MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
01304     }
01305     else
01306     {
01307         /* Otherwise, insert this page into the standby list */
01308         ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
01309         MiInsertStandbyListAtFront(PageFrameIndex);
01310     }
01311 }
01312 
01313 VOID
01314 NTAPI
01315 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
01316                                IN PMMPTE PointerPte,
01317                                IN PFN_NUMBER PteFrame)
01318 {
01319     PMMPFN Pfn1;
01320 
01321     /* Setup the PTE */
01322     Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
01323     Pfn1->PteAddress = PointerPte;
01324 
01325     /* Make this a software PTE */
01326     MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
01327 
01328     /* Setup the page */
01329     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
01330     Pfn1->u3.e2.ReferenceCount = 1;
01331     Pfn1->u2.ShareCount = 1;
01332     Pfn1->u3.e1.PageLocation = ActiveAndValid;
01333     Pfn1->u3.e1.Modified = TRUE;
01334     Pfn1->u4.InPageError = FALSE;
01335 
01336     /* Did we get a PFN for the page table */
01337     if (PteFrame)
01338     {
01339         /* Store it */
01340         Pfn1->u4.PteFrame = PteFrame;
01341 
01342         /* Increase its share count so we don't get rid of it */
01343         Pfn1 = MI_PFN_ELEMENT(PteFrame);
01344         Pfn1->u2.ShareCount++;
01345     }
01346 }
01347 
01348 /* EOF */

Generated on Sun May 27 2012 04:37:34 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.