[NTOSKRNL] Move KDBG MM functions implementation to their own file
[reactos.git] / ntoskrnl / mm / ARM3 / expool.c
index 4bf0196..6a791e5 100644 (file)
@@ -13,7 +13,7 @@
 #include <debug.h>
 
 #define MODULE_INVOLVED_IN_ARM3
-#include "../ARM3/miarm.h"
+#include <mm/ARM3/miarm.h>
 
 #undef ExAllocatePoolWithQuota
 #undef ExAllocatePoolWithQuotaTag
@@ -460,11 +460,177 @@ ExpComputePartialHashForAddress(IN PVOID BaseAddress)
     return (Result >> 24) ^ (Result >> 16) ^ (Result >> 8) ^ Result;
 }
 
+#if DBG
+FORCEINLINE
+BOOLEAN
+ExpTagAllowPrint(CHAR Tag)
+{
+    if ((Tag >= 'a' && Tag <= 'z') ||
+        (Tag >= 'A' && Tag <= 'Z') ||
+        (Tag >= '0' && Tag <= '9') ||
+        Tag == ' ' || Tag == '=' ||
+        Tag == '?' || Tag == '@')
+    {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+#ifdef KDBG
+#define MiDumperPrint(dbg, fmt, ...)        \
+    if (dbg) KdbpPrint(fmt, ##__VA_ARGS__); \
+    else DPRINT1(fmt, ##__VA_ARGS__)
+#else
+#define MiDumperPrint(dbg, fmt, ...)        \
+    DPRINT1(fmt, ##__VA_ARGS__)
+#endif
+
+VOID
+MiDumpPoolConsumers(BOOLEAN CalledFromDbg, ULONG Tag, ULONG Mask, ULONG Flags)
+{
+    SIZE_T i;
+    BOOLEAN Verbose;
+
+    //
+    // Only print header if called from OOM situation
+    //
+    if (!CalledFromDbg)
+    {
+        DPRINT1("---------------------\n");
+        DPRINT1("Out of memory dumper!\n");
+    }
+#ifdef KDBG
+    else
+    {
+        KdbpPrint("Pool Used:\n");
+    }
+#endif
+
+    //
+    // Remember whether we'll have to be verbose
+    // This is the only supported flag!
+    //
+    Verbose = BooleanFlagOn(Flags, 1);
+
+    //
+    // Print table header
+    //
+    if (Verbose)
+    {
+        MiDumperPrint(CalledFromDbg, "\t\t\t\tNonPaged\t\t\t\t\t\t\tPaged\n");
+        MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\t\tAllocs\t\tFrees\t\tDiff\t\tUsed\n");
+    }
+    else
+    {
+        MiDumperPrint(CalledFromDbg, "\t\tNonPaged\t\t\tPaged\n");
+        MiDumperPrint(CalledFromDbg, "Tag\t\tAllocs\t\tUsed\t\tAllocs\t\tUsed\n");
+    }
+
+    //
+    // We'll extract allocations for all the tracked pools
+    //
+    for (i = 0; i < PoolTrackTableSize; ++i)
+    {
+        PPOOL_TRACKER_TABLE TableEntry;
+
+        TableEntry = &PoolTrackTable[i];
+
+        //
+        // We only care about tags which have allocated memory
+        //
+        if (TableEntry->NonPagedBytes != 0 || TableEntry->PagedBytes != 0)
+        {
+            //
+            // If there's a tag, attempt to do a pretty print
+            // only if it matches the caller's tag, or if
+            // any tag is allowed
+            // For checking whether it matches caller's tag,
+            // use the mask to make sure not to mess with the wildcards
+            //
+            if (TableEntry->Key != 0 && TableEntry->Key != TAG_NONE &&
+                (Tag == 0 || (TableEntry->Key & Mask) == (Tag & Mask)))
+            {
+                CHAR Tag[4];
+
+                //
+                // Extract each 'component' and check whether they are printable
+                //
+                Tag[0] = TableEntry->Key & 0xFF;
+                Tag[1] = TableEntry->Key >> 8 & 0xFF;
+                Tag[2] = TableEntry->Key >> 16 & 0xFF;
+                Tag[3] = TableEntry->Key >> 24 & 0xFF;
+
+                if (ExpTagAllowPrint(Tag[0]) && ExpTagAllowPrint(Tag[1]) && ExpTagAllowPrint(Tag[2]) && ExpTagAllowPrint(Tag[3]))
+                {
+                    //
+                    // Print in direct order to make !poolused TAG usage easier
+                    //
+                    if (Verbose)
+                    {
+                        MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+                                      TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+                                      (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+                                      TableEntry->PagedAllocs, TableEntry->PagedFrees,
+                                      (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+                    }
+                    else
+                    {
+                        MiDumperPrint(CalledFromDbg, "'%c%c%c%c'\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", Tag[0], Tag[1], Tag[2], Tag[3],
+                                      TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+                                      TableEntry->PagedAllocs, TableEntry->PagedBytes);
+                    }
+                }
+                else
+                {
+                    if (Verbose)
+                    {
+                        MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+                                      TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+                                      (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+                                      TableEntry->PagedAllocs, TableEntry->PagedFrees,
+                                      (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+                    }
+                    else
+                    {
+                        MiDumperPrint(CalledFromDbg, "%x\t%ld\t\t%ld\t\t%ld\t\t%ld\n", TableEntry->Key,
+                                      TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+                                      TableEntry->PagedAllocs, TableEntry->PagedBytes);
+                    }
+                }
+            }
+            else if (Tag == 0 || (Tag & Mask) == (TAG_NONE & Mask))
+            {
+                if (Verbose)
+                {
+                    MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+                                  TableEntry->NonPagedAllocs, TableEntry->NonPagedFrees,
+                                  (TableEntry->NonPagedAllocs - TableEntry->NonPagedFrees), TableEntry->NonPagedBytes,
+                                  TableEntry->PagedAllocs, TableEntry->PagedFrees,
+                                  (TableEntry->PagedAllocs - TableEntry->PagedFrees), TableEntry->PagedBytes);
+                }
+                else
+                {
+                    MiDumperPrint(CalledFromDbg, "Anon\t\t%ld\t\t%ld\t\t%ld\t\t%ld\n",
+                                  TableEntry->NonPagedAllocs, TableEntry->NonPagedBytes,
+                                  TableEntry->PagedAllocs, TableEntry->PagedBytes);
+                }
+            }
+        }
+    }
+
+    if (!CalledFromDbg)
+    {
+        DPRINT1("---------------------\n");
+    }
+}
+#endif
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
+INIT_FUNCTION
 VOID
 NTAPI
-INIT_FUNCTION
 ExpSeedHotTags(VOID)
 {
     ULONG i, Key, Hash, Index;
@@ -792,9 +958,9 @@ ExpInsertPoolTracker(IN ULONG Key,
     DPRINT1("Out of pool tag space, ignoring...\n");
 }
 
+INIT_FUNCTION
 VOID
 NTAPI
-INIT_FUNCTION
 ExInitializePoolDescriptor(IN PPOOL_DESCRIPTOR PoolDescriptor,
                            IN POOL_TYPE PoolType,
                            IN ULONG PoolIndex,
@@ -843,9 +1009,9 @@ ExInitializePoolDescriptor(IN PPOOL_DESCRIPTOR PoolDescriptor,
     ASSERT(PoolType != PagedPoolSession);
 }
 
+INIT_FUNCTION
 VOID
 NTAPI
-INIT_FUNCTION
 InitializePool(IN POOL_TYPE PoolType,
                IN ULONG Threshold)
 {
@@ -932,7 +1098,7 @@ InitializePool(IN POOL_TYPE PoolType,
         }
 
         //
-        // Finally, add one entry, compute the hash, and zero the table
+        // Add one entry, compute the hash, and zero the table
         //
         PoolTrackTableSize++;
         PoolTrackTableMask = PoolTrackTableSize - 2;
@@ -940,6 +1106,11 @@ InitializePool(IN POOL_TYPE PoolType,
         RtlZeroMemory(PoolTrackTable,
                       PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
 
+        //
+        // Finally, add the most used tags to speed up those allocations
+        //
+        ExpSeedHotTags();
+
         //
         // We now do the exact same thing with the tracker table for big pages
         //
@@ -1008,9 +1179,9 @@ InitializePool(IN POOL_TYPE PoolType,
         //
         // During development, print this out so we can see what's happening
         //
-        DPRINT1("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+        DPRINT("EXPOOL: Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
                 PoolTrackTable, PoolTrackTableSize * sizeof(POOL_TRACKER_TABLE));
-        DPRINT1("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
+        DPRINT("EXPOOL: Big Pool Tracker Table at: 0x%p with 0x%lx bytes\n",
                 PoolBigPageTable, PoolBigPageTableSize * sizeof(POOL_TRACKER_BIG_PAGES));
 
         //
@@ -1336,7 +1507,7 @@ ExpAddTagForBigPages(IN PVOID Va,
             InterlockedIncrementUL(&ExpPoolBigEntriesInUse);
             if ((i >= 16) && (ExpPoolBigEntriesInUse > (TableSize / 4)))
             {
-                DPRINT1("Should attempt expansion since we now have %lu entries\n",
+                DPRINT("Should attempt expansion since we now have %lu entries\n",
                         ExpPoolBigEntriesInUse);
             }
 
@@ -1498,10 +1669,77 @@ ExQueryPoolUsage(OUT PULONG PagedPoolPages,
 #endif
 
     //
-    // FIXME: Not yet supported
+    // Get the amount of hits in the system lookaside lists
     //
-    *NonPagedPoolLookasideHits += 0;
-    *PagedPoolLookasideHits += 0;
+    if (!IsListEmpty(&ExPoolLookasideListHead))
+    {
+        PLIST_ENTRY ListEntry;
+
+        for (ListEntry = ExPoolLookasideListHead.Flink;
+             ListEntry != &ExPoolLookasideListHead;
+             ListEntry = ListEntry->Flink)
+        {
+            PGENERAL_LOOKASIDE Lookaside;
+
+            Lookaside = CONTAINING_RECORD(ListEntry, GENERAL_LOOKASIDE, ListEntry);
+
+            if (Lookaside->Type == NonPagedPool)
+            {
+                *NonPagedPoolLookasideHits += Lookaside->AllocateHits;
+            }
+            else
+            {
+                *PagedPoolLookasideHits += Lookaside->AllocateHits;
+            }
+        }
+    }
+}
+
+VOID
+NTAPI
+ExReturnPoolQuota(IN PVOID P)
+{
+    PPOOL_HEADER Entry;
+    POOL_TYPE PoolType;
+    USHORT BlockSize;
+    PEPROCESS Process;
+
+    if ((ExpPoolFlags & POOL_FLAG_SPECIAL_POOL) &&
+        (MmIsSpecialPoolAddress(P)))
+    {
+        return;
+    }
+
+    Entry = P;
+    Entry--;
+    ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
+
+    PoolType = Entry->PoolType - 1;
+    BlockSize = Entry->BlockSize;
+
+    if (PoolType & QUOTA_POOL_MASK)
+    {
+        Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
+        ASSERT(Process != NULL);
+        if (Process)
+        {
+            if (Process->Pcb.Header.Type != ProcessObject)
+            {
+                DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
+                        Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
+                KeBugCheckEx(BAD_POOL_CALLER,
+                             0x0D,
+                             (ULONG_PTR)P,
+                             Entry->PoolTag,
+                             (ULONG_PTR)Process);
+            }
+            ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
+            PsReturnPoolQuota(Process,
+                              PoolType & BASE_POOL_TYPE_MASK,
+                              BlockSize * POOL_BLOCK_SIZE);
+            ObDereferenceObject(Process);
+        }
+    }
 }
 
 /* PUBLIC FUNCTIONS ***********************************************************/
@@ -1589,6 +1827,19 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
         Entry = MiAllocatePoolPages(OriginalType, NumberOfBytes);
         if (!Entry)
         {
+#if DBG
+            //
+            // Out of memory, display current consumption
+            // Let's consider that if the caller wanted more
+            // than a hundred pages, that's a bogus caller
+            // and we are not out of memory
+            //
+            if (NumberOfBytes < 100 * PAGE_SIZE)
+            {
+                MiDumpPoolConsumers(FALSE, 0, 0, 0);
+            }
+#endif
+
             //
             // Must succeed pool is deprecated, but still supported. These allocation
             // failures must cause an immediate bugcheck
@@ -1613,7 +1864,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
             //
             if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
             {
-                DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+                DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
                         NumberOfBytes,
                         OriginalType);
                 if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
@@ -1627,6 +1878,8 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
             {
                 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
             }
+
+            return NULL;
         }
 
         //
@@ -1708,7 +1961,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
             // Get the real entry, write down its pool type, and track it
             //
             Entry--;
-            Entry->PoolType = PoolType + 1;
+            Entry->PoolType = OriginalType + 1;
             ExpInsertPoolTracker(Tag,
                                  Entry->BlockSize * POOL_BLOCK_SIZE,
                                  OriginalType);
@@ -1880,7 +2133,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
             // We have found an entry for this allocation, so set the pool type
             // and release the lock since we're done
             //
-            Entry->PoolType = PoolType + 1;
+            Entry->PoolType = OriginalType + 1;
             ExpCheckPoolBlocks(Entry);
             ExUnlockPool(PoolDesc, OldIrql);
 
@@ -1910,9 +2163,22 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
     //
     // There were no free entries left, so we have to allocate a new fresh page
     //
-    Entry = MiAllocatePoolPages(PoolType, PAGE_SIZE);
+    Entry = MiAllocatePoolPages(OriginalType, PAGE_SIZE);
     if (!Entry)
     {
+#if DBG
+        //
+        // Out of memory, display current consumption
+        // Let's consider that if the caller wanted more
+        // than a hundred pages, that's a bogus caller
+        // and we are not out of memory
+        //
+        if (NumberOfBytes < 100 * PAGE_SIZE)
+        {
+            MiDumpPoolConsumers(FALSE, 0, 0, 0);
+        }
+#endif
+
         //
         // Must succeed pool is deprecated, but still supported. These allocation
         // failures must cause an immediate bugcheck
@@ -1937,7 +2203,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
         //
         if (ExpPoolFlags & POOL_FLAG_DBGPRINT_ON_FAILURE)
         {
-            DPRINT1("EX: ExAllocatePool (%p, 0x%x) returning NULL\n",
+            DPRINT1("EX: ExAllocatePool (%lu, 0x%x) returning NULL\n",
                     NumberOfBytes,
                     OriginalType);
             if (ExpPoolFlags & POOL_FLAG_CRASH_ON_FAILURE) DbgBreakPoint();
@@ -1963,7 +2229,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
     //
     Entry->Ulong1 = 0;
     Entry->BlockSize = i;
-    Entry->PoolType = PoolType + 1;
+    Entry->PoolType = OriginalType + 1;
 
     //
     // This page will have two entries -- one for the allocation (which we just
@@ -2023,7 +2289,7 @@ ExAllocatePoolWithTag(IN POOL_TYPE PoolType,
     InterlockedIncrement((PLONG)&PoolDesc->RunningAllocs);
     ExpInsertPoolTracker(Tag,
                          Entry->BlockSize * POOL_BLOCK_SIZE,
-                         PoolType);
+                         OriginalType);
 
     //
     // And return the pool allocation
@@ -2041,10 +2307,25 @@ NTAPI
 ExAllocatePool(POOL_TYPE PoolType,
                SIZE_T NumberOfBytes)
 {
-    //
-    // Use a default tag of "None"
-    //
-    return ExAllocatePoolWithTag(PoolType, NumberOfBytes, TAG_NONE);
+    ULONG Tag = TAG_NONE;
+#if 0 && DBG
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+
+    /* Use the first four letters of the driver name, or "None" if unavailable */
+    LdrEntry = KeGetCurrentIrql() <= APC_LEVEL
+                ? MiLookupDataTableEntry(_ReturnAddress())
+                : NULL;
+    if (LdrEntry)
+    {
+        ULONG i;
+        Tag = 0;
+        for (i = 0; i < min(4, LdrEntry->BaseDllName.Length / sizeof(WCHAR)); i++)
+            Tag = Tag >> 8 | (LdrEntry->BaseDllName.Buffer[i] & 0xff) << 24;
+        for (; i < 4; i++)
+            Tag = Tag >> 8 | ' ' << 24;
+    }
+#endif
+    return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
 }
 
 /*
@@ -2065,6 +2346,7 @@ ExFreePoolWithTag(IN PVOID P,
     PFN_NUMBER PageCount, RealPageCount;
     PKPRCB Prcb = KeGetCurrentPrcb();
     PGENERAL_LOOKASIDE LookasideList;
+    PEPROCESS Process;
 
     //
     // Check if any of the debug flags are enabled
@@ -2219,6 +2501,7 @@ ExFreePoolWithTag(IN PVOID P,
     //
     Entry = P;
     Entry--;
+    ASSERT((ULONG_PTR)Entry % POOL_BLOCK_SIZE == 0);
 
     //
     // Get the size of the entry, and it's pool type, then load the descriptor
@@ -2255,6 +2538,29 @@ ExFreePoolWithTag(IN PVOID P,
                          BlockSize * POOL_BLOCK_SIZE,
                          Entry->PoolType - 1);
 
+    //
+    // Release pool quota, if any
+    //
+    if ((Entry->PoolType - 1) & QUOTA_POOL_MASK)
+    {
+        Process = ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1];
+        if (Process)
+        {
+            if (Process->Pcb.Header.Type != ProcessObject)
+            {
+                DPRINT1("Object %p is not a process. Type %u, pool type 0x%x, block size %u\n",
+                        Process, Process->Pcb.Header.Type, Entry->PoolType, BlockSize);
+                KeBugCheckEx(BAD_POOL_CALLER,
+                             0x0D,
+                             (ULONG_PTR)P,
+                             Tag,
+                             (ULONG_PTR)Process);
+            }
+            PsReturnPoolQuota(Process, PoolType, BlockSize * POOL_BLOCK_SIZE);
+            ObDereferenceObject(Process);
+        }
+    }
+
     //
     // Is this allocation small enough to have come from a lookaside list?
     //
@@ -2482,7 +2788,7 @@ ExAllocatePoolWithQuota(IN POOL_TYPE PoolType,
     //
     // Allocate the pool
     //
-    return ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, 'enoN');
+    return ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE);
 }
 
 /*
@@ -2495,11 +2801,18 @@ ExAllocatePoolWithTagPriority(IN POOL_TYPE PoolType,
                               IN ULONG Tag,
                               IN EX_POOL_PRIORITY Priority)
 {
+    PVOID Buffer;
+
     //
     // Allocate the pool
     //
-    UNIMPLEMENTED;
-    return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+    Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
+    if (Buffer == NULL)
+    {
+        UNIMPLEMENTED;
+    }
+
+    return Buffer;
 }
 
 /*
@@ -2511,110 +2824,114 @@ ExAllocatePoolWithQuotaTag(IN POOL_TYPE PoolType,
                            IN SIZE_T NumberOfBytes,
                            IN ULONG Tag)
 {
-    //
-    // Allocate the pool
-    //
-    UNIMPLEMENTED;
-    return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
-}
-
-#if DBG && KDBG
-
-BOOLEAN
-ExpKdbgExtPool(
-    ULONG Argc,
-    PCHAR Argv[])
-{
-    ULONG_PTR Address = 0, Flags = 0;
-    PVOID PoolPage;
+    BOOLEAN Raise = TRUE;
+    PVOID Buffer;
     PPOOL_HEADER Entry;
-    BOOLEAN ThisOne;
-    PULONG Data;
+    NTSTATUS Status;
+    PEPROCESS Process = PsGetCurrentProcess();
 
-    if (Argc > 1)
+    //
+    // Check if we should fail instead of raising an exception
+    //
+    if (PoolType & POOL_QUOTA_FAIL_INSTEAD_OF_RAISE)
     {
-        /* Get address */
-        if (!KdbpGetHexNumber(Argv[1], &Address))
-        {
-            KdbpPrint("Invalid parameter: %s\n", Argv[0]);
-            return TRUE;
-        }
+        Raise = FALSE;
+        PoolType &= ~POOL_QUOTA_FAIL_INSTEAD_OF_RAISE;
     }
 
-    if (Argc > 2)
-    {
-        /* Get address */
-        if (!KdbpGetHexNumber(Argv[1], &Flags))
-        {
-            KdbpPrint("Invalid parameter: %s\n", Argv[0]);
-            return TRUE;
-        }
-    }
+    //
+    // Inject the pool quota mask
+    //
+    PoolType += QUOTA_POOL_MASK;
 
-    /* Check if we got an address */
-    if (Address != 0)
+    //
+    // Check if we have enough space to add the quota owner process, as long as
+    // this isn't the system process, which never gets charged quota
+    //
+    ASSERT(NumberOfBytes != 0);
+    if ((NumberOfBytes <= (PAGE_SIZE - POOL_BLOCK_SIZE - sizeof(PVOID))) &&
+        (Process != PsInitialSystemProcess))
     {
-        /* Get the base page */
-        PoolPage = PAGE_ALIGN(Address);
+        //
+        // Add space for our EPROCESS pointer
+        //
+        NumberOfBytes += sizeof(PEPROCESS);
     }
     else
     {
-        KdbpPrint("Heap is unimplemented\n");
-        return TRUE;
-    }
-
-    /* No paging support! */
-    if (!MmIsAddressValid(PoolPage))
-    {
-        KdbpPrint("Address not accessible!\n");
-        return TRUE;
+        //
+        // We won't be able to store the pointer, so don't use quota for this
+        //
+        PoolType -= QUOTA_POOL_MASK;
     }
 
-    /* Get pool type */
-    if ((Address >= (ULONG_PTR)MmPagedPoolStart) && (Address <= (ULONG_PTR)MmPagedPoolEnd))
-        KdbpPrint("Allocation is from PagedPool region\n");
-    else if ((Address >= (ULONG_PTR)MmNonPagedPoolStart) && (Address <= (ULONG_PTR)MmNonPagedPoolEnd))
-        KdbpPrint("Allocation is from NonPagedPool region\n");
-    else
-    {
-        KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID)Address);
-        return TRUE;
-    }
+    //
+    // Allocate the pool buffer now
+    //
+    Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
 
-    /* Loop all entries of that page */
-    Entry = PoolPage;
-    do
+    //
+    // If the buffer is page-aligned, this is a large page allocation and we
+    // won't touch it
+    //
+    if (PAGE_ALIGN(Buffer) != Buffer)
     {
-        /* Check if the address is within that entry */
-        ThisOne = ((Address >= (ULONG_PTR)Entry) &&
-                   (Address < (ULONG_PTR)(Entry + Entry->BlockSize)));
-
-        if (!(Flags & 1) || ThisOne)
+        //
+        // Also if special pool is enabled, and this was allocated from there,
+        // we won't touch it either
+        //
+        if ((ExpPoolFlags & POOL_FLAG_SPECIAL_POOL) &&
+            (MmIsSpecialPoolAddress(Buffer)))
         {
-            /* Print the line */
-            KdbpPrint("%c%p size: %4d previous size: %4d  %s  %.4s\n",
-                     ThisOne ? '*' : ' ', Entry, Entry->BlockSize, Entry->PreviousSize,
-                     (Flags & 0x80000000) ? "" : (Entry->PoolType ? "(Allocated)" : "(Free)     "),
-                     (Flags & 0x80000000) ? "" : (PCHAR)&Entry->PoolTag);
+            return Buffer;
         }
 
-        if (Flags & 1)
+        //
+        // If it wasn't actually allocated with quota charges, ignore it too
+        //
+        if (!(PoolType & QUOTA_POOL_MASK)) return Buffer;
+
+        //
+        // If this is the system process, we don't charge quota, so ignore
+        //
+        if (Process == PsInitialSystemProcess) return Buffer;
+
+        //
+        // Actually go and charge quota for the process now
+        //
+        Entry = POOL_ENTRY(Buffer);
+        Status = PsChargeProcessPoolQuota(Process,
+                                          PoolType & BASE_POOL_TYPE_MASK,
+                                          Entry->BlockSize * POOL_BLOCK_SIZE);
+        if (!NT_SUCCESS(Status))
         {
-            Data = (PULONG)(Entry + 1);
-            KdbpPrint("    %p  %08lx %08lx %08lx %08lx\n"
-                     "    %p  %08lx %08lx %08lx %08lx\n",
-                     &Data[0], Data[0], Data[1], Data[2], Data[3],
-                     &Data[4], Data[4], Data[5], Data[6], Data[7]);
+            //
+            // Quota failed, back out the allocation, clear the owner, and fail
+            //
+            ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = NULL;
+            ExFreePoolWithTag(Buffer, Tag);
+            if (Raise) RtlRaiseStatus(Status);
+            return NULL;
         }
 
-        /* Go to next entry */
-        Entry = POOL_BLOCK(Entry, Entry->BlockSize);
+        //
+        // Quota worked, write the owner and then reference it before returning
+        //
+        ((PVOID *)POOL_NEXT_BLOCK(Entry))[-1] = Process;
+        ObReferenceObject(Process);
+    }
+    else if (!(Buffer) && (Raise))
+    {
+        //
+        // The allocation failed, raise an error if we are in raise mode
+        //
+        RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
     }
-    while ((Entry->BlockSize != 0) && ((ULONG_PTR)Entry < (ULONG_PTR)PoolPage + PAGE_SIZE));
 
-    return TRUE;
+    //
+    // Return the allocated buffer
+    //
+    return Buffer;
 }
 
-#endif // DBG && KDBG
-
 /* EOF */