#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;
}

























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































