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

freelist.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS kernel
00004  * FILE:            ntoskrnl/mm/freelist.c
00005  * PURPOSE:         Handle the list of free physical pages
00006  *
00007  * PROGRAMMERS:     David Welch (welch@cwcom.net)
00008  *                  Robert Bergkvist
00009  */
00010 
00011 /* INCLUDES ****************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 #if defined (ALLOC_PRAGMA)
00018 #pragma alloc_text(INIT, MmInitializePageList)
00019 #endif
00020 
00021 #define MODULE_INVOLVED_IN_ARM3
00022 #include "ARM3/miarm.h"
00023 
00024 /* GLOBALS ****************************************************************/
00025 
00026 // ReactOS to NT Physical Page Descriptor Entry Legacy Mapping Definitions
00027 #define PHYSICAL_PAGE        MMPFN
00028 #define PPHYSICAL_PAGE       PMMPFN
00029 
00030 PPHYSICAL_PAGE MmPfnDatabase;
00031 
00032 PFN_NUMBER MmAvailablePages;
00033 PFN_NUMBER MmResidentAvailablePages;
00034 PFN_NUMBER MmResidentAvailableAtInit;
00035 
00036 SIZE_T MmTotalCommittedPages;
00037 SIZE_T MmSharedCommit;
00038 SIZE_T MmDriverCommit;
00039 SIZE_T MmProcessCommit;
00040 SIZE_T MmPagedPoolCommit;
00041 SIZE_T MmPeakCommitment;
00042 SIZE_T MmtotalCommitLimitMaximum;
00043 
00044 static RTL_BITMAP MiUserPfnBitMap;
00045 
00046 /* FUNCTIONS *************************************************************/
00047 
00048 VOID
00049 NTAPI
00050 MiInitializeUserPfnBitmap(VOID)
00051 {
00052     PVOID Bitmap;
00053 
00054     /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
00055     Bitmap = ExAllocatePoolWithTag(NonPagedPool,
00056                                    (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
00057                                    '  mM');
00058     ASSERT(Bitmap);
00059 
00060     /* Initialize it and clear all the bits to begin with */
00061     RtlInitializeBitMap(&MiUserPfnBitMap,
00062                         Bitmap,
00063                         (ULONG)MmHighestPhysicalPage + 1);
00064     RtlClearAllBits(&MiUserPfnBitMap);
00065 }
00066 
00067 PFN_NUMBER
00068 NTAPI
00069 MmGetLRUFirstUserPage(VOID)
00070 {
00071     ULONG Position;
00072     KIRQL OldIrql;
00073 
00074     /* Find the first user page */
00075     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00076     Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
00077     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00078     if (Position == 0xFFFFFFFF) return 0;
00079 
00080     /* Return it */
00081     ASSERT(Position != 0);
00082     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
00083     return Position;
00084 }
00085 
00086 VOID
00087 NTAPI
00088 MmInsertLRULastUserPage(PFN_NUMBER Pfn)
00089 {
00090     KIRQL OldIrql;
00091 
00092     /* Set the page as a user page */
00093     ASSERT(Pfn != 0);
00094     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Pfn));
00095     ASSERT(!RtlCheckBit(&MiUserPfnBitMap, (ULONG)Pfn));
00096     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00097     RtlSetBit(&MiUserPfnBitMap, (ULONG)Pfn);
00098     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00099 }
00100 
00101 PFN_NUMBER
00102 NTAPI
00103 MmGetLRUNextUserPage(PFN_NUMBER PreviousPfn)
00104 {
00105     ULONG Position;
00106     KIRQL OldIrql;
00107 
00108     /* Find the next user page */
00109     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00110     Position = RtlFindSetBits(&MiUserPfnBitMap, 1, (ULONG)PreviousPfn + 1);
00111     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00112     if (Position == 0xFFFFFFFF) return 0;
00113 
00114     /* Return it */
00115     ASSERT(Position != 0);
00116     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
00117     return Position;
00118 }
00119 
00120 VOID
00121 NTAPI
00122 MmRemoveLRUUserPage(PFN_NUMBER Page)
00123 {
00124     KIRQL OldIrql;
00125 
00126     /* Unset the page as a user page */
00127     ASSERT(Page != 0);
00128     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Page));
00129     ASSERT(RtlCheckBit(&MiUserPfnBitMap, (ULONG)Page));
00130     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00131     RtlClearBit(&MiUserPfnBitMap, (ULONG)Page);
00132     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00133 }
00134 
00135 BOOLEAN
00136 NTAPI
00137 MiIsPfnFree(IN PMMPFN Pfn1)
00138 {
00139     /* Must be a free or zero page, with no references, linked */
00140     return ((Pfn1->u3.e1.PageLocation <= StandbyPageList) &&
00141             (Pfn1->u1.Flink) &&
00142             (Pfn1->u2.Blink) &&
00143             !(Pfn1->u3.e2.ReferenceCount));
00144 }
00145 
00146 BOOLEAN
00147 NTAPI
00148 MiIsPfnInUse(IN PMMPFN Pfn1)
00149 {
00150     /* Standby list or higher, unlinked, and with references */
00151     return !MiIsPfnFree(Pfn1);
00152 }
00153 
00154 PMDL
00155 NTAPI
00156 MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
00157                       IN PHYSICAL_ADDRESS HighAddress,
00158                       IN PHYSICAL_ADDRESS SkipBytes,
00159                       IN SIZE_T TotalBytes,
00160                       IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute,
00161                       IN ULONG MdlFlags)
00162 {
00163     PMDL Mdl;
00164     PFN_NUMBER PageCount, LowPage, HighPage, SkipPages, PagesFound = 0, Page;
00165     PPFN_NUMBER MdlPage, LastMdlPage;
00166     KIRQL OldIrql;
00167     PPHYSICAL_PAGE Pfn1;
00168     INT LookForZeroedPages;
00169     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
00170     DPRINT1("ARM3-DEBUG: Being called with %I64x %I64x %I64x %lx %d %d\n", LowAddress, HighAddress, SkipBytes, TotalBytes, CacheAttribute, MdlFlags);
00171 
00172     //
00173     // Convert the low address into a PFN
00174     //
00175     LowPage = (PFN_NUMBER)(LowAddress.QuadPart >> PAGE_SHIFT);
00176 
00177     //
00178     // Convert, and normalize, the high address into a PFN
00179     //
00180     HighPage = (PFN_NUMBER)(HighAddress.QuadPart >> PAGE_SHIFT);
00181     if (HighPage > MmHighestPhysicalPage) HighPage = MmHighestPhysicalPage;
00182 
00183     //
00184     // Validate skipbytes and convert them into pages
00185     //
00186     if (BYTE_OFFSET(SkipBytes.LowPart)) return NULL;
00187     SkipPages = (PFN_NUMBER)(SkipBytes.QuadPart >> PAGE_SHIFT);
00188 
00189     /* This isn't supported at all */
00190     if (SkipPages) DPRINT1("WARNING: Caller requesting SkipBytes, MDL might be mismatched\n");
00191 
00192     //
00193     // Now compute the number of pages the MDL will cover
00194     //
00195     PageCount = (PFN_NUMBER)ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, TotalBytes);
00196     do
00197     {
00198         //
00199         // Try creating an MDL for these many pages
00200         //
00201         Mdl = MmCreateMdl(NULL, NULL, PageCount << PAGE_SHIFT);
00202         if (Mdl) break;
00203 
00204         //
00205         // This function is not required to return the amount of pages requested
00206         // In fact, it can return as little as 1 page, and callers are supposed
00207         // to deal with this scenario. So re-attempt the allocation with less
00208         // pages than before, and see if it worked this time.
00209         //
00210         PageCount -= (PageCount >> 4);
00211     } while (PageCount);
00212 
00213     //
00214     // Wow, not even a single page was around!
00215     //
00216     if (!Mdl) return NULL;
00217 
00218     //
00219     // This is where the page array starts....
00220     //
00221     MdlPage = (PPFN_NUMBER)(Mdl + 1);
00222 
00223     //
00224     // Lock the PFN database
00225     //
00226     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00227 
00228     //
00229     // Are we looking for any pages, without discriminating?
00230     //
00231     if ((LowPage == 0) && (HighPage == MmHighestPhysicalPage))
00232     {
00233         //
00234         // Well then, let's go shopping
00235         //
00236         while (PagesFound < PageCount)
00237         {
00238             /* Grab a page */
00239             MI_SET_USAGE(MI_USAGE_MDL);
00240             MI_SET_PROCESS2("Kernel");
00241             Page = MiRemoveAnyPage(0);
00242             if (Page == 0)
00243             {
00244                 /* This is not good... hopefully we have at least SOME pages */
00245                 ASSERT(PagesFound);
00246                 break;
00247             }
00248 
00249             /* Grab the page entry for it */
00250             Pfn1 = MiGetPfnEntry(Page);
00251 
00252             //
00253             // Make sure it's really free
00254             //
00255             ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00256 
00257             /* Now setup the page and mark it */
00258             Pfn1->u3.e2.ReferenceCount = 1;
00259             Pfn1->u2.ShareCount = 1;
00260             MI_SET_PFN_DELETED(Pfn1);
00261             Pfn1->u4.PteFrame = 0x1FFEDCB;
00262             Pfn1->u3.e1.StartOfAllocation = 1;
00263             Pfn1->u3.e1.EndOfAllocation = 1;
00264             Pfn1->u4.VerifierAllocation = 0;
00265 
00266             //
00267             // Save it into the MDL
00268             //
00269             *MdlPage++ = MiGetPfnEntryIndex(Pfn1);
00270             PagesFound++;
00271         }
00272     }
00273     else
00274     {
00275         //
00276         // You want specific range of pages. We'll do this in two runs
00277         //
00278         for (LookForZeroedPages = 1; LookForZeroedPages >= 0; LookForZeroedPages--)
00279         {
00280             //
00281             // Scan the range you specified
00282             //
00283             for (Page = LowPage; Page < HighPage; Page++)
00284             {
00285                 //
00286                 // Get the PFN entry for this page
00287                 //
00288                 Pfn1 = MiGetPfnEntry(Page);
00289                 ASSERT(Pfn1);
00290 
00291                 //
00292                 // Make sure it's free and if this is our first pass, zeroed
00293                 //
00294                 if (MiIsPfnInUse(Pfn1)) continue;
00295                 if ((Pfn1->u3.e1.PageLocation == ZeroedPageList) != LookForZeroedPages) continue;
00296 
00297                 /* Remove the page from the free or zero list */
00298                 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
00299                 MI_SET_USAGE(MI_USAGE_MDL);
00300                 MI_SET_PROCESS2("Kernel");
00301                 MiUnlinkFreeOrZeroedPage(Pfn1);
00302 
00303                 //
00304                 // Sanity checks
00305                 //
00306                 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
00307 
00308                 //
00309                 // Now setup the page and mark it
00310                 //
00311                 Pfn1->u3.e2.ReferenceCount = 1;
00312                 Pfn1->u2.ShareCount = 1;
00313                 MI_SET_PFN_DELETED(Pfn1);
00314                 Pfn1->u4.PteFrame = 0x1FFEDCB;
00315                 Pfn1->u3.e1.StartOfAllocation = 1;
00316                 Pfn1->u3.e1.EndOfAllocation = 1;
00317                 Pfn1->u4.VerifierAllocation = 0;
00318 
00319                 //
00320                 // Save this page into the MDL
00321                 //
00322                 *MdlPage++ = Page;
00323                 if (++PagesFound == PageCount) break;
00324             }
00325 
00326             //
00327             // If the first pass was enough, don't keep going, otherwise, go again
00328             //
00329             if (PagesFound == PageCount) break;
00330         }
00331     }
00332 
00333     //
00334     // Now release the PFN count
00335     //
00336     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00337 
00338     //
00339     // We might've found less pages, but not more ;-)
00340     //
00341     if (PagesFound != PageCount) ASSERT(PagesFound < PageCount);
00342     if (!PagesFound)
00343     {
00344         //
00345         // If we didn' tfind any pages at all, fail
00346         //
00347         DPRINT1("NO MDL PAGES!\n");
00348         ExFreePool(Mdl);
00349         return NULL;
00350     }
00351 
00352     //
00353     // Write out how many pages we found
00354     //
00355     Mdl->ByteCount = (ULONG)(PagesFound << PAGE_SHIFT);
00356 
00357     //
00358     // Terminate the MDL array if there's certain missing pages
00359     //
00360     if (PagesFound != PageCount) *MdlPage = LIST_HEAD;
00361 
00362     //
00363     // Now go back and loop over all the MDL pages
00364     //
00365     MdlPage = (PPFN_NUMBER)(Mdl + 1);
00366     LastMdlPage = MdlPage + PagesFound;
00367     while (MdlPage < LastMdlPage)
00368     {
00369         //
00370         // Check if we've reached the end
00371         //
00372         Page = *MdlPage++;
00373         if (Page == LIST_HEAD) break;
00374 
00375         //
00376         // Get the PFN entry for the page and check if we should zero it out
00377         //
00378         Pfn1 = MiGetPfnEntry(Page);
00379         ASSERT(Pfn1);
00380         if (Pfn1->u3.e1.PageLocation != ZeroedPageList) MiZeroPhysicalPage(Page);
00381         Pfn1->u3.e1.PageLocation = ActiveAndValid;
00382     }
00383 
00384     //
00385     // We're done, mark the pages as locked
00386     //
00387     Mdl->Process = NULL;
00388     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
00389     return Mdl;
00390 }
00391 
00392 VOID
00393 NTAPI
00394 MmSetRmapListHeadPage(PFN_NUMBER Pfn, PMM_RMAP_ENTRY ListHead)
00395 {
00396     KIRQL oldIrql;
00397     PMMPFN Pfn1;
00398 
00399     oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00400     Pfn1 = MiGetPfnEntry(Pfn);
00401     ASSERT(Pfn1);
00402     ASSERT_IS_ROS_PFN(Pfn1);
00403 
00404     if (ListHead)
00405     {
00406         /* Should not be trying to insert an RMAP for a non-active page */
00407         ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
00408 
00409         /* Set the list head address */
00410         MI_GET_ROS_DATA(Pfn1)->RmapListHead = ListHead;
00411     }
00412     else
00413     {
00414         /* ReactOS semantics dictate the page is STILL active right now */
00415         ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
00416 
00417         /* In this case, the RMAP is actually being removed, so clear field */
00418         MI_GET_ROS_DATA(Pfn1)->RmapListHead = NULL;
00419 
00420         /* ReactOS semantics will now release the page, which will make it free and enter a colored list */
00421     }
00422 
00423     KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
00424 }
00425 
00426 PMM_RMAP_ENTRY
00427 NTAPI
00428 MmGetRmapListHeadPage(PFN_NUMBER Pfn)
00429 {
00430     KIRQL oldIrql;
00431     PMM_RMAP_ENTRY ListHead;
00432     PMMPFN Pfn1;
00433 
00434     /* Lock PFN database */
00435     oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00436 
00437     /* Get the entry */
00438     Pfn1 = MiGetPfnEntry(Pfn);
00439     ASSERT(Pfn1);
00440     ASSERT_IS_ROS_PFN(Pfn1);
00441 
00442     /* Get the list head */
00443     ListHead = MI_GET_ROS_DATA(Pfn1)->RmapListHead;
00444 
00445     /* Should not have an RMAP for a non-active page */
00446     ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
00447 
00448     /* Release PFN database and return rmap list head */
00449     KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
00450     return ListHead;
00451 }
00452 
00453 VOID
00454 NTAPI
00455 MmSetSavedSwapEntryPage(PFN_NUMBER Pfn,  SWAPENTRY SwapEntry)
00456 {
00457    KIRQL oldIrql;
00458    PPHYSICAL_PAGE Page;
00459 
00460    Page = MiGetPfnEntry(Pfn);
00461    ASSERT(Page);
00462    ASSERT_IS_ROS_PFN(Page);
00463 
00464    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00465    MI_GET_ROS_DATA(Page)->SwapEntry = SwapEntry;
00466    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
00467 }
00468 
00469 SWAPENTRY
00470 NTAPI
00471 MmGetSavedSwapEntryPage(PFN_NUMBER Pfn)
00472 {
00473    SWAPENTRY SwapEntry;
00474    KIRQL oldIrql;
00475    PPHYSICAL_PAGE Page;
00476 
00477    Page = MiGetPfnEntry(Pfn);
00478    ASSERT(Page);
00479    ASSERT_IS_ROS_PFN(Page);
00480 
00481    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00482    SwapEntry = MI_GET_ROS_DATA(Page)->SwapEntry;
00483    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
00484 
00485    return(SwapEntry);
00486 }
00487 
00488 VOID
00489 NTAPI
00490 MmReferencePage(PFN_NUMBER Pfn)
00491 {
00492    PPHYSICAL_PAGE Page;
00493 
00494    DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn << PAGE_SHIFT);
00495 
00496    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00497    ASSERT(Pfn != 0);
00498    ASSERT(Pfn <= MmHighestPhysicalPage);
00499 
00500    Page = MiGetPfnEntry(Pfn);
00501    ASSERT(Page);
00502    ASSERT_IS_ROS_PFN(Page);
00503 
00504    ASSERT(Page->u3.e2.ReferenceCount != 0);
00505    Page->u3.e2.ReferenceCount++;
00506 }
00507 
00508 ULONG
00509 NTAPI
00510 MmGetReferenceCountPage(PFN_NUMBER Pfn)
00511 {
00512    KIRQL oldIrql;
00513    ULONG RCount;
00514    PPHYSICAL_PAGE Page;
00515 
00516    DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
00517 
00518    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00519    Page = MiGetPfnEntry(Pfn);
00520    ASSERT(Page);
00521    ASSERT_IS_ROS_PFN(Page);
00522 
00523    RCount = Page->u3.e2.ReferenceCount;
00524 
00525    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
00526    return(RCount);
00527 }
00528 
00529 BOOLEAN
00530 NTAPI
00531 MmIsPageInUse(PFN_NUMBER Pfn)
00532 {
00533     return MiIsPfnInUse(MiGetPfnEntry(Pfn));
00534 }
00535 
00536 VOID
00537 NTAPI
00538 MmDereferencePage(PFN_NUMBER Pfn)
00539 {
00540    PPHYSICAL_PAGE Page;
00541    DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
00542 
00543    Page = MiGetPfnEntry(Pfn);
00544    ASSERT(Page);
00545    ASSERT_IS_ROS_PFN(Page);
00546 
00547    ASSERT(Page->u3.e2.ReferenceCount != 0);
00548    Page->u3.e2.ReferenceCount--;
00549    if (Page->u3.e2.ReferenceCount == 0)
00550    {
00551         /* Mark the page temporarily as valid, we're going to make it free soon */
00552         Page->u3.e1.PageLocation = ActiveAndValid;
00553 
00554         /* It's not a ROS PFN anymore */
00555         Page->u4.AweAllocation = FALSE;
00556         ExFreePool(MI_GET_ROS_DATA(Page));
00557         Page->RosMmData = 0;
00558 
00559         /* Bring it back into the free list */
00560         DPRINT("Legacy free: %lx\n", Pfn);
00561         MiInsertPageInFreeList(Pfn);
00562    }
00563 }
00564 
00565 PFN_NUMBER
00566 NTAPI
00567 MmAllocPage(ULONG Type)
00568 {
00569    PFN_NUMBER PfnOffset;
00570    PMMPFN Pfn1;
00571 
00572    PfnOffset = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
00573 
00574    if (!PfnOffset)
00575    {
00576        DPRINT1("MmAllocPage(): Out of memory\n");
00577        return 0;
00578    }
00579 
00580    DPRINT("Legacy allocate: %lx\n", PfnOffset);
00581    Pfn1 = MiGetPfnEntry(PfnOffset);
00582    Pfn1->u3.e2.ReferenceCount = 1;
00583    Pfn1->u3.e1.PageLocation = ActiveAndValid;
00584 
00585    /* This marks the PFN as a ReactOS PFN */
00586    Pfn1->u4.AweAllocation = TRUE;
00587 
00588    /* Allocate the extra ReactOS Data and zero it out */
00589    Pfn1->RosMmData = (LONG)ExAllocatePoolWithTag(NonPagedPool, sizeof(MMROSPFN), 'RsPf');
00590    ASSERT(MI_GET_ROS_DATA(Pfn1) != NULL);
00591    ASSERT_IS_ROS_PFN(Pfn1);
00592    MI_GET_ROS_DATA(Pfn1)->SwapEntry = 0;
00593    MI_GET_ROS_DATA(Pfn1)->RmapListHead = NULL;
00594 
00595    return PfnOffset;
00596 }
00597 
00598 /* EOF */

Generated on Sun May 27 2012 04:37:38 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.