[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / freelist.c
index 9551e18..afdad86 100644 (file)
 //
 // ReactOS to NT Physical Page Descriptor Entry Legacy Mapping Definitions
 //
-typedef union
-{
-    MMPFN;// Pfn;
-
-    struct
-    {
-        LIST_ENTRY ListEntry; // 0x000
-        ULONG_PTR RmapListHead;   // 0x008
-        USHORT ReferenceCount; // 0x00C
-        struct // 0x00$
-        {
-            USHORT _unused1:1;
-            USHORT StartOfAllocation:1;
-            USHORT EndOfAllocation:1;
-            USHORT Zero:1; 
-            USHORT LockCount:4;
-            USHORT Consumer:3;
-            USHORT _unused2:1;
-            USHORT Type:2;
-            USHORT _unused3:1;
-            USHORT _unused4:1;
-        } Flags;
-        LONG MapCount; // 0x10
-        ULONG_PTR SavedSwapEntry; // 0x018
-    };
-} PHYSICAL_PAGE, *PPHYSICAL_PAGE;
-
-C_ASSERT(sizeof(PHYSICAL_PAGE) == sizeof(MMPFN));
-
-#define MiInsertInListTail(x, y) MiInsertInListTail(x, (PMMPFN)y)
-//#define MiGetPfnEntry(Pfn) ((PPHYSICAL_PAGE)MiGetPfnEntry(Pfn))
-#define MiGetPfnEntryIndex(x) MiGetPfnEntryIndex((struct _MMPFN*)x)
-#define LockCount            Flags.LockCount
-
-/* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
-PMMPFN MmPfnDatabase[2];
-#define MmPfnDatabase ((PPHYSICAL_PAGE*)MmPfnDatabase)
-
-//#define MMPFN PHYSICAL_PAGE
-//#define PMMPFN PPHYSICAL_PAGE
+//        REACTOS                 NT
+//
+#define RmapListHead         AweReferenceCount
+#define PHYSICAL_PAGE        MMPFN
+#define PPHYSICAL_PAGE       PMMPFN
 
 /* The first array contains ReactOS PFNs, the second contains ARM3 PFNs */
-//PPHYSICAL_PAGE MmPfnDatabase[2];
+PPHYSICAL_PAGE MmPfnDatabase[2];
 
 PFN_NUMBER MmAvailablePages;
 PFN_NUMBER MmResidentAvailablePages;
+PFN_NUMBER MmResidentAvailableAtInit;
 
 SIZE_T MmTotalCommitLimit;
 SIZE_T MmTotalCommittedPages;
@@ -83,7 +49,7 @@ SIZE_T MmPagedPoolCommit;
 SIZE_T MmPeakCommitment; 
 SIZE_T MmtotalCommitLimitMaximum;
 
-static KEVENT ZeroPageThreadEvent;
+KEVENT ZeroPageThreadEvent;
 static BOOLEAN ZeroPageThreadShouldTerminate = FALSE;
 static RTL_BITMAP MiUserPfnBitMap;
 
@@ -108,7 +74,7 @@ MiInitializeUserPfnBitmap(VOID)
     RtlClearAllBits(&MiUserPfnBitMap);
 }
 
-PFN_NUMBER
+PFN_TYPE
 NTAPI
 MmGetLRUFirstUserPage(VOID)
 {
@@ -127,7 +93,7 @@ MmGetLRUFirstUserPage(VOID)
 
 VOID
 NTAPI
-MmInsertLRULastUserPage(PFN_NUMBER Pfn)
+MmInsertLRULastUserPage(PFN_TYPE Pfn)
 {
     KIRQL OldIrql;
 
@@ -137,9 +103,9 @@ MmInsertLRULastUserPage(PFN_NUMBER Pfn)
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
 }
 
-PFN_NUMBER
+PFN_TYPE
 NTAPI
-MmGetLRUNextUserPage(PFN_NUMBER PreviousPfn)
+MmGetLRUNextUserPage(PFN_TYPE PreviousPfn)
 {
     ULONG Position;
     KIRQL OldIrql;
@@ -156,7 +122,7 @@ MmGetLRUNextUserPage(PFN_NUMBER PreviousPfn)
 
 VOID
 NTAPI
-MmRemoveLRUUserPage(PFN_NUMBER Page)
+MmRemoveLRUUserPage(PFN_TYPE Page)
 {
     /* Unset the page as a user page */
     RtlClearBit(&MiUserPfnBitMap, Page);
@@ -164,198 +130,21 @@ MmRemoveLRUUserPage(PFN_NUMBER Page)
 
 BOOLEAN
 NTAPI
-MiIsPfnInUse(IN PMMPFN Pfn1)
+MiIsPfnFree(IN PMMPFN Pfn1)
 {
-    return ((Pfn1->u3.e1.PageLocation != FreePageList) &&
-            (Pfn1->u3.e1.PageLocation != ZeroedPageList));
+    /* Must be a free or zero page, with no references, linked */
+    return ((Pfn1->u3.e1.PageLocation <= StandbyPageList) &&
+            (Pfn1->u1.Flink) &&
+            (Pfn1->u2.Blink) &&
+            !(Pfn1->u3.e2.ReferenceCount));
 }
 
-PFN_NUMBER
+BOOLEAN
 NTAPI
-MiFindContiguousPages(IN PFN_NUMBER LowestPfn,
-                      IN PFN_NUMBER HighestPfn,
-                      IN PFN_NUMBER BoundaryPfn,
-                      IN PFN_NUMBER SizeInPages,
-                      IN MEMORY_CACHING_TYPE CacheType)
+MiIsPfnInUse(IN PMMPFN Pfn1)
 {
-    PFN_NUMBER Page, PageCount, LastPage, Length, BoundaryMask;
-    ULONG i = 0;
-    PMMPFN Pfn1, EndPfn;
-    KIRQL OldIrql;
-    PAGED_CODE ();
-    ASSERT(SizeInPages != 0);
-        
-    //
-    // Convert the boundary PFN into an alignment mask
-    //
-    BoundaryMask = ~(BoundaryPfn - 1);
-    
-    //
-    // Loop all the physical memory blocks
-    //
-    do
-    {
-        //
-        // Capture the base page and length of this memory block
-        //
-        Page = MmPhysicalMemoryBlock->Run[i].BasePage;
-        PageCount = MmPhysicalMemoryBlock->Run[i].PageCount;
-        
-        //
-        // Check how far this memory block will go
-        //
-        LastPage = Page + PageCount;
-        
-        //
-        // Trim it down to only the PFNs we're actually interested in
-        //
-        if ((LastPage - 1) > HighestPfn) LastPage = HighestPfn + 1;
-        if (Page < LowestPfn) Page = LowestPfn;
-        
-        //
-        // Skip this run if it's empty or fails to contain all the pages we need
-        //
-        if (!(PageCount) || ((Page + SizeInPages) > LastPage)) continue;
-        
-        //
-        // Now scan all the relevant PFNs in this run
-        //
-        Length = 0;
-        for (Pfn1 = MiGetPfnEntry(Page); Page < LastPage; Page++, Pfn1++)
-        {
-            //
-            // If this PFN is in use, ignore it
-            //
-            if (MiIsPfnInUse(Pfn1)) continue;
-            
-            //
-            // If we haven't chosen a start PFN yet and the caller specified an
-            // alignment, make sure the page matches the alignment restriction
-            //
-            if ((!(Length) && (BoundaryPfn)) &&
-                (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask)))
-            {
-                //
-                // It does not, so bail out
-                //
-                continue;
-            }
-            
-            //
-            // Increase the number of valid pages, and check if we have enough
-            //
-            if (++Length == SizeInPages)
-            {
-                //
-                // It appears we've amassed enough legitimate pages, rollback
-                //
-                Pfn1 -= (Length - 1);
-                Page -= (Length - 1);
-                
-                //
-                // Acquire the PFN lock
-                //
-                OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-                do
-                {
-                    //
-                    // Things might've changed for us. Is the page still free?
-                    //
-                    if (MiIsPfnInUse(Pfn1)) break;
-                    
-                    //
-                    // So far so good. Is this the last confirmed valid page?
-                    //
-                    if (!--Length)
-                    {
-                        //
-                        // Sanity check that we didn't go out of bounds
-                        //
-                        ASSERT(i != MmPhysicalMemoryBlock->NumberOfRuns);
-                        
-                        //
-                        // Loop until all PFN entries have been processed
-                        //
-                        EndPfn = Pfn1 - SizeInPages + 1;
-                        do
-                        {
-                            //
-                            // This PFN is now a used page, set it up
-                            //
-                            MiUnlinkFreeOrZeroedPage(Pfn1);
-                            Pfn1->u3.e2.ReferenceCount = 1;
-                            
-                            //
-                            // Check if it was already zeroed
-                            //
-                            if (Pfn1->u3.e1.PageLocation != ZeroedPageList)
-                            {
-                                //
-                                // It wasn't, so zero it
-                                //
-                                MiZeroPage(MiGetPfnEntryIndex(Pfn1));
-                            }
-                            
-                            //
-                            // Mark it in use
-                            //
-                            Pfn1->u3.e1.PageLocation = ActiveAndValid;
-
-                            //
-                            // Check if this is the last PFN, otherwise go on
-                            //
-                            if (Pfn1 == EndPfn) break;
-                            Pfn1--;
-                        } while (TRUE);
-                        
-                        //
-                        // Mark the first and last PFN so we can find them later
-                        //
-                        Pfn1->u3.e1.StartOfAllocation = 1;
-                        (Pfn1 + SizeInPages - 1)->u3.e1.EndOfAllocation = 1;
-                        
-                        //
-                        // Now it's safe to let go of the PFN lock
-                        //
-                        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-                        
-                        //
-                        // Quick sanity check that the last PFN is consistent
-                        //
-                        EndPfn = Pfn1 + SizeInPages;
-                        ASSERT(EndPfn == MiGetPfnEntry(Page + 1));
-                        
-                        //
-                        // Compute the first page, and make sure it's consistent
-                        //
-                        Page -= SizeInPages - 1;
-                        ASSERT(Pfn1 == MiGetPfnEntry(Page));
-                        ASSERT(Page != 0);
-                        return Page;                                
-                    }
-                    
-                    //
-                    // Keep going. The purpose of this loop is to reconfirm that
-                    // after acquiring the PFN lock these pages are still usable
-                    //
-                    Pfn1++;
-                    Page++;
-                } while (TRUE);
-                
-                //
-                // If we got here, something changed while we hadn't acquired
-                // the PFN lock yet, so we'll have to restart
-                //
-                KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-                Length = 0;
-            }
-        }
-    } while (++i != MmPhysicalMemoryBlock->NumberOfRuns);
-    
-    //
-    // And if we get here, it means no suitable physical memory runs were found
-    //
-    return 0;    
+    /* Standby list or higher, unlinked, and with references */
+    return !MiIsPfnFree(Pfn1);
 }
 
 PMDL
@@ -371,7 +160,7 @@ MiAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
     PFN_NUMBER PageCount, LowPage, HighPage, SkipPages, PagesFound = 0, Page;
     PPFN_NUMBER MdlPage, LastMdlPage;
     KIRQL OldIrql;
-    PMMPFN Pfn1;
+    PPHYSICAL_PAGE Pfn1;
     INT LookForZeroedPages;
     ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
     
@@ -608,7 +397,7 @@ NTAPI
 MmDumpPfnDatabase(VOID)
 {
     ULONG i;
-    PMMPFN Pfn1;
+    PPHYSICAL_PAGE Pfn1;
     PCHAR State = "????", Type = "Unknown";
     KIRQL OldIrql;
     ULONG Totals[5] = {0}, FreePages = 0;
@@ -646,7 +435,7 @@ MmDumpPfnDatabase(VOID)
                  State,
                  Type,
                  Pfn1->u3.e2.ReferenceCount,
-                 ((PPHYSICAL_PAGE)Pfn1)->RmapListHead);
+                 Pfn1->RmapListHead);
     }
     
     DbgPrint("Nonpaged Pool:       %d pages\t[%d KB]\n", Totals[MC_NPPOOL], (Totals[MC_NPPOOL] << PAGE_SHIFT) / 1024);
@@ -668,12 +457,16 @@ MmInitializePageList(VOID)
     PMEMORY_ALLOCATION_DESCRIPTOR Md;
     PLIST_ENTRY NextEntry;
     ULONG NrSystemPages = 0;
+    KIRQL OldIrql;
 
     /* This is what a used page looks like */
     RtlZeroMemory(&UsedPage, sizeof(UsedPage));
     UsedPage.u3.e1.PageLocation = ActiveAndValid;
     UsedPage.u3.e2.ReferenceCount = 1;
 
+    /* Lock PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
     /* Loop the memory descriptors */
     for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
          NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
@@ -729,6 +522,9 @@ MmInitializePageList(VOID)
         MmPfnDatabase[0][i] = UsedPage;
         NrSystemPages++;
     }
+
+    /* Release the PFN database lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
     
     KeInitializeEvent(&ZeroPageThreadEvent, NotificationEvent, TRUE);
     DPRINT("Pages: %x %x\n", MmAvailablePages, NrSystemPages);
@@ -737,24 +533,24 @@ MmInitializePageList(VOID)
 
 VOID
 NTAPI
-MmSetRmapListHeadPage(PFN_NUMBER Pfn, struct _MM_RMAP_ENTRY* ListHead)
+MmSetRmapListHeadPage(PFN_TYPE Pfn, struct _MM_RMAP_ENTRY* ListHead)
 {
    KIRQL oldIrql;
     
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   ((PPHYSICAL_PAGE)MiGetPfnEntry(Pfn))->RmapListHead = (LONG_PTR)ListHead;
+   MiGetPfnEntry(Pfn)->RmapListHead = (LONG)ListHead;
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
 }
 
 struct _MM_RMAP_ENTRY*
 NTAPI
-MmGetRmapListHeadPage(PFN_NUMBER Pfn)
+MmGetRmapListHeadPage(PFN_TYPE Pfn)
 {
    KIRQL oldIrql;
    struct _MM_RMAP_ENTRY* ListHead;
     
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   ListHead = (struct _MM_RMAP_ENTRY*)((PPHYSICAL_PAGE)MiGetPfnEntry(Pfn))->RmapListHead;
+   ListHead = (struct _MM_RMAP_ENTRY*)MiGetPfnEntry(Pfn)->RmapListHead;
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
     
    return(ListHead);
@@ -762,7 +558,7 @@ MmGetRmapListHeadPage(PFN_NUMBER Pfn)
 
 VOID
 NTAPI
-MmSetSavedSwapEntryPage(PFN_NUMBER Pfn,  SWAPENTRY SwapEntry)
+MmSetSavedSwapEntryPage(PFN_TYPE Pfn,  SWAPENTRY SwapEntry)
 {
    KIRQL oldIrql;
 
@@ -773,7 +569,7 @@ MmSetSavedSwapEntryPage(PFN_NUMBER Pfn,  SWAPENTRY SwapEntry)
 
 SWAPENTRY
 NTAPI
-MmGetSavedSwapEntryPage(PFN_NUMBER Pfn)
+MmGetSavedSwapEntryPage(PFN_TYPE Pfn)
 {
    SWAPENTRY SwapEntry;
    KIRQL oldIrql;
@@ -787,7 +583,7 @@ MmGetSavedSwapEntryPage(PFN_NUMBER Pfn)
 
 VOID
 NTAPI
-MmReferencePage(PFN_NUMBER Pfn)
+MmReferencePage(PFN_TYPE Pfn)
 {
    PPHYSICAL_PAGE Page;
 
@@ -798,7 +594,7 @@ MmReferencePage(PFN_NUMBER Pfn)
       return;
    }
 
-   Page = (PVOID)MiGetPfnEntry(Pfn);
+   Page = MiGetPfnEntry(Pfn);
    ASSERT(Page);
 
    Page->u3.e2.ReferenceCount++;
@@ -806,7 +602,7 @@ MmReferencePage(PFN_NUMBER Pfn)
 
 ULONG
 NTAPI
-MmGetReferenceCountPage(PFN_NUMBER Pfn)
+MmGetReferenceCountPage(PFN_TYPE Pfn)
 {
    KIRQL oldIrql;
    ULONG RCount;
@@ -815,7 +611,7 @@ MmGetReferenceCountPage(PFN_NUMBER Pfn)
    DPRINT("MmGetReferenceCountPage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
 
    oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-   Page = (PVOID)MiGetPfnEntry(Pfn);
+   Page = MiGetPfnEntry(Pfn);
    ASSERT(Page);
 
    RCount = Page->u3.e2.ReferenceCount;
@@ -826,14 +622,14 @@ MmGetReferenceCountPage(PFN_NUMBER Pfn)
 
 BOOLEAN
 NTAPI
-MmIsPageInUse(PFN_NUMBER Pfn)
+MmIsPageInUse(PFN_TYPE Pfn)
 {
     return MiIsPfnInUse(MiGetPfnEntry(Pfn));
 }
 
 VOID
 NTAPI
-MiSetConsumer(IN PFN_NUMBER Pfn,
+MiSetConsumer(IN PFN_TYPE Pfn,
               IN ULONG Type)
 {
     MiGetPfnEntry(Pfn)->u3.e1.PageLocation = ActiveAndValid;
@@ -841,13 +637,13 @@ MiSetConsumer(IN PFN_NUMBER Pfn,
 
 VOID
 NTAPI
-MmDereferencePage(PFN_NUMBER Pfn)
+MmDereferencePage(PFN_TYPE Pfn)
 {
    PPHYSICAL_PAGE Page;
 
    DPRINT("MmDereferencePage(PhysicalAddress %x)\n", Pfn << PAGE_SHIFT);
 
-   Page = (PVOID)MiGetPfnEntry(Pfn);
+   Page = MiGetPfnEntry(Pfn);
    ASSERT(Page);
 
    Page->u3.e2.ReferenceCount--;
@@ -863,11 +659,11 @@ MmDereferencePage(PFN_NUMBER Pfn)
    }
 }
 
-PFN_NUMBER
+PFN_TYPE
 NTAPI
 MmAllocPage(ULONG Type)
 {
-   PFN_NUMBER PfnOffset;
+   PFN_TYPE PfnOffset;
    PPHYSICAL_PAGE PageDescriptor;
    BOOLEAN NeedClear = FALSE;
 
@@ -886,13 +682,13 @@ MmAllocPage(ULONG Type)
          DPRINT1("MmAllocPage(): Out of memory\n");
          return 0;
       }
-      PageDescriptor = (PVOID)MiRemoveHeadList(&MmFreePageListHead);
+      PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
 
       NeedClear = TRUE;
    }
    else
    {
-      PageDescriptor = (PVOID)MiRemoveHeadList(&MmZeroedPageListHead);
+      PageDescriptor = MiRemoveHeadList(&MmZeroedPageListHead);
    }
 
    PageDescriptor->u3.e2.ReferenceCount = 1;
@@ -911,7 +707,7 @@ MmAllocPage(ULONG Type)
 
 NTSTATUS
 NTAPI
-MiZeroPage(PFN_NUMBER Page)
+MiZeroPage(PFN_TYPE Page)
 {
     KIRQL Irql;
     PVOID TempAddress;
@@ -935,7 +731,7 @@ MmZeroPageThreadMain(PVOID Ignored)
    NTSTATUS Status;
    KIRQL oldIrql;
    PPHYSICAL_PAGE PageDescriptor;
-   PFN_NUMBER Pfn;
+   PFN_TYPE Pfn;
    ULONG Count;
 
    /* Free initial kernel memory */
@@ -962,7 +758,7 @@ MmZeroPageThreadMain(PVOID Ignored)
       oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
       while (MmFreePageListHead.Total)
       {
-         PageDescriptor = (PVOID)MiRemoveHeadList(&MmFreePageListHead);
+         PageDescriptor = MiRemoveHeadList(&MmFreePageListHead);
          /* We set the page to used, because MmCreateVirtualMapping failed with unused pages */
          KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
          Pfn = PageDescriptor - MmPfnDatabase[0];