2442 lines
60 KiB
C
2442 lines
60 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
llcmem.c
|
||
|
||
Abstract:
|
||
|
||
Functions for allocating & freeing memory. Split out from llclib.c. The
|
||
reasons this module created are to isolate the memory allocators and to
|
||
convert from using the Zone package to just using non-paged pool for all
|
||
of DLC's memory requirements.
|
||
|
||
Functions in this module are used by both DLC & LLC. These functions must
|
||
go into a statically-linked library if DLC is ever divorced from LLC
|
||
|
||
We use pools to avoid the overhead of calling the system allocation & free
|
||
functions (although in practice, we end up allocating additional memory
|
||
because the packet count in the pool is usually insufficient). The downside
|
||
is that we may allocate memory that in the majority of situations is not
|
||
used, but the packets in pools tend to be small and few in number
|
||
|
||
To aid in tracking memory resources, DLC/LLC now defines the following
|
||
memory categories:
|
||
|
||
Memory
|
||
- arbitrary sized blocks allocated out of non-paged pool using
|
||
ExAllocatePool(NonPagedPool, ...)
|
||
|
||
ZeroMemory
|
||
- arbitrary sized blocks allocated out of non-paged pool using
|
||
ExAllocatePool(NonPagedPool, ...) and initialized to zeroes
|
||
|
||
Pool
|
||
- small sets of (relatively) small packets are allocated in one
|
||
block from Memory or ZeroMemory as a Pool and then subdivided
|
||
into packets (CreatePacketPool, DeletePacketPool, AllocatePacket,
|
||
DeallocatePacket)
|
||
|
||
Object
|
||
- structures which may be packets allocated from Pool which have
|
||
a known size and initialization values. Pseudo-category mainly
|
||
for debugging purposes
|
||
|
||
Contents:
|
||
InitializeMemoryPackage (DEBUG)
|
||
PullEntryList (DEBUG)
|
||
LinkMemoryUsage (DEBUG)
|
||
UnlinkMemoryUsage (DEBUG)
|
||
ChargeNonPagedPoolUsage (DEBUG)
|
||
RefundNonPagedPoolUsage (DEBUG)
|
||
AllocateMemory (DEBUG)
|
||
AllocateZeroMemory
|
||
DeallocateMemory (DEBUG)
|
||
AllocateObject (DEBUG)
|
||
FreeObject (DEBUG)
|
||
ValidateObject (DEBUG)
|
||
GetObjectSignature (DEBUG)
|
||
GetObjectBaseSize (DEBUG)
|
||
CreatePacketPool
|
||
DeletePacketPool
|
||
AllocatePacket
|
||
DeallocatePacket
|
||
CreateObjectPool (DEBUG)
|
||
AllocatePoolObject (DEBUG)
|
||
DeallocatePoolObject (DEBUG)
|
||
DeleteObjectPool (DEBUG)
|
||
CheckMemoryReturned (DEBUG)
|
||
CheckDriverMemoryUsage (DEBUG)
|
||
MemoryAllocationError (DEBUG)
|
||
UpdateCounter (DEBUG)
|
||
MemoryCounterOverflow (DEBUG)
|
||
DumpMemoryMetrics (DEBUG)
|
||
DumpPoolStats (DEBUG)
|
||
MapObjectId (DEBUG)
|
||
DumpPool (DEBUG)
|
||
DumpPoolList (DEBUG)
|
||
DumpPacketHead (DEBUG)
|
||
DumpMemoryUsageList (DEBUG)
|
||
DumpMemoryUsage (DEBUG)
|
||
x86SleazeCallersAddress (DEBUG)
|
||
CollectReturnAddresses (DEBUG)
|
||
GetLastReturnAddress (DEBUG)
|
||
VerifyElementOnList (DEBUG)
|
||
CheckList (DEBUG)
|
||
CheckEntryOnList (DEBUG)
|
||
DumpPrivateMemoryHeader (DEBUG)
|
||
ReportSwitchSettings (DEBUG)
|
||
|
||
Author:
|
||
|
||
Richard L Firth (rfirth) 10-Mar-1993
|
||
|
||
Environment:
|
||
|
||
kernel mode only.
|
||
|
||
Notes:
|
||
|
||
In non-debug version, DeallocateMemory is replaced with a macro which calls
|
||
ExFreePool(...) and AllocateMemory is replaced by a macro which calls
|
||
ExAllocatePool(NonPagedPool, ...)
|
||
|
||
Revision History:
|
||
|
||
09-Mar-1993 RFirth
|
||
Created
|
||
|
||
--*/
|
||
|
||
#ifndef i386
|
||
#define LLC_PRIVATE_PROTOTYPES
|
||
#endif
|
||
|
||
#include <ntddk.h>
|
||
#include <ndis.h>
|
||
#define APIENTRY
|
||
#include <dlcapi.h>
|
||
#include <dlcio.h>
|
||
#include "llcapi.h"
|
||
#include "dlcdef.h"
|
||
#include "dlcreg.h"
|
||
#include "dlctyp.h"
|
||
#include "llcdef.h"
|
||
#include "llcmem.h"
|
||
#include "llctyp.h"
|
||
|
||
#define DWORD_ROUNDUP(d) (((d) + 3) & ~3)
|
||
|
||
#define YES_NO(thing) ((thing) ? "Yes" : "No")
|
||
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// some variables to keep track of memory allocations from non-paged pool. These
|
||
// are the cumulative totals for all of DLC's non-paged pool memory usage
|
||
//
|
||
|
||
KSPIN_LOCK MemoryCountersLock;
|
||
KIRQL MemoryCountersIrql;
|
||
|
||
ULONG GoodNonPagedPoolAllocs = 0;
|
||
ULONG BadNonPagedPoolAllocs = 0;
|
||
ULONG GoodNonPagedPoolFrees = 0;
|
||
ULONG BadNonPagedPoolFrees = 0;
|
||
ULONG NonPagedPoolRequested = 0;
|
||
ULONG NonPagedPoolAllocated = 0;
|
||
ULONG TotalNonPagedPoolRequested = 0;
|
||
ULONG TotalNonPagedPoolAllocated = 0;
|
||
ULONG TotalNonPagedPoolFreed = 0;
|
||
|
||
KSPIN_LOCK MemoryAllocatorLock;
|
||
ULONG InMemoryAllocator = 0;
|
||
|
||
KSPIN_LOCK PoolCreatorLock;
|
||
ULONG InPoolCreator = 0;
|
||
|
||
//
|
||
// MemoryUsageList - linked list of all MEMORY_USAGE structures in driver. If we
|
||
// allocate something that has a MEMORY_USAGE structure (& what doesn't?) then
|
||
// don't delete it, we can later scan this list to find out what is still allocated
|
||
//
|
||
|
||
PMEMORY_USAGE MemoryUsageList = NULL;
|
||
KSPIN_LOCK MemoryUsageLock;
|
||
|
||
//
|
||
// flags to aid in debugging - change states via debugger
|
||
//
|
||
|
||
//BOOLEAN DebugDump = TRUE;
|
||
BOOLEAN DebugDump = FALSE;
|
||
|
||
//BOOLEAN DeleteBusyListAnyway = TRUE;
|
||
BOOLEAN DeleteBusyListAnyway = FALSE;
|
||
|
||
BOOLEAN MemoryCheckNotify = TRUE;
|
||
//BOOLEAN MemoryCheckNotify = FALSE;
|
||
|
||
BOOLEAN MemoryCheckStop = TRUE;
|
||
//BOOLEAN MemoryCheckStop = FALSE;
|
||
|
||
BOOLEAN MaintainPrivateLists = TRUE;
|
||
//BOOLEAN MaintainPrivateLists = FALSE;
|
||
|
||
BOOLEAN MaintainGlobalLists = TRUE;
|
||
//BOOLEAN MaintainGlobalLists = FALSE;
|
||
|
||
BOOLEAN ZapDeallocatedPackets = TRUE;
|
||
//BOOLEAN ZapDeallocatedPackets = FALSE;
|
||
|
||
BOOLEAN ZapFreedMemory = TRUE;
|
||
//BOOLEAN ZapFreedMemory = FALSE;
|
||
|
||
//
|
||
// DlcGlobalMemoryList - every block that is allocated is linked to this list
|
||
// and removed when deleted. Helps us keep track of who allocated which block
|
||
//
|
||
|
||
KSPIN_LOCK DlcGlobalMemoryListLock;
|
||
LIST_ENTRY DlcGlobalMemoryList;
|
||
ULONG DlcGlobalMemoryListCount = 0;
|
||
|
||
//
|
||
// local function prototypes
|
||
//
|
||
|
||
VOID MemoryAllocationError(PCHAR, PVOID);
|
||
VOID UpdateCounter(PULONG, LONG);
|
||
VOID MemoryCounterOverflow(PULONG, LONG);
|
||
VOID DumpMemoryMetrics(VOID);
|
||
VOID DumpPoolStats(PCHAR, PPACKET_POOL);
|
||
PCHAR MapObjectId(DLC_OBJECT_TYPE);
|
||
VOID DumpPool(PPACKET_POOL);
|
||
VOID DumpPoolList(PCHAR, PSINGLE_LIST_ENTRY);
|
||
VOID DumpPacketHead(PPACKET_HEAD, ULONG);
|
||
VOID DumpMemoryUsageList(VOID);
|
||
VOID DumpMemoryUsage(PMEMORY_USAGE, BOOLEAN);
|
||
VOID CollectReturnAddresses(PVOID*, ULONG, ULONG);
|
||
PVOID* GetLastReturnAddress(PVOID**);
|
||
VOID x86SleazeCallersAddress(PVOID*, PVOID*);
|
||
BOOLEAN VerifyElementOnList(PSINGLE_LIST_ENTRY, PSINGLE_LIST_ENTRY);
|
||
VOID CheckList(PSINGLE_LIST_ENTRY, ULONG);
|
||
VOID CheckEntryOnList(PLIST_ENTRY, PLIST_ENTRY, BOOLEAN);
|
||
VOID DumpPrivateMemoryHeader(PPRIVATE_NON_PAGED_POOL_HEAD);
|
||
VOID ReportSwitchSettings(PSTR);
|
||
|
||
#define GRAB_SPINLOCK() KeAcquireSpinLock(&MemoryCountersLock, &MemoryCountersIrql)
|
||
#define FREE_SPINLOCK() KeReleaseSpinLock(&MemoryCountersLock, MemoryCountersIrql)
|
||
|
||
#ifdef i386
|
||
#define GET_CALLERS_ADDRESS x86SleazeCallersAddress
|
||
#else
|
||
#define GET_CALLERS_ADDRESS RtlGetCallersAddress
|
||
#endif
|
||
|
||
//
|
||
// private prototypes
|
||
//
|
||
|
||
ULONG
|
||
GetObjectSignature(
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
);
|
||
|
||
ULONG
|
||
GetObjectBaseSize(
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
);
|
||
|
||
#else
|
||
|
||
#define GRAB_SPINLOCK()
|
||
#define FREE_SPINLOCK()
|
||
|
||
#endif
|
||
|
||
//
|
||
// functions
|
||
//
|
||
|
||
|
||
|
||
#if DBG
|
||
|
||
VOID
|
||
InitializeMemoryPackage(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs initialization for memory allocation functions
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KeInitializeSpinLock(&MemoryCountersLock);
|
||
KeInitializeSpinLock(&MemoryAllocatorLock);
|
||
KeInitializeSpinLock(&PoolCreatorLock);
|
||
KeInitializeSpinLock(&MemoryUsageLock);
|
||
KeInitializeSpinLock(&DlcGlobalMemoryListLock);
|
||
DriverMemoryUsage.OwnerObjectId = DlcDriverObject;
|
||
DriverMemoryUsage.OwnerInstance = 0x4D454D; // 'MEM'
|
||
InitializeListHead(&DriverMemoryUsage.PrivateList);
|
||
LinkMemoryUsage(&DriverMemoryUsage);
|
||
DriverStringUsage.OwnerObjectId = DlcDriverObject;
|
||
DriverStringUsage.OwnerInstance = 0x535452; // 'STR'
|
||
InitializeListHead(&DriverStringUsage.PrivateList);
|
||
LinkMemoryUsage(&DriverStringUsage);
|
||
InitializeListHead(&DlcGlobalMemoryList);
|
||
ReportSwitchSettings("DLC.InitializeMemoryPackage (DEBUG version only)");
|
||
}
|
||
|
||
|
||
PSINGLE_LIST_ENTRY
|
||
PullEntryList(
|
||
IN PSINGLE_LIST_ENTRY List,
|
||
IN PSINGLE_LIST_ENTRY Element
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The missing SINGLE_LIST_ENTRY function. Removes an entry from a single-linked
|
||
list. The entry can be anywhere on the list. Reduces size of list elements
|
||
by one pointer, at expense of increased time to traverse list.
|
||
|
||
This function SHOULD NOT return NULL: if it does then the code is broken
|
||
since it assumes that an element is on a list, when it ain't
|
||
|
||
Arguments:
|
||
|
||
List - pointer to singly-linked list anchor. This MUST be the address of
|
||
the pointer to the list, not the first element in the list
|
||
Element - pointer to element to remove from List
|
||
|
||
Return Value:
|
||
|
||
PSINGLE_LIST_ENTRY
|
||
Success - Element
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PSINGLE_LIST_ENTRY prev = List;
|
||
|
||
ASSERT(List);
|
||
ASSERT(Element);
|
||
|
||
while (List = List->Next) {
|
||
if (List == Element) {
|
||
prev->Next = Element->Next;
|
||
return Element;
|
||
}
|
||
prev = List;
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
VOID
|
||
LinkMemoryUsage(
|
||
IN PMEMORY_USAGE pMemoryUsage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add pMemoryUsage to linked list of MEMORY_USAGE structures
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure to add
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&MemoryUsageLock, &irql);
|
||
PushEntryList((PSINGLE_LIST_ENTRY)&MemoryUsageList, (PSINGLE_LIST_ENTRY)pMemoryUsage);
|
||
KeReleaseSpinLock(&MemoryUsageLock, irql);
|
||
}
|
||
|
||
|
||
VOID
|
||
UnlinkMemoryUsage(
|
||
IN PMEMORY_USAGE pMemoryUsage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Remove pMemoryUsage from linked list of MEMORY_USAGE structures
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure to remove
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
|
||
ASSERT(pMemoryUsage);
|
||
CheckMemoryReturned(pMemoryUsage);
|
||
KeAcquireSpinLock(&MemoryUsageLock, &irql);
|
||
ASSERT(PullEntryList((PSINGLE_LIST_ENTRY)&MemoryUsageList, (PSINGLE_LIST_ENTRY)pMemoryUsage));
|
||
KeReleaseSpinLock(&MemoryUsageLock, irql);
|
||
}
|
||
|
||
|
||
VOID
|
||
ChargeNonPagedPoolUsage(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN ULONG Size,
|
||
IN PPRIVATE_NON_PAGED_POOL_HEAD Block
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Charges this non-paged pool allocation to a specific memory user
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to structure recording memory usage
|
||
Size - size of block allocated
|
||
Block - pointer to private header of allocated block
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&pMemoryUsage->SpinLock, &irql);
|
||
if (pMemoryUsage->NonPagedPoolAllocated + Size < pMemoryUsage->NonPagedPoolAllocated) {
|
||
if (MemoryCheckNotify) {
|
||
DbgPrint("DLC.ChargeNonPagedPoolUsage: Overcharged? Usage @ %08x\n", pMemoryUsage);
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DumpMemoryUsage(pMemoryUsage, TRUE);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
pMemoryUsage->NonPagedPoolAllocated += Size;
|
||
++pMemoryUsage->AllocateCount;
|
||
|
||
//
|
||
// link this block to the memory usage private list
|
||
//
|
||
|
||
if (MaintainPrivateLists) {
|
||
if (pMemoryUsage->PrivateList.Flink == NULL) {
|
||
|
||
//
|
||
// slight hack to make initializing MEMORY_USAGEs easier...
|
||
//
|
||
|
||
InitializeListHead(&pMemoryUsage->PrivateList);
|
||
}
|
||
InsertTailList(&pMemoryUsage->PrivateList, &Block->PrivateList);
|
||
}
|
||
KeReleaseSpinLock(&pMemoryUsage->SpinLock, irql);
|
||
}
|
||
|
||
|
||
VOID
|
||
RefundNonPagedPoolUsage(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN ULONG Size,
|
||
IN PPRIVATE_NON_PAGED_POOL_HEAD Block
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Refunds a non-paged pool allocation to a specific memory user
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to structure recording memory usage
|
||
Size - size of block allocated
|
||
Block - pointer to private header of allocated block
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&pMemoryUsage->SpinLock, &irql);
|
||
if (pMemoryUsage->NonPagedPoolAllocated - Size > pMemoryUsage->NonPagedPoolAllocated) {
|
||
if (MemoryCheckNotify) {
|
||
DbgPrint("DLC.RefundNonPagedPoolUsage: Error: Freeing unallocated memory? Usage @ %08x, %d\n",
|
||
pMemoryUsage,
|
||
Size
|
||
);
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DumpMemoryUsage(pMemoryUsage, TRUE);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
|
||
//
|
||
// unlink this block from the memory usage private list
|
||
//
|
||
|
||
if (MaintainPrivateLists) {
|
||
CheckEntryOnList(&Block->PrivateList, &pMemoryUsage->PrivateList, TRUE);
|
||
RemoveEntryList(&Block->PrivateList);
|
||
}
|
||
pMemoryUsage->NonPagedPoolAllocated -= Size;
|
||
++pMemoryUsage->FreeCount;
|
||
KeReleaseSpinLock(&pMemoryUsage->SpinLock, irql);
|
||
}
|
||
|
||
|
||
PVOID
|
||
AllocateMemory(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates memory out of non-paged pool. For the debug version, we round up
|
||
the requested size to the next 4-byte boundary and we add header and tail
|
||
sections which contain a signature to check for over-write, and in-use and
|
||
size information
|
||
|
||
In the non-debug version, this function is replaced by a call to
|
||
ExAllocatePool(NonPagedPool, ...)
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
Size - number of bytes to allocate
|
||
|
||
Return Value:
|
||
|
||
PVOID
|
||
Success - pointer to allocated memory
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID pMem;
|
||
ULONG OriginalSize = Size;
|
||
PUCHAR pMemEnd;
|
||
|
||
/*
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.AllocateMemory: Error: Memory allocator clash on entry. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
++InMemoryAllocator;
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
|
||
Size = DWORD_ROUNDUP(Size)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_HEAD)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_TAIL);
|
||
|
||
pMem = ExAllocatePoolWithTag(NonPagedPool, (ULONG)Size, DLC_POOL_TAG);
|
||
if (pMem) {
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Size = Size;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->OriginalSize = OriginalSize;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Flags = MEM_FLAGS_IN_USE;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Signature = SIGNATURE1;
|
||
|
||
pMemEnd = (PUCHAR)pMem
|
||
+ DWORD_ROUNDUP(OriginalSize)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_HEAD);
|
||
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Size = Size;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Signature = SIGNATURE2;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Pattern1 = PATTERN1;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Pattern2 = PATTERN2;
|
||
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&GoodNonPagedPoolAllocs, 1);
|
||
UpdateCounter(&NonPagedPoolAllocated, (LONG)Size);
|
||
UpdateCounter(&NonPagedPoolRequested, (LONG)OriginalSize);
|
||
UpdateCounter(&TotalNonPagedPoolRequested, (LONG)OriginalSize);
|
||
UpdateCounter(&TotalNonPagedPoolAllocated, (LONG)Size);
|
||
FREE_SPINLOCK();
|
||
|
||
if (MaintainGlobalLists) {
|
||
|
||
KIRQL irql;
|
||
|
||
//
|
||
// record the caller and add this block to the global list
|
||
//
|
||
|
||
GET_CALLERS_ADDRESS(&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Stack[0],
|
||
&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Stack[1]
|
||
);
|
||
KeAcquireSpinLock(&DlcGlobalMemoryListLock, &irql);
|
||
InsertTailList(&DlcGlobalMemoryList,
|
||
&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->GlobalList
|
||
);
|
||
++DlcGlobalMemoryListCount;
|
||
KeReleaseSpinLock(&DlcGlobalMemoryListLock, irql);
|
||
}
|
||
ChargeNonPagedPoolUsage(pMemoryUsage, Size, (PPRIVATE_NON_PAGED_POOL_HEAD)pMem);
|
||
pMem = (PVOID)((PUCHAR)pMem + sizeof(PRIVATE_NON_PAGED_POOL_HEAD));
|
||
} else {
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&BadNonPagedPoolAllocs, 1);
|
||
FREE_SPINLOCK();
|
||
}
|
||
|
||
/*
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
--InMemoryAllocator;
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.AllocateMemory: Error: Memory allocator clash on exit. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
|
||
return pMem;
|
||
}
|
||
|
||
|
||
VOID
|
||
DeallocateMemory(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN PVOID Pointer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
frees memory to non-paged pool
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
Pointer - pointer to previously allocated non-paged pool memory
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPRIVATE_NON_PAGED_POOL_HEAD pHead;
|
||
PPRIVATE_NON_PAGED_POOL_TAIL pTail;
|
||
|
||
/*
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.DeallocateMemory: Error: Memory allocator clash on entry. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
++InMemoryAllocator;
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
|
||
pHead = (PPRIVATE_NON_PAGED_POOL_HEAD)((PUCHAR)Pointer - sizeof(PRIVATE_NON_PAGED_POOL_HEAD));
|
||
pTail = (PPRIVATE_NON_PAGED_POOL_TAIL)((PUCHAR)pHead + pHead->Size - sizeof(PRIVATE_NON_PAGED_POOL_TAIL));
|
||
|
||
if (MaintainGlobalLists) {
|
||
CheckEntryOnList(&pHead->GlobalList, &DlcGlobalMemoryList, TRUE);
|
||
|
||
if (pHead->GlobalList.Flink == NULL
|
||
|| pHead->GlobalList.Blink == NULL) {
|
||
if (MemoryCheckNotify) {
|
||
DbgPrint("DLC.DeallocateMemory: Error: Block already globally freed: %08x\n", pHead);
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
|
||
if (pHead->Signature != SIGNATURE1
|
||
|| !(pHead->Flags & MEM_FLAGS_IN_USE)
|
||
|| pTail->Size != pHead->Size
|
||
|| pTail->Signature != SIGNATURE2
|
||
|| pTail->Pattern1 != PATTERN1
|
||
|| pTail->Pattern2 != PATTERN2) {
|
||
if (MemoryCheckNotify || MemoryCheckStop) {
|
||
MemoryAllocationError("DeallocateMemory", (PVOID)pHead);
|
||
}
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&BadNonPagedPoolFrees, 1);
|
||
FREE_SPINLOCK();
|
||
} else {
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&GoodNonPagedPoolFrees, 1);
|
||
FREE_SPINLOCK();
|
||
}
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&NonPagedPoolRequested, -(LONG)pHead->OriginalSize);
|
||
UpdateCounter(&NonPagedPoolAllocated, -(LONG)pHead->Size);
|
||
UpdateCounter(&TotalNonPagedPoolFreed, (LONG)pHead->Size);
|
||
FREE_SPINLOCK();
|
||
|
||
//
|
||
// access Size field before ExFreePool zaps it/somebody else allocates memory
|
||
//
|
||
|
||
RefundNonPagedPoolUsage(pMemoryUsage, pHead->Size, pHead);
|
||
|
||
if (MaintainGlobalLists) {
|
||
|
||
//
|
||
// remove this block from the global list
|
||
//
|
||
|
||
RemoveEntryList(&pHead->GlobalList);
|
||
--DlcGlobalMemoryListCount;
|
||
pHead->GlobalList.Flink = pHead->GlobalList.Flink = NULL;
|
||
}
|
||
|
||
if (ZapFreedMemory) {
|
||
RtlFillMemory(pHead + 1,
|
||
DWORD_ROUNDUP(pHead->OriginalSize),
|
||
ZAP_EX_FREE_VALUE
|
||
);
|
||
}
|
||
|
||
ExFreePool((PVOID)pHead);
|
||
|
||
/*
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
--InMemoryAllocator;
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.DeallocateMemory: Error: Memory allocator clash on exit. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
}
|
||
|
||
|
||
PVOID
|
||
AllocateObject(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN DLC_OBJECT_TYPE ObjectType,
|
||
IN ULONG ObjectSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates a pseudo-object
|
||
|
||
Arguments:
|
||
|
||
ObjectType - type of object to allocate
|
||
ObjectSize - size of object; mainly because some objects have variable size
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
|
||
Return Value:
|
||
|
||
PVOID
|
||
Success - pointer to object allocated from non-paged pool
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
POBJECT_ID pObject;
|
||
ULONG signature;
|
||
ULONG baseSize;
|
||
|
||
signature = GetObjectSignature(ObjectType);
|
||
baseSize = GetObjectBaseSize(ObjectType);
|
||
if (baseSize < ObjectSize) {
|
||
DbgPrint("DLC.AllocateObject: Error: Invalid size %d for ObjectType %08x (should be >= %d)\n",
|
||
ObjectSize,
|
||
ObjectType,
|
||
baseSize
|
||
);
|
||
DbgBreakPoint();
|
||
}
|
||
pObject = (POBJECT_ID)AllocateZeroMemory(pMemoryUsage, ObjectSize);
|
||
if (pObject) {
|
||
pObject->Signature = signature;
|
||
pObject->Type = ObjectType;
|
||
pObject->Size = baseSize;
|
||
pObject->Extra = ObjectSize - baseSize;
|
||
}
|
||
return (PVOID)pObject;
|
||
}
|
||
|
||
|
||
VOID
|
||
FreeObject(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN PVOID pObject,
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Deallocates a pseudo-object
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
pObject - pointer to object allocated with AllocateObject
|
||
ObjectType - type of object pObject supposed to be
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ValidateObject(pObject, ObjectType);
|
||
DeallocateMemory(pMemoryUsage, pObject);
|
||
}
|
||
|
||
|
||
VOID
|
||
ValidateObject(
|
||
IN POBJECT_ID pObject,
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks that an object is what its supposed to be
|
||
|
||
Arguments:
|
||
|
||
pObject - pointer to object to check
|
||
ObjectType - type of object pObject supposed to point to
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG signature = GetObjectSignature(ObjectType);
|
||
ULONG baseSize = GetObjectBaseSize(ObjectType);
|
||
|
||
if (pObject->Signature != signature
|
||
|| pObject->Type != ObjectType
|
||
|| pObject->Size != baseSize) {
|
||
DbgPrint("DLC.ValidateObject: Error: InvalidObject %08x, Type=%08x\n",
|
||
pObject,
|
||
ObjectType
|
||
);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
|
||
|
||
ULONG
|
||
GetObjectSignature(
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns the signature for an object type
|
||
|
||
Arguments:
|
||
|
||
ObjectType - type of object to return signature for
|
||
|
||
Return Value:
|
||
|
||
ULONG
|
||
|
||
--*/
|
||
|
||
{
|
||
switch (ObjectType) {
|
||
case FileContextObject:
|
||
return SIGNATURE_FILE;
|
||
|
||
case AdapterContextObject:
|
||
return SIGNATURE_ADAPTER;
|
||
|
||
case BindingContextObject:
|
||
return SIGNATURE_BINDING;
|
||
|
||
case DlcSapObject:
|
||
case DlcGroupSapObject:
|
||
return SIGNATURE_DLC_SAP;
|
||
|
||
case DlcLinkObject:
|
||
return SIGNATURE_DLC_LINK;
|
||
|
||
case DlcDixObject:
|
||
return SIGNATURE_DIX;
|
||
|
||
case LlcDataLinkObject:
|
||
return SIGNATURE_LLC_LINK;
|
||
|
||
case LlcSapObject:
|
||
case LlcGroupSapObject:
|
||
return SIGNATURE_LLC_SAP;
|
||
|
||
default:
|
||
DbgPrint("DLC.GetObjectSignature: Error: unknown object type %08x\n", ObjectType);
|
||
DbgBreakPoint();
|
||
return 0;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
ULONG
|
||
GetObjectBaseSize(
|
||
IN DLC_OBJECT_TYPE ObjectType
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
returns the base size for an object
|
||
|
||
Arguments:
|
||
|
||
ObjectType - type of object to return base size for
|
||
|
||
Return Value:
|
||
|
||
ULONG
|
||
|
||
--*/
|
||
|
||
{
|
||
switch (ObjectType) {
|
||
case FileContextObject:
|
||
return sizeof(DLC_FILE_CONTEXT);
|
||
|
||
case AdapterContextObject:
|
||
return sizeof(ADAPTER_CONTEXT);
|
||
|
||
case BindingContextObject:
|
||
return sizeof(BINDING_CONTEXT);
|
||
|
||
case DlcSapObject:
|
||
case DlcGroupSapObject:
|
||
return sizeof(DLC_OBJECT);
|
||
|
||
case DlcLinkObject:
|
||
return sizeof(DLC_OBJECT);
|
||
|
||
case DlcDixObject:
|
||
return sizeof(DLC_OBJECT);
|
||
|
||
case LlcDataLinkObject:
|
||
return sizeof(DATA_LINK);
|
||
|
||
case LlcSapObject:
|
||
case LlcGroupSapObject:
|
||
return sizeof(LLC_OBJECT);
|
||
|
||
default:
|
||
DbgPrint("DLC.GetObjectBaseSize: Error: unknown object type %08x\n", ObjectType);
|
||
DbgBreakPoint();
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
PVOID
|
||
AllocateZeroMemory(
|
||
#if DBG
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
#endif
|
||
IN ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allocates memory out of non-paged pool. For the debug version, we round up
|
||
the requested size to the next 4-byte boundary and we add header and tail
|
||
sections which contain a signature to check for over-write, and in-use and
|
||
size information
|
||
|
||
The memory is zeroed before being returned to the caller
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
Size - number of bytes to allocate
|
||
|
||
Return Value:
|
||
|
||
PVOID
|
||
Success - pointer to allocated memory
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID pMem;
|
||
|
||
#if DBG
|
||
|
||
ULONG OriginalSize = Size;
|
||
PUCHAR pMemEnd;
|
||
|
||
/*
|
||
KIRQL irql;
|
||
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.AllocateZeroMemory: Error: Memory allocator clash on entry. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
++InMemoryAllocator;
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
|
||
Size = DWORD_ROUNDUP(Size)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_HEAD)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_TAIL);
|
||
|
||
#endif
|
||
|
||
pMem = ExAllocatePoolWithTag(NonPagedPool, (ULONG)Size, DLC_POOL_TAG);
|
||
if (pMem) {
|
||
LlcZeroMem(pMem, Size);
|
||
|
||
#if DBG
|
||
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Size = Size;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->OriginalSize = OriginalSize;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Flags = MEM_FLAGS_IN_USE;
|
||
((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Signature = SIGNATURE1;
|
||
|
||
pMemEnd = (PUCHAR)pMem
|
||
+ DWORD_ROUNDUP(OriginalSize)
|
||
+ sizeof(PRIVATE_NON_PAGED_POOL_HEAD);
|
||
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Size = Size;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Signature = SIGNATURE2;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Pattern1 = PATTERN1;
|
||
((PPRIVATE_NON_PAGED_POOL_TAIL)pMemEnd)->Pattern2 = PATTERN2;
|
||
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&GoodNonPagedPoolAllocs, 1);
|
||
UpdateCounter(&NonPagedPoolAllocated, (LONG)Size);
|
||
UpdateCounter(&NonPagedPoolRequested, (LONG)OriginalSize);
|
||
UpdateCounter(&TotalNonPagedPoolRequested, (LONG)OriginalSize);
|
||
UpdateCounter(&TotalNonPagedPoolAllocated, (LONG)Size);
|
||
FREE_SPINLOCK();
|
||
|
||
if (MaintainGlobalLists) {
|
||
|
||
KIRQL irql;
|
||
|
||
//
|
||
// record the caller and add this block to the global list
|
||
//
|
||
|
||
GET_CALLERS_ADDRESS(&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Stack[0],
|
||
&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->Stack[1]
|
||
);
|
||
|
||
KeAcquireSpinLock(&DlcGlobalMemoryListLock, &irql);
|
||
InsertTailList(&DlcGlobalMemoryList,
|
||
&((PPRIVATE_NON_PAGED_POOL_HEAD)pMem)->GlobalList
|
||
);
|
||
++DlcGlobalMemoryListCount;
|
||
KeReleaseSpinLock(&DlcGlobalMemoryListLock, irql);
|
||
}
|
||
ChargeNonPagedPoolUsage(pMemoryUsage, Size, (PPRIVATE_NON_PAGED_POOL_HEAD)pMem);
|
||
pMem = (PVOID)((PUCHAR)pMem + sizeof(PRIVATE_NON_PAGED_POOL_HEAD));
|
||
} else {
|
||
GRAB_SPINLOCK();
|
||
UpdateCounter(&BadNonPagedPoolAllocs, 1);
|
||
FREE_SPINLOCK();
|
||
}
|
||
|
||
/*
|
||
KeAcquireSpinLock(&MemoryAllocatorLock, &irql);
|
||
--InMemoryAllocator;
|
||
if (InMemoryAllocator) {
|
||
DbgPrint("DLC.AllocateZeroMemory: Error: Memory allocator clash on exit. Count = %d\n",
|
||
InMemoryAllocator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
KeReleaseSpinLock(&MemoryAllocatorLock, irql);
|
||
*/
|
||
|
||
#else
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
return pMem;
|
||
}
|
||
|
||
|
||
PPACKET_POOL
|
||
CreatePacketPool(
|
||
#if DBG
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN PVOID pOwner,
|
||
IN DLC_OBJECT_TYPE ObjectType,
|
||
#endif
|
||
IN ULONG PacketSize,
|
||
IN ULONG NumberOfPackets
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
creates a packet pool. A packet pool is a collection of same-sized packets
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
pOwner - pointer to owner object
|
||
ObjectType - type of object for owner
|
||
PacketSize - size of packet in bytes
|
||
NumberOfPackets - initial number of packets in pool
|
||
|
||
Return Value:
|
||
|
||
PPACKET_POOL
|
||
Success - pointer to PACKET_POOL structure allocated from non-paged pool
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
PPACKET_POOL pPacketPool;
|
||
PPACKET_HEAD pPacketHead;
|
||
|
||
#if DBG
|
||
/*
|
||
// DbgPrint("DLC.CreatePacketPool(%d, %d)\n", PacketSize, NumberOfPackets);
|
||
if (InPoolCreator) {
|
||
DbgPrint("DLC.CreatePacketPool: Error: Pool Creator clash on entry. Count = %d\n",
|
||
InPoolCreator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
++InPoolCreator;
|
||
*/
|
||
|
||
pPacketPool = AllocateZeroMemory(pMemoryUsage, sizeof(PACKET_POOL));
|
||
#else
|
||
pPacketPool = AllocateZeroMemory(sizeof(PACKET_POOL));
|
||
#endif
|
||
|
||
if (pPacketPool) {
|
||
|
||
#if DBG
|
||
pPacketPool->OriginalPacketCount = NumberOfPackets;
|
||
pPacketPool->MemoryUsage.Owner = pPacketPool;
|
||
pPacketPool->MemoryUsage.OwnerObjectId = ObjectType;
|
||
#endif
|
||
|
||
while (NumberOfPackets--) {
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// charge memory for individual packets to the pool
|
||
//
|
||
|
||
pPacketHead = (PPACKET_HEAD)AllocateZeroMemory(&pPacketPool->MemoryUsage,
|
||
sizeof(PACKET_HEAD) + PacketSize
|
||
);
|
||
#else
|
||
pPacketHead = (PPACKET_HEAD)AllocateZeroMemory(sizeof(PACKET_HEAD) + PacketSize);
|
||
#endif
|
||
|
||
if (pPacketHead) {
|
||
#if DBG
|
||
pPacketHead->Signature = PACKET_HEAD_SIGNATURE;
|
||
pPacketHead->pPacketPool = pPacketPool;
|
||
++pPacketPool->FreeCount;
|
||
#endif
|
||
|
||
pPacketHead->Flags = PACKET_FLAGS_FREE;
|
||
PushEntryList(&pPacketPool->FreeList, (PSINGLE_LIST_ENTRY)pPacketHead);
|
||
} else {
|
||
while (pPacketPool->FreeList.Next) {
|
||
|
||
PVOID ptr = (PVOID)PopEntryList(&pPacketPool->FreeList);
|
||
|
||
#if DBG
|
||
DeallocateMemory(&pPacketPool->MemoryUsage, ptr);
|
||
#else
|
||
DeallocateMemory(ptr);
|
||
#endif
|
||
}
|
||
|
||
#if DBG
|
||
DbgPrint("DLC.CreatePacketPool: Error: couldn't allocate %d packets\n",
|
||
pPacketPool->OriginalPacketCount
|
||
);
|
||
DeallocateMemory(pMemoryUsage, pPacketPool);
|
||
/*
|
||
--InPoolCreator;
|
||
if (InPoolCreator) {
|
||
DbgPrint("DLC.CreatePacketPool: Error: Pool Creator clash on exit. Count = %d\n",
|
||
InPoolCreator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
*/
|
||
|
||
#else
|
||
DeallocateMemory(pPacketPool);
|
||
#endif
|
||
|
||
return NULL;
|
||
}
|
||
}
|
||
KeInitializeSpinLock(&pPacketPool->PoolLock);
|
||
pPacketPool->PacketSize = PacketSize;
|
||
|
||
#if DBG
|
||
pPacketPool->Signature = PACKET_POOL_SIGNATURE;
|
||
pPacketPool->Viable = TRUE;
|
||
pPacketPool->CurrentPacketCount = pPacketPool->OriginalPacketCount;
|
||
pPacketPool->Flags = POOL_FLAGS_IN_USE;
|
||
pPacketPool->pMemoryUsage = pMemoryUsage;
|
||
|
||
//
|
||
// add the memory usage structure for this pool to the memory usage
|
||
// list
|
||
//
|
||
|
||
LinkMemoryUsage(&pPacketPool->MemoryUsage);
|
||
|
||
if (DebugDump) {
|
||
DbgPrint("DLC.CreatePacketPool: %08x\n", pPacketPool);
|
||
DumpPool(pPacketPool);
|
||
}
|
||
} else {
|
||
DbgPrint("DLC.CreatePacketPool: Error: couldn't allocate memory for PACKET_POOL\n");
|
||
}
|
||
|
||
//
|
||
// debug counters in PACKET_POOL structure are already zero thanks to
|
||
// AllocateZeroMemory automatically zeroing all memory allocated from
|
||
// non-paged pool
|
||
//
|
||
|
||
/*
|
||
--InPoolCreator;
|
||
if (InPoolCreator) {
|
||
DbgPrint("DLC.CreatePacketPool: Error: Pool Creator clash on exit. Count = %d\n",
|
||
InPoolCreator
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
*/
|
||
|
||
#else
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
return pPacketPool;
|
||
}
|
||
|
||
|
||
VOID
|
||
DeletePacketPool(
|
||
#if DBG
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
#endif
|
||
IN PPACKET_POOL* ppPacketPool
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
frees a previously created packet pool
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure for charging mem usage
|
||
ppPacketPool - pointer to pointer to PACKET_POOL structure. Zero on return
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
PPACKET_HEAD pPacketHead;
|
||
PPACKET_POOL pPacketPool = *ppPacketPool;
|
||
|
||
#if DBG
|
||
ULONG packetCount;
|
||
#endif
|
||
|
||
//
|
||
// for various reasons, we can receive a NULL pointer. No action in this case
|
||
//
|
||
|
||
if (pPacketPool == NULL) {
|
||
|
||
#if DBG
|
||
PVOID callerAddress, callersCaller;
|
||
|
||
GET_CALLERS_ADDRESS(&callerAddress, &callersCaller);
|
||
DbgPrint("DLC.DeletePacketPool: NULL pointer. Caller = %x (caller's caller = %x)\n",
|
||
callerAddress,
|
||
callersCaller
|
||
);
|
||
#endif
|
||
|
||
return;
|
||
}
|
||
|
||
#if DBG
|
||
// DbgPrint("DLC.DeletePacketPool(%08x)\n", pPacketPool);
|
||
// DumpPool(pPacketPool);
|
||
if (pPacketPool->ClashCount) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: Memory allocator clash on entry: Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
++pPacketPool->ClashCount;
|
||
|
||
if (pPacketPool->Signature != PACKET_POOL_SIGNATURE) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: Invalid Pool Handle %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
if (!pPacketPool->Viable) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: Unviable Packet Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
KeAcquireSpinLock(&pPacketPool->PoolLock, &irql);
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// mark the packet pool structure as unviable: if anybody tries to allocate
|
||
// or deallocate while we are destroying the pool, we will break into debugger
|
||
//
|
||
|
||
pPacketPool->Viable = FALSE;
|
||
pPacketPool->Signature = 0xFFFFFFFF;
|
||
|
||
//
|
||
// assert that the busy list is empty
|
||
//
|
||
|
||
if (pPacketPool->BusyList.Next != NULL) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: %d packets busy. Pool = %08x\n",
|
||
pPacketPool->BusyCount,
|
||
pPacketPool
|
||
);
|
||
if (!DeleteBusyListAnyway) {
|
||
DumpPool(pPacketPool);
|
||
DbgBreakPoint();
|
||
} else {
|
||
DbgPrint("DLC.DeletePacketPool: Deleting BusyList anyway\n");
|
||
}
|
||
}
|
||
|
||
packetCount = 0;
|
||
|
||
#endif
|
||
|
||
while (pPacketPool->FreeList.Next != NULL) {
|
||
pPacketHead = (PPACKET_HEAD)PopEntryList(&pPacketPool->FreeList);
|
||
|
||
#if DBG
|
||
if (pPacketHead->Signature != PACKET_HEAD_SIGNATURE
|
||
|| pPacketHead->pPacketPool != pPacketPool
|
||
|| (pPacketHead->Flags & PACKET_FLAGS_BUSY)
|
||
|| !(pPacketHead->Flags & PACKET_FLAGS_FREE)) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: Bad packet %08x. Pool = %08x\n",
|
||
pPacketHead,
|
||
pPacketPool
|
||
);
|
||
DbgBreakPoint();
|
||
}
|
||
++packetCount;
|
||
DeallocateMemory(&pPacketPool->MemoryUsage, pPacketHead);
|
||
#else
|
||
DeallocateMemory(pPacketHead);
|
||
#endif
|
||
|
||
}
|
||
|
||
#if DBG
|
||
|
||
if (DeleteBusyListAnyway) {
|
||
while (pPacketPool->BusyList.Next != NULL) {
|
||
pPacketHead = (PPACKET_HEAD)PopEntryList(&pPacketPool->BusyList);
|
||
|
||
if (pPacketHead->Signature != PACKET_HEAD_SIGNATURE
|
||
|| pPacketHead->pPacketPool != pPacketPool
|
||
|| (pPacketHead->Flags & PACKET_FLAGS_FREE)
|
||
|| !(pPacketHead->Flags & PACKET_FLAGS_BUSY)) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: Bad packet %08x. Pool = %08x\n",
|
||
pPacketHead,
|
||
pPacketPool
|
||
);
|
||
DbgBreakPoint();
|
||
}
|
||
++packetCount;
|
||
DeallocateMemory(&pPacketPool->MemoryUsage, pPacketHead);
|
||
}
|
||
}
|
||
|
||
//
|
||
// did any packets get unwittingly added or removed?
|
||
//
|
||
|
||
if (packetCount != pPacketPool->CurrentPacketCount) {
|
||
DbgPrint("DLC.DeletePacketPool: Error: PacketCount (%d) != PoolCount (%d)\n",
|
||
packetCount,
|
||
pPacketPool->CurrentPacketCount
|
||
);
|
||
DumpPool(pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
//
|
||
// ensure we returned all the memory allocated to this pool
|
||
//
|
||
|
||
CheckMemoryReturned(&pPacketPool->MemoryUsage);
|
||
|
||
//
|
||
// dump the counters every time we delete a pool
|
||
//
|
||
|
||
// DumpPoolStats("DeletePacketPool", pPacketPool);
|
||
|
||
//
|
||
// remove the pool's memory usage structure - all memory allocated has been
|
||
// freed, so we're in the clear for this one
|
||
//
|
||
|
||
UnlinkMemoryUsage(&pPacketPool->MemoryUsage);
|
||
|
||
#endif
|
||
|
||
KeReleaseSpinLock(&pPacketPool->PoolLock, irql);
|
||
|
||
#if DBG
|
||
DeallocateMemory(pMemoryUsage, pPacketPool);
|
||
#else
|
||
DeallocateMemory(pPacketPool);
|
||
#endif
|
||
|
||
*ppPacketPool = NULL;
|
||
}
|
||
|
||
|
||
PVOID
|
||
AllocatePacket(
|
||
IN PPACKET_POOL pPacketPool
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
allocates a packet from a packet pool. We expect that we can always get a
|
||
packet from the previously allocated pool. However, if all packets are
|
||
currently in use, allocate another from non-paged pool
|
||
|
||
Arguments:
|
||
|
||
pPacketPool - pointer to PACKET_POOL structure
|
||
|
||
Return Value:
|
||
|
||
PVOID
|
||
Success - pointer to allocated packet
|
||
Failure - NULL
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
PPACKET_HEAD pPacketHead;
|
||
|
||
#if DBG
|
||
if (pPacketPool->ClashCount) {
|
||
DbgPrint("DLC.AllocatePacket: Error: Memory allocator clash on entry: Pool %08x, Count %d\n",
|
||
pPacketPool,
|
||
pPacketPool->ClashCount
|
||
);
|
||
// DbgBreakPoint();
|
||
}
|
||
++pPacketPool->ClashCount;
|
||
#endif
|
||
|
||
KeAcquireSpinLock(&pPacketPool->PoolLock, &irql);
|
||
|
||
#if DBG
|
||
if (pPacketPool->Signature != PACKET_POOL_SIGNATURE) {
|
||
DbgPrint("DLC.AllocatePacket: Error: Invalid Pool Handle %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
if (!pPacketPool->Viable) {
|
||
DbgPrint("DLC.AllocatePacket: Error: Unviable Packet Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
if (pPacketPool->FreeList.Next != NULL) {
|
||
pPacketHead = (PPACKET_HEAD)PopEntryList(&pPacketPool->FreeList);
|
||
|
||
#if DBG
|
||
--pPacketPool->FreeCount;
|
||
if (pPacketHead->Flags & PACKET_FLAGS_BUSY
|
||
|| !(pPacketHead->Flags & PACKET_FLAGS_FREE)) {
|
||
DbgPrint("DLC.AllocatePacket: Error: BUSY packet %08x on FreeList; Pool=%08x\n",
|
||
pPacketHead,
|
||
pPacketPool
|
||
);
|
||
DumpPacketHead(pPacketHead, 0);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
} else {
|
||
|
||
//
|
||
// Miscalculated pool usage
|
||
//
|
||
|
||
#if DBG
|
||
pPacketHead = (PPACKET_HEAD)AllocateZeroMemory(&pPacketPool->MemoryUsage,
|
||
sizeof(PACKET_HEAD) + pPacketPool->PacketSize
|
||
);
|
||
#else
|
||
pPacketHead = (PPACKET_HEAD)AllocateZeroMemory(sizeof(PACKET_HEAD) + pPacketPool->PacketSize);
|
||
#endif
|
||
|
||
if (pPacketHead) {
|
||
|
||
//
|
||
// mark this packet as allocated after the pool was created - this
|
||
// means our initial estimation of packet requirement for this
|
||
// pool was inadequate
|
||
//
|
||
|
||
pPacketHead->Flags = PACKET_FLAGS_POST_ALLOC | PACKET_FLAGS_FREE;
|
||
}
|
||
|
||
#if DBG
|
||
++pPacketPool->NoneFreeCount;
|
||
if (pPacketHead) {
|
||
|
||
PVOID caller;
|
||
PVOID callersCaller;
|
||
|
||
GET_CALLERS_ADDRESS(&caller, &callersCaller);
|
||
if (DebugDump) {
|
||
DbgPrint("DLC.AllocatePacket: Adding new packet %08x to pool %08x. ret=%08x,%08x\n",
|
||
pPacketHead,
|
||
pPacketPool,
|
||
caller,
|
||
callersCaller
|
||
);
|
||
}
|
||
pPacketHead->Signature = PACKET_HEAD_SIGNATURE;
|
||
pPacketHead->pPacketPool = pPacketPool;
|
||
|
||
++pPacketPool->CurrentPacketCount;
|
||
DumpPoolStats("AllocatePacket", pPacketPool);
|
||
} else {
|
||
DbgPrint("DLC.AllocatePacket: Error: couldn't allocate packet for Pool %08x\n",
|
||
pPacketPool
|
||
);
|
||
}
|
||
#endif
|
||
|
||
}
|
||
if (pPacketHead) {
|
||
|
||
//
|
||
// turn on BUSY flag, turn off FREE flag
|
||
//
|
||
|
||
pPacketHead->Flags ^= (PACKET_FLAGS_FREE | PACKET_FLAGS_BUSY);
|
||
|
||
//
|
||
// zero the contents of the packet!
|
||
//
|
||
|
||
LlcZeroMem((PVOID)(pPacketHead + 1), pPacketPool->PacketSize);
|
||
PushEntryList(&pPacketPool->BusyList, (PSINGLE_LIST_ENTRY)pPacketHead);
|
||
|
||
#if DBG
|
||
GET_CALLERS_ADDRESS(&pPacketHead->CallersAddress_A,
|
||
&pPacketHead->CallersCaller_A
|
||
);
|
||
++pPacketPool->BusyCount;
|
||
++pPacketPool->Allocations;
|
||
++pPacketPool->MaxInUse;
|
||
#endif
|
||
|
||
}
|
||
|
||
KeReleaseSpinLock(&pPacketPool->PoolLock, irql);
|
||
|
||
#if DBG
|
||
--pPacketPool->ClashCount;
|
||
if (pPacketPool->ClashCount) {
|
||
DbgPrint("DLC.AllocatePacket: Error: Memory allocator clash on exit: Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// return pointer to packet body, not packet header
|
||
//
|
||
|
||
return pPacketHead ? (PVOID)(pPacketHead + 1) : (PVOID)pPacketHead;
|
||
}
|
||
|
||
|
||
VOID
|
||
DeallocatePacket(
|
||
IN PPACKET_POOL pPacketPool,
|
||
IN PVOID pPacket
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns a packet to its pool
|
||
|
||
Arguments:
|
||
|
||
pPacketPool - pointer to PACKET_POOL structure describing this pool
|
||
pPacket - pointer to previously allocated packet
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL irql;
|
||
PPACKET_HEAD pPacketHead = ((PPACKET_HEAD)pPacket) - 1;
|
||
PSINGLE_LIST_ENTRY p;
|
||
PSINGLE_LIST_ENTRY prev;
|
||
|
||
#if DBG
|
||
if (pPacketPool->ClashCount) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: Memory allocator clash on entry: Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
++pPacketPool->ClashCount;
|
||
#endif
|
||
|
||
KeAcquireSpinLock(&pPacketPool->PoolLock, &irql);
|
||
|
||
#if DBG
|
||
if (pPacketPool->Signature != PACKET_POOL_SIGNATURE) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: Invalid Pool Handle %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
if (!pPacketPool->Viable) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: Unviable Packet Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
if (pPacketHead->Signature != PACKET_HEAD_SIGNATURE
|
||
|| pPacketHead->pPacketPool != pPacketPool
|
||
|| !(pPacketHead->Flags & PACKET_FLAGS_BUSY)
|
||
|| pPacketHead->Flags & PACKET_FLAGS_FREE) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: Invalid Packet Header %08x, Pool = %08x\n",
|
||
pPacketHead,
|
||
pPacketPool
|
||
);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// remove this packet from single linked list on BusyList
|
||
//
|
||
|
||
prev = (PSINGLE_LIST_ENTRY)&pPacketPool->BusyList;
|
||
for (p = prev->Next; p; p = p->Next) {
|
||
if (p == (PSINGLE_LIST_ENTRY)pPacketHead) {
|
||
break;
|
||
} else {
|
||
prev = p;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
if (!p) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: packet %08x not on BusyList of pool %08x\n",
|
||
pPacketHead,
|
||
pPacketPool
|
||
);
|
||
DumpPool(pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
prev->Next = pPacketHead->List.Next;
|
||
|
||
#if DBG
|
||
if (ZapDeallocatedPackets) {
|
||
|
||
//
|
||
// fill the deallocated packet with 'Z's. This will quickly tell us if
|
||
// the packet is still being used after it is deallocated
|
||
//
|
||
|
||
RtlFillMemory(pPacketHead + 1, pPacketPool->PacketSize, ZAP_DEALLOC_VALUE);
|
||
}
|
||
#endif
|
||
|
||
PushEntryList(&pPacketPool->FreeList, (PSINGLE_LIST_ENTRY)pPacketHead);
|
||
|
||
//
|
||
// turn off BUSY flag, turn on FREE flag
|
||
//
|
||
|
||
pPacketHead->Flags ^= (PACKET_FLAGS_BUSY | PACKET_FLAGS_FREE);
|
||
|
||
#if DBG
|
||
++pPacketPool->FreeCount;
|
||
--pPacketPool->BusyCount;
|
||
++pPacketPool->Frees;
|
||
--pPacketPool->MaxInUse;
|
||
// pPacketHead->CallersAddress_A = (PVOID)-1;
|
||
// pPacketHead->CallersCaller_A = (PVOID)-1;
|
||
GET_CALLERS_ADDRESS(&pPacketHead->CallersAddress_D,
|
||
&pPacketHead->CallersCaller_D
|
||
);
|
||
#endif
|
||
|
||
KeReleaseSpinLock(&pPacketPool->PoolLock, irql);
|
||
|
||
#if DBG
|
||
--pPacketPool->ClashCount;
|
||
if (pPacketPool->ClashCount) {
|
||
DbgPrint("DLC.DeallocatePacket: Error: Memory allocator clash on exit: Pool %08x\n", pPacketPool);
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
|
||
#if DBG
|
||
|
||
#ifdef TRACK_DLC_OBJECTS
|
||
|
||
POBJECT_POOL
|
||
CreateObjectPool(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN DLC_OBJECT_TYPE ObjectType,
|
||
IN ULONG SizeOfObject,
|
||
IN ULONG NumberOfObjects
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage -
|
||
ObjectType -
|
||
SizeOfObject -
|
||
NumberOfObjects -
|
||
|
||
Return Value:
|
||
|
||
POBJECT_POOL
|
||
|
||
--*/
|
||
|
||
{
|
||
}
|
||
|
||
|
||
VOID
|
||
DeleteObjectPool(
|
||
IN PMEMORY_USAGE pMemoryUsage,
|
||
IN DLC_OBJECT_TYPE ObjectType,
|
||
IN POBJECT_POOL pObjectPool
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage -
|
||
ObjectType -
|
||
pObjectPool -
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
}
|
||
|
||
|
||
POBJECT_HEAD
|
||
AllocatePoolObject(
|
||
IN POBJECT_POOL pObjectPool
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
pObjectPool -
|
||
|
||
Return Value:
|
||
|
||
POBJECT_HEAD
|
||
|
||
--*/
|
||
|
||
{
|
||
}
|
||
|
||
|
||
POBJECT_POOL
|
||
FreePoolObject(
|
||
IN DLC_OBJECT_TYPE ObjectType,
|
||
IN POBJECT_HEAD pObjectHead
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
description-of-function.
|
||
|
||
Arguments:
|
||
|
||
ObjectType -
|
||
pObjectHead -
|
||
|
||
Return Value:
|
||
|
||
POBJECT_POOL
|
||
|
||
--*/
|
||
|
||
{
|
||
}
|
||
|
||
#endif // TRACK_DLC_OBJECTS
|
||
|
||
|
||
VOID
|
||
CheckMemoryReturned(
|
||
IN PMEMORY_USAGE pMemoryUsage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called when a 'handle' which owns a MEMORY_USAGE structure is being closed.
|
||
Checks that all memory has been returned and that number of allocations is
|
||
the same as number of frees
|
||
|
||
Arguments:
|
||
|
||
pMemoryUsage - pointer to MEMORY_USAGE structure to check
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (pMemoryUsage->AllocateCount != pMemoryUsage->FreeCount || pMemoryUsage->NonPagedPoolAllocated) {
|
||
if (MemoryCheckNotify) {
|
||
if (pMemoryUsage->AllocateCount != pMemoryUsage->FreeCount) {
|
||
DbgPrint("DLC.CheckMemoryReturned: Error: AllocateCount != FreeCount. Usage @ %08x\n",
|
||
pMemoryUsage
|
||
);
|
||
} else {
|
||
DbgPrint("DLC.CheckMemoryReturned: Error: NonPagedPoolAllocated != 0. Usage @ %08x\n",
|
||
pMemoryUsage
|
||
);
|
||
}
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DumpMemoryUsage(pMemoryUsage, TRUE);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
CheckDriverMemoryUsage(
|
||
IN BOOLEAN Break
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks if the driver has allocated memory & dumps usage to debugger
|
||
|
||
Arguments:
|
||
|
||
Break - if true && driver has memory, breaks into debugger
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DbgPrint("DLC.CheckDriverMemoryUsage\n");
|
||
DumpMemoryMetrics();
|
||
if (Break && NonPagedPoolAllocated) {
|
||
if (MemoryCheckNotify) {
|
||
DbgPrint("DLC.CheckDriverMemoryUsage: Error: Driver still has memory allocated\n");
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID MemoryAllocationError(PCHAR Routine, PVOID Address) {
|
||
DbgPrint("DLC.%s: Error: Memory Allocation error in block @ %08x\n", Routine, Address);
|
||
DumpMemoryMetrics();
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
VOID UpdateCounter(PULONG pCounter, LONG Value) {
|
||
if (Value > 0) {
|
||
if (*pCounter + Value < *pCounter) {
|
||
MemoryCounterOverflow(pCounter, Value);
|
||
}
|
||
} else {
|
||
if (*pCounter + Value > *pCounter) {
|
||
MemoryCounterOverflow(pCounter, Value);
|
||
}
|
||
}
|
||
*pCounter += Value;
|
||
}
|
||
|
||
VOID MemoryCounterOverflow(PULONG pCounter, LONG Value) {
|
||
DbgPrint("DLC: Memory Counter Overflow: &Counter=%08x, Count=%d, Value=%d\n",
|
||
pCounter,
|
||
*pCounter,
|
||
Value
|
||
);
|
||
DumpMemoryMetrics();
|
||
}
|
||
|
||
VOID DumpMemoryMetrics() {
|
||
DbgPrint("DLC Device Driver Non-Paged Pool Usage:\n"
|
||
"\tNumber Of Good Non-Paged Pool Allocations. : %d\n"
|
||
"\tNumber Of Bad Non-Paged Pool Allocations. : %d\n"
|
||
"\tNumber Of Good Non-Paged Pool Frees. . . . : %d\n"
|
||
"\tNumber Of Bad Non-Paged Pool Frees. . . . : %d\n",
|
||
GoodNonPagedPoolAllocs,
|
||
BadNonPagedPoolAllocs,
|
||
GoodNonPagedPoolFrees,
|
||
BadNonPagedPoolFrees
|
||
);
|
||
DbgPrint("\tTotal Non-Paged Pool Currently Requested . : %d\n"
|
||
"\tTotal Non-Paged Pool Currently Allocated . : %d\n"
|
||
"\tCumulative Total Non-Paged Pool Requested. : %d\n"
|
||
"\tCumulative Total Non-Paged Pool Allocated. : %d\n"
|
||
"\tCumulative Total Non-Paged Pool Freed. . . : %d\n"
|
||
"\n",
|
||
NonPagedPoolRequested,
|
||
NonPagedPoolAllocated,
|
||
TotalNonPagedPoolRequested,
|
||
TotalNonPagedPoolAllocated,
|
||
TotalNonPagedPoolFreed
|
||
);
|
||
DumpMemoryUsageList();
|
||
}
|
||
|
||
VOID DumpPoolStats(PCHAR Routine, PPACKET_POOL pPacketPool) {
|
||
if (!DebugDump) {
|
||
return;
|
||
}
|
||
DbgPrint("DLC.%s: Stats For Pool %08x:\n"
|
||
"\tPool Owner . . . . . . . . . . . . . . . . . . . : %08x\n"
|
||
"\tPool Owner Object ID . . . . . . . . . . . . . . : %08x [%s]\n",
|
||
Routine,
|
||
pPacketPool,
|
||
pPacketPool->pMemoryUsage->Owner,
|
||
pPacketPool->pMemoryUsage->OwnerObjectId,
|
||
MapObjectId(pPacketPool->pMemoryUsage->OwnerObjectId)
|
||
);
|
||
DbgPrint("\tFree List. . . . . . . . . . . . . . . . . . . . : %08x\n"
|
||
"\tBusy List. . . . . . . . . . . . . . . . . . . . : %08x\n",
|
||
pPacketPool->FreeList,
|
||
pPacketPool->BusyList
|
||
);
|
||
DbgPrint("\tPacket Size. . . . . . . . . . . . . . . . . . . : %d\n"
|
||
"\tOriginal Number Of Packets In Pool . . . . . . . : %d\n"
|
||
"\tCurrent Number Of Packets In Pool. . . . . . . . : %d\n"
|
||
"\tNumber Of Allocations From Pool. . . . . . . . . : %d\n"
|
||
"\tNumber Of Deallocations To Pool. . . . . . . . . : %d\n"
|
||
"\tNumber Of Times No Available Packets On Allocate : %d\n"
|
||
"\tMax. Number Of Packets Allocated At Any One Time : %d\n"
|
||
"\tNumber Of Packets On Free List . . . . . . . . . : %d\n"
|
||
"\tNumber Of Packets On Busy List . . . . . . . . . : %d\n"
|
||
"\n",
|
||
pPacketPool->PacketSize,
|
||
pPacketPool->OriginalPacketCount,
|
||
pPacketPool->CurrentPacketCount,
|
||
pPacketPool->Allocations,
|
||
pPacketPool->Frees,
|
||
pPacketPool->NoneFreeCount,
|
||
pPacketPool->MaxInUse,
|
||
pPacketPool->FreeCount,
|
||
pPacketPool->BusyCount
|
||
);
|
||
DumpMemoryUsage(&pPacketPool->MemoryUsage, FALSE);
|
||
}
|
||
|
||
PCHAR MapObjectId(DLC_OBJECT_TYPE ObjectType) {
|
||
switch (ObjectType) {
|
||
case DlcDriverObject:
|
||
return "DlcDriverObject";
|
||
|
||
case FileContextObject:
|
||
return "FileContextObject";
|
||
|
||
case AdapterContextObject:
|
||
return "AdapterContextObject";
|
||
|
||
case BindingContextObject:
|
||
return "BindingContextObject";
|
||
|
||
case DlcSapObject:
|
||
return "DlcSapObject";
|
||
|
||
case DlcGroupSapObject:
|
||
return "DlcGroupSapObject";
|
||
|
||
case DlcLinkObject:
|
||
return "DlcLinkObject";
|
||
|
||
case DlcDixObject:
|
||
return "DlcDixObject";
|
||
|
||
case LlcDataLinkObject:
|
||
return "LlcDataLinkObject";
|
||
|
||
case LLcDirectObject:
|
||
return "LLcDirectObject";
|
||
|
||
case LlcSapObject:
|
||
return "LlcSapObject";
|
||
|
||
case LlcGroupSapObject:
|
||
return "LlcGroupSapObject";
|
||
|
||
case DlcBufferPoolObject:
|
||
return "DlcBufferPoolObject";
|
||
|
||
case DlcLinkPoolObject:
|
||
return "DlcLinkPoolObject";
|
||
|
||
case DlcPacketPoolObject:
|
||
return "DlcPacketPoolObject";
|
||
|
||
case LlcLinkPoolObject:
|
||
return "LlcLinkPoolObject";
|
||
|
||
case LlcPacketPoolObject:
|
||
return "LlcPacketPoolObject";
|
||
|
||
default:
|
||
return "*** UNKNOWN OBJECT TYPE ***";
|
||
}
|
||
}
|
||
|
||
VOID DumpPool(PPACKET_POOL pPacketPool) {
|
||
if (!DebugDump) {
|
||
return;
|
||
}
|
||
DumpPoolStats("DumpPool", pPacketPool);
|
||
DumpPoolList("Free", &pPacketPool->FreeList);
|
||
DumpPoolList("Busy", &pPacketPool->BusyList);
|
||
}
|
||
|
||
VOID DumpPoolList(PCHAR Name, PSINGLE_LIST_ENTRY List) {
|
||
|
||
ULONG count = 0;
|
||
|
||
if (List->Next) {
|
||
DbgPrint("\n%s List @ %08x:\n", Name, List);
|
||
while (List->Next) {
|
||
List = List->Next;
|
||
DumpPacketHead((PPACKET_HEAD)List, ++count);
|
||
}
|
||
} else {
|
||
DbgPrint("%s List is EMPTY\n\n", Name);
|
||
}
|
||
}
|
||
|
||
VOID DumpPacketHead(PPACKET_HEAD pPacketHead, ULONG Number) {
|
||
|
||
CHAR numbuf[5];
|
||
|
||
if (!DebugDump) {
|
||
return;
|
||
}
|
||
if (Number) {
|
||
|
||
int i;
|
||
ULONG div = 1000; // 1000 packets in a pool?
|
||
|
||
while (!(Number / div)) {
|
||
div /= 10;
|
||
}
|
||
for (i = 0; Number; ++i) {
|
||
numbuf[i] = (CHAR)('0' + Number / div);
|
||
Number %= div;
|
||
div /= 10;
|
||
}
|
||
numbuf[i] = 0;
|
||
Number = 1; // flag
|
||
}
|
||
DbgPrint("%s\tPACKET_HEAD @ %08x:\n"
|
||
"\tList . . . . . . . . : %08x\n"
|
||
"\tFlags. . . . . . . . : %08x\n"
|
||
"\tSignature. . . . . . : %08x\n"
|
||
"\tpPacketPool. . . . . : %08x\n"
|
||
"\tCallers Address (A). : %08x\n"
|
||
"\tCallers Caller (A) . : %08x\n"
|
||
"\tCallers Address (D). : %08x\n"
|
||
"\tCallers Caller (D) . : %08x\n"
|
||
"\n",
|
||
Number ? numbuf : "",
|
||
pPacketHead,
|
||
pPacketHead->List,
|
||
pPacketHead->Flags,
|
||
pPacketHead->Signature,
|
||
pPacketHead->pPacketPool,
|
||
pPacketHead->CallersAddress_A,
|
||
pPacketHead->CallersCaller_A,
|
||
pPacketHead->CallersAddress_D,
|
||
pPacketHead->CallersCaller_D
|
||
);
|
||
}
|
||
|
||
VOID DumpMemoryUsageList() {
|
||
|
||
PMEMORY_USAGE pMemoryUsage;
|
||
KIRQL irql;
|
||
BOOLEAN allocatedMemoryFound = FALSE;
|
||
|
||
KeAcquireSpinLock(&MemoryUsageLock, &irql);
|
||
for (pMemoryUsage = MemoryUsageList; pMemoryUsage; pMemoryUsage = pMemoryUsage->List) {
|
||
if (pMemoryUsage->NonPagedPoolAllocated) {
|
||
allocatedMemoryFound = TRUE;
|
||
DbgPrint("DLC.DumpMemoryUsageList: %08x: %d bytes memory allocated\n",
|
||
pMemoryUsage,
|
||
pMemoryUsage->NonPagedPoolAllocated
|
||
);
|
||
DumpMemoryUsage(pMemoryUsage, FALSE);
|
||
}
|
||
}
|
||
KeReleaseSpinLock(&MemoryUsageLock, irql);
|
||
if (!allocatedMemoryFound) {
|
||
DbgPrint("DLC.DumpMemoryUsageList: No allocated memory found\n");
|
||
}
|
||
}
|
||
|
||
VOID DumpMemoryUsage(PMEMORY_USAGE pMemoryUsage, BOOLEAN Override) {
|
||
if (!DebugDump && !Override) {
|
||
return;
|
||
}
|
||
DbgPrint("MEMORY_USAGE @ %08x:\n"
|
||
"\tOwner. . . . . . . . . . . . . : %08x\n"
|
||
"\tOwner Object ID. . . . . . . . : %08x [%s]\n"
|
||
"\tOwner Instance . . . . . . . . : %x\n",
|
||
pMemoryUsage,
|
||
pMemoryUsage->Owner,
|
||
pMemoryUsage->OwnerObjectId,
|
||
MapObjectId(pMemoryUsage->OwnerObjectId),
|
||
pMemoryUsage->OwnerInstance
|
||
);
|
||
DbgPrint("\tNon Paged Pool Allocated . . . : %d\n"
|
||
"\tNumber Of Allocations. . . . . : %d\n"
|
||
"\tNumber Of Frees. . . . . . . . : %d\n"
|
||
"\tPrivate Allocation List Flink. : %08x\n"
|
||
"\tPrivate Allocation List Blink. : %08x\n"
|
||
"\n",
|
||
pMemoryUsage->NonPagedPoolAllocated,
|
||
pMemoryUsage->AllocateCount,
|
||
pMemoryUsage->FreeCount,
|
||
pMemoryUsage->PrivateList.Flink,
|
||
pMemoryUsage->PrivateList.Blink
|
||
);
|
||
}
|
||
|
||
VOID
|
||
CollectReturnAddresses(
|
||
OUT PVOID* ReturnAddresses,
|
||
IN ULONG AddressesToCollect,
|
||
IN ULONG AddressesToSkip
|
||
)
|
||
{
|
||
PVOID* ebp = (PVOID*)*(PVOID**)&ReturnAddresses - 2;
|
||
|
||
while (AddressesToSkip--) {
|
||
GetLastReturnAddress(&ebp);
|
||
}
|
||
while (AddressesToCollect--) {
|
||
*ReturnAddresses++ = GetLastReturnAddress(&ebp);
|
||
}
|
||
}
|
||
|
||
PVOID* GetLastReturnAddress(PVOID** pEbp) {
|
||
|
||
PVOID* returnAddress = *(*pEbp + 1);
|
||
|
||
*pEbp = **pEbp;
|
||
return returnAddress;
|
||
}
|
||
|
||
#ifdef i386
|
||
VOID x86SleazeCallersAddress(PVOID* pCaller, PVOID* pCallerCaller) {
|
||
|
||
//
|
||
// this only works on x86 and only if not fpo functions!
|
||
//
|
||
|
||
PVOID* ebp;
|
||
|
||
ebp = (PVOID*)&pCaller - 2; // told you it was sleazy
|
||
ebp = (PVOID*)*(PVOID*)ebp;
|
||
*pCaller = *(ebp + 1);
|
||
ebp = (PVOID*)*(PVOID*)ebp;
|
||
*pCallerCaller = *(ebp + 1);
|
||
}
|
||
#endif
|
||
|
||
BOOLEAN VerifyElementOnList(PSINGLE_LIST_ENTRY List, PSINGLE_LIST_ENTRY Element) {
|
||
while (List) {
|
||
if (List == Element) {
|
||
return TRUE;
|
||
}
|
||
List = List->Next;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
VOID CheckList(PSINGLE_LIST_ENTRY List, ULONG NumberOfElements) {
|
||
|
||
PSINGLE_LIST_ENTRY originalList = List;
|
||
|
||
while (NumberOfElements--) {
|
||
if (List->Next == NULL) {
|
||
DbgPrint("DLC.CheckList: Error: too few entries on list %08x\n", originalList);
|
||
DbgBreakPoint();
|
||
} else {
|
||
List = List->Next;
|
||
}
|
||
}
|
||
if (List->Next != NULL) {
|
||
DbgPrint("DLC.CheckList: Error: too many entries on list %08x\n", originalList);
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
|
||
VOID CheckEntryOnList(PLIST_ENTRY Entry, PLIST_ENTRY List, BOOLEAN Sense) {
|
||
|
||
BOOLEAN found = FALSE;
|
||
PLIST_ENTRY p;
|
||
|
||
if (!IsListEmpty(List)) {
|
||
for (p = List->Flink; p != List; p = p->Flink) {
|
||
if (p == Entry) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (found != Sense) {
|
||
if (found) {
|
||
DbgPrint("DLC.CheckEntryOnList: Error: Entry %08x found on list %08x. Not supposed to be there\n",
|
||
Entry,
|
||
List
|
||
);
|
||
} else {
|
||
DbgPrint("DLC.CheckEntryOnList: Error: Entry %08x not found on list %08x\n",
|
||
Entry,
|
||
List
|
||
);
|
||
}
|
||
if (MemoryCheckStop) {
|
||
DbgBreakPoint();
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID DumpPrivateMemoryHeader(PPRIVATE_NON_PAGED_POOL_HEAD pHead) {
|
||
DbgPrint("Private Non Paged Pool Header @ %08x:\n"
|
||
"\tSize . . . . . . . : %d\n"
|
||
"\tOriginal Size. . . : %d\n"
|
||
"\tFlags. . . . . . . : %08x\n"
|
||
"\tSignature. . . . . : %08x\n"
|
||
"\tGlobalList.Flink . : %08x\n"
|
||
"\tGlobalList.Blink . : %08x\n"
|
||
"\tPrivateList.Flink. : %08x\n"
|
||
"\tPrivateList.Blink. : %08x\n"
|
||
"\tStack[0] . . . . . : %08x\n"
|
||
"\tStack[1] . . . . . : %08x\n"
|
||
"\tStack[2] . . . . . : %08x\n"
|
||
"\tStack[3] . . . . . : %08x\n"
|
||
"\n",
|
||
pHead->Size,
|
||
pHead->OriginalSize,
|
||
pHead->Flags,
|
||
pHead->Signature,
|
||
pHead->GlobalList.Flink,
|
||
pHead->GlobalList.Blink,
|
||
pHead->PrivateList.Flink,
|
||
pHead->PrivateList.Blink,
|
||
pHead->Stack[0],
|
||
pHead->Stack[1],
|
||
pHead->Stack[2],
|
||
pHead->Stack[3]
|
||
);
|
||
}
|
||
|
||
VOID ReportSwitchSettings(PSTR str) {
|
||
DbgPrint("%s: LLCMEM Switches:\n"
|
||
"\tDebugDump . . . . . . : %s\n"
|
||
"\tDeleteBusyListAnyway. : %s\n"
|
||
"\tMemoryCheckNotify . . : %s\n"
|
||
"\tMemoryCheckStop . . . : %s\n"
|
||
"\tMaintainGlobalLists . : %s\n"
|
||
"\tMaintainPrivateLists. : %s\n"
|
||
"\tZapDeallocatedPackets : %s\n"
|
||
"\tZapFreedMemory. . . . : %s\n"
|
||
"\n",
|
||
str,
|
||
YES_NO(DebugDump),
|
||
YES_NO(DeleteBusyListAnyway),
|
||
YES_NO(MemoryCheckNotify),
|
||
YES_NO(MemoryCheckStop),
|
||
YES_NO(MaintainGlobalLists),
|
||
YES_NO(MaintainPrivateLists),
|
||
YES_NO(ZapDeallocatedPackets),
|
||
YES_NO(ZapFreedMemory)
|
||
);
|
||
}
|
||
|
||
#endif
|