[NTOS]: Kill some debug spew.
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / pool.c
index aa2603a..37cb2e5 100644 (file)
@@ -22,14 +22,108 @@ LIST_ENTRY MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS];
 PFN_NUMBER MmNumberOfFreeNonPagedPool, MiExpansionPoolPagesInitialCharge;
 PVOID MmNonPagedPoolEnd0;
 PFN_NUMBER MiStartOfInitialPoolFrame, MiEndOfInitialPoolFrame;
-
+KGUARDED_MUTEX MmPagedPoolMutex;
 MM_PAGED_POOL_INFO MmPagedPoolInfo;
+SIZE_T MmAllocatedNonPagedPool;
+ULONG MmSpecialPoolTag;
+ULONG MmConsumedPoolPercentage;
+BOOLEAN MmProtectFreedNonPagedPool;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
 VOID
 NTAPI
-MiInitializeArmPool(VOID)
+MiInitializeNonPagedPoolThresholds(VOID)
+{
+    PFN_NUMBER Size = MmMaximumNonPagedPoolInPages;
+
+    /* Default low threshold of 8MB or one third of nonpaged pool */
+    MiLowNonPagedPoolThreshold = (8 * _1MB) >> PAGE_SHIFT;
+    MiLowNonPagedPoolThreshold = min(MiLowNonPagedPoolThreshold, Size / 3);
+
+    /* Default high threshold of 20MB or 50% */
+    MiHighNonPagedPoolThreshold = (20 * _1MB) >> PAGE_SHIFT;
+    MiHighNonPagedPoolThreshold = min(MiHighNonPagedPoolThreshold, Size / 2);
+    ASSERT(MiLowNonPagedPoolThreshold < MiHighNonPagedPoolThreshold);
+}
+
+VOID
+NTAPI
+MiInitializePoolEvents(VOID)
+{
+    KIRQL OldIrql;
+    PFN_NUMBER FreePoolInPages;
+
+    /* Lock paged pool */
+    KeAcquireGuardedMutex(&MmPagedPoolMutex);
+
+    /* Total size of the paged pool minus the allocated size, is free */
+    FreePoolInPages = MmSizeOfPagedPoolInPages - MmPagedPoolInfo.AllocatedPagedPool;
+
+    /* Check the initial state high state */
+    if (FreePoolInPages >= MiHighPagedPoolThreshold)
+    {
+        /* We have plenty of pool */
+        KeSetEvent(MiHighPagedPoolEvent, 0, FALSE);
+    }
+    else
+    {
+        /* We don't */
+        KeClearEvent(MiHighPagedPoolEvent);
+    }
+
+    /* Check the initial low state */
+    if (FreePoolInPages <= MiLowPagedPoolThreshold)
+    {
+        /* We're very low in free pool memory */
+        KeSetEvent(MiLowPagedPoolEvent, 0, FALSE);
+    }
+    else
+    {
+        /* We're not */
+        KeClearEvent(MiLowPagedPoolEvent);
+    }
+
+    /* Release the paged pool lock */
+    KeReleaseGuardedMutex(&MmPagedPoolMutex);
+
+    /* Now it's time for the nonpaged pool lock */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
+
+    /* Free pages are the maximum minus what's been allocated */
+    FreePoolInPages = MmMaximumNonPagedPoolInPages - MmAllocatedNonPagedPool;
+
+    /* Check if we have plenty */
+    if (FreePoolInPages >= MiHighNonPagedPoolThreshold)
+    {
+        /* We do, set the event */
+        KeSetEvent(MiHighNonPagedPoolEvent, 0, FALSE);
+    }
+    else
+    {
+        /* We don't, clear the event */
+        KeClearEvent(MiHighNonPagedPoolEvent);
+    }
+
+    /* Check if we have very little */
+    if (FreePoolInPages <= MiLowNonPagedPoolThreshold)
+    {
+        /* We do, set the event */
+        KeSetEvent(MiLowNonPagedPoolEvent, 0, FALSE);
+    }
+    else
+    {
+        /* We don't, clear it */
+        KeClearEvent(MiLowNonPagedPoolEvent);
+    }
+
+    /* We're done, release the nonpaged pool lock */
+    KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
+}
+
+VOID
+NTAPI
+MiInitializeNonPagedPool(VOID)
 {
     ULONG i;
     PFN_NUMBER PoolPages;
@@ -139,14 +233,217 @@ MiAllocatePoolPages(IN POOL_TYPE PoolType,
     PMMPTE PointerPte, StartPte;
     MMPTE TempPte;
     PMMPFN Pfn1;
-    PVOID BaseVa;
+    PVOID BaseVa, BaseVaStart;
     PMMFREE_POOL_ENTRY FreeEntry;
+    PKSPIN_LOCK_QUEUE LockQueue;
     
     //
     // Figure out how big the allocation is in pages
     //
     SizeInPages = BYTES_TO_PAGES(SizeInBytes);
     
+    //
+    // Handle paged pool
+    //
+    if (PoolType == PagedPool)
+    {
+        //
+        // Lock the paged pool mutex
+        //
+        KeAcquireGuardedMutex(&MmPagedPoolMutex);
+        
+        //
+        // Find some empty allocation space
+        //
+        i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
+                                   SizeInPages,
+                                   MmPagedPoolInfo.PagedPoolHint);
+        if (i == 0xFFFFFFFF)
+        {
+            //
+            // Get the page bit count
+            //
+            i = ((SizeInPages - 1) / 1024) + 1;
+            DPRINT1("Paged pool expansion: %d %x\n", i, SizeInPages);
+            
+            //
+            // Check if there is enougn paged pool expansion space left
+            //
+            if (MmPagedPoolInfo.NextPdeForPagedPoolExpansion >
+                MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
+            {
+                //
+                // Out of memory!
+                //
+                DPRINT1("OUT OF PAGED POOL!!!\n");
+                KeReleaseGuardedMutex(&MmPagedPoolMutex);
+                return NULL;
+            }
+            
+            //
+            // Check if we'll have to expand past the last PTE we have available
+            //            
+            if (((i - 1) + MmPagedPoolInfo.NextPdeForPagedPoolExpansion) >
+                 MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
+            {
+                //
+                // We can only support this much then
+                //
+                SizeInPages = MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool) - 
+                              MmPagedPoolInfo.NextPdeForPagedPoolExpansion +
+                              1;
+                ASSERT(SizeInPages < i);
+                i = SizeInPages;
+            }
+            else
+            {
+                //
+                // Otherwise, there is plenty of space left for this expansion
+                //
+                SizeInPages = i;
+            }
+            
+            //
+            // Get the template PTE we'll use to expand
+            //
+            TempPte = ValidKernelPte;
+            
+            //
+            // Get the first PTE in expansion space
+            //
+            PointerPte = MmPagedPoolInfo.NextPdeForPagedPoolExpansion;
+            BaseVa = MiPteToAddress(PointerPte);
+            BaseVaStart = BaseVa;
+            
+            //
+            // Lock the PFN database and loop pages
+            //            
+            OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);          
+            do
+            {
+                //
+                // It should not already be valid
+                //
+                ASSERT(PointerPte->u.Hard.Valid == 0);
+                
+                /* Request a page */
+                PageFrameNumber = MiRemoveAnyPage(0);
+                TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
+                
+                //
+                // Save it into our double-buffered system page directory
+                //
+                /* This seems to be making the assumption that one PDE is one page long */
+                C_ASSERT(PAGE_SIZE == (PD_COUNT * (sizeof(MMPTE) * PDE_COUNT)));
+                MmSystemPagePtes[(ULONG_PTR)PointerPte & (PAGE_SIZE - 1) /
+                                 sizeof(MMPTE)] = TempPte;
+                            
+                /* Initialize the PFN */
+                MiInitializePfnForOtherProcess(PageFrameNumber,
+                                               PointerPte,
+                                               MmSystemPageDirectory[(PointerPte - (PMMPTE)PDE_BASE) / PDE_COUNT]);
+                             
+                /* Write the actual PTE now */
+                ASSERT(TempPte.u.Hard.Valid == 1);
+                *PointerPte++ = TempPte;
+                
+                //
+                // Move on to the next expansion address
+                //
+                BaseVa = (PVOID)((ULONG_PTR)BaseVa + PAGE_SIZE);
+            } while (--i > 0);
+            
+            //
+            // Release the PFN database lock
+            //            
+            KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+            
+            //
+            // These pages are now available, clear their availablity bits
+            //
+            RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap,
+                         (MmPagedPoolInfo.NextPdeForPagedPoolExpansion -
+                          MiAddressToPte(MmPagedPoolInfo.FirstPteForPagedPool)) *
+                         1024,
+                         SizeInPages * 1024);
+                        
+            //
+            // Update the next expansion location
+            //
+            MmPagedPoolInfo.NextPdeForPagedPoolExpansion += SizeInPages;
+            
+            //
+            // Zero out the newly available memory
+            //
+            RtlZeroMemory(BaseVaStart, SizeInPages * PAGE_SIZE);
+            
+            //
+            // Now try consuming the pages again
+            //
+            SizeInPages = BYTES_TO_PAGES(SizeInBytes);
+            i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
+                                       SizeInPages,
+                                       0);
+            if (i == 0xFFFFFFFF) 
+            {
+                //
+                // Out of memory!
+                //
+                DPRINT1("OUT OF PAGED POOL!!!\n");
+                KeReleaseGuardedMutex(&MmPagedPoolMutex);
+                return NULL;
+            }
+        }
+        
+        //
+        // Update the pool hint if the request was just one page
+        //
+        if (SizeInPages == 1) MmPagedPoolInfo.PagedPoolHint = i + 1;
+        
+        //
+        // Update the end bitmap so we know the bounds of this allocation when
+        // the time comes to free it
+        //
+        RtlSetBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, i + SizeInPages - 1);
+        
+        //
+        // Now we can release the lock (it mainly protects the bitmap)
+        //
+        KeReleaseGuardedMutex(&MmPagedPoolMutex);
+        
+        //
+        // Now figure out where this allocation starts
+        //
+        BaseVa = (PVOID)((ULONG_PTR)MmPagedPoolStart + (i << PAGE_SHIFT));
+        
+        //
+        // Flush the TLB
+        //
+        KeFlushEntireTb(TRUE, TRUE);
+        
+        /* Setup a demand-zero writable PTE */
+        MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
+        
+        //
+        // Find the first and last PTE, then loop them all
+        //
+        PointerPte = MiAddressToPte(BaseVa);
+        StartPte = PointerPte + SizeInPages;
+        do
+        {
+            //
+            // Write the demand zero PTE and keep going
+            //
+            ASSERT(PointerPte->u.Hard.Valid == 0);
+            *PointerPte++ = TempPte;
+        } while (PointerPte < StartPte);
+        
+        //
+        // Return the allocation address to the caller
+        //
+        return BaseVa;
+    }    
+    
     //
     // Allocations of less than 4 pages go into their individual buckets
     //
@@ -285,27 +582,27 @@ MiAllocatePoolPages(IN POOL_TYPE PoolType,
     //
     // Lock the PFN database too
     //
-    //KeAcquireQueuedSpinLockAtDpcLevel(LockQueuePfnLock);
+    LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock];
+    KeAcquireQueuedSpinLockAtDpcLevel(LockQueue);
     
     //
     // Loop the pages
     //
-    TempPte = HyperTemplatePte;
+    TempPte = ValidKernelPte;
     do
     {
-        //
-        // Allocate a page
-        //
-        PageFrameNumber = MmAllocPage(MC_NPPOOL, 0);
+        /* Allocate a page */
+        PageFrameNumber = MiRemoveAnyPage(0);
         
-        //
-        // Get the PFN entry for it
-        //
+        /* Get the PFN entry for it and fill it out */
         Pfn1 = MiGetPfnEntry(PageFrameNumber);
+        Pfn1->u3.e2.ReferenceCount = 1;
+        Pfn1->u2.ShareCount = 1;
+        Pfn1->PteAddress = PointerPte;
+        Pfn1->u3.e1.PageLocation = ActiveAndValid;
+        Pfn1->u4.VerifierAllocation = 0;
         
-        //
-        // Write the PTE for it
-        //
+        /* Write the PTE for it */
         TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
         ASSERT(PointerPte->u.Hard.Valid == 0);
         ASSERT(TempPte.u.Hard.Valid == 1);
@@ -326,7 +623,7 @@ MiAllocatePoolPages(IN POOL_TYPE PoolType,
     //
     // Release the PFN and nonpaged pool lock
     //
-    //KeReleaseQueuedSpinLockFromDpcLevel(LockQueuePfnLock);
+    KeReleaseQueuedSpinLockFromDpcLevel(LockQueue);
     KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
     
     //
@@ -344,7 +641,62 @@ MiFreePoolPages(IN PVOID StartingVa)
     PFN_NUMBER FreePages, NumberOfPages;
     KIRQL OldIrql;
     PMMFREE_POOL_ENTRY FreeEntry, NextEntry, LastEntry;
-    ULONG i;
+    ULONG i, End;
+    
+    //
+    // Handle paged pool
+    //
+    if ((StartingVa >= MmPagedPoolStart) && (StartingVa <= MmPagedPoolEnd))
+    {
+        //
+        // Calculate the offset from the beginning of paged pool, and convert it
+        // into pages
+        //
+        i = ((ULONG_PTR)StartingVa - (ULONG_PTR)MmPagedPoolStart) >> PAGE_SHIFT;
+        End = i;
+        
+        //
+        // Now use the end bitmap to scan until we find a set bit, meaning that
+        // this allocation finishes here
+        //
+        while (!RtlTestBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End)) End++;
+        
+        //
+        // Now calculate the total number of pages this allocation spans
+        //
+        NumberOfPages = End - i + 1;
+        
+        /* Delete the actual pages */
+        PointerPte = MmPagedPoolInfo.FirstPteForPagedPool + i;
+        FreePages = MiDeleteSystemPageableVm(PointerPte, NumberOfPages, 0, NULL);
+        ASSERT(FreePages == NumberOfPages);
+        
+        //
+        // Acquire the paged pool lock
+        //
+        KeAcquireGuardedMutex(&MmPagedPoolMutex);
+        
+        //
+        // Clear the allocation and free bits
+        //
+        RtlClearBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, i);
+        RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, i, NumberOfPages);
+        
+        //
+        // Update the hint if we need to
+        //
+        if (i < MmPagedPoolInfo.PagedPoolHint) MmPagedPoolInfo.PagedPoolHint = i;
+        
+        //
+        // Release the lock protecting the bitmaps
+        //
+        KeReleaseGuardedMutex(&MmPagedPoolMutex);
+        
+        //
+        // And finally return the number of pages freed
+        //
+        return NumberOfPages;
+    }
     
     //
     // Get the first PTE and its corresponding PFN entry
@@ -582,4 +934,44 @@ MiFreePoolPages(IN PVOID StartingVa)
     return NumberOfPages;
 }
 
+
+BOOLEAN
+NTAPI
+MiRaisePoolQuota(IN POOL_TYPE PoolType,
+                 IN ULONG CurrentMaxQuota,
+                 OUT PULONG NewMaxQuota)
+{
+    //
+    // Not implemented
+    //
+    UNIMPLEMENTED;
+    *NewMaxQuota = CurrentMaxQuota + 65536;
+    return TRUE;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+MmAllocateMappingAddress(IN SIZE_T NumberOfBytes,
+                         IN ULONG PoolTag)
+{
+       UNIMPLEMENTED;
+       return NULL;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+NTAPI
+MmFreeMappingAddress(IN PVOID BaseAddress,
+                     IN ULONG PoolTag)
+{
+       UNIMPLEMENTED;
+}
+
 /* EOF */