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;
PMMPTE PointerPte, StartPte;
MMPTE TempPte;
PMMPFN Pfn1;
- PVOID BaseVa;
+ PVOID BaseVa, BaseVaStart;
PMMFREE_POOL_ENTRY FreeEntry;
PKSPIN_LOCK_QUEUE LockQueue;
if (i == 0xFFFFFFFF)
{
//
- // Out of memory!
+ // 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;
+
//
- DPRINT1("OUT OF PAGED POOL!!!\n");
- KeReleaseGuardedMutex(&MmPagedPoolMutex);
- return NULL;
+ // 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;
+ }
}
//
//
KeFlushEntireTb(TRUE, TRUE);
- //
- // Setup a demand-zero writable PTE
- //
- TempPte.u.Long = 0;
- MI_MAKE_WRITE_PAGE(&TempPte);
+ /* Setup a demand-zero writable PTE */
+ MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
//
// Find the first and last PTE, then loop them all
//
// Write the demand zero PTE and keep going
//
+ ASSERT(PointerPte->u.Hard.Valid == 0);
*PointerPte++ = TempPte;
} while (PointerPte < StartPte);
//
// 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);
//
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
//