#include
"
iop.h
"
#include " ntddft.h "
#include < inbv.h >
#include < windef.h >
//
// Processor specific macros.
//
#if defined (i386)
#define PROGRAM_COUNTER(_context) ((_context)->Eip)
#define STACK_POINTER(_context) ((_context)->Esp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_I386
#define PaeEnabled() X86PaeEnabled()
#elif defined (ALPHA)
#define PROGRAM_COUNTER(_context) ((_context)->Fir)
#define STACK_POINTER(_context) ((_context)->IntSp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_ALPHA
#define PaeEnabled() (FALSE)
#elif defined (_IA64_)
#define PROGRAM_COUNTER(_context) ((_context)->StIIP)
#define STACK_POINTER(_context) ((_context)->IntSp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_IA64
#define PaeEnabled() (FALSE)
#else
#error ("unknown processor type")
#endif
//
// min3(_a,_b,_c)
//
// Same as min() but takes 3 parameters.
//
#define min3(_a,_b,_c) ( min ( min ((_a), (_b)), min ((_a), (_c))) )
//
// Global variables
//
extern PVOID MmPfnDatabase;
extern PFN_NUMBER MmHighestPossiblePhysicalPage;
NTSTATUS IopFinalCrashDumpStatus = - 1 ;
ULONG IopCrashDumpStateChange = 0 ;
BOOLEAN IopDumpFileContainsNewDump = FALSE;
//
// Max dump transfer sizes
//
#define IO_DUMP_MAXIMUM_TRANSFER_SIZE ( 1024 * 64 )
#define IO_DUMP_MINIMUM_TRANSFER_SIZE ( 1024 * 32 )
#define IO_DUMP_MINIMUM_FILE_SIZE ( PAGE_SIZE * 256 )
#define MAX_UNICODE_LENGTH ( 512 )
#define DEFAULT_DRIVER_PATH L"\\SystemRoot\\System32\\Drivers\\"
#define DEFAULT_DUMP_DRIVER L"\\SystemRoot\\System32\\Drivers\\diskdump.sys"
#define SCSIPORT_DRIVER_NAME L"scsiport.sys"
#define MAX_TRIAGE_STACK_SIZE ( 16 * 1024 )
#define DEFAULT_TRIAGE_DUMP_FLAGS (0xFFFFFFFF)
//
// Function prototypes
//
NTSTATUS
IopWriteTriageDump(
IN ULONG FieldsToWrite,
IN PDUMP_DRIVER_WRITE WriteRoutine,
IN OUT PLARGE_INTEGER Mcb,
IN OUT PMDL Mdl,
IN ULONG DiverTransferSize,
IN PCONTEXT Context,
IN LPBYTE Buffer,
IN ULONG BufferSize,
IN ULONG ServicePackBuild,
IN ULONG TriageOptions
);
NTSTATUS
IopWriteSummaryDump(
IN PRTL_BITMAP PageMap,
IN PDUMP_DRIVER_WRITE WriteRoutine,
IN PANSI_STRING ProgressMessage,
IN PUCHAR MessageBuffer,
IN OUT PLARGE_INTEGER Mcb,
IN ULONG DiverTransferSize
);
NTSTATUS
IopWriteToDisk(
IN PVOID Buffer,
IN ULONG WriteLength,
IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
IN OUT PLARGE_INTEGER * Mcb,
IN OUT PMDL Mdl,
IN ULONG DriverTransferSize
);
VOID
IopMapPhysicalMemory(
IN OUT PMDL Mdl,
IN ULONG_PTR MemoryAddress,
IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
IN ULONG Length
);
NTSTATUS
IopLoadDumpDriver (
IN OUT PDUMP_STACK_CONTEXT DumpStack,
IN PWCHAR DriverNameString,
IN PWCHAR NewBaseNameString
);
NTSTATUS
IoSetCrashDumpState(
IN SYSTEM_CRASH_STATE_INFORMATION * pDumpState
);
PSUMMARY_DUMP_HEADER
IopInitializeSummaryDump(
IN PDUMP_CONTROL_BLOCK pDcb
);
NTSTATUS
IopWriteSummaryHeader(
IN PSUMMARY_DUMP_HEADER pSummaryHeader,
IN PDUMP_DRIVER_WRITE pfWrite,
IN OUT PLARGE_INTEGER * pMcbBuffer,
IN OUT PMDL pMdl,
IN ULONG dwWriteSize,
IN ULONG dwLength
);
VOID
IopMapVirtualToPhysicalMdl(
IN OUT PMDL pMdl,
IN ULONG_PTR dwMemoryAddress,
IN ULONG dwLength
);
ULONG
IopCreateSummaryDump (
IN PSUMMARY_DUMP_HEADER pHeader
);
VOID
IopDeleteNonExistentMemory(
PSUMMARY_DUMP_HEADER pHeader,
PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
);
NTSTATUS
IopGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN PUNICODE_STRING pUniDeviceName,
IN PWSTR pDumpDriverName,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
);
BOOLEAN
IopInitializeDCB(
);
LARGE_INTEGER
IopCalculateRequiredDumpSpace(
IN ULONG dwDmpFlags,
IN ULONG dwHeaderSize,
IN PFN_NUMBER dwMaxPages,
IN PFN_NUMBER dwMaxSummaryPages
);
NTSTATUS
IopCompleteDumpInitialization(
IN HANDLE FileHandle
);
#if DBG
VOID
IopDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
);
#define IoDebugPrint(X) IopDebugPrint X
#else
#define IoDebugPrint(X)
#endif // DBG
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,IoGetDumpStack)
#pragma alloc_text(PAGE,IopLoadDumpDriver)
#pragma alloc_text(PAGE,IoFreeDumpStack)
#pragma alloc_text(PAGE,IoGetCrashDumpInformation)
#pragma alloc_text(PAGE,IoGetCrashDumpStateInformation)
#pragma alloc_text(PAGE,IoSetCrashDumpState)
#endif
#if defined (i386)
//
// Functions
//
BOOL
X86PaeEnabled(
)
/*++
Routine Description:
Is PAE currently enabled?
Return Values:
Return TRUE if PAE is enabled in the CR4 register, FALSE otherwise.
--*/
{
ULONG Reg_Cr4;
_asm {
_emit 0Fh
_emit 20h
_emit 0E0h ;; mov eax, cr4
mov Reg_Cr4, eax
}
return (Reg_Cr4 & CR4_PAE ? TRUE : FALSE);
}
#endif
BOOLEAN
IopIsAddressRangeValid(
IN PVOID VirtualAddress,
IN SIZE_T Length
)
/*++
Routine Description:
Validate a range of addresses.
Arguments:
Virtual Address - Beginning of of memory block to validate.
Length - Length of memory block to validate.
Return Value:
TRUE - Address range is valid.
FALSE - Address range is not valid.
--*/
{
UINT_PTR Va;
ULONG Pages;
Va = (UINT_PTR) PAGE_ALIGN (VirtualAddress);
Pages = COMPUTE_PAGES_SPANNED (VirtualAddress, Length);
while (Pages) {
if (!MmIsAddressValid ( (LPVOID) Va)) {
return FALSE;
}
Va += PAGE_SIZE;
Pages--;
}
return TRUE;
}
NTSTATUS
IoGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
)
/*++
Routine Description:
This routine loads a dump stack instance and returns an allocated
context structure to track the loaded dumps stack.
Arguments:
ModePrefix - The prefix to prepent to BaseName during the load
operation. This allows loading the same drivers
multiple times with different virtual names and
linkages.
pDumpStack - The returned dump stack context structure
UsageType - The Device Notification Usage Type for this file, that
this routine will send as to the device object once the
file has been successfully created and initialized.
IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
this to succeed anyway.
Return Value:
Status
--*/
{
PAGED_CODE();
return IopGetDumpStack(ModulePrefix,
pDumpStack,
&IoArcBootDeviceName,
DEFAULT_DUMP_DRIVER,
UsageType,
IgnoreDeviceUsageFailure
);
}
NTSTATUS
IopGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN PUNICODE_STRING pUniDeviceName,
IN PWCHAR pDumpDriverName,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
)
/*++
Routine Description:
This routine loads a dump stack instance and returns an allocated
context structure to track the loaded dumps stack.
Arguments:
ModePrefix - The prefix to prepent to BaseName during the load
operation. This allows loading the same drivers
multiple times with different virtual names and
linkages.
pDumpStack - The returned dump stack context structure
pDeviceName - The name of the target dump device
pDumpDriverName - The name of the target dump driver
UsageType - The Device Notification Usage Type for this file, that
this routine will send as to the device object once the
file has been successfully created and initialized.
IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
this to succeed anyway.
Return Value:
Status
--*/
{
PDUMP_STACK_CONTEXT DumpStack;
PUCHAR Buffer;
PUCHAR PartitionName;
ANSI_STRING AnsiString;
UNICODE_STRING TempName;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE DeviceHandle;
SCSI_ADDRESS ScsiAddress;
BOOLEAN ScsiDump;
PARTITION_INFORMATION PartitionInfo;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PINITIALIZATION_CONTEXT DumpInit;
PDUMP_POINTERS DumpPointers;
UNICODE_STRING DriverName;
PDRIVER_OBJECT DriverObject;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK IoStatus;
PWCHAR DumpName, NameOffset;
KEVENT Event;
PVOID p1;
PHYSICAL_ADDRESS pa;
ULONG i;
IO_STACK_LOCATION irpSp;
ULONG information;
IoDebugPrint((2,"IopGetDumpStack: Prefix:%ws stk: %x device:%ws driver:%ws\n",
ModulePrefix, pDumpStack, pUniDeviceName->Buffer,pDumpDriverName));
ASSERT (DeviceUsageTypeUndefined != UsageType);
DumpStack = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (DUMP_STACK_CONTEXT) + sizeof (DUMP_POINTERS),
'pmuD'
);
if (!DumpStack) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(DumpStack, sizeof(DUMP_STACK_CONTEXT)+sizeof(DUMP_POINTERS));
DumpInit = &DumpStack->Init;
DumpPointers = (PDUMP_POINTERS) (DumpStack + 1);
DumpStack->DumpPointers = DumpPointers;
InitializeListHead (&DumpStack->DriverList);
DumpName = NULL;
//
// Allocate scratch buffer
//
Buffer = ExAllocatePoolWithTag (PagedPool, PAGE_SIZE, 'pmuD');
if (!Buffer) {
ExFreePool (DumpStack);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (!KeGetBugMessageText(BUGCODE_PSS_CRASH_INIT, &DumpStack->InitMsg) ||
!KeGetBugMessageText(BUGCODE_PSS_CRASH_PROGRESS, &DumpStack->ProgMsg) ||
!KeGetBugMessageText(BUGCODE_PSS_CRASH_DONE, &DumpStack->DoneMsg)) {
Status = STATUS_UNSUCCESSFUL;
goto Done;
}
InitializeObjectAttributes(
&ObjectAttributes,
pUniDeviceName,
0,
NULL,
NULL
);
Status = ZwOpenFile(
&DeviceHandle,
FILE_READ_DATA | SYNCHRONIZE,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE
);
if (!NT_SUCCESS(Status)) {
IoDebugPrint ((0,
"IODUMP: Could not open boot device partition, %s\n",
Buffer
));
goto Done;
}
//
// Check to see whether or not the system was booted from a SCSI device.
//
Status = ZwDeviceIoControlFile (
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_SCSI_GET_ADDRESS,
NULL,
0,
&ScsiAddress,
sizeof( SCSI_ADDRESS )
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
ScsiDump = (BOOLEAN) (NT_SUCCESS(Status));
//
// If SCSI then allocate storage to contain the target address information.
//
DumpInit->TargetAddress = NULL;
if (ScsiDump) {
DumpInit->TargetAddress = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (SCSI_ADDRESS),
'pmuD'
);
//
// It is ok If the allocation fails. The scsi dump driver will scan
// all devices if the targetaddress information does not exist
//
if (DumpInit->TargetAddress) {
RtlCopyMemory(DumpInit->TargetAddress,&ScsiAddress,sizeof(SCSI_ADDRESS));
}
}
//
// Determine the disk signature for the device from which the system was
// booted and get the partition offset.
//
Status = ZwDeviceIoControlFile(
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
&PartitionInfo,
sizeof( PARTITION_INFORMATION )
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
IoDebugPrint((2,"Partition Type = %x\n",PartitionInfo.PartitionType));
IoDebugPrint((2,"Boot Indicator = %x\n",PartitionInfo.BootIndicator));
Status = ZwDeviceIoControlFile(
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_DRIVE_LAYOUT,
NULL,
0,
Buffer,
PAGE_SIZE
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
DumpInit->DiskSignature = ((PDRIVE_LAYOUT_INFORMATION) Buffer)->Signature;
//
// Get the adapter object and base mapping registers for the disk from
// the disk driver. These will be used to call the HAL once the system
// system has crashed, since it is not possible at that point to recreate
// them from scratch.
//
ObReferenceObjectByHandle (
DeviceHandle,
0,
IoFileObjectType,
KernelMode,
(PVOID *) &FileObject,
NULL
);
DeviceObject = IoGetRelatedDeviceObject (FileObject);
KeInitializeEvent( &Event, NotificationEvent, FALSE );
Irp = IoBuildDeviceIoControlRequest(
IOCTL_SCSI_GET_DUMP_POINTERS,
DeviceObject,
NULL,
0,
DumpPointers,
sizeof (DUMP_POINTERS),
FALSE,
&Event,
&IoStatus
);
if (!Irp) {
ObDereferenceObject (FileObject);
ZwClose (DeviceHandle);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
IrpSp = IoGetNextIrpStackLocation (Irp);
IrpSp->FileObject = FileObject;
Status = IoCallDriver( DeviceObject, Irp );
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (!NT_SUCCESS(Status) || IoStatus.Information < FIELD_OFFSET(DUMP_POINTERS, DeviceObject)) {
IoDebugPrint ((0,
"IODUMP: Could not get dump pointers; error = %x, length %x\n",
Status,
IoStatus.Information
));
ObDereferenceObject (FileObject);
// NtClose (DeviceHandle);
ZwClose (DeviceHandle);
goto Done;
}
DumpStack->PointersLength = (ULONG) IoStatus.Information;
//
// If the driver returned a pointer to a device object, that is the
// object for the dump driver (non-scsi case)
//
DeviceObject = (PDEVICE_OBJECT) DumpPointers->DeviceObject;
if (DeviceObject) {
DriverObject = DeviceObject->DriverObject;
//
// Loop through the name of the driver looking for the end of the name,
// which is the name of the dump image.
//
DumpName = DriverObject->DriverName.Buffer;
while ( NameOffset = wcsstr( DumpName, L"\\" )) {
DumpName = ++NameOffset;
}
ScsiDump = FALSE;
}
//
// Release the handle, but keep the reference to the file object as it
// will be needed at free dump dump driver time
//
DumpStack->FileObject = FileObject;
ZwClose (DeviceHandle);
//
// Fill in some DumpInit results
//
DumpInit->Length = sizeof (INITIALIZATION_CONTEXT);
DumpInit->StallRoutine = &KeStallExecutionProcessor;
DumpInit->AdapterObject = DumpPointers->AdapterObject;
DumpInit->MappedRegisterBase = DumpPointers->MappedRegisterBase;
DumpInit->PortConfiguration = DumpPointers->DumpData;
DumpStack->ModulePrefix = ModulePrefix;
DumpStack->PartitionOffset = PartitionInfo.StartingOffset;
DumpStack->UsageType = DeviceUsageTypeUndefined;
//
// The minimum common buffer size is IO_DUMP_COMMON_BUFFER_SIZE (compatability)
// This is used by the dump driver for SRB extension, CachedExtension, and sense buffer
//
if (DumpPointers->CommonBufferSize < IO_DUMP_COMMON_BUFFER_SIZE) {
DumpPointers->CommonBufferSize = IO_DUMP_COMMON_BUFFER_SIZE;
}
DumpInit->CommonBufferSize = DumpPointers->CommonBufferSize;
//
// Allocate the required common buffers
//
if (DumpPointers->AllocateCommonBuffers) {
pa.QuadPart = 0x1000000 - 1;
for (i=0; i < 2; i++) {
if (DumpInit->AdapterObject) {
#if !defined(NO_LEGACY_DRIVERS)
p1 = HalAllocateCommonBuffer(
DumpInit->AdapterObject,
DumpPointers->CommonBufferSize,
&pa,
FALSE
);
#else
p1 = (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations->
AllocateCommonBuffer)(
(PDMA_ADAPTER)DumpInit->AdapterObject,
DumpPointers->CommonBufferSize,
&pa,
FALSE
);
#endif // NO_LEGACY_DRIVERS
} else {
p1 = MmAllocateContiguousMemory (
DumpPointers->CommonBufferSize,
pa
);
if (!p1) {
p1 = MmAllocateNonCachedMemory (DumpPointers->CommonBufferSize);
}
pa = MmGetPhysicalAddress(p1);
}
if (!p1) {
IoDebugPrint ((0, "IODUMP: Could not allocate common buffers for dump\n"));
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
DumpInit->CommonBuffer[i] = p1;
DumpInit->PhysicalAddress[i] = pa;
}
}
//
// Determine whether or not the system booted from SCSI.
//
if (ScsiDump) {
//
// Load the boot disk and port driver to be used by the various
// miniports for writing memory to the disk.
//
Status = IopLoadDumpDriver (
DumpStack,
pDumpDriverName,
SCSIPORT_DRIVER_NAME
);
if (!NT_SUCCESS(Status)) {
IopLogErrorEvent(0,9,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
goto Done;
}
//
// The disk and port dump driver has been loaded. Load the appropriate
// miniport driver as well so that the boot device can be accessed.
//
DriverName.Length = 0;
DriverName.Buffer = (PVOID) Buffer;
DriverName.MaximumLength = PAGE_SIZE;
//
// The system was booted from SCSI. Get the name of the appropriate
// miniport driver and load it.
//
sprintf(Buffer, "\\Device\\ScsiPort%d", ScsiAddress.PortNumber );
RtlInitAnsiString( &AnsiString, Buffer );
RtlAnsiStringToUnicodeString( &TempName, &AnsiString, TRUE );
InitializeObjectAttributes(
&ObjectAttributes,
&TempName,
0,
NULL,
NULL
);
Status = ZwOpenFile(
&DeviceHandle,
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE
);
RtlFreeUnicodeString( &TempName );
if (!NT_SUCCESS( Status )) {
IoDebugPrint ((0,
"IODUMP: Could not open SCSI port %d, error = %x\n",
ScsiAddress.PortNumber,
Status
));
goto Done;
}
//
// Convert the file handle into a pointer to the device object, and
// get the name of the driver from its driver object.
//
ObReferenceObjectByHandle(
DeviceHandle,
0,
IoFileObjectType,
KernelMode,
(PVOID *) &FileObject,
NULL
);
DriverObject = FileObject->DeviceObject->DriverObject;
ObDereferenceObject( FileObject );
ZwClose( DeviceHandle );
//
// Loop through the name of the driver looking for the end of the name,
// which is the name of the miniport image.
//
DumpName = DriverObject->DriverName.Buffer;
while ( NameOffset = wcsstr( DumpName, L"\\" )) {
DumpName = ++NameOffset;
}
}
//
// Load the dump driver
//
if (!DumpName) {
Status = STATUS_NOT_SUPPORTED;
goto Done;
}
swprintf ((PWCHAR) Buffer, L"\\SystemRoot\\System32\\Drivers\\%s.sys", DumpName);
Status = IopLoadDumpDriver (
DumpStack,
(PWCHAR) Buffer,
NULL
);
if (!NT_SUCCESS(Status)) {
IopLogErrorEvent(0,10,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
goto Done;
}
//
// Claim the file as part of specific device usage path.
//
FileObject = DumpStack->FileObject;
DeviceObject = IoGetRelatedDeviceObject (FileObject);
RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
irpSp.MajorFunction = IRP_MJ_PNP;
irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
irpSp.Parameters.UsageNotification.Type = UsageType;
irpSp.Parameters.UsageNotification.InPath = TRUE;
irpSp.FileObject = FileObject;
Status = IopSynchronousCall (DeviceObject, &irpSp, (VOID **) &information);
ASSERT (0 == information);
if (!NT_SUCCESS(Status) && IgnoreDeviceUsageFailure) {
IoDebugPrint ((0,
"IopGetDumpStack: DEVICE_USAGE_NOTIFICATION "
"Error ignored (%x)\n",
Status));
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status)) {
DumpStack->UsageType = UsageType;
}
Done:
if (NT_SUCCESS(Status)) {
*pDumpStack = DumpStack;
} else {
IoFreeDumpStack (DumpStack);
}
ExFreePool (Buffer);
return Status;
}
NTSTATUS
IopLoadDumpDriver (
IN OUT PDUMP_STACK_CONTEXT DumpStack,
IN PWCHAR DriverNameString,
IN PWCHAR NewBaseNameString OPTIONAL
)
/*++
Routine Description:
Worker function for IoGetDumpStack to load a particular driver into
the current DumpStack being created
Arguments:
DumpStack - Dump driver stack being built
DriverNameString - The string name of the driver to load
NewBaseNameString - The modified basename of the driver once loaded
Return Value:
Status
--*/
{
NTSTATUS Status;
PDUMP_STACK_IMAGE DumpImage;
PLDR_DATA_TABLE_ENTRY ImageLdrInfo;
UNICODE_STRING DriverName;
UNICODE_STRING BaseName;
UNICODE_STRING Prefix;
PUNICODE_STRING LoadBaseName;
//
// Allocate space to track this dump driver
//
DumpImage = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (DUMP_STACK_IMAGE),
'pmuD'
);
if (!DumpImage) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Load the system image
//
RtlInitUnicodeString (&DriverName, DriverNameString);
RtlInitUnicodeString (&Prefix, DumpStack->ModulePrefix);
LoadBaseName = NULL;
if (NewBaseNameString) {
LoadBaseName = &BaseName;
RtlInitUnicodeString (&BaseName, NewBaseNameString);
BaseName.MaximumLength = Prefix.Length + BaseName.Length;
BaseName.Buffer = ExAllocatePoolWithTag (
NonPagedPool,
BaseName.MaximumLength,
'pmuD'
);
if (!BaseName.Buffer) {
ExFreePool (DumpImage);
return STATUS_INSUFFICIENT_RESOURCES;
}
BaseName.Length = 0;
RtlAppendUnicodeStringToString (&BaseName, &Prefix);
RtlAppendUnicodeToString (&BaseName, NewBaseNameString);
}
Status = MmLoadAndLockSystemImage(
&DriverName,
&Prefix,
LoadBaseName,
&DumpImage->Image,
&DumpImage->ImageBase
);
if (NewBaseNameString) {
ExFreePool (BaseName.Buffer);
}
if (!NT_SUCCESS (Status)) {
IoDebugPrint ((0,
"IODUMP: Could not load %wZ; error = %x\n",
&DriverName,
Status));
ExFreePool (DumpImage);
return Status;
}
//
// Put this driver on the list of drivers to be processed at crash time
//
DumpImage->SizeOfImage = DumpImage->Image->SizeOfImage;
InsertTailList (&DumpStack->DriverList, &DumpImage->Link);
return STATUS_SUCCESS;
}
ULONG
IopGetDumpControlBlockCheck (
IN PDUMP_CONTROL_BLOCK Dcb
)
/*++
Routine Description:
Return the current checksum total for the Dcb
Arguments:
DumpStack - Dump driver stack to checksum
Return Value:
Checksum value
--*/
{
ULONG Check;
PLIST_ENTRY Link;
PDUMP_STACK_IMAGE DumpImage;
PMAPPED_ADDRESS MappedAddress;
PDUMP_STACK_CONTEXT DumpStack;
//
// Check the DCB, memory descriptor array, and the FileDescriptorArray
//
Check = PoSimpleCheck(0, Dcb, sizeof(DUMP_CONTROL_BLOCK));
Check = PoSimpleCheck(
Check,
Dcb->MemoryDescriptor,
Dcb->MemoryDescriptorLength
);
Check = PoSimpleCheck(Check, Dcb->FileDescriptorArray, Dcb->FileDescriptorSize);
DumpStack = Dcb->DumpStack;
if (DumpStack) {
//
// Include the dump stack context structure, and dump driver images
//
Check = PoSimpleCheck(Check, DumpStack, sizeof(DUMP_STACK_CONTEXT));
Check = PoSimpleCheck(Check, DumpStack->DumpPointers, DumpStack->PointersLength);
for (Link = DumpStack->DriverList.Flink;
Link != &DumpStack->DriverList;
Link = Link->Flink) {
DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
Check = PoSimpleCheck(Check, DumpImage, sizeof(DUMP_STACK_IMAGE));
Check = PoSimpleCheck(Check, DumpImage->ImageBase, DumpImage->SizeOfImage);
}
//
// Include the mapped addresses
//
// If this is non-null it is treated as a PMAPPED_ADDRESS * (see scsiport and atdisk)
//
if (DumpStack->Init.MappedRegisterBase != NULL) {
MappedAddress = *(PMAPPED_ADDRESS *)DumpStack->Init.MappedRegisterBase;
} else {
MappedAddress = NULL;
}
while (MappedAddress) {
Check = PoSimpleCheck (Check, MappedAddress, sizeof(MAPPED_ADDRESS));
MappedAddress = MappedAddress->NextMappedAddress;
}
}
return Check;
}
#include " ntddft.h "
#include < inbv.h >
#include < windef.h >
//
// Processor specific macros.
//
#if defined (i386)
#define PROGRAM_COUNTER(_context) ((_context)->Eip)
#define STACK_POINTER(_context) ((_context)->Esp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_I386
#define PaeEnabled() X86PaeEnabled()
#elif defined (ALPHA)
#define PROGRAM_COUNTER(_context) ((_context)->Fir)
#define STACK_POINTER(_context) ((_context)->IntSp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_ALPHA
#define PaeEnabled() (FALSE)
#elif defined (_IA64_)
#define PROGRAM_COUNTER(_context) ((_context)->StIIP)
#define STACK_POINTER(_context) ((_context)->IntSp)
#define CURRENT_IMAGE_TYPE() IMAGE_FILE_MACHINE_IA64
#define PaeEnabled() (FALSE)
#else
#error ("unknown processor type")
#endif
//
// min3(_a,_b,_c)
//
// Same as min() but takes 3 parameters.
//
#define min3(_a,_b,_c) ( min ( min ((_a), (_b)), min ((_a), (_c))) )
//
// Global variables
//
extern PVOID MmPfnDatabase;
extern PFN_NUMBER MmHighestPossiblePhysicalPage;
NTSTATUS IopFinalCrashDumpStatus = - 1 ;
ULONG IopCrashDumpStateChange = 0 ;
BOOLEAN IopDumpFileContainsNewDump = FALSE;
//
// Max dump transfer sizes
//
#define IO_DUMP_MAXIMUM_TRANSFER_SIZE ( 1024 * 64 )
#define IO_DUMP_MINIMUM_TRANSFER_SIZE ( 1024 * 32 )
#define IO_DUMP_MINIMUM_FILE_SIZE ( PAGE_SIZE * 256 )
#define MAX_UNICODE_LENGTH ( 512 )
#define DEFAULT_DRIVER_PATH L"\\SystemRoot\\System32\\Drivers\\"
#define DEFAULT_DUMP_DRIVER L"\\SystemRoot\\System32\\Drivers\\diskdump.sys"
#define SCSIPORT_DRIVER_NAME L"scsiport.sys"
#define MAX_TRIAGE_STACK_SIZE ( 16 * 1024 )
#define DEFAULT_TRIAGE_DUMP_FLAGS (0xFFFFFFFF)
//
// Function prototypes
//
NTSTATUS
IopWriteTriageDump(
IN ULONG FieldsToWrite,
IN PDUMP_DRIVER_WRITE WriteRoutine,
IN OUT PLARGE_INTEGER Mcb,
IN OUT PMDL Mdl,
IN ULONG DiverTransferSize,
IN PCONTEXT Context,
IN LPBYTE Buffer,
IN ULONG BufferSize,
IN ULONG ServicePackBuild,
IN ULONG TriageOptions
);
NTSTATUS
IopWriteSummaryDump(
IN PRTL_BITMAP PageMap,
IN PDUMP_DRIVER_WRITE WriteRoutine,
IN PANSI_STRING ProgressMessage,
IN PUCHAR MessageBuffer,
IN OUT PLARGE_INTEGER Mcb,
IN ULONG DiverTransferSize
);
NTSTATUS
IopWriteToDisk(
IN PVOID Buffer,
IN ULONG WriteLength,
IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
IN OUT PLARGE_INTEGER * Mcb,
IN OUT PMDL Mdl,
IN ULONG DriverTransferSize
);
VOID
IopMapPhysicalMemory(
IN OUT PMDL Mdl,
IN ULONG_PTR MemoryAddress,
IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
IN ULONG Length
);
NTSTATUS
IopLoadDumpDriver (
IN OUT PDUMP_STACK_CONTEXT DumpStack,
IN PWCHAR DriverNameString,
IN PWCHAR NewBaseNameString
);
NTSTATUS
IoSetCrashDumpState(
IN SYSTEM_CRASH_STATE_INFORMATION * pDumpState
);
PSUMMARY_DUMP_HEADER
IopInitializeSummaryDump(
IN PDUMP_CONTROL_BLOCK pDcb
);
NTSTATUS
IopWriteSummaryHeader(
IN PSUMMARY_DUMP_HEADER pSummaryHeader,
IN PDUMP_DRIVER_WRITE pfWrite,
IN OUT PLARGE_INTEGER * pMcbBuffer,
IN OUT PMDL pMdl,
IN ULONG dwWriteSize,
IN ULONG dwLength
);
VOID
IopMapVirtualToPhysicalMdl(
IN OUT PMDL pMdl,
IN ULONG_PTR dwMemoryAddress,
IN ULONG dwLength
);
ULONG
IopCreateSummaryDump (
IN PSUMMARY_DUMP_HEADER pHeader
);
VOID
IopDeleteNonExistentMemory(
PSUMMARY_DUMP_HEADER pHeader,
PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
);
NTSTATUS
IopGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN PUNICODE_STRING pUniDeviceName,
IN PWSTR pDumpDriverName,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
);
BOOLEAN
IopInitializeDCB(
);
LARGE_INTEGER
IopCalculateRequiredDumpSpace(
IN ULONG dwDmpFlags,
IN ULONG dwHeaderSize,
IN PFN_NUMBER dwMaxPages,
IN PFN_NUMBER dwMaxSummaryPages
);
NTSTATUS
IopCompleteDumpInitialization(
IN HANDLE FileHandle
);
#if DBG
VOID
IopDebugPrint(
ULONG DebugPrintLevel,
PCCHAR DebugMessage,
);
#define IoDebugPrint(X) IopDebugPrint X
#else
#define IoDebugPrint(X)
#endif // DBG
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,IoGetDumpStack)
#pragma alloc_text(PAGE,IopLoadDumpDriver)
#pragma alloc_text(PAGE,IoFreeDumpStack)
#pragma alloc_text(PAGE,IoGetCrashDumpInformation)
#pragma alloc_text(PAGE,IoGetCrashDumpStateInformation)
#pragma alloc_text(PAGE,IoSetCrashDumpState)
#endif
#if defined (i386)
//
// Functions
//
BOOL
X86PaeEnabled(
)
/*++
Routine Description:
Is PAE currently enabled?
Return Values:
Return TRUE if PAE is enabled in the CR4 register, FALSE otherwise.
--*/
{
ULONG Reg_Cr4;
_asm {
_emit 0Fh
_emit 20h
_emit 0E0h ;; mov eax, cr4
mov Reg_Cr4, eax
}
return (Reg_Cr4 & CR4_PAE ? TRUE : FALSE);
}
#endif
BOOLEAN
IopIsAddressRangeValid(
IN PVOID VirtualAddress,
IN SIZE_T Length
)
/*++
Routine Description:
Validate a range of addresses.
Arguments:
Virtual Address - Beginning of of memory block to validate.
Length - Length of memory block to validate.
Return Value:
TRUE - Address range is valid.
FALSE - Address range is not valid.
--*/
{
UINT_PTR Va;
ULONG Pages;
Va = (UINT_PTR) PAGE_ALIGN (VirtualAddress);
Pages = COMPUTE_PAGES_SPANNED (VirtualAddress, Length);
while (Pages) {
if (!MmIsAddressValid ( (LPVOID) Va)) {
return FALSE;
}
Va += PAGE_SIZE;
Pages--;
}
return TRUE;
}
NTSTATUS
IoGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
)
/*++
Routine Description:
This routine loads a dump stack instance and returns an allocated
context structure to track the loaded dumps stack.
Arguments:
ModePrefix - The prefix to prepent to BaseName during the load
operation. This allows loading the same drivers
multiple times with different virtual names and
linkages.
pDumpStack - The returned dump stack context structure
UsageType - The Device Notification Usage Type for this file, that
this routine will send as to the device object once the
file has been successfully created and initialized.
IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
this to succeed anyway.
Return Value:
Status
--*/
{
PAGED_CODE();
return IopGetDumpStack(ModulePrefix,
pDumpStack,
&IoArcBootDeviceName,
DEFAULT_DUMP_DRIVER,
UsageType,
IgnoreDeviceUsageFailure
);
}
NTSTATUS
IopGetDumpStack (
IN PWCHAR ModulePrefix,
OUT PDUMP_STACK_CONTEXT * pDumpStack,
IN PUNICODE_STRING pUniDeviceName,
IN PWCHAR pDumpDriverName,
IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
IN ULONG IgnoreDeviceUsageFailure
)
/*++
Routine Description:
This routine loads a dump stack instance and returns an allocated
context structure to track the loaded dumps stack.
Arguments:
ModePrefix - The prefix to prepent to BaseName during the load
operation. This allows loading the same drivers
multiple times with different virtual names and
linkages.
pDumpStack - The returned dump stack context structure
pDeviceName - The name of the target dump device
pDumpDriverName - The name of the target dump driver
UsageType - The Device Notification Usage Type for this file, that
this routine will send as to the device object once the
file has been successfully created and initialized.
IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
this to succeed anyway.
Return Value:
Status
--*/
{
PDUMP_STACK_CONTEXT DumpStack;
PUCHAR Buffer;
PUCHAR PartitionName;
ANSI_STRING AnsiString;
UNICODE_STRING TempName;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE DeviceHandle;
SCSI_ADDRESS ScsiAddress;
BOOLEAN ScsiDump;
PARTITION_INFORMATION PartitionInfo;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PINITIALIZATION_CONTEXT DumpInit;
PDUMP_POINTERS DumpPointers;
UNICODE_STRING DriverName;
PDRIVER_OBJECT DriverObject;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK IoStatus;
PWCHAR DumpName, NameOffset;
KEVENT Event;
PVOID p1;
PHYSICAL_ADDRESS pa;
ULONG i;
IO_STACK_LOCATION irpSp;
ULONG information;
IoDebugPrint((2,"IopGetDumpStack: Prefix:%ws stk: %x device:%ws driver:%ws\n",
ModulePrefix, pDumpStack, pUniDeviceName->Buffer,pDumpDriverName));
ASSERT (DeviceUsageTypeUndefined != UsageType);
DumpStack = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (DUMP_STACK_CONTEXT) + sizeof (DUMP_POINTERS),
'pmuD'
);
if (!DumpStack) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(DumpStack, sizeof(DUMP_STACK_CONTEXT)+sizeof(DUMP_POINTERS));
DumpInit = &DumpStack->Init;
DumpPointers = (PDUMP_POINTERS) (DumpStack + 1);
DumpStack->DumpPointers = DumpPointers;
InitializeListHead (&DumpStack->DriverList);
DumpName = NULL;
//
// Allocate scratch buffer
//
Buffer = ExAllocatePoolWithTag (PagedPool, PAGE_SIZE, 'pmuD');
if (!Buffer) {
ExFreePool (DumpStack);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (!KeGetBugMessageText(BUGCODE_PSS_CRASH_INIT, &DumpStack->InitMsg) ||
!KeGetBugMessageText(BUGCODE_PSS_CRASH_PROGRESS, &DumpStack->ProgMsg) ||
!KeGetBugMessageText(BUGCODE_PSS_CRASH_DONE, &DumpStack->DoneMsg)) {
Status = STATUS_UNSUCCESSFUL;
goto Done;
}
InitializeObjectAttributes(
&ObjectAttributes,
pUniDeviceName,
0,
NULL,
NULL
);
Status = ZwOpenFile(
&DeviceHandle,
FILE_READ_DATA | SYNCHRONIZE,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE
);
if (!NT_SUCCESS(Status)) {
IoDebugPrint ((0,
"IODUMP: Could not open boot device partition, %s\n",
Buffer
));
goto Done;
}
//
// Check to see whether or not the system was booted from a SCSI device.
//
Status = ZwDeviceIoControlFile (
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_SCSI_GET_ADDRESS,
NULL,
0,
&ScsiAddress,
sizeof( SCSI_ADDRESS )
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
ScsiDump = (BOOLEAN) (NT_SUCCESS(Status));
//
// If SCSI then allocate storage to contain the target address information.
//
DumpInit->TargetAddress = NULL;
if (ScsiDump) {
DumpInit->TargetAddress = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (SCSI_ADDRESS),
'pmuD'
);
//
// It is ok If the allocation fails. The scsi dump driver will scan
// all devices if the targetaddress information does not exist
//
if (DumpInit->TargetAddress) {
RtlCopyMemory(DumpInit->TargetAddress,&ScsiAddress,sizeof(SCSI_ADDRESS));
}
}
//
// Determine the disk signature for the device from which the system was
// booted and get the partition offset.
//
Status = ZwDeviceIoControlFile(
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_PARTITION_INFO,
NULL,
0,
&PartitionInfo,
sizeof( PARTITION_INFORMATION )
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
IoDebugPrint((2,"Partition Type = %x\n",PartitionInfo.PartitionType));
IoDebugPrint((2,"Boot Indicator = %x\n",PartitionInfo.BootIndicator));
Status = ZwDeviceIoControlFile(
DeviceHandle,
NULL,
NULL,
NULL,
&IoStatus,
IOCTL_DISK_GET_DRIVE_LAYOUT,
NULL,
0,
Buffer,
PAGE_SIZE
);
if (Status == STATUS_PENDING) {
ZwWaitForSingleObject (
DeviceHandle,
FALSE,
NULL
);
Status = IoStatus.Status;
}
DumpInit->DiskSignature = ((PDRIVE_LAYOUT_INFORMATION) Buffer)->Signature;
//
// Get the adapter object and base mapping registers for the disk from
// the disk driver. These will be used to call the HAL once the system
// system has crashed, since it is not possible at that point to recreate
// them from scratch.
//
ObReferenceObjectByHandle (
DeviceHandle,
0,
IoFileObjectType,
KernelMode,
(PVOID *) &FileObject,
NULL
);
DeviceObject = IoGetRelatedDeviceObject (FileObject);
KeInitializeEvent( &Event, NotificationEvent, FALSE );
Irp = IoBuildDeviceIoControlRequest(
IOCTL_SCSI_GET_DUMP_POINTERS,
DeviceObject,
NULL,
0,
DumpPointers,
sizeof (DUMP_POINTERS),
FALSE,
&Event,
&IoStatus
);
if (!Irp) {
ObDereferenceObject (FileObject);
ZwClose (DeviceHandle);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
IrpSp = IoGetNextIrpStackLocation (Irp);
IrpSp->FileObject = FileObject;
Status = IoCallDriver( DeviceObject, Irp );
if (Status == STATUS_PENDING) {
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (!NT_SUCCESS(Status) || IoStatus.Information < FIELD_OFFSET(DUMP_POINTERS, DeviceObject)) {
IoDebugPrint ((0,
"IODUMP: Could not get dump pointers; error = %x, length %x\n",
Status,
IoStatus.Information
));
ObDereferenceObject (FileObject);
// NtClose (DeviceHandle);
ZwClose (DeviceHandle);
goto Done;
}
DumpStack->PointersLength = (ULONG) IoStatus.Information;
//
// If the driver returned a pointer to a device object, that is the
// object for the dump driver (non-scsi case)
//
DeviceObject = (PDEVICE_OBJECT) DumpPointers->DeviceObject;
if (DeviceObject) {
DriverObject = DeviceObject->DriverObject;
//
// Loop through the name of the driver looking for the end of the name,
// which is the name of the dump image.
//
DumpName = DriverObject->DriverName.Buffer;
while ( NameOffset = wcsstr( DumpName, L"\\" )) {
DumpName = ++NameOffset;
}
ScsiDump = FALSE;
}
//
// Release the handle, but keep the reference to the file object as it
// will be needed at free dump dump driver time
//
DumpStack->FileObject = FileObject;
ZwClose (DeviceHandle);
//
// Fill in some DumpInit results
//
DumpInit->Length = sizeof (INITIALIZATION_CONTEXT);
DumpInit->StallRoutine = &KeStallExecutionProcessor;
DumpInit->AdapterObject = DumpPointers->AdapterObject;
DumpInit->MappedRegisterBase = DumpPointers->MappedRegisterBase;
DumpInit->PortConfiguration = DumpPointers->DumpData;
DumpStack->ModulePrefix = ModulePrefix;
DumpStack->PartitionOffset = PartitionInfo.StartingOffset;
DumpStack->UsageType = DeviceUsageTypeUndefined;
//
// The minimum common buffer size is IO_DUMP_COMMON_BUFFER_SIZE (compatability)
// This is used by the dump driver for SRB extension, CachedExtension, and sense buffer
//
if (DumpPointers->CommonBufferSize < IO_DUMP_COMMON_BUFFER_SIZE) {
DumpPointers->CommonBufferSize = IO_DUMP_COMMON_BUFFER_SIZE;
}
DumpInit->CommonBufferSize = DumpPointers->CommonBufferSize;
//
// Allocate the required common buffers
//
if (DumpPointers->AllocateCommonBuffers) {
pa.QuadPart = 0x1000000 - 1;
for (i=0; i < 2; i++) {
if (DumpInit->AdapterObject) {
#if !defined(NO_LEGACY_DRIVERS)
p1 = HalAllocateCommonBuffer(
DumpInit->AdapterObject,
DumpPointers->CommonBufferSize,
&pa,
FALSE
);
#else
p1 = (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations->
AllocateCommonBuffer)(
(PDMA_ADAPTER)DumpInit->AdapterObject,
DumpPointers->CommonBufferSize,
&pa,
FALSE
);
#endif // NO_LEGACY_DRIVERS
} else {
p1 = MmAllocateContiguousMemory (
DumpPointers->CommonBufferSize,
pa
);
if (!p1) {
p1 = MmAllocateNonCachedMemory (DumpPointers->CommonBufferSize);
}
pa = MmGetPhysicalAddress(p1);
}
if (!p1) {
IoDebugPrint ((0, "IODUMP: Could not allocate common buffers for dump\n"));
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
DumpInit->CommonBuffer[i] = p1;
DumpInit->PhysicalAddress[i] = pa;
}
}
//
// Determine whether or not the system booted from SCSI.
//
if (ScsiDump) {
//
// Load the boot disk and port driver to be used by the various
// miniports for writing memory to the disk.
//
Status = IopLoadDumpDriver (
DumpStack,
pDumpDriverName,
SCSIPORT_DRIVER_NAME
);
if (!NT_SUCCESS(Status)) {
IopLogErrorEvent(0,9,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
goto Done;
}
//
// The disk and port dump driver has been loaded. Load the appropriate
// miniport driver as well so that the boot device can be accessed.
//
DriverName.Length = 0;
DriverName.Buffer = (PVOID) Buffer;
DriverName.MaximumLength = PAGE_SIZE;
//
// The system was booted from SCSI. Get the name of the appropriate
// miniport driver and load it.
//
sprintf(Buffer, "\\Device\\ScsiPort%d", ScsiAddress.PortNumber );
RtlInitAnsiString( &AnsiString, Buffer );
RtlAnsiStringToUnicodeString( &TempName, &AnsiString, TRUE );
InitializeObjectAttributes(
&ObjectAttributes,
&TempName,
0,
NULL,
NULL
);
Status = ZwOpenFile(
&DeviceHandle,
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE
);
RtlFreeUnicodeString( &TempName );
if (!NT_SUCCESS( Status )) {
IoDebugPrint ((0,
"IODUMP: Could not open SCSI port %d, error = %x\n",
ScsiAddress.PortNumber,
Status
));
goto Done;
}
//
// Convert the file handle into a pointer to the device object, and
// get the name of the driver from its driver object.
//
ObReferenceObjectByHandle(
DeviceHandle,
0,
IoFileObjectType,
KernelMode,
(PVOID *) &FileObject,
NULL
);
DriverObject = FileObject->DeviceObject->DriverObject;
ObDereferenceObject( FileObject );
ZwClose( DeviceHandle );
//
// Loop through the name of the driver looking for the end of the name,
// which is the name of the miniport image.
//
DumpName = DriverObject->DriverName.Buffer;
while ( NameOffset = wcsstr( DumpName, L"\\" )) {
DumpName = ++NameOffset;
}
}
//
// Load the dump driver
//
if (!DumpName) {
Status = STATUS_NOT_SUPPORTED;
goto Done;
}
swprintf ((PWCHAR) Buffer, L"\\SystemRoot\\System32\\Drivers\\%s.sys", DumpName);
Status = IopLoadDumpDriver (
DumpStack,
(PWCHAR) Buffer,
NULL
);
if (!NT_SUCCESS(Status)) {
IopLogErrorEvent(0,10,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
goto Done;
}
//
// Claim the file as part of specific device usage path.
//
FileObject = DumpStack->FileObject;
DeviceObject = IoGetRelatedDeviceObject (FileObject);
RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
irpSp.MajorFunction = IRP_MJ_PNP;
irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
irpSp.Parameters.UsageNotification.Type = UsageType;
irpSp.Parameters.UsageNotification.InPath = TRUE;
irpSp.FileObject = FileObject;
Status = IopSynchronousCall (DeviceObject, &irpSp, (VOID **) &information);
ASSERT (0 == information);
if (!NT_SUCCESS(Status) && IgnoreDeviceUsageFailure) {
IoDebugPrint ((0,
"IopGetDumpStack: DEVICE_USAGE_NOTIFICATION "
"Error ignored (%x)\n",
Status));
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status)) {
DumpStack->UsageType = UsageType;
}
Done:
if (NT_SUCCESS(Status)) {
*pDumpStack = DumpStack;
} else {
IoFreeDumpStack (DumpStack);
}
ExFreePool (Buffer);
return Status;
}
NTSTATUS
IopLoadDumpDriver (
IN OUT PDUMP_STACK_CONTEXT DumpStack,
IN PWCHAR DriverNameString,
IN PWCHAR NewBaseNameString OPTIONAL
)
/*++
Routine Description:
Worker function for IoGetDumpStack to load a particular driver into
the current DumpStack being created
Arguments:
DumpStack - Dump driver stack being built
DriverNameString - The string name of the driver to load
NewBaseNameString - The modified basename of the driver once loaded
Return Value:
Status
--*/
{
NTSTATUS Status;
PDUMP_STACK_IMAGE DumpImage;
PLDR_DATA_TABLE_ENTRY ImageLdrInfo;
UNICODE_STRING DriverName;
UNICODE_STRING BaseName;
UNICODE_STRING Prefix;
PUNICODE_STRING LoadBaseName;
//
// Allocate space to track this dump driver
//
DumpImage = ExAllocatePoolWithTag (
NonPagedPool,
sizeof (DUMP_STACK_IMAGE),
'pmuD'
);
if (!DumpImage) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Load the system image
//
RtlInitUnicodeString (&DriverName, DriverNameString);
RtlInitUnicodeString (&Prefix, DumpStack->ModulePrefix);
LoadBaseName = NULL;
if (NewBaseNameString) {
LoadBaseName = &BaseName;
RtlInitUnicodeString (&BaseName, NewBaseNameString);
BaseName.MaximumLength = Prefix.Length + BaseName.Length;
BaseName.Buffer = ExAllocatePoolWithTag (
NonPagedPool,
BaseName.MaximumLength,
'pmuD'
);
if (!BaseName.Buffer) {
ExFreePool (DumpImage);
return STATUS_INSUFFICIENT_RESOURCES;
}
BaseName.Length = 0;
RtlAppendUnicodeStringToString (&BaseName, &Prefix);
RtlAppendUnicodeToString (&BaseName, NewBaseNameString);
}
Status = MmLoadAndLockSystemImage(
&DriverName,
&Prefix,
LoadBaseName,
&DumpImage->Image,
&DumpImage->ImageBase
);
if (NewBaseNameString) {
ExFreePool (BaseName.Buffer);
}
if (!NT_SUCCESS (Status)) {
IoDebugPrint ((0,
"IODUMP: Could not load %wZ; error = %x\n",
&DriverName,
Status));
ExFreePool (DumpImage);
return Status;
}
//
// Put this driver on the list of drivers to be processed at crash time
//
DumpImage->SizeOfImage = DumpImage->Image->SizeOfImage;
InsertTailList (&DumpStack->DriverList, &DumpImage->Link);
return STATUS_SUCCESS;
}
ULONG
IopGetDumpControlBlockCheck (
IN PDUMP_CONTROL_BLOCK Dcb
)
/*++
Routine Description:
Return the current checksum total for the Dcb
Arguments:
DumpStack - Dump driver stack to checksum
Return Value:
Checksum value
--*/
{
ULONG Check;
PLIST_ENTRY Link;
PDUMP_STACK_IMAGE DumpImage;
PMAPPED_ADDRESS MappedAddress;
PDUMP_STACK_CONTEXT DumpStack;
//
// Check the DCB, memory descriptor array, and the FileDescriptorArray
//
Check = PoSimpleCheck(0, Dcb, sizeof(DUMP_CONTROL_BLOCK));
Check = PoSimpleCheck(
Check,
Dcb->MemoryDescriptor,
Dcb->MemoryDescriptorLength
);
Check = PoSimpleCheck(Check, Dcb->FileDescriptorArray, Dcb->FileDescriptorSize);
DumpStack = Dcb->DumpStack;
if (DumpStack) {
//
// Include the dump stack context structure, and dump driver images
//
Check = PoSimpleCheck(Check, DumpStack, sizeof(DUMP_STACK_CONTEXT));
Check = PoSimpleCheck(Check, DumpStack->DumpPointers, DumpStack->PointersLength);
for (Link = DumpStack->DriverList.Flink;
Link != &DumpStack->DriverList;
Link = Link->Flink) {
DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
Check = PoSimpleCheck(Check, DumpImage, sizeof(DUMP_STACK_IMAGE));
Check = PoSimpleCheck(Check, DumpImage->ImageBase, DumpImage->SizeOfImage);
}
//
// Include the mapped addresses
//
// If this is non-null it is treated as a PMAPPED_ADDRESS * (see scsiport and atdisk)
//
if (DumpStack->Init.MappedRegisterBase != NULL) {
MappedAddress = *(PMAPPED_ADDRESS *)DumpStack->Init.MappedRegisterBase;
} else {
MappedAddress = NULL;
}
while (MappedAddress) {
Check = PoSimpleCheck (Check, MappedAddress, sizeof(MAPPED_ADDRESS));
MappedAddress = MappedAddress->NextMappedAddress;
}
}
return Check;
}