Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2040 lines
51 KiB

//
// Template Driver
// Copyright (c) Microsoft Corporation, 1999.
//
// Module: tdriver.c
// Author: Silviu Calinoiu (SilviuC)
// Created: 4/20/1999 2:39pm
//
// This module contains a template driver.
//
// --- History ---
//
// 4/20/1999 (SilviuC): initial version.
//
// 10/25/1999 (DMihai): Aded tests for:
// - paged pool size
// - non paged pool size
// - number of free system PTEs
//
#include <ntddk.h>
#include "active.h"
#include "mmtests.h"
#include "physmem.h"
#include "tdriver.h"
#if !MMTESTS_ACTIVE
//
// Dummy implementation if the module is inactive
//
VOID MmTestDisabled (VOID)
{
DbgPrint ("Buggy: mmtests module is disabled (check \\driver\\active.h header) \n");
}
VOID MmTestProbeLockForEverStress (
IN PVOID NotUsed
)
{
MmTestDisabled ();
}
VOID MmTestNameToAddressStress (
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID MmTestEccBadStress (
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
TdSysPagedPoolMaxTest(
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
TdSysPagedPoolTotalTest(
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
TdNonPagedPoolMaxTest(
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
TdNonPagedPoolTotalTest(
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
TdFreeSystemPtesTest(
IN PVOID IrpAddress
)
{
MmTestDisabled ();
}
VOID
StressPoolFlag (
PVOID NotUsed
)
{
MmTestDisabled ();
}
VOID
StressPoolTagTableExtension (
PVOID NotUsed
)
{
MmTestDisabled ();
}
#else
//
// Real implementation if the module is active
//
ULONG BuggyPP = (96 * 1024 * 1024);
PVOID BuggyOld;
SIZE_T UserVaSize = (50 * 1024 * 1024);
ULONG BuggyHold = 1;
ULONG OverrideStart;
ULONG OverrideSize;
ULONG OverrideCount;
#define VERBOSITY_PRINT 0x0001
#define VERBOSITY_BREAK 0x0002
ULONG Verbosity = 0x0003;
NTSYSCALLAPI
NTSTATUS
NTAPI
ZwAllocateVirtualMemory(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG_PTR ZeroBits,
IN OUT PSIZE_T RegionSize,
IN ULONG AllocationType,
IN ULONG Protect
);
NTSTATUS
MmMarkPhysicalMemoryAsBad (
IN PPHYSICAL_ADDRESS StartAddress,
IN OUT PLARGE_INTEGER NumberOfBytes
);
NTSTATUS
MmMarkPhysicalMemoryAsGood (
IN PPHYSICAL_ADDRESS StartAddress,
IN OUT PLARGE_INTEGER NumberOfBytes
);
VOID MmTestProbeLockForEverStress (
IN PVOID IrpAddress
)
{
PIRP Irp = (PIRP) IrpAddress;
PIO_STACK_LOCATION IrpStack;
ULONG InputBufferLength;
ULONG OutputBufferLength;
ULONG Ioctl;
NTSTATUS Status;
ULONG BufferSize;
ULONG ReturnedSize;
IrpStack = IoGetCurrentIrpStackLocation (Irp);
InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
{
SIZE_T RegionSize;
PVOID UserVa;
PMDL Mdl;
UserVa = NULL;
RegionSize = UserVaSize;
Status = ZwAllocateVirtualMemory (NtCurrentProcess(),
(PVOID *)&UserVa,
0,
&RegionSize,
MEM_COMMIT,
PAGE_READWRITE);
if (NT_SUCCESS(Status)) {
Mdl = IoAllocateMdl (
UserVa,
(ULONG)RegionSize,
FALSE, // not secondary buffer
FALSE, // do not charge quota
NULL); // no irp
if (Mdl != NULL) {
try {
MmProbeAndLockPages (Mdl,
KernelMode,
IoReadAccess);
DbgPrint ("Buggy: locked pages in MDL %p\n", Mdl);
DbgBreakPoint ();
//
// Don't exit now without unlocking !
//
while (BuggyHold != 0) {
KeDelayExecutionThread (KernelMode, FALSE, &BuggyOneSecond);
}
MmUnlockPages (Mdl);
IoFreeMdl (Mdl);
}
except (EXCEPTION_EXECUTE_HANDLER) {
DbgPrint ("Buggy: exception raised while locking %p\n", Mdl);
DbgBreakPoint ();
}
}
}
}
DbgPrint ("Buggy: finish with probe-and-lock forever ioctl \n");
Status = STATUS_SUCCESS;
}
VOID MmTestNameToAddressStress (
IN PVOID IrpAddress
)
{
PIRP Irp = (PIRP) IrpAddress;
PIO_STACK_LOCATION IrpStack;
ULONG InputBufferLength;
ULONG OutputBufferLength;
ULONG Ioctl;
NTSTATUS Status;
ULONG BufferSize;
ULONG ReturnedSize;
IrpStack = IoGetCurrentIrpStackLocation (Irp);
InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
{
#define CONSTANT_UNICODE_STRING(s) { sizeof( s ) - sizeof( WCHAR ), sizeof( s ), s }
const UNICODE_STRING RoutineA = CONSTANT_UNICODE_STRING( L"KfRaiseIrql" );
const UNICODE_STRING RoutineList[] = {
CONSTANT_UNICODE_STRING( L"KeBugCheckEx" ),
CONSTANT_UNICODE_STRING( L"KiBugCheckData" ),
CONSTANT_UNICODE_STRING( L"KeWaitForSingleObject" ),
CONSTANT_UNICODE_STRING( L"KeWaitForMutexObject" ),
CONSTANT_UNICODE_STRING( L"Junk1" ),
CONSTANT_UNICODE_STRING( L"CcCanIWrite" ),
CONSTANT_UNICODE_STRING( L"Junk" ),
};
PVOID Addr;
ULONG i;
Addr = MmGetSystemRoutineAddress ((PUNICODE_STRING)&RoutineA);
DbgPrint ("Addr is %p\n", Addr);
for (i = 0; i < sizeof (RoutineList) / sizeof (UNICODE_STRING); i += 1) {
Addr = MmGetSystemRoutineAddress ((PUNICODE_STRING)&RoutineList[i]);
DbgPrint ("Addr0 is %p\n", Addr);
}
}
}
VOID MmTestEccBadStress (
IN PVOID IrpAddress
)
{
PIRP Irp = (PIRP) IrpAddress;
PIO_STACK_LOCATION IrpStack;
ULONG InputBufferLength;
ULONG OutputBufferLength;
ULONG Ioctl;
NTSTATUS Status;
ULONG BufferSize;
ULONG ReturnedSize;
IrpStack = IoGetCurrentIrpStackLocation (Irp);
InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
DbgPrint ("Buggy: mark physical memory ECC bad ioctl \n");
{
ULONG i;
PPHYSICAL_MEMORY_RANGE Ranges;
PPHYSICAL_MEMORY_RANGE p;
PHYSICAL_ADDRESS StartAddress;
LARGE_INTEGER NumberOfBytes;
PHYSICAL_ADDRESS InputAddress;
LARGE_INTEGER InputBytes;
Ranges = MmGetPhysicalMemoryRanges ();
if (Ranges == NULL) {
DbgPrint ("Buggy: MmRemovePhysicalMemory cannot get ranges\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
return;
}
i = 0;
DbgPrint("StartAddress @ %p, OverrideSize @ %p, OverrideCount @ %p\n", &OverrideStart, &OverrideSize, &OverrideCount);
DbgBreakPoint();
p = Ranges;
while (p->BaseAddress.QuadPart != 0 && p->NumberOfBytes.QuadPart != 0) {
StartAddress.QuadPart = p->BaseAddress.QuadPart;
NumberOfBytes.QuadPart = p->NumberOfBytes.QuadPart;
if (OverrideStart != 0) {
StartAddress.LowPart = OverrideStart;
}
InputAddress.QuadPart = StartAddress.QuadPart;
InputBytes.QuadPart = NumberOfBytes.QuadPart;
#ifdef BIG_REMOVES
if (InputBytes.QuadPart > (64 * 1024)) {
InputBytes.QuadPart = (64 * 1024);
}
#else
if (InputBytes.QuadPart > (4 * 1024)) {
InputBytes.QuadPart = (4 * 1024);
}
#endif
if (OverrideSize != 0) {
InputBytes.LowPart = OverrideSize;
}
while (InputAddress.QuadPart + InputBytes.QuadPart <=
StartAddress.QuadPart + NumberOfBytes.QuadPart) {
if (OverrideCount != 0 && i > OverrideCount) {
break;
}
i += 1;
DbgPrint ("buggy: MmMarkPhysicalMemoryAsBad %x %x %x %x\n",
InputAddress.HighPart,
InputAddress.LowPart,
InputBytes.HighPart,
InputBytes.LowPart);
Status = MmMarkPhysicalMemoryAsBad (&InputAddress,
&InputBytes);
DbgPrint ("buggy: MmMarkPhysicalMemoryAsBad %x %x %x %x %x\n\n",
Status,
InputAddress.HighPart,
InputAddress.LowPart,
InputBytes.HighPart,
InputBytes.LowPart);
KeDelayExecutionThread (KernelMode, FALSE, &BuggyOneSecond);
if (NT_SUCCESS(Status)) {
DbgPrint ("buggy: MmMarkPhysicalMemoryAsGood %x %x %x %x\n",
InputAddress.HighPart,
InputAddress.LowPart,
InputBytes.HighPart,
InputBytes.LowPart);
Status = MmMarkPhysicalMemoryAsGood (&InputAddress,
&InputBytes);
if (NT_SUCCESS(Status)) {
DbgPrint ("\n\n***************\nbuggy: MmMarkPhysicalMemoryAsGood WORKED %x %x %x %x %x\n****************\n",
Status,
InputAddress.HighPart,
InputAddress.LowPart,
InputBytes.HighPart,
InputBytes.LowPart);
}
else {
DbgPrint ("buggy: MmMarkPhysicalMemoryAsGood FAILED %x %x %x %x %x\n\n",
Status,
InputAddress.HighPart,
InputAddress.LowPart,
InputBytes.HighPart,
InputBytes.LowPart);
DbgBreakPoint ();
}
}
if (InputAddress.QuadPart + InputBytes.QuadPart ==
StartAddress.QuadPart + NumberOfBytes.QuadPart) {
break;
}
InputAddress.QuadPart += InputBytes.QuadPart;
if (InputAddress.QuadPart + InputBytes.QuadPart >
StartAddress.QuadPart + NumberOfBytes.QuadPart) {
InputBytes.QuadPart = StartAddress.QuadPart + NumberOfBytes.QuadPart - InputAddress.QuadPart;
}
}
if (OverrideCount != 0 && i > OverrideCount) {
break;
}
p += 1;
}
ExFreePool (Ranges);
DbgPrint ("Buggy: MmMarkPhysicalMemory Ecc BAD test finished\n");
}
}
////////////////////////////////////////////////////////////////////////////
typedef struct
{
LIST_ENTRY List;
PVOID ChunkPointers[ ( 63 * 1024 ) / sizeof( PVOID ) ];
} ALLOCATION_TABLE, *PALLOCATION_TABLE;
LIST_ENTRY PagedPoolAllocationListHead;
LIST_ENTRY NonPagedPoolAllocationListHead;
LIST_ENTRY SessionPoolAllocationListHead;
const SIZE_T PoolChunkSize = 64 * 1024 - 32;
//
//
//
VOID
TdpWriteSignature(
PVOID Allocation,
SIZE_T CurrentSize
)
{
PSIZE_T CrtSignature;
SIZE_T CrtSignatureValue;
CrtSignature = (PSIZE_T)Allocation;
CrtSignatureValue = ( (SIZE_T)Allocation ) ^ CurrentSize;
if( CurrentSize > 100 * 1024 * 1024 )
{
DbgPrint( "Buggy: Writing signature %p from address %p, size %p\n",
CrtSignatureValue,
CrtSignature,
CurrentSize );
}
while( 100 * PAGE_SIZE <= CurrentSize )
{
*CrtSignature = CrtSignatureValue;
CrtSignatureValue +=1;
CrtSignature = (PSIZE_T)( (PCHAR)CrtSignature + 100 * PAGE_SIZE );
CurrentSize -= 100 * PAGE_SIZE;
}
}
//
//
//
VOID
TdpVerifySignature(
PVOID Allocation,
SIZE_T CurrentSize )
{
PSIZE_T CrtSignature;
SIZE_T CrtSignatureValue;
CrtSignature = (PSIZE_T)Allocation;
CrtSignatureValue = ( (SIZE_T)Allocation ) ^ CurrentSize;
if( CurrentSize > 100 * 1024 * 1024 )
{
DbgPrint( "Buggy: Verifying signature %p from address %p, size %p\n",
CrtSignatureValue,
CrtSignature,
CurrentSize );
}
while( 100 * PAGE_SIZE <= CurrentSize )
{
if( *CrtSignature != CrtSignatureValue )
{
DbgPrint ("Buggy: Signature at %p is incorrect, expected %p, base allocation %p\n",
CrtSignature,
CrtSignatureValue,
Allocation );
DbgBreakPoint ();
}
CrtSignatureValue +=1;
CrtSignature = (PSIZE_T)( (PCHAR)CrtSignature + 100 * PAGE_SIZE );
CurrentSize -= 100 * PAGE_SIZE;
}
}
//
//
//
VOID
TdpCleanupPoolAllocationTable(
PLIST_ENTRY ListHead,
SIZE_T Allocations
)
{
PLIST_ENTRY NextEntry;
PALLOCATION_TABLE AllocationTable;
SIZE_T ChunksPerAllocationEntry;
SIZE_T CrtChunksIndex;
ChunksPerAllocationEntry = ARRAY_LENGTH( AllocationTable->ChunkPointers );
NextEntry = ListHead->Flink;
while( NextEntry != ListHead )
{
RemoveEntryList( NextEntry );
AllocationTable = CONTAINING_RECORD( NextEntry, ALLOCATION_TABLE, List );
DbgPrint( "Buggy: Current allocation table = %p\n",
AllocationTable );
for( CrtChunksIndex = 0; CrtChunksIndex < ChunksPerAllocationEntry; CrtChunksIndex++ )
{
if( 0 == Allocations )
{
//
// Freed them all
//
break;
}
else
{
Allocations -= 1;
if( 0 == Allocations % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: cleaning up allocation index %p\n",
Allocations );
}
/*
DbgPrint( "Buggy: Verify and free chunk index %p (from the end) at address %p\n",
Allocations,
AllocationTable->ChunkPointers[ CrtChunksIndex ] );
*/
TdpVerifySignature(
AllocationTable->ChunkPointers[ CrtChunksIndex ],
PoolChunkSize );
ExFreePoolWithTag(
AllocationTable->ChunkPointers[ CrtChunksIndex ],
TD_POOL_TAG );
}
}
//
// Free the table as well
//
ExFreePoolWithTag(
AllocationTable,
TD_POOL_TAG );
//
// Go to the next allocations table
//
NextEntry = ListHead->Flink;
}
//
// At this point, Allocations should be zero and the
// list should be empty
//
if( 0 != Allocations )
{
DbgPrint ("Buggy: Emptied the allocation table list but still have %p allocations - this is a bug\n",
Allocations );
DbgBreakPoint();
}
if( ! IsListEmpty( ListHead ) )
{
DbgPrint ("Buggy: No allocations left but the list at %p is not empty yet - this is a bug\n",
ListHead );
DbgBreakPoint();
}
}
//
// Delay execution for a few seconds so we can get a chance to use
// !poolused, poolmon.exe, etc.
//
VOID
TdpSleep( ULONG Seconds )
{
LARGE_INTEGER Interval = {(ULONG)(-1000 * 1000 * 10), -1}; // One second.
DbgPrint( "Buggy: Sleeping for %u seconds\n",
Seconds );
Interval.QuadPart *= Seconds;
KeDelayExecutionThread( KernelMode,
FALSE,
&Interval );
}
//
// Determine the maximum size of a block of paged pool currently available
//
VOID
TdSysPagedPoolMaxTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentSize;
SIZE_T SizeIncrement;
ULONG Increment;
PVOID Allocation;
#ifdef _WIN64
CurrentSize = 0xFFFFFFFF00000000;
#else
CurrentSize = 0xFFFFFFFF;
#endif //#ifdef _WIN64
do
{
DbgPrint ("Buggy: Trying to allocate %p bytes paged pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
PagedPool,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: allocated %p bytes paged pool at %p\n",
CurrentSize,
Allocation);
TdpWriteSignature(
Allocation,
CurrentSize );
TdpVerifySignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
CurrentSize /= 2;
}
}
while( NULL == Allocation && PAGE_SIZE <= CurrentSize );
if( NULL != Allocation )
{
//
// Try to find an even bigger size in 10% increments
//
SizeIncrement = CurrentSize / 10;
if( PAGE_SIZE <= SizeIncrement )
{
for( Increment = 0; Increment < 10; Increment += 1 )
{
CurrentSize += SizeIncrement;
DbgPrint ("Buggy: Trying to allocate %p bytes paged pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
PagedPool,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: Better result of the test: allocated %p bytes paged pool at %p\n",
CurrentSize,
Allocation);
TdpSleep( 15 );
TdpWriteSignature(
Allocation,
CurrentSize );
TdpVerifySignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
DbgPrint ("Buggy: could not allocate %p bytes paged pool - done\n",
CurrentSize );
break;
}
}
}
}
}
//
// Determine the total size of the paged pool currently available (64 Kb - 32 bytes blocks)
//
VOID
TdSysPagedPoolTotalTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentChunkIndex;
SIZE_T ChunksPerAllocationEntry;
SIZE_T TotalBytes;
PALLOCATION_TABLE AllocationListEntry;
PVOID Allocation;
//
// No allocations yet
//
InitializeListHead(
&PagedPoolAllocationListHead );
//
// We want to allocate 64 k chunks but leave space for the pool block header
//
ChunksPerAllocationEntry = ARRAY_LENGTH( AllocationListEntry->ChunkPointers );
CurrentChunkIndex = 0;
do
{
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// Need a new allocation entry structure
//
AllocationListEntry = (PALLOCATION_TABLE) ExAllocatePoolWithTag(
PagedPool,
sizeof( ALLOCATION_TABLE ),
TD_POOL_TAG );
if( NULL == AllocationListEntry )
{
DbgPrint ("Buggy: could not allocate new ALLOCATION_TABLE - aborting test here\n" );
break;
}
RtlZeroMemory(
AllocationListEntry,
sizeof( ALLOCATION_TABLE ) );
DbgPrint( "Buggy: New allocation table = %p\n",
AllocationListEntry );
}
//
// Try to allocate a new chunk
//
Allocation = ExAllocatePoolWithTag(
PagedPool,
PoolChunkSize,
TD_POOL_TAG );
if( NULL == Allocation )
{
DbgPrint ("Buggy: could not allocate paged pool chunk index %p - done\n",
CurrentChunkIndex );
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - free it now because
// we don't want to have empty tables in the list so we didn't insert it yet so we didn't insert it yet
//
ExFreePoolWithTag(
AllocationListEntry,
TD_POOL_TAG );
}
}
else
{
if( 0 == CurrentChunkIndex % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: Allocated pool chunk index = %p\n",
CurrentChunkIndex );
}
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - add it to our list only now because
// we don't want to have empty tables in the list so we didn't insert it yet
//
InsertTailList(
&PagedPoolAllocationListHead,
&AllocationListEntry->List );
}
AllocationListEntry->ChunkPointers[ CurrentChunkIndex % ChunksPerAllocationEntry ] = Allocation;
TdpWriteSignature(
Allocation,
PoolChunkSize );
/*
DbgPrint( "Buggy: Written signature to chunk index %p at address %p\n",
CurrentChunkIndex,
Allocation );
*/
CurrentChunkIndex += 1;
}
}
while( NULL != Allocation );
TotalBytes = CurrentChunkIndex * 64 * 1024;
DbgPrint ("Buggy: Result of the test: approx. %p total bytes of paged pool allocated\n",
TotalBytes );
//
// Clean-up what we have allocated
//
TdpCleanupPoolAllocationTable(
&PagedPoolAllocationListHead,
CurrentChunkIndex );
}
VOID
TdNonPagedPoolMaxTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentSize;
SIZE_T SizeIncrement;
ULONG Increment;
PVOID Allocation;
#ifdef _WIN64
CurrentSize = 0xFFFFFFFF00000000;
#else
CurrentSize = 0xFFFFFFFF;
#endif //#ifdef _WIN64
do
{
DbgPrint ("Buggy: Trying to allocate %p bytes non-paged pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
NonPagedPool,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: allocated %p bytes non-paged pool at %p\n",
CurrentSize,
Allocation);
TdpWriteSignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
CurrentSize /= 2;
}
}
while( NULL == Allocation && PAGE_SIZE <= CurrentSize );
if( NULL != Allocation )
{
//
// Try to find an even bigger size in 10% increments
//
SizeIncrement = CurrentSize / 10;
if( PAGE_SIZE <= SizeIncrement )
{
for( Increment = 0; Increment < 10; Increment += 1 )
{
CurrentSize += SizeIncrement;
DbgPrint ("Buggy: Trying to allocate %p bytes non-paged pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
NonPagedPool,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: Better result of the test: allocated %p bytes non-paged pool at %p\n",
CurrentSize,
Allocation);
TdpSleep( 15 );
TdpWriteSignature(
Allocation,
CurrentSize );
TdpVerifySignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
DbgPrint ("Buggy: could not allocate %p bytes non-paged pool - done\n",
CurrentSize );
break;
}
}
}
}
}
//
// Determine the total size of the non-paged pool currently available (64 Kb - 32 bytes blocks)
//
VOID
TdNonPagedPoolTotalTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentChunkIndex;
SIZE_T ChunksPerAllocationEntry;
SIZE_T TotalBytes;
PALLOCATION_TABLE AllocationListEntry;
PVOID Allocation;
//
// No allocations yet
//
InitializeListHead(
&NonPagedPoolAllocationListHead );
//
// We want to allocate 64 k chunks but leave space for the pool block header
//
ChunksPerAllocationEntry = ARRAY_LENGTH( AllocationListEntry->ChunkPointers );
CurrentChunkIndex = 0;
do
{
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// Need a new allocation entry structure
//
AllocationListEntry = (PALLOCATION_TABLE) ExAllocatePoolWithTag(
PagedPool,
sizeof( ALLOCATION_TABLE ),
TD_POOL_TAG );
if( NULL == AllocationListEntry )
{
DbgPrint ("Buggy: could not allocate new ALLOCATION_TABLE - aborting test here\n" );
break;
}
}
//
// Try to allocate a new chunk
//
Allocation = ExAllocatePoolWithTag(
NonPagedPool,
PoolChunkSize,
TD_POOL_TAG );
if( NULL == Allocation )
{
DbgPrint ("Buggy: could not allocate non-paged pool chunk index %p - done\n",
CurrentChunkIndex );
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - free it now because
// we don't want to have empty tables in the list so we didn't insert it yet so we didn't insert it yet
//
ExFreePoolWithTag(
AllocationListEntry,
TD_POOL_TAG );
}
}
else
{
if( 0 == CurrentChunkIndex % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: Allocated pool chunk index = %p\n",
CurrentChunkIndex );
}
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - add it to our list only now because
// we don't want to have empty tables in the list so we didn't insert it yet
//
InsertTailList(
&NonPagedPoolAllocationListHead,
&AllocationListEntry->List );
}
AllocationListEntry->ChunkPointers[ CurrentChunkIndex % ChunksPerAllocationEntry ] = Allocation;
TdpWriteSignature(
Allocation,
PoolChunkSize );
CurrentChunkIndex += 1;
}
}
while( NULL != Allocation );
TotalBytes = CurrentChunkIndex * 64 * 1024;
DbgPrint ("Buggy: Result of the test: approx. %p total bytes of non-paged pool allocated\n",
TotalBytes );
//
// Clean-up what we have allocated
//
TdpCleanupPoolAllocationTable(
&NonPagedPoolAllocationListHead,
CurrentChunkIndex );
}
/////////////////////////////////////////////////////////////////////////////////////
typedef struct
{
LIST_ENTRY List;
PMDL Mappings[ ( 63 * 1024 ) / sizeof( PMDL ) ];
} MAPPING_TABLE_ENTRY, *PMAPPING_TABLE_ENTRY;
LIST_ENTRY IoMappingsListHead;
ULONG BytesPerIoMapping = 1024 * 1024;
//
//
//
VOID
TdpCleanupMappingsAllocationTable(
PLIST_ENTRY ListHead,
SIZE_T Mappings
)
{
PLIST_ENTRY NextEntry;
PMAPPING_TABLE_ENTRY MappingTableEntry;
SIZE_T MappingsPerMappingTableEntry;
SIZE_T CrtMappingIndex;
MappingsPerMappingTableEntry = ARRAY_LENGTH( MappingTableEntry->Mappings );
NextEntry = ListHead->Flink;
while( NextEntry != ListHead )
{
RemoveEntryList( NextEntry );
MappingTableEntry = CONTAINING_RECORD( NextEntry, MAPPING_TABLE_ENTRY, List );
for( CrtMappingIndex = 0; CrtMappingIndex < MappingsPerMappingTableEntry; CrtMappingIndex++ )
{
if( 0 == Mappings )
{
//
// Freed them all
//
break;
}
else
{
Mappings -= 1;
if( 0 == Mappings % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: cleaning up mapping index %p\n",
Mappings );
}
//
// Unmap
//
MmUnmapIoSpace(
MappingTableEntry->Mappings[ CrtMappingIndex ],
BytesPerIoMapping );
}
}
//
// Free the table as well
//
ExFreePoolWithTag(
MappingTableEntry,
TD_POOL_TAG );
//
// Go to the next allocations table
//
NextEntry = ListHead->Flink;
}
//
// At this point, Mappings should be zero and the
// list should be empty
//
if( 0 != Mappings )
{
DbgPrint ("Buggy: Emptied the mappings table list but still have %p allocations - this is a bug\n",
Mappings );
DbgBreakPoint();
}
if( ! IsListEmpty( ListHead ) )
{
DbgPrint ("Buggy: No mappings left but the list at %p is not empty yet - this is a bug\n",
ListHead );
DbgBreakPoint();
}
}
//
// Determine the total amount of memory that can be mapped using system PTEs (1 Mb chunks)
//
VOID
TdFreeSystemPtesTest(
IN PVOID IrpAddress
)
{
ULONG MemType;
PHYSICAL_ADDRESS PortAddress;
PHYSICAL_ADDRESS MyPhysicalAddress;
SIZE_T CurrentMappingIndex;
SIZE_T MappingsPerMappingTableEntry;
SIZE_T TotalBytes;
PVOID NewMapping;
PMAPPING_TABLE_ENTRY MappingTableEntry;
PMDL NewMdl;
NTSTATUS Status;
//
// Use some joystick port address
//
MemType = 1; // IO space
PortAddress.LowPart = 0x200;
PortAddress.HighPart = 0;
HalTranslateBusAddress(
Isa,
0,
PortAddress,
&MemType,
&MyPhysicalAddress);
//
// No Mappings allocated yet
//
InitializeListHead(
&IoMappingsListHead );
//
// Map a ~64 Kb chunk over and over again to consume system PTEs
//
MappingsPerMappingTableEntry = ARRAY_LENGTH( MappingTableEntry->Mappings );
CurrentMappingIndex = 0;
do
{
if( 0 == CurrentMappingIndex % MappingsPerMappingTableEntry )
{
//
// Need a new allocation entry structure
//
MappingTableEntry = (PMAPPING_TABLE_ENTRY) ExAllocatePoolWithTag(
PagedPool,
sizeof( MAPPING_TABLE_ENTRY ),
TD_POOL_TAG );
if( NULL == MappingTableEntry )
{
DbgPrint ("Buggy: could not allocate new MAPPING_TABLE_ENTRY - aborting test here\n" );
break;
}
}
NewMapping = MmMapIoSpace(
MyPhysicalAddress,
BytesPerIoMapping,
MmNonCached );
if( NULL == NewMapping )
{
DbgPrint ("Buggy: could not create mapping index %p\n",
CurrentMappingIndex );
if( 0 == CurrentMappingIndex % MappingsPerMappingTableEntry )
{
//
// We are using a new list entry - free it now because
// we don't want to have empty tables in the list so we didn't insert it yet so we didn't insert it yet
//
ExFreePoolWithTag(
MappingTableEntry,
TD_POOL_TAG );
}
}
else
{
//DbgPrint ("Buggy: created Mapping index %p at address %p\n",
// CurrentMappingIndex,
// NewMapping );
if( 0 == CurrentMappingIndex % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: mapped chunk index = %p\n",
CurrentMappingIndex );
}
if( 0 == CurrentMappingIndex % MappingsPerMappingTableEntry )
{
//
// We are using a new list entry - add it to our list only now because
// we don't want to have empty tables in the list so we didn't insert it yet
//
InsertTailList(
&IoMappingsListHead,
&MappingTableEntry->List );
}
MappingTableEntry->Mappings[ CurrentMappingIndex % MappingsPerMappingTableEntry ] = NewMapping;
CurrentMappingIndex += 1;
}
}
while( NULL != NewMapping );
TotalBytes = CurrentMappingIndex * BytesPerIoMapping;
DbgPrint( "Buggy: Result of the test: %p total bytes mapped\n",
TotalBytes );
//
// Clean-up what we have allocated and locked
//
TdpCleanupMappingsAllocationTable(
&IoMappingsListHead,
CurrentMappingIndex );
}
//
// Function:
//
// GetTag
//
// Description:
//
// This function transforms an integer into a four letter
// string. This is useful for the pool tag dynamic table
// in order to populate it with many different tags.
//
ULONG
GetTag (
ULONG Index
)
{
UCHAR Value[4];
Value[0] = (UCHAR)(((Index & 0x000F) >> 0 )) + 'A';
Value[1] = (UCHAR)(((Index & 0x00F0) >> 4 )) + 'A';
Value[2] = (UCHAR)(((Index & 0x0F00) >> 8 )) + 'A';
Value[3] = (UCHAR)(((Index & 0xF000) >> 12)) + 'A';
return *((PULONG)Value);
}
VOID
StressPoolFlag (
PVOID NotUsed
)
/*++
Routine Description:
This function iterates through all the pool types, pool flags
and pool sizes (1 .. 8 * PAGE_SIZE).
Arguments:
None.
Return Value:
None.
Environment:
Kernel mode.
--*/
{
POOL_TYPE PoolType;
SIZE_T NumberOfBytes;
EX_POOL_PRIORITY Priority;
PVOID Va;
ULONG i;
for (PoolType = NonPagedPool; PoolType < 0xff; PoolType += 1) {
for (Priority = LowPoolPriority; Priority < LowPoolPriority + 2; Priority += 1) {
for (i = 1; i < 8 * PAGE_SIZE; i += 1) {
NumberOfBytes = i;
if (PoolType & 0x40) {
break;
}
if ((NumberOfBytes > PAGE_SIZE) && (PoolType & 0x2)) {
break;
}
try {
Va = ExAllocatePoolWithTagPriority (
PoolType,
NumberOfBytes,
'ZXCV',
Priority);
}
except (EXCEPTION_EXECUTE_HANDLER) {
if (Verbosity & VERBOSITY_PRINT) {
DbgPrint( "buggy: ExAllocatePool exceptioned %x %x %x\n",
PoolType, NumberOfBytes, Priority);
}
if (Verbosity & VERBOSITY_BREAK) {
DbgBreakPoint ();
}
Va = NULL;
}
if (Va) {
ExFreePool (Va);
}
else {
if (Verbosity & VERBOSITY_PRINT) {
DbgPrint( "buggy: ExAllocatePool failed %x %x %x\n",
PoolType, NumberOfBytes, Priority);
}
if (Verbosity & VERBOSITY_BREAK) {
DbgBreakPoint ();
}
}
}
}
}
DbgPrint ("Buggy: ExAllocatePoolFlag test finished\n");
}
VOID
StressPoolTagTableExtension (
PVOID NotUsed
)
/*++
Routine Description:
This function stresses the pool tag table dynamic extension.
Arguments:
None.
Return Value:
None.
Environment:
Kernel mode.
--*/
{
PVOID * Blocks;
ULONG Index;
Blocks = ExAllocatePoolWithTag (
NonPagedPool,
16384 * sizeof(PVOID),
'tguB');
if (Blocks == NULL) {
DbgPrint ("Buggy: cannot allocate pool buffer\n");
}
else {
//
// Loop with 8 byte size.
//
for (Index = 0; Index < 10000; Index++) {
if (Index && Index % 100 == 0) {
DbgPrint ("Index(a): %u \n", Index);
}
Blocks[Index] = ExAllocatePoolWithTag (
NonPagedPool,
8,
GetTag(Index));
}
for (Index = 0; Index < 10000; Index++) {
if (Index && Index % 100 == 0) {
DbgPrint ("Index(f): %u \n", Index);
}
if (Blocks[Index]) {
ExFreePool (Blocks[Index]);
}
}
//
// Loop with PAGE_SIZE byte size.
//
for (Index = 0; Index < 4000; Index++) {
if (Index && Index % 100 == 0) {
DbgPrint ("Index(A): %u \n", Index);
}
Blocks[Index] = ExAllocatePoolWithTag (
NonPagedPool,
PAGE_SIZE,
GetTag(Index + 16384));
}
for (Index = 0; Index < 4000; Index++) {
if (Index && Index % 100 == 0) {
DbgPrint ("Index(F): %u \n", Index);
}
if (Blocks[Index]) {
ExFreePool (Blocks[Index]);
}
}
//
// Free block info.
//
ExFreePool (Blocks);
}
}
//
// Determine the maximum size of a block of session pool currently available
//
VOID
TdSessionPoolMaxTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentSize;
SIZE_T SizeIncrement;
ULONG Increment;
PVOID Allocation;
#ifdef _WIN64
CurrentSize = 0xFFFFFFFF00000000;
#else
CurrentSize = 0xFFFFFFFF;
#endif //#ifdef _WIN64
do
{
DbgPrint ("Buggy: Trying to allocate %p bytes session pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
PagedPool | SESSION_POOL_MASK,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: allocated %p bytes session pool at %p\n",
CurrentSize,
Allocation);
TdpWriteSignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
CurrentSize /= 2;
}
}
while( NULL == Allocation && PAGE_SIZE <= CurrentSize );
if( NULL != Allocation )
{
//
// Try to find an even bigger size in 10% increments
//
SizeIncrement = CurrentSize / 10;
if( PAGE_SIZE <= SizeIncrement )
{
for( Increment = 0; Increment < 10; Increment += 1 )
{
CurrentSize += SizeIncrement;
DbgPrint ("Buggy: Trying to allocate %p bytes session pool\n",
CurrentSize );
Allocation = ExAllocatePoolWithTag(
PagedPool | SESSION_POOL_MASK,
CurrentSize,
TD_POOL_TAG );
if( NULL != Allocation )
{
DbgPrint ("Buggy: Better result of the test: allocated %p bytes sesssion pool at %p\n",
CurrentSize,
Allocation);
TdpSleep( 15 );
TdpWriteSignature(
Allocation,
CurrentSize );
TdpVerifySignature(
Allocation,
CurrentSize );
ExFreePoolWithTag(
Allocation,
TD_POOL_TAG );
}
else
{
DbgPrint ("Buggy: could not allocate %p bytes session pool - done\n",
CurrentSize );
break;
}
}
}
}
}
//
// Determine the total size of the session pool currently available (64 Kb - 32 bytes blocks)
//
VOID
TdSessionPoolTotalTest(
IN PVOID IrpAddress
)
{
SIZE_T CurrentChunkIndex;
SIZE_T ChunksPerAllocationEntry;
SIZE_T TotalBytes;
PALLOCATION_TABLE AllocationListEntry;
PVOID Allocation;
//
// No allocations yet
//
InitializeListHead(
&SessionPoolAllocationListHead );
//
// We want to allocate 64 k chunks but leave space for the pool block header
//
ChunksPerAllocationEntry = ARRAY_LENGTH( AllocationListEntry->ChunkPointers );
CurrentChunkIndex = 0;
do
{
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// Need a new allocation entry structure
//
AllocationListEntry = (PALLOCATION_TABLE) ExAllocatePoolWithTag(
PagedPool | SESSION_POOL_MASK,
sizeof( ALLOCATION_TABLE ),
TD_POOL_TAG );
if( NULL == AllocationListEntry )
{
DbgPrint ("Buggy: could not allocate new ALLOCATION_TABLE - aborting test here\n" );
break;
}
RtlZeroMemory(
AllocationListEntry,
sizeof( ALLOCATION_TABLE ) );
DbgPrint( "Buggy: New allocation table = %p\n",
AllocationListEntry );
}
//
// Try to allocate a new chunk
//
Allocation = ExAllocatePoolWithTag(
PagedPool | SESSION_POOL_MASK,
PoolChunkSize,
TD_POOL_TAG );
if( NULL == Allocation )
{
DbgPrint ("Buggy: could not allocate session pool chunk index %p - done\n",
CurrentChunkIndex );
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - free it now because
// we don't want to have empty tables in the list so we didn't insert it yet so we didn't insert it yet
//
ExFreePoolWithTag(
AllocationListEntry,
TD_POOL_TAG );
}
}
else
{
if( 0 == CurrentChunkIndex % 0x100 )
{
//
// Let the user know that we are still working on something
//
DbgPrint( "Buggy: Allocated pool chunk index = %p\n",
CurrentChunkIndex );
}
if( 0 == CurrentChunkIndex % ChunksPerAllocationEntry )
{
//
// We are using a new list entry - add it to our list only now because
// we don't want to have empty tables in the list so we didn't insert it yet
//
InsertTailList(
&SessionPoolAllocationListHead,
&AllocationListEntry->List );
}
AllocationListEntry->ChunkPointers[ CurrentChunkIndex % ChunksPerAllocationEntry ] = Allocation;
TdpWriteSignature(
Allocation,
PoolChunkSize );
/*
DbgPrint( "Buggy: Written signature to chunk index %p at address %p\n",
CurrentChunkIndex,
Allocation );
*/
CurrentChunkIndex += 1;
}
}
while( NULL != Allocation );
TotalBytes = CurrentChunkIndex * 64 * 1024;
DbgPrint ("Buggy: Result of the test: approx. %p total bytes of session pool allocated\n",
TotalBytes );
//
// Clean-up what we have allocated
//
TdpCleanupPoolAllocationTable(
&SessionPoolAllocationListHead,
CurrentChunkIndex );
}
//
//
//
#define BUGGY_PAGE_DIRECTORY_BOUNDARY ((PVOID)0x40000000)
#define BUGGY_VAD_GRANULARITY (64 * 1024)
#if defined( _IA64_ )
#define BUGGY_PDE_GRANULARITY (8 * 1024 * 1024)
#elif defined( _AMD64_ )
#define BUGGY_PDE_GRANULARITY (2 * 1024 * 1024)
#else
#define BUGGY_PDE_GRANULARITY (4 * 1024 * 1024)
#endif
typedef struct _BUGGY_PAGEDPOOLMDLTEST {
PVOID RequestedUserVa;
PMDL Mdl;
PVOID MappedAddress;
ULONG NumberOfPages;
} BUGGY_PAGEDPOOLMDLTEST, *PBUGGY_PAGEDPOOLMDLTEST;
BUGGY_PAGEDPOOLMDLTEST PagedPoolMdlTestArray [] =
{
{BUGGY_PAGE_DIRECTORY_BOUNDARY, NULL, NULL, 3},
{(PCHAR)BUGGY_PAGE_DIRECTORY_BOUNDARY + BUGGY_VAD_GRANULARITY, NULL, NULL, 3},
{(PCHAR)BUGGY_PAGE_DIRECTORY_BOUNDARY - BUGGY_VAD_GRANULARITY, NULL, NULL, 3},
{(PCHAR)BUGGY_PAGE_DIRECTORY_BOUNDARY + BUGGY_PDE_GRANULARITY - BUGGY_VAD_GRANULARITY,
NULL, NULL, (2 * BUGGY_VAD_GRANULARITY) / PAGE_SIZE}
};
VOID
TdNonPagedPoolMdlTestMap(
IN PVOID IrpAddress
)
{
PVOID VirtualAddress;
ULONG MapIndex;
ULONG SizeToMap;
#if defined( _IA64_ )
//
// IA64
//
// 0xe0000168`02000000 maps NonCached 0x800 pages starting with PFN 0x78000 on dmihai-ita.
//
VirtualAddress = (PVOID)0xe000016802000000;
#elif defined( _AMD64_ )
//
// AMD64
//
// 0xfffffadf`f0a91000 maps WriteCombined 0x100 pages starting with PFN 0xd0200 on dmihai-amd64.
//
//VirtualAddress = (PVOID)0xffffffffffd00000;
VirtualAddress = (PVOID)0xfffffadff0a91000;
#else
//
// X86
//
// f1000000 maps NonChached 0x800 pages starting with PFN f5000 on dmihai-amd.
//
VirtualAddress = (PVOID)0xf1000000;
#endif
for (MapIndex = 0 ; MapIndex < ARRAY_LENGTH (PagedPoolMdlTestArray); MapIndex += 1)
{
//
//
//
SizeToMap = PAGE_SIZE * PagedPoolMdlTestArray [MapIndex].NumberOfPages;
PagedPoolMdlTestArray [MapIndex].Mdl = IoAllocateMdl (VirtualAddress,
SizeToMap,
FALSE,
FALSE,
NULL);
if (PagedPoolMdlTestArray [MapIndex].Mdl == NULL)
{
DbgPrint ("IoAllocateMdl failed\n");
return;
}
DbgPrint ("Mdl %p allocated\n",
PagedPoolMdlTestArray [MapIndex].Mdl);
//
//
//
MmBuildMdlForNonPagedPool (PagedPoolMdlTestArray [MapIndex].Mdl);
//
//
//
/*
UserVANonPagedPoolMdlTest = MmMapLockedPages (MdlNonPagedPoolMdlTest,
UserMode);
*/
PagedPoolMdlTestArray [MapIndex].MappedAddress = MmMapLockedPagesSpecifyCache (
PagedPoolMdlTestArray [MapIndex].Mdl,
UserMode,
MmNonCached,
PagedPoolMdlTestArray [MapIndex].RequestedUserVa,
FALSE,
HighPagePriority);
DbgPrint ("Mapped %p bytes at address %p\n",
SizeToMap,
PagedPoolMdlTestArray [MapIndex].MappedAddress);
}
//DbgBreakPoint ();
}
VOID
TdNonPagedPoolMdlTestUnMap(
IN PVOID IrpAddress
)
{
ULONG MapIndex;
for (MapIndex = 0 ; MapIndex < ARRAY_LENGTH (PagedPoolMdlTestArray); MapIndex += 1)
{
if (PagedPoolMdlTestArray [MapIndex].MappedAddress != NULL)
{
//
// Unmap
//
MmUnmapLockedPages (PagedPoolMdlTestArray [MapIndex].MappedAddress,
PagedPoolMdlTestArray [MapIndex].Mdl);
PagedPoolMdlTestArray [MapIndex].MappedAddress = NULL;
}
if (PagedPoolMdlTestArray [MapIndex].Mdl != NULL)
{
//
// Free Mdl
//
IoFreeMdl (PagedPoolMdlTestArray [MapIndex].Mdl);
PagedPoolMdlTestArray [MapIndex].Mdl = NULL;
}
}
}
#endif // #if !MMTESTS_ACTIVE
//
// End of file
//