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
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
|
|
//
|
|
|
|
|
|
|