[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / freelist.c
index b909751..62a5e62 100644 (file)
 #define MODULE_INVOLVED_IN_ARM3
 #include "ARM3/miarm.h"
 
-/* GLOBALS ****************************************************************/
+#define ASSERT_IS_ROS_PFN(x) ASSERT(MI_IS_ROS_PFN(x) == TRUE);
 
-// ReactOS to NT Physical Page Descriptor Entry Legacy Mapping Definitions
-#define PHYSICAL_PAGE        MMPFN
-#define PPHYSICAL_PAGE       PMMPFN
+/* GLOBALS ****************************************************************/
 
-PPHYSICAL_PAGE MmPfnDatabase;
+PMMPFN MmPfnDatabase;
 
 PFN_NUMBER MmAvailablePages;
 PFN_NUMBER MmResidentAvailablePages;
@@ -38,7 +36,7 @@ SIZE_T MmSharedCommit;
 SIZE_T MmDriverCommit;
 SIZE_T MmProcessCommit;
 SIZE_T MmPagedPoolCommit;
-SIZE_T MmPeakCommitment; 
+SIZE_T MmPeakCommitment;
 SIZE_T MmtotalCommitLimitMaximum;
 
 static RTL_BITMAP MiUserPfnBitMap;
@@ -50,7 +48,7 @@ NTAPI
 MiInitializeUserPfnBitmap(VOID)
 {
     PVOID Bitmap;
-    
+
     /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */
     Bitmap = ExAllocatePoolWithTag(NonPagedPool,
                                    (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
@@ -60,7 +58,7 @@ MiInitializeUserPfnBitmap(VOID)
     /* Initialize it and clear all the bits to begin with */
     RtlInitializeBitMap(&MiUserPfnBitMap,
                         Bitmap,
-                        MmHighestPhysicalPage + 1);
+                        (ULONG)MmHighestPhysicalPage + 1);
     RtlClearAllBits(&MiUserPfnBitMap);
 }
 
@@ -70,13 +68,13 @@ MmGetLRUFirstUserPage(VOID)
 {
     ULONG Position;
     KIRQL OldIrql;
-    
+
     /* Find the first user page */
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
     Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
     if (Position == 0xFFFFFFFF) return 0;
-    
+
     /* Return it */
     ASSERT(Position != 0);
     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
@@ -92,8 +90,9 @@ MmInsertLRULastUserPage(PFN_NUMBER Pfn)
     /* Set the page as a user page */
     ASSERT(Pfn != 0);
     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Pfn));
+    ASSERT(!RtlCheckBit(&MiUserPfnBitMap, (ULONG)Pfn));
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    RtlSetBit(&MiUserPfnBitMap, Pfn);
+    RtlSetBit(&MiUserPfnBitMap, (ULONG)Pfn);
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
 }
 
@@ -103,13 +102,13 @@ MmGetLRUNextUserPage(PFN_NUMBER PreviousPfn)
 {
     ULONG Position;
     KIRQL OldIrql;
-    
+
     /* Find the next user page */
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    Position = RtlFindSetBits(&MiUserPfnBitMap, 1, PreviousPfn + 1);
+    Position = RtlFindSetBits(&MiUserPfnBitMap, 1, (ULONG)PreviousPfn + 1);
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
     if (Position == 0xFFFFFFFF) return 0;
-    
+
     /* Return it */
     ASSERT(Position != 0);
     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Position));
@@ -120,10 +119,15 @@ VOID
 NTAPI
 MmRemoveLRUUserPage(PFN_NUMBER Page)
 {
+    KIRQL OldIrql;
+
     /* Unset the page as a user page */
     ASSERT(Page != 0);
     ASSERT_IS_ROS_PFN(MiGetPfnEntry(Page));
-    RtlClearBit(&MiUserPfnBitMap, Page);
+    ASSERT(RtlCheckBit(&MiUserPfnBitMap, (ULONG)Page));
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    RtlClearBit(&MiUserPfnBitMap, (ULONG)Page);
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
 }
 
 BOOLEAN
@@ -158,27 +162,28 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
     PFN_NUMBER PageCount, LowPage, HighPage, SkipPages, PagesFound = 0, Page;
     PPFN_NUMBER MdlPage, LastMdlPage;
     KIRQL OldIrql;
-    PPHYSICAL_PAGE Pfn1;
+    PMMPFN Pfn1;
     INT LookForZeroedPages;
     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
-    
+    DPRINT1("ARM3-DEBUG: Being called with %I64x %I64x %I64x %lx %d %lu\n", LowAddress, HighAddress, SkipBytes, TotalBytes, CacheAttribute, MdlFlags);
+
     //
     // Convert the low address into a PFN
     //
     LowPage = (PFN_NUMBER)(LowAddress.QuadPart >> PAGE_SHIFT);
-    
+
     //
     // Convert, and normalize, the high address into a PFN
     //
-    HighPage = (PFN_NUMBER)(HighAddress.QuadPart >> PAGE_SHIFT);    
+    HighPage = (PFN_NUMBER)(HighAddress.QuadPart >> PAGE_SHIFT);
     if (HighPage > MmHighestPhysicalPage) HighPage = MmHighestPhysicalPage;
-    
+
     //
     // Validate skipbytes and convert them into pages
     //
     if (BYTE_OFFSET(SkipBytes.LowPart)) return NULL;
     SkipPages = (PFN_NUMBER)(SkipBytes.QuadPart >> PAGE_SHIFT);
-    
+
     /* This isn't supported at all */
     if (SkipPages) DPRINT1("WARNING: Caller requesting SkipBytes, MDL might be mismatched\n");
 
@@ -193,7 +198,7 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
         //
         Mdl = MmCreateMdl(NULL, NULL, PageCount << PAGE_SHIFT);
         if (Mdl) break;
-        
+
         //
         // This function is not required to return the amount of pages requested
         // In fact, it can return as little as 1 page, and callers are supposed
@@ -202,22 +207,22 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
         //
         PageCount -= (PageCount >> 4);
     } while (PageCount);
-    
+
     //
     // Wow, not even a single page was around!
     //
     if (!Mdl) return NULL;
-    
+
     //
     // This is where the page array starts....
     //
     MdlPage = (PPFN_NUMBER)(Mdl + 1);
-    
+
     //
     // Lock the PFN database
     //
     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    
+
     //
     // Are we looking for any pages, without discriminating?
     //
@@ -238,15 +243,15 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
                 ASSERT(PagesFound);
                 break;
             }
-            
+
             /* Grab the page entry for it */
             Pfn1 = MiGetPfnEntry(Page);
-            
+
             //
             // Make sure it's really free
             //
             ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
-            
+
             /* Now setup the page and mark it */
             Pfn1->u3.e2.ReferenceCount = 1;
             Pfn1->u2.ShareCount = 1;
@@ -255,7 +260,7 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
             Pfn1->u3.e1.StartOfAllocation = 1;
             Pfn1->u3.e1.EndOfAllocation = 1;
             Pfn1->u4.VerifierAllocation = 0;
-            
+
             //
             // Save it into the MDL
             //
@@ -280,24 +285,24 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
                 //
                 Pfn1 = MiGetPfnEntry(Page);
                 ASSERT(Pfn1);
-                
+
                 //
                 // Make sure it's free and if this is our first pass, zeroed
                 //
                 if (MiIsPfnInUse(Pfn1)) continue;
                 if ((Pfn1->u3.e1.PageLocation == ZeroedPageList) != LookForZeroedPages) continue;
-                
+
                 /* Remove the page from the free or zero list */
                 ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
                 MI_SET_USAGE(MI_USAGE_MDL);
                 MI_SET_PROCESS2("Kernel");
                 MiUnlinkFreeOrZeroedPage(Pfn1);
-                
+
                 //
                 // Sanity checks
                 //
                 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
-                
+
                 //
                 // Now setup the page and mark it
                 //
@@ -315,19 +320,19 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
                 *MdlPage++ = Page;
                 if (++PagesFound == PageCount) break;
             }
-            
+
             //
             // If the first pass was enough, don't keep going, otherwise, go again
             //
             if (PagesFound == PageCount) break;
         }
     }
-    
+
     //
     // Now release the PFN count
     //
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-    
+
     //
     // We might've found less pages, but not more ;-)
     //
@@ -338,20 +343,20 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
         // If we didn' tfind any pages at all, fail
         //
         DPRINT1("NO MDL PAGES!\n");
-        ExFreePool(Mdl);
+        ExFreePoolWithTag(Mdl, TAG_MDL);
         return NULL;
     }
-    
+
     //
     // Write out how many pages we found
     //
     Mdl->ByteCount = (ULONG)(PagesFound << PAGE_SHIFT);
-    
+
     //
     // Terminate the MDL array if there's certain missing pages
     //
     if (PagesFound != PageCount) *MdlPage = LIST_HEAD;
-    
+
     //
     // Now go back and loop over all the MDL pages
     //
@@ -364,7 +369,7 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
         //
         Page = *MdlPage++;
         if (Page == LIST_HEAD) break;
-        
+
         //
         // Get the PFN entry for the page and check if we should zero it out
         //
@@ -373,12 +378,12 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
         if (Pfn1->u3.e1.PageLocation != ZeroedPageList) MiZeroPhysicalPage(Page);
         Pfn1->u3.e1.PageLocation = ActiveAndValid;
     }
-    
+
     //
     // We're done, mark the pages as locked
     //
     Mdl->Process = NULL;
-    Mdl->MdlFlags |= MDL_PAGES_LOCKED; 
+    Mdl->MdlFlags |= MDL_PAGES_LOCKED;
     return Mdl;
 }
 
@@ -388,7 +393,7 @@ MmSetRmapListHeadPage(PFN_NUMBER Pfn, PMM_RMAP_ENTRY ListHead)
 {
     KIRQL oldIrql;
     PMMPFN Pfn1;
-    
+
     oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
     Pfn1 = MiGetPfnEntry(Pfn);
     ASSERT(Pfn1);
@@ -398,21 +403,21 @@ MmSetRmapListHeadPage(PFN_NUMBER Pfn, PMM_RMAP_ENTRY ListHead)
     {
         /* Should not be trying to insert an RMAP for a non-active page */
         ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
-        
+
         /* Set the list head address */
-        MI_GET_ROS_DATA(Pfn1)->RmapListHead = ListHead;
+        Pfn1->RmapListHead = ListHead;
     }
     else
     {
         /* ReactOS semantics dictate the page is STILL active right now */
         ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
-        
+
         /* In this case, the RMAP is actually being removed, so clear field */
-        MI_GET_ROS_DATA(Pfn1)->RmapListHead = NULL;
+        Pfn1->RmapListHead = NULL;
 
         /* ReactOS semantics will now release the page, which will make it free and enter a colored list */
     }
-    
+
     KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
 }
 
@@ -431,13 +436,13 @@ MmGetRmapListHeadPage(PFN_NUMBER Pfn)
     Pfn1 = MiGetPfnEntry(Pfn);
     ASSERT(Pfn1);
     ASSERT_IS_ROS_PFN(Pfn1);
-    
+
     /* Get the list head */
-    ListHead = MI_GET_ROS_DATA(Pfn1)->RmapListHead;
-  
+    ListHead = Pfn1->RmapListHead;
+
     /* Should not have an RMAP for a non-active page */
     ASSERT(MiIsPfnInUse(Pfn1) == TRUE);
-   
+
     /* Release PFN database and return rmap list head */
     KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
     return ListHead;
@@ -448,14 +453,14 @@ NTAPI
 MmSetSavedSwapEntryPage(PFN_NUMBER Pfn,  SWAPENTRY SwapEntry)
 {
    KIRQL oldIrql;
-   PPHYSICAL_PAGE Page;
-   
-   Page = MiGetPfnEntry(Pfn);
-   ASSERT(Page);
-   ASSERT_IS_ROS_PFN(Page);
-   
+   PMMPFN Pfn1;
+
+   Pfn1 = MiGetPfnEntry(Pfn);
+   ASSERT(Pfn1);
+   ASSERT_IS_ROS_PFN(Pfn1);
+
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   MI_GET_ROS_DATA(Page)->SwapEntry = SwapEntry;
+   Pfn1->u1.SwapEntry = SwapEntry;
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
 }
 
@@ -465,14 +470,14 @@ MmGetSavedSwapEntryPage(PFN_NUMBER Pfn)
 {
    SWAPENTRY SwapEntry;
    KIRQL oldIrql;
-   PPHYSICAL_PAGE Page;
-   
-   Page = MiGetPfnEntry(Pfn);
-   ASSERT(Page);
-   ASSERT_IS_ROS_PFN(Page);
+   PMMPFN Pfn1;
+
+   Pfn1 = MiGetPfnEntry(Pfn);
+   ASSERT(Pfn1);
+   ASSERT_IS_ROS_PFN(Pfn1);
 
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   SwapEntry = MI_GET_ROS_DATA(Page)->SwapEntry;
+   SwapEntry = Pfn1->u1.SwapEntry;
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
 
    return(SwapEntry);
@@ -482,20 +487,20 @@ VOID
 NTAPI
 MmReferencePage(PFN_NUMBER Pfn)
 {
-   PPHYSICAL_PAGE Page;
+   PMMPFN Pfn1;
 
    DPRINT("MmReferencePage(PysicalAddress %x)\n", Pfn << PAGE_SHIFT);
 
-   if (Pfn == 0 || Pfn > MmHighestPhysicalPage)
-   {
-      return;
-   }
+   ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+   ASSERT(Pfn != 0);
+   ASSERT(Pfn <= MmHighestPhysicalPage);
+
+   Pfn1 = MiGetPfnEntry(Pfn);
+   ASSERT(Pfn1);
+   ASSERT_IS_ROS_PFN(Pfn1);
 
-   Page = MiGetPfnEntry(Pfn);
-   ASSERT(Page);
-   ASSERT_IS_ROS_PFN(Page);
-   
-   Page->u3.e2.ReferenceCount++;
+   ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+   Pfn1->u3.e2.ReferenceCount++;
 }
 
 ULONG
@@ -504,16 +509,16 @@ MmGetReferenceCountPage(PFN_NUMBER Pfn)
 {
    KIRQL oldIrql;
    ULONG RCount;
-   PPHYSICAL_PAGE Page;
+   PMMPFN Pfn1;
 
    DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
 
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   Page = MiGetPfnEntry(Pfn);
-   ASSERT(Page);
-   ASSERT_IS_ROS_PFN(Page);
+   Pfn1 = MiGetPfnEntry(Pfn);
+   ASSERT(Pfn1);
+   ASSERT_IS_ROS_PFN(Pfn1);
 
-   RCount = Page->u3.e2.ReferenceCount;
+   RCount = Pfn1->u3.e2.ReferenceCount;
 
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
    return(RCount);
@@ -530,23 +535,22 @@ VOID
 NTAPI
 MmDereferencePage(PFN_NUMBER Pfn)
 {
-   PPHYSICAL_PAGE Page;
+   PMMPFN Pfn1;
    DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
 
-   Page = MiGetPfnEntry(Pfn);
-   ASSERT(Page);
-   ASSERT_IS_ROS_PFN(Page);
-   
-   Page->u3.e2.ReferenceCount--;
-   if (Page->u3.e2.ReferenceCount == 0)
+   Pfn1 = MiGetPfnEntry(Pfn);
+   ASSERT(Pfn1);
+   ASSERT_IS_ROS_PFN(Pfn1);
+
+   ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+   Pfn1->u3.e2.ReferenceCount--;
+   if (Pfn1->u3.e2.ReferenceCount == 0)
    {
         /* Mark the page temporarily as valid, we're going to make it free soon */
-        Page->u3.e1.PageLocation = ActiveAndValid;
-        
+        Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
         /* It's not a ROS PFN anymore */
-        Page->u4.AweAllocation = FALSE;
-        ExFreePool(MI_GET_ROS_DATA(Page));
-        Page->RosMmData = 0;
+        Pfn1->u4.AweAllocation = FALSE;
 
         /* Bring it back into the free list */
         DPRINT("Legacy free: %lx\n", Pfn);
@@ -560,7 +564,7 @@ MmAllocPage(ULONG Type)
 {
    PFN_NUMBER PfnOffset;
    PMMPFN Pfn1;
-   
+
    PfnOffset = MiRemoveZeroPage(MI_GET_NEXT_COLOR());
 
    if (!PfnOffset)
@@ -573,17 +577,14 @@ MmAllocPage(ULONG Type)
    Pfn1 = MiGetPfnEntry(PfnOffset);
    Pfn1->u3.e2.ReferenceCount = 1;
    Pfn1->u3.e1.PageLocation = ActiveAndValid;
-   
+
    /* This marks the PFN as a ReactOS PFN */
    Pfn1->u4.AweAllocation = TRUE;
-   
+
    /* Allocate the extra ReactOS Data and zero it out */
-   Pfn1->RosMmData = (LONG)ExAllocatePoolWithTag(NonPagedPool, sizeof(MMROSPFN), 'RsPf');
-   ASSERT(MI_GET_ROS_DATA(Pfn1) != NULL);
-   ASSERT_IS_ROS_PFN(Pfn1);
-   MI_GET_ROS_DATA(Pfn1)->SwapEntry = 0;
-   MI_GET_ROS_DATA(Pfn1)->RmapListHead = NULL;
-   
+   Pfn1->u1.SwapEntry = 0;
+   Pfn1->RmapListHead = NULL;
+
    return PfnOffset;
 }