[ros-diffs] [ros-arm-bringup] 41657: - Reimplement MmAllocateContiguousMemory, MmAllocateContiguousMemorySpecifyCache, MmFreeContiguousMemory, MmFreeContiguousMemorySpecifyCache: - Use a smarter algorithm (as described here: http://www.microsoft.com/whdc/Driver/tips/ContigMem.mspx) to first try to satisfy the allocation by a simple nonpaged pool allocation (for cached requests only). - This range is then checked for physical continuity, since it's not guaranteed for non-initial-pool allocations (and right now in ReactOS, it never is). - As a fallback, Windows NT then attempts to scan free nonpaged pool pages. This is not yet implemented since the ReactOS nonpaged pool is not usually contiguous (to the level that NT's is). - When the ARM pool is implemented and replaces nonpaged pool, this code path will have to be implemented. - As a last resort, the actual PFN database is scanned for contiguous free pages. - ReactOS used MmGetContiguousPages for this, which blindly scanned the PFN database. New MiFindContinuousPages will scan the physical memory descriptor block recently implemented, which avoids going over pages we already know are going to be unusable. - The ReactOS function also held the PFN lock for the entire duration of the scan, which is significant on systems with large memory. Instead, we make an initial unsafe scan first, and only lock when we think we've found a correct range (and we'll then reconfirm the ranges). - Finally, the older function actually did a double-scan to try to avoid using memory ranges under 16MB, which was useless on today's systems and also rather inefficient. - Other than that, the actual setup of the PFN entry is copy-pasted from the old ReactOS function, so nothing's changed there -- the page still looks the same, but the selection algorithm is faster and more accurate. - Once the pages are found, we piggyback on the new I/O mapping mechanism (which uses System PTEs) instead of doing it all over by hand as before. - Since the underlying support is still System PTEs, once again, optimizations to that component will yield significant improvements here too.

ros-arm-bringup at svn.reactos.org ros-arm-bringup at svn.reactos.org
Sun Jun 28 10:32:40 CEST 2009


Author: ros-arm-bringup
Date: Sun Jun 28 09:43:12 2009
New Revision: 41657

URL: http://svn.reactos.org/svn/reactos?rev=41657&view=rev
Log:
- Reimplement MmAllocateContiguousMemory, MmAllocateContiguousMemorySpecifyCache, MmFreeContiguousMemory, MmFreeContiguousMemorySpecifyCache:
  - Use a smarter algorithm (as described here: http://www.microsoft.com/whdc/Driver/tips/ContigMem.mspx) to first try to satisfy the allocation by a simple nonpaged pool allocation (for cached requests only).
    - This range is then checked for physical continuity, since it's not guaranteed for non-initial-pool allocations (and right now in ReactOS, it never is).
  - As a fallback, Windows NT then attempts to scan free nonpaged pool pages. This is not yet implemented since the ReactOS nonpaged pool is not usually contiguous (to the level that NT's is).
    - When the ARM pool is implemented and replaces nonpaged pool, this code path will have to be implemented.
  - As a last resort, the actual PFN database is scanned for contiguous free pages.
    - ReactOS used MmGetContiguousPages for this, which blindly scanned the PFN database. New MiFindContinuousPages will scan the physical memory descriptor block recently implemented, which avoids going over pages we already know are going to be unusable.
    - The ReactOS function also held the PFN lock for the entire duration of the scan, which is significant on systems with large memory. Instead, we make an initial unsafe scan first, and only lock when we think we've found a correct range (and we'll then reconfirm the ranges).
    - Finally, the older function actually did a double-scan to try to avoid using memory ranges under 16MB, which was useless on today's systems and also rather inefficient.
    - Other than that, the actual setup of the PFN entry is copy-pasted from the old ReactOS function, so nothing's changed there -- the page still looks the same, but the selection algorithm is faster and more accurate.
  - Once the pages are found, we piggyback on the new I/O mapping mechanism (which uses System PTEs) instead of doing it all over by hand as before.
  - Since the underlying support is still System PTEs, once again, optimizations to that component will yield significant improvements here too.

Added:
    trunk/reactos/ntoskrnl/mm/ARM3/contmem.c
      - copied, changed from r41647, trunk/reactos/ntoskrnl/mm/cont.c
Removed:
    trunk/reactos/ntoskrnl/mm/cont.c
Modified:
    trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
    trunk/reactos/ntoskrnl/mm/freelist.c
    trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild

Copied: trunk/reactos/ntoskrnl/mm/ARM3/contmem.c (from r41647, trunk/reactos/ntoskrnl/mm/cont.c)
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/contmem.c?p2=trunk/reactos/ntoskrnl/mm/ARM3/contmem.c&p1=trunk/reactos/ntoskrnl/mm/cont.c&r1=41647&r2=41657&rev=41657&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/cont.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/contmem.c [iso-8859-1] Sun Jun 28 09:43:12 2009
@@ -1,241 +1,440 @@
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/mm/cont.c
- * PURPOSE:         Manages continuous memory
- *
- * PROGRAMMERS:     David Welch (welch at cwcom.net)
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/mm/ARM3/contmem.c
+ * PURPOSE:         ARM Memory Manager Contiguous Memory Allocator
+ * PROGRAMMERS:     ReactOS Portable Systems Group
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS *****************************************************************/
-
-static VOID
-MmFreeContinuousPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
-                     PFN_TYPE Page, SWAPENTRY SwapEntry,
-                     BOOLEAN Dirty)
-{
-   ASSERT(SwapEntry == 0);
-   if (Page != 0)
-   {
-      MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
-   }
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmAllocateContiguousMemorySpecifyCache at 32
- *
- * DESCRIPTION
-  *  Allocates a range of physically contiguous memory
- * with a cache parameter.
- *
- * ARGUMENTS
- * NumberOfBytes
- *  Size of the memory block to allocate;
- *
- * LowestAcceptableAddress
- *  Lowest address valid for the caller.
- *
- * HighestAcceptableAddress
- *  Highest address valid for the caller.
- *
- * BoundaryAddressMultiple
- *  Address multiple not to be crossed by allocated buffer (optional).
- *
- * CacheType
- *  Type of caching to use.
- *
- * RETURN VALUE
- *  The virtual address of the memory block on success;
- * NULL on error.
- *
- * REVISIONS
- *
+#line 15 "ARM³::CONTMEM"
+#define MODULE_INVOLVED_IN_ARM3
+#include "../ARM3/miarm.h"
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+PVOID
+NTAPI
+MiCheckForContiguousMemory(IN PVOID BaseAddress,
+                           IN PFN_NUMBER BaseAddressPages,
+                           IN PFN_NUMBER SizeInPages,
+                           IN PFN_NUMBER LowestPfn,
+                           IN PFN_NUMBER HighestPfn,
+                           IN PFN_NUMBER BoundaryPfn,
+                           IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute)
+{
+    PMMPTE StartPte, EndPte;
+    PFN_NUMBER PreviousPage = 0, Page, HighPage, BoundaryMask, Pages = 0;
+    
+    //
+    // Okay, first of all check if the PFNs match our restrictions
+    //
+    if (LowestPfn > HighestPfn) return NULL;
+    if (LowestPfn + SizeInPages <= LowestPfn) return NULL;
+    if (LowestPfn + SizeInPages - 1 > HighestPfn) return NULL;
+    if (BaseAddressPages < SizeInPages) return NULL;
+    
+    //
+    // This is the last page we need to get to and the boundary requested
+    //
+    HighPage = HighestPfn + 1 - SizeInPages;
+    BoundaryMask = ~(BoundaryPfn - 1);
+    
+    //
+    // And here's the PTEs for this allocation. Let's go scan them.
+    //
+    StartPte = MiAddressToPte(BaseAddress);
+    EndPte = StartPte + BaseAddressPages;
+    while (StartPte < EndPte)
+    {
+        //
+        // Get this PTE's page number
+        //
+        ASSERT (StartPte->u.Hard.Valid == 1);
+        Page = PFN_FROM_PTE(StartPte);
+        
+        //
+        // Is this the beginning of our adventure?
+        //
+        if (!Pages)
+        {
+            //
+            // Check if this PFN is within our range
+            //
+            if ((Page >= LowestPfn) && (Page <= HighPage))
+            {
+                //
+                // It is! Do you care about boundary (alignment)?
+                //
+                if (!(BoundaryPfn) ||
+                    (!((Page ^ (Page + SizeInPages - 1)) & BoundaryMask)))
+                {
+                    //
+                    // You don't care, or you do care but we deliver
+                    //
+                    Pages++;
+                }
+            }
+            
+            //
+            // Have we found all the pages we need by now?
+            // Incidently, this means you only wanted one page
+            //
+            if (Pages == SizeInPages)
+            {
+                //
+                // Mission complete
+                //
+                return MiPteToAddress(StartPte);
+            }
+        }
+        else
+        {
+            //
+            // Have we found a page that doesn't seem to be contiguous?
+            //
+            if (Page != (PreviousPage + 1))
+            {
+                //
+                // Ah crap, we have to start over
+                //
+                Pages = 0;
+                continue;
+            }
+            
+            //
+            // Otherwise, we're still in the game. Do we have all our pages?
+            //
+            if (++Pages == SizeInPages)
+            {
+                //
+                // We do! This entire range was contiguous, so we'll return it!
+                //
+                return MiPteToAddress(StartPte - Pages + 1);
+            }
+        }
+        
+        //
+        // Try with the next PTE, remember this PFN
+        //
+        PreviousPage = Page;
+        StartPte++;
+        continue;
+    }
+    
+    //
+    // All good returns are within the loop...
+    //
+    return NULL;
+}
+
+PVOID
+NTAPI
+MiFindContiguousMemory(IN PFN_NUMBER LowestPfn,
+                       IN PFN_NUMBER HighestPfn,
+                       IN PFN_NUMBER BoundaryPfn,
+                       IN PFN_NUMBER SizeInPages,
+                       IN MEMORY_CACHING_TYPE CacheType)
+{
+    PFN_NUMBER Page;
+    PHYSICAL_ADDRESS PhysicalAddress;
+    PAGED_CODE ();
+    ASSERT(SizeInPages != 0);
+
+    //
+    // Our last hope is to scan the free page list for contiguous pages
+    //
+    Page = MiFindContiguousPages(LowestPfn,
+                                 HighestPfn,
+                                 BoundaryPfn,
+                                 SizeInPages,
+                                 CacheType);
+    if (!Page) return NULL;
+    
+    //
+    // We'll just piggyback on the I/O memory mapper
+    //
+    PhysicalAddress.QuadPart = Page << PAGE_SHIFT;
+    return MmMapIoSpace(PhysicalAddress, SizeInPages << PAGE_SHIFT, CacheType);
+}
+
+PVOID
+NTAPI
+MiAllocateContiguousMemory(IN SIZE_T NumberOfBytes,
+                           IN PFN_NUMBER LowestAcceptablePfn,
+                           IN PFN_NUMBER HighestAcceptablePfn,
+                           IN PFN_NUMBER BoundaryPfn,
+                           IN MEMORY_CACHING_TYPE CacheType)
+{
+    PVOID BaseAddress;
+    PFN_NUMBER SizeInPages;
+    MI_PFN_CACHE_ATTRIBUTE CacheAttribute;   
+    ASSERT(NumberOfBytes != 0);
+    
+    //
+    // Compute size requested
+    //
+    SizeInPages = BYTES_TO_PAGES(NumberOfBytes);
+    
+    //
+    // Convert the cache attribute and check for cached requests
+    //
+    CacheAttribute = MiPlatformCacheAttributes[FALSE][CacheType];
+    if (CacheAttribute == MiCached)
+    {
+        //
+        // Because initial nonpaged pool is supposed to be contiguous, go ahead
+        // and try making a nonpaged pool allocation first.
+        //
+        BaseAddress = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
+                                            NumberOfBytes,
+                                            'mCmM');
+        if (BaseAddress)
+        {    
+            //
+            // Now make sure it's actually contiguous (if it came from expansion
+            // it might not be).
+            //
+            if (MiCheckForContiguousMemory(BaseAddress,
+                                           SizeInPages,
+                                           SizeInPages,
+                                           LowestAcceptablePfn,
+                                           HighestAcceptablePfn,
+                                           BoundaryPfn,
+                                           CacheAttribute))
+            {
+                //
+                // Sweet, we're in business!
+                //
+                return BaseAddress;
+            }
+            
+            //
+            // No such luck
+            //
+            ExFreePool(BaseAddress);
+        }
+    }
+    
+    //
+    // According to MSDN, the system won't try anything else if you're higher
+    // than APC level.
+    //
+    if (KeGetCurrentIrql() > APC_LEVEL) return NULL;
+    
+    //
+    // Otherwise, we'll go try to find some
+    //
+    return MiFindContiguousMemory(LowestAcceptablePfn,
+                                  HighestAcceptablePfn,
+                                  BoundaryPfn,
+                                  SizeInPages,
+                                  CacheType);
+}
+
+VOID
+NTAPI
+MiFreeContiguousMemory(IN PVOID BaseAddress)
+{
+    KIRQL OldIrql;
+    PFN_NUMBER PageFrameIndex, LastPage, PageCount;
+    PMMPFN Pfn1, StartPfn;
+    PAGED_CODE();
+    
+    //
+    // First, check if the memory came from initial nonpaged pool, or expansion
+    //
+    if (((BaseAddress >= MmNonPagedPoolStart) &&
+         (BaseAddress < (PVOID)((ULONG_PTR)MmNonPagedPoolStart +
+                                MmSizeOfNonPagedPoolInBytes))) ||
+        ((BaseAddress >= MmNonPagedPoolExpansionStart) &&
+         (BaseAddress < MmNonPagedPoolEnd)))
+    {
+        //
+        // It did, so just use the pool to free this
+        //
+        ExFreePool(BaseAddress);
+        return;
+    }
+    
+    //
+    // Otherwise, get the PTE and page number for the allocation
+    //
+    PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(BaseAddress));
+    
+    //
+    // Now get the PFN entry for this, and make sure it's the correct one
+    //
+    Pfn1 = MiGetPfnEntry(PageFrameIndex);        
+    if (Pfn1->u3.e1.StartOfAllocation == 0)
+    {
+        //
+        // This probably means you did a free on an address that was in between
+        //
+        KeBugCheckEx (BAD_POOL_CALLER,
+                      0x60,
+                      (ULONG_PTR)BaseAddress,
+                      0,
+                      0);
+    }
+    
+    //
+    // Now this PFN isn't the start of any allocation anymore, it's going out
+    //
+    StartPfn = Pfn1;
+    Pfn1->u3.e1.StartOfAllocation = 0;
+    
+    //
+    // Look the PFNs
+    //
+    do
+    {
+        //
+        // Until we find the one that marks the end of the allocation
+        //
+    } while (Pfn1++->u3.e1.EndOfAllocation == 0);
+    
+    //
+    // Found it, unmark it
+    //
+    Pfn1--;
+    Pfn1->u3.e1.EndOfAllocation = 0;
+    
+    //
+    // Now compute how many pages this represents
+    //
+    PageCount = (ULONG)(Pfn1 - StartPfn + 1);
+    
+    //
+    // So we can know how much to unmap (recall we piggyback on I/O mappings)
+    //
+    MmUnmapIoSpace(BaseAddress, PageCount << PAGE_SHIFT);
+    
+    //
+    // Lock the PFN database
+    //
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+    
+    //
+    // Loop all the pages
+    //
+    LastPage = PageFrameIndex + PageCount;    
+    do
+    {
+        //
+        // Free each one, and move on
+        //
+        MmReleasePageMemoryConsumer(MC_NPPOOL, PageFrameIndex);
+    } while (++PageFrameIndex < LastPage);
+    
+    //
+    // Release the PFN lock
+    //
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
  * @implemented
  */
-PVOID NTAPI
+PVOID
+NTAPI
 MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes,
                                        IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL,
                                        IN PHYSICAL_ADDRESS HighestAcceptableAddress,
                                        IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL,
                                        IN MEMORY_CACHING_TYPE CacheType OPTIONAL)
 {
-   PMEMORY_AREA MArea;
-   NTSTATUS Status;
-   PVOID BaseAddress = NULL;
-   PFN_TYPE PBase;
-   ULONG Protect;
-   ULONG i;
-
-   Protect = PAGE_EXECUTE_READWRITE | PAGE_SYSTEM;
-   if (CacheType == MmNonCached || CacheType == MmWriteCombined)
-   {
-      Protect |= PAGE_NOCACHE;
-   }
-   if (CacheType == MmWriteCombined)
-   {
-      Protect |= PAGE_WRITECOMBINE;
-   }
-
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
-                               MEMORY_AREA_CONTINUOUS_MEMORY,
-                               &BaseAddress,
-                               NumberOfBytes,
-                               PAGE_READWRITE,
-                               &MArea,
-                               FALSE,
-                               0,
-                               RtlConvertLongToLargeInteger(0));
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-
-   if (!NT_SUCCESS(Status))
-   {
-      return(NULL);
-   }
-   DPRINT( "Base = %x\n", BaseAddress );
-   PBase = MmGetContinuousPages(NumberOfBytes,
-                                LowestAcceptableAddress,
-                                HighestAcceptableAddress,
-                                BoundaryAddressMultiple,
-                                TRUE);
-   if (PBase == 0)
-   {
-      MmLockAddressSpace(MmGetKernelAddressSpace());
-      MmFreeMemoryArea(MmGetKernelAddressSpace(),
-                       MArea,
-                       NULL,
-                       NULL);
-      MmUnlockAddressSpace(MmGetKernelAddressSpace());
-      return(NULL);
-   }
-   for (i = 0; i < (PAGE_ROUND_UP(NumberOfBytes) / PAGE_SIZE); i++, PBase++)
-   {
-      MmCreateVirtualMapping(NULL,
-                             (char*)BaseAddress + (i * PAGE_SIZE),
-                             Protect,
-                             &PBase,
-			     1);
-   }
-   return(BaseAddress);
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmAllocateContiguousMemory at 12
- *
- * DESCRIPTION
- *  Allocates a range of physically contiguous cache aligned
- * memory from the non-paged pool.
- *
- * ARGUMENTS
- * NumberOfBytes
- *  Size of the memory block to allocate;
- *
- * HighestAcceptableAddress
- *  Highest address valid for the caller.
- *
- * RETURN VALUE
- *  The virtual address of the memory block on success;
- * NULL on error.
- *
- * NOTE
- *  Description taken from include/ddk/mmfuncs.h.
- *  Code taken from ntoskrnl/mm/special.c.
- *
- * REVISIONS
- *
+    PFN_NUMBER LowestPfn, HighestPfn, BoundaryPfn;
+    ASSERT (NumberOfBytes != 0);
+    
+    //
+    // Convert the lowest address into a PFN
+    //
+    LowestPfn = (PFN_NUMBER)(LowestAcceptableAddress.QuadPart >> PAGE_SHIFT);
+    if (BYTE_OFFSET(LowestAcceptableAddress.LowPart)) LowestPfn++;
+    
+    //
+    // Convert and validate the boundary address into a PFN
+    //
+    if (BYTE_OFFSET(BoundaryAddressMultiple.LowPart)) return NULL;
+    BoundaryPfn = (PFN_NUMBER)(BoundaryAddressMultiple.QuadPart >> PAGE_SHIFT);
+    
+    //
+    // Convert the highest address into a PFN
+    //
+    HighestPfn = (PFN_NUMBER)(HighestAcceptableAddress.QuadPart >> PAGE_SHIFT);
+    if (HighestPfn > MmHighestPhysicalPage) HighestPfn = MmHighestPhysicalPage;
+    
+    //
+    // Validate the PFN bounds
+    //
+    if (LowestPfn > HighestPfn) return NULL;
+    
+    //
+    // Let the contiguous memory allocator handle it
+    //    
+    return MiAllocateContiguousMemory(NumberOfBytes,
+                                      LowestPfn,
+                                      HighestPfn,
+                                      BoundaryPfn,
+                                      CacheType);
+}
+
+/*
  * @implemented
  */
-PVOID NTAPI
-MmAllocateContiguousMemory (IN ULONG NumberOfBytes,
-                            IN PHYSICAL_ADDRESS HighestAcceptableAddress)
-{
-   return MmAllocateContiguousMemorySpecifyCache(NumberOfBytes,
-                                                 RtlConvertLongToLargeInteger(0),
-                                                 HighestAcceptableAddress,
-                                                 RtlConvertLongToLargeInteger(0),
-                                                 MmCached);
-}
-
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmFreeContiguousMemory at 4
- *
- * DESCRIPTION
- * Releases a range of physically contiguous memory allocated
- * with MmAllocateContiguousMemory.
- *
- * ARGUMENTS
- * BaseAddress
- *  Virtual address of the memory to be freed.
- *
- * RETURN VALUE
- *  None.
- *
- * NOTE
- *  Description taken from include/ddk/mmfuncs.h.
- *  Code taken from ntoskrnl/mm/special.c.
- *
- * REVISIONS
- *
+PVOID
+NTAPI
+MmAllocateContiguousMemory(IN ULONG NumberOfBytes,
+                           IN PHYSICAL_ADDRESS HighestAcceptableAddress)
+{
+    PFN_NUMBER HighestPfn;
+    
+    //
+    // Convert and normalize the highest address into a PFN
+    //
+    HighestPfn = (PFN_NUMBER)(HighestAcceptableAddress.QuadPart >> PAGE_SHIFT);
+    if (HighestPfn > MmHighestPhysicalPage) HighestPfn = MmHighestPhysicalPage;
+    
+    //
+    // Let the contiguous memory allocator handle it
+    //    
+    return MiAllocateContiguousMemory(NumberOfBytes, 0, HighestPfn, 0, MmCached);
+}
+
+/*
  * @implemented
  */
-VOID NTAPI
+VOID
+NTAPI
 MmFreeContiguousMemory(IN PVOID BaseAddress)
 {
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
-                         BaseAddress,
-                         MmFreeContinuousPage,
-                         NULL);
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmFreeContiguousMemorySpecifyCache at 12
- *
- * DESCRIPTION
- * Releases a range of physically contiguous memory allocated
- * with MmAllocateContiguousMemorySpecifyCache.
- *
- * ARGUMENTS
- * BaseAddress
- *  Virtual address of the memory to be freed.
- *
- * NumberOfBytes
- *  Size of the memory block to free.
- *
- * CacheType
- *  Type of caching used.
- *
- * RETURN VALUE
- *  None.
- *
- * REVISIONS
- *
+    //
+    // Let the contiguous memory allocator handle it
+    //
+    MiFreeContiguousMemory(BaseAddress);
+}
+
+/*
  * @implemented
  */
-VOID NTAPI
+VOID
+NTAPI
 MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress,
                                    IN ULONG NumberOfBytes,
                                    IN MEMORY_CACHING_TYPE CacheType)
 {
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
-                         BaseAddress,
-                         MmFreeContinuousPage,
-                         NULL);
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-}
-
+    //
+    // Just call the non-cached version (there's no cache issues for freeing)
+    //
+    MiFreeContiguousMemory(BaseAddress);
+}
 
 /* EOF */

Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?rev=41657&r1=41656&r2=41657&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Sun Jun 28 09:43:12 2009
@@ -47,8 +47,10 @@
 extern ULONG MmMaximumNonPagedPoolInBytes;
 extern PVOID MmNonPagedPoolStart;
 extern PVOID MmNonPagedPoolExpansionStart;
+extern PVOID MmNonPagedPoolEnd;
 extern PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
 extern PMMPTE MiFirstReservedZeroingPte;
+extern MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType];
 extern PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
 
 VOID
@@ -80,4 +82,27 @@
     IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
 );
 
+
+PFN_NUMBER
+NTAPI
+MiFindContiguousPages(
+    IN PFN_NUMBER LowestPfn,
+    IN PFN_NUMBER HighestPfn,
+    IN PFN_NUMBER BoundaryPfn,
+    IN PFN_NUMBER SizeInPages,
+    IN MEMORY_CACHING_TYPE CacheType
+);
+
+PVOID
+NTAPI
+MiCheckForContiguousMemory(
+    IN PVOID BaseAddress,
+    IN PFN_NUMBER BaseAddressPages,
+    IN PFN_NUMBER SizeInPages,
+    IN PFN_NUMBER LowestPfn,
+    IN PFN_NUMBER HighestPfn,
+    IN PFN_NUMBER BoundaryPfn,
+    IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
+);
+
 /* EOF */

Removed: trunk/reactos/ntoskrnl/mm/cont.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/cont.c?rev=41656&view=auto
==============================================================================
--- trunk/reactos/ntoskrnl/mm/cont.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/cont.c (removed)
@@ -1,241 +1,0 @@
-/*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/mm/cont.c
- * PURPOSE:         Manages continuous memory
- *
- * PROGRAMMERS:     David Welch (welch at cwcom.net)
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <debug.h>
-
-/* FUNCTIONS *****************************************************************/
-
-static VOID
-MmFreeContinuousPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
-                     PFN_TYPE Page, SWAPENTRY SwapEntry,
-                     BOOLEAN Dirty)
-{
-   ASSERT(SwapEntry == 0);
-   if (Page != 0)
-   {
-      MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
-   }
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmAllocateContiguousMemorySpecifyCache at 32
- *
- * DESCRIPTION
-  *  Allocates a range of physically contiguous memory
- * with a cache parameter.
- *
- * ARGUMENTS
- * NumberOfBytes
- *  Size of the memory block to allocate;
- *
- * LowestAcceptableAddress
- *  Lowest address valid for the caller.
- *
- * HighestAcceptableAddress
- *  Highest address valid for the caller.
- *
- * BoundaryAddressMultiple
- *  Address multiple not to be crossed by allocated buffer (optional).
- *
- * CacheType
- *  Type of caching to use.
- *
- * RETURN VALUE
- *  The virtual address of the memory block on success;
- * NULL on error.
- *
- * REVISIONS
- *
- * @implemented
- */
-PVOID NTAPI
-MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes,
-                                       IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL,
-                                       IN PHYSICAL_ADDRESS HighestAcceptableAddress,
-                                       IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL,
-                                       IN MEMORY_CACHING_TYPE CacheType OPTIONAL)
-{
-   PMEMORY_AREA MArea;
-   NTSTATUS Status;
-   PVOID BaseAddress = NULL;
-   PFN_TYPE PBase;
-   ULONG Protect;
-   ULONG i;
-
-   Protect = PAGE_EXECUTE_READWRITE | PAGE_SYSTEM;
-   if (CacheType == MmNonCached || CacheType == MmWriteCombined)
-   {
-      Protect |= PAGE_NOCACHE;
-   }
-   if (CacheType == MmWriteCombined)
-   {
-      Protect |= PAGE_WRITECOMBINE;
-   }
-
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
-                               MEMORY_AREA_CONTINUOUS_MEMORY,
-                               &BaseAddress,
-                               NumberOfBytes,
-                               PAGE_READWRITE,
-                               &MArea,
-                               FALSE,
-                               0,
-                               RtlConvertLongToLargeInteger(0));
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-
-   if (!NT_SUCCESS(Status))
-   {
-      return(NULL);
-   }
-   DPRINT( "Base = %x\n", BaseAddress );
-   PBase = MmGetContinuousPages(NumberOfBytes,
-                                LowestAcceptableAddress,
-                                HighestAcceptableAddress,
-                                BoundaryAddressMultiple,
-                                TRUE);
-   if (PBase == 0)
-   {
-      MmLockAddressSpace(MmGetKernelAddressSpace());
-      MmFreeMemoryArea(MmGetKernelAddressSpace(),
-                       MArea,
-                       NULL,
-                       NULL);
-      MmUnlockAddressSpace(MmGetKernelAddressSpace());
-      return(NULL);
-   }
-   for (i = 0; i < (PAGE_ROUND_UP(NumberOfBytes) / PAGE_SIZE); i++, PBase++)
-   {
-      MmCreateVirtualMapping(NULL,
-                             (char*)BaseAddress + (i * PAGE_SIZE),
-                             Protect,
-                             &PBase,
-			     1);
-   }
-   return(BaseAddress);
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmAllocateContiguousMemory at 12
- *
- * DESCRIPTION
- *  Allocates a range of physically contiguous cache aligned
- * memory from the non-paged pool.
- *
- * ARGUMENTS
- * NumberOfBytes
- *  Size of the memory block to allocate;
- *
- * HighestAcceptableAddress
- *  Highest address valid for the caller.
- *
- * RETURN VALUE
- *  The virtual address of the memory block on success;
- * NULL on error.
- *
- * NOTE
- *  Description taken from include/ddk/mmfuncs.h.
- *  Code taken from ntoskrnl/mm/special.c.
- *
- * REVISIONS
- *
- * @implemented
- */
-PVOID NTAPI
-MmAllocateContiguousMemory (IN ULONG NumberOfBytes,
-                            IN PHYSICAL_ADDRESS HighestAcceptableAddress)
-{
-   return MmAllocateContiguousMemorySpecifyCache(NumberOfBytes,
-                                                 RtlConvertLongToLargeInteger(0),
-                                                 HighestAcceptableAddress,
-                                                 RtlConvertLongToLargeInteger(0),
-                                                 MmCached);
-}
-
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmFreeContiguousMemory at 4
- *
- * DESCRIPTION
- * Releases a range of physically contiguous memory allocated
- * with MmAllocateContiguousMemory.
- *
- * ARGUMENTS
- * BaseAddress
- *  Virtual address of the memory to be freed.
- *
- * RETURN VALUE
- *  None.
- *
- * NOTE
- *  Description taken from include/ddk/mmfuncs.h.
- *  Code taken from ntoskrnl/mm/special.c.
- *
- * REVISIONS
- *
- * @implemented
- */
-VOID NTAPI
-MmFreeContiguousMemory(IN PVOID BaseAddress)
-{
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
-                         BaseAddress,
-                         MmFreeContinuousPage,
-                         NULL);
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-}
-
-/**********************************************************************
- * NAME       EXPORTED
- * MmFreeContiguousMemorySpecifyCache at 12
- *
- * DESCRIPTION
- * Releases a range of physically contiguous memory allocated
- * with MmAllocateContiguousMemorySpecifyCache.
- *
- * ARGUMENTS
- * BaseAddress
- *  Virtual address of the memory to be freed.
- *
- * NumberOfBytes
- *  Size of the memory block to free.
- *
- * CacheType
- *  Type of caching used.
- *
- * RETURN VALUE
- *  None.
- *
- * REVISIONS
- *
- * @implemented
- */
-VOID NTAPI
-MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress,
-                                   IN ULONG NumberOfBytes,
-                                   IN MEMORY_CACHING_TYPE CacheType)
-{
-   MmLockAddressSpace(MmGetKernelAddressSpace());
-   MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
-                         BaseAddress,
-                         MmFreeContinuousPage,
-                         NULL);
-   MmUnlockAddressSpace(MmGetKernelAddressSpace());
-}
-
-
-/* EOF */

Modified: trunk/reactos/ntoskrnl/mm/freelist.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/freelist.c?rev=41657&r1=41656&r2=41657&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/freelist.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/freelist.c [iso-8859-1] Sun Jun 28 09:43:12 2009
@@ -18,6 +18,8 @@
 #pragma alloc_text(INIT, MmInitializePageList)
 #endif
 
+#define MODULE_INVOLVED_IN_ARM3
+#include "ARM3/miarm.h"
 
 /* TYPES *******************************************************************/
 
@@ -235,6 +237,206 @@
    }
    KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
    return 0;
+}
+
+PFN_NUMBER
+NTAPI
+MiFindContiguousPages(IN PFN_NUMBER LowestPfn,
+                      IN PFN_NUMBER HighestPfn,
+                      IN PFN_NUMBER BoundaryPfn,
+                      IN PFN_NUMBER SizeInPages,
+                      IN MEMORY_CACHING_TYPE CacheType)
+{
+    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 (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) 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 (Pfn1->Flags.Type != MM_PHYSICAL_PAGE_FREE) 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
+                        {
+                            //
+                            // If this was an unzeroed page, there are now less
+                            //
+                            if (Pfn1->Flags.Zero == 0) UnzeroedPageCount--;
+                            
+                            //
+                            // One less free page, one more system page
+                            //
+                            MmStats.NrFreePages--;
+                            MmStats.NrSystemPages++;
+                            
+                            //
+                            // This PFN is now a used page, set it up
+                            //
+                            RemoveEntryList(&Pfn1->ListEntry);
+                            Pfn1->Flags.Type = MM_PHYSICAL_PAGE_USED;
+                            Pfn1->Flags.Consumer = MC_NPPOOL;
+                            Pfn1->ReferenceCount = 1;
+                            Pfn1->LockCount = 0;
+                            Pfn1->MapCount = 0;
+                            Pfn1->SavedSwapEntry = 0;
+                            
+                            //
+                            // Check if it was already zeroed
+                            //
+                            if (Pfn1->Flags.Zero == 0)
+                            {
+                                //
+                                // It wasn't, so zero it
+                                //
+                                MiZeroPage(MiGetPfnEntryIndex(Pfn1));
+                            }
+
+                            //
+                            // 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->Flags.StartOfAllocation = 1;
+                        (Pfn1 + SizeInPages - 1)->Flags.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;    
 }
 
 PFN_TYPE

Modified: trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild?rev=41657&r1=41656&r2=41657&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] Sun Jun 28 09:43:12 2009
@@ -360,6 +360,7 @@
 			</directory>
 		</if>
 		<directory name="ARM3">
+			<file>contmem.c</file>
 			<file>dynamic.c</file>
 			<file>hypermap.c</file>
 			<file>init.c</file>
@@ -370,7 +371,6 @@
 		</directory>
 		<file>anonmem.c</file>
 		<file>balance.c</file>
-		<file>cont.c</file>
 		<file>dbgpool.c</file>
 		<file>drvlck.c</file>
 		<file>freelist.c</file>



More information about the Ros-diffs mailing list