You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2441 lines
63 KiB
2441 lines
63 KiB
/*++
|
|
|
|
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
|