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