705 lines
20 KiB
C
705 lines
20 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dumpctl.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code to dump memory to disk after a crash.
|
||
|
||
Author:
|
||
|
||
Darryl E. Havens (darrylh) 17-dec-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "iop.h"
|
||
|
||
//
|
||
// Forward declarations
|
||
//
|
||
|
||
static
|
||
VOID
|
||
MapPhysicalMemory(
|
||
IN OUT PMDL Mdl,
|
||
IN ULONG MemoryAddress,
|
||
IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
|
||
IN ULONG Length
|
||
);
|
||
|
||
extern PULONG MmPfnDatabase;
|
||
|
||
NTSTATUS IopFinalCrashDumpStatus = -1;
|
||
|
||
#if 0
|
||
#if DBG
|
||
ULONG BreakDiskByteOffset;
|
||
ULONG BreakPfn;
|
||
#endif // DBG
|
||
#endif // 0
|
||
|
||
BOOLEAN
|
||
IoWriteCrashDump(
|
||
IN ULONG BugCheckCode,
|
||
IN ULONG BugCheckParameter1,
|
||
IN ULONG BugCheckParameter2,
|
||
IN ULONG BugCheckParameter3,
|
||
IN ULONG BugCheckParameter4,
|
||
IN PVOID ContextSave
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks to see whether or not crash dumps are enabled and, if
|
||
so, writes all of physical memory to the system disk's paging file.
|
||
|
||
Arguments:
|
||
|
||
BugCheckCode/ParameterN - Code and parameters w/which BugCheck was called.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDUMP_CONTROL_BLOCK dcb;
|
||
INITIALIZATION_CONTEXT initContext;
|
||
PLIST_ENTRY nextEntry;
|
||
PMINIPORT_NODE mpNode;
|
||
PDUMP_DRIVER_OPEN open;
|
||
PDUMP_DRIVER_WRITE write;
|
||
PDUMP_DRIVER_FINISH finishUp;
|
||
PDUMP_HEADER header;
|
||
EXCEPTION_RECORD exception;
|
||
PCONTEXT context = ContextSave;
|
||
PULONG block;
|
||
LARGE_INTEGER diskByteOffset;
|
||
PULONG page;
|
||
ULONG localMdl[(sizeof( MDL )/4) + 17];
|
||
PMDL mdl;
|
||
PLARGE_INTEGER mcb;
|
||
ULONG memoryAddress;
|
||
ULONG byteOffset;
|
||
ULONG byteCount;
|
||
ULONG bytesRemaining;
|
||
NTSTATUS status;
|
||
PMAPPED_ADDRESS addresses;
|
||
ULONG addressCount;
|
||
ULONG addressChecksum;
|
||
UCHAR messageBuffer[128];
|
||
|
||
//
|
||
// Begin by determining whether or not crash dumps are enabled. If not,
|
||
// check to see whether or not auto-rebooting is enabled. If not, return
|
||
// immediately since there is nothing to do.
|
||
//
|
||
|
||
dcb = IopDumpControlBlock;
|
||
if (!dcb) {
|
||
return FALSE;
|
||
}
|
||
|
||
if (dcb->Flags & DCB_DUMP_ENABLED || dcb->Flags & DCB_SUMMARY_ENABLED) {
|
||
|
||
IopFinalCrashDumpStatus = STATUS_PENDING;
|
||
|
||
//
|
||
// A dump is to be written to the paging file. Ensure that all of the
|
||
// descriptor data for what needs to be done is valid, otherwise it
|
||
// could be that part of the reason for the bugcheck is that this data
|
||
// was corrupted. Or, it could be that no paging file was found yet,
|
||
// or any number of other situations.
|
||
//
|
||
// The rules for determining this are as follows:
|
||
//
|
||
// 1) The dump control block must be a dump control block.
|
||
//
|
||
// 2) The dump control block structure checksum must match.
|
||
//
|
||
// 3) The disk dump driver checksum must match.
|
||
//
|
||
// 4) The miniport queue must be consistent and all driver
|
||
// checksums must match.
|
||
//
|
||
// 5) The file descriptor pointer must be valid and its checksum
|
||
// must match.
|
||
//
|
||
// 6) All buffers must have been allocated.
|
||
//
|
||
// 7) The module list address must be valid.
|
||
//
|
||
|
||
if (dcb->Type != IO_TYPE_DCB ||
|
||
|
||
dcb->Size < sizeof( DUMP_CONTROL_BLOCK ) ||
|
||
|
||
IopChecksum( dcb, dcb->Size ) != IopDumpControlBlockChecksum ||
|
||
|
||
///////// IopChecksum( dcb->DiskDumpDriver->DllBase, dcb->DiskDumpDriver->SizeOfImage ) != dcb->DiskDumpChecksum ||
|
||
|
||
IsListEmpty( &dcb->MiniportQueue ) ||
|
||
|
||
!dcb->FileDescriptorArray ||
|
||
|
||
IopChecksum( dcb->FileDescriptorArray, dcb->FileDescriptorSize ) != dcb->FileDescriptorChecksum ||
|
||
|
||
!dcb->NonCachedBufferVa1 ||
|
||
|
||
!dcb->NonCachedBufferVa2 ||
|
||
|
||
!dcb->Buffer ||
|
||
|
||
!dcb->HeaderPage ||
|
||
|
||
dcb->LoadedModuleList != &PsLoadedModuleList) {
|
||
|
||
#if DBG
|
||
if (dcb->Type != IO_TYPE_DCB) {
|
||
DbgPrint( "DCB Type field is invalid\n" );
|
||
}
|
||
if (dcb->Size < sizeof( DUMP_CONTROL_BLOCK )) {
|
||
DbgPrint( "DCB Size field is invalid\n" );
|
||
}
|
||
if (IopChecksum( dcb, dcb->Size ) != IopDumpControlBlockChecksum) {
|
||
DbgPrint( "DCB checksum is inconsistent\n" );
|
||
}
|
||
///////// if (IopChecksum( dcb->DiskDumpDriver, dcb->DiskDumpDriver->SizeOfImage) != dcb->DiskDumpChecksum) {
|
||
///////// DbgPrint( "Disk dump driver checksum is inconsistent\n" );
|
||
///////// }
|
||
if (IsListEmpty( &dcb->MiniportQueue )) {
|
||
DbgPrint( "Miniport queue is empty\n" );
|
||
}
|
||
if (!dcb->FileDescriptorArray) {
|
||
DbgPrint( "No boot device paging file was found or was too small\n" );
|
||
}
|
||
if (IopChecksum( dcb->FileDescriptorArray, dcb->FileDescriptorSize ) != dcb->FileDescriptorChecksum) {
|
||
DbgPrint( "Page file descriptor checksum is inconsistent\n" );
|
||
}
|
||
DbgPrint( "CRASHDUMP: Disk dump routine returning due to DCB integrity error\n" );
|
||
DbgPrint( " No dump will be created\n" );
|
||
#endif // DBG
|
||
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Finally, check the mapped registers in the driver to guarantee that
|
||
// they are consistent as well.
|
||
//
|
||
|
||
addressCount = 0;
|
||
addressChecksum = 0;
|
||
addresses = * (PMAPPED_ADDRESS *) dcb->MappedRegisterBase;
|
||
|
||
while (addresses) {
|
||
addressCount++;
|
||
addressChecksum += IopChecksum( addresses, sizeof( MAPPED_ADDRESS ) );
|
||
addresses = addresses->NextMappedAddress;
|
||
}
|
||
|
||
if (addressCount != dcb->MappedAddressCount ||
|
||
addressChecksum != dcb->MappedAddressChecksum) {
|
||
#if DBG
|
||
DbgPrint( "Mapped address count or checksum failed\n" );
|
||
#endif // DBG
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// The dump control block appears to be in good order. Begin by
|
||
// initializing the disk dump driver.
|
||
//
|
||
|
||
initContext.Length = sizeof( INITIALIZATION_CONTEXT );
|
||
initContext.DiskSignature = dcb->DiskSignature;
|
||
initContext.MemoryBlock = dcb->Buffer;
|
||
initContext.CommonBuffer[0] = dcb->NonCachedBufferVa1;
|
||
initContext.CommonBuffer[1] = dcb->NonCachedBufferVa2;
|
||
initContext.PhysicalAddress[0] = dcb->NonCachedBufferPa1;
|
||
initContext.PhysicalAddress[1] = dcb->NonCachedBufferPa2;
|
||
initContext.StallRoutine = &KeStallExecutionProcessor;
|
||
initContext.AdapterObject = dcb->AdapterObject;
|
||
initContext.MappedRegisterBase = dcb->MappedRegisterBase;
|
||
initContext.PortConfiguration = dcb->PortConfiguration;
|
||
|
||
status = ((PDRIVER_INITIALIZE) (dcb->DiskDumpDriver->EntryPoint))( (PDRIVER_OBJECT) NULL,
|
||
(PUNICODE_STRING) &initContext );
|
||
if (!NT_SUCCESS( status )) {
|
||
#if DBG
|
||
DbgPrint( "CRASHDUMP: Unable to initialize disk dump driver; error = %x\n", status );
|
||
#endif // DBG
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Record the dump driver's two entry points.
|
||
//
|
||
|
||
open = initContext.OpenRoutine;
|
||
write = initContext.WriteRoutine;
|
||
finishUp = initContext.FinishRoutine;
|
||
|
||
//
|
||
// Display message on screen that we are starting the crashdump
|
||
//
|
||
|
||
sprintf( messageBuffer, "%Z\n", &dcb->PssInitMsg );
|
||
HalDisplayString( messageBuffer );
|
||
|
||
|
||
//
|
||
// Now initialize each of the miniport drivers.
|
||
//
|
||
|
||
nextEntry = dcb->MiniportQueue.Flink;
|
||
|
||
while (nextEntry != &dcb->MiniportQueue) {
|
||
|
||
mpNode = CONTAINING_RECORD( nextEntry,
|
||
MINIPORT_NODE,
|
||
ListEntry );
|
||
|
||
if (IopChecksum( mpNode->DriverEntry->DllBase, mpNode->DriverEntry->SizeOfImage ) != mpNode->DriverChecksum) {
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
status = ((PDRIVER_INITIALIZE) (mpNode->DriverEntry->EntryPoint))( NULL, NULL );
|
||
|
||
if (!NT_SUCCESS( status )) {
|
||
#if DBG
|
||
DbgPrint( "CRASHDUMP: Could not initialize miniport; error = %x\n", status );
|
||
#endif // DBG
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
nextEntry = nextEntry->Flink;
|
||
}
|
||
|
||
//
|
||
// Now attempt to open the partition from which the system was booted.
|
||
// This returns TRUE if the disk w/the appropriate signature was found,
|
||
// otherwise a NULL, in which case there is no way to continue.
|
||
//
|
||
|
||
if (!open( dcb->PartitionOffset )) {
|
||
#if DBG
|
||
DbgPrint( "CRASHDUMP: Could not find/open partition offset\n" );
|
||
#endif // DBG
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// The boot partition was found, so put together a dump file header
|
||
// and write it to the disk.
|
||
//
|
||
|
||
block = dcb->HeaderPage;
|
||
header = (PDUMP_HEADER) block;
|
||
|
||
RtlFillMemoryUlong( header, PAGE_SIZE, 'EGAP' );
|
||
header->ValidDump = 'PMUD';
|
||
header->BugCheckCode = BugCheckCode;
|
||
header->BugCheckParameter1 = BugCheckParameter1;
|
||
header->BugCheckParameter2 = BugCheckParameter2;
|
||
header->BugCheckParameter3 = BugCheckParameter3;
|
||
header->BugCheckParameter4 = BugCheckParameter4;
|
||
header->DirectoryTableBase = PsInitialSystemProcess->Pcb.DirectoryTableBase[0];
|
||
header->PfnDataBase = MmPfnDatabase;
|
||
header->PsLoadedModuleList = &PsLoadedModuleList;
|
||
header->PsActiveProcessHead = &PsActiveProcessHead;
|
||
header->NumberProcessors = dcb->NumberProcessors;
|
||
header->MajorVersion = dcb->MajorVersion;
|
||
header->MinorVersion = dcb->MinorVersion;
|
||
|
||
#ifdef i386
|
||
header->MachineImageType = IMAGE_FILE_MACHINE_I386;
|
||
#endif // i386
|
||
|
||
#ifdef MIPS
|
||
header->MachineImageType = IMAGE_FILE_MACHINE_R4000;
|
||
#endif // MIPS
|
||
|
||
#ifdef ALPHA
|
||
header->MachineImageType = IMAGE_FILE_MACHINE_ALPHA;
|
||
#endif // ALPHA
|
||
|
||
#ifdef _PPC_
|
||
header->MachineImageType = IMAGE_FILE_MACHINE_POWERPC;
|
||
#endif // PPC
|
||
|
||
if (!(dcb->Flags & DCB_DUMP_ENABLED)) {
|
||
dcb->MemoryDescriptor->NumberOfPages = 1;
|
||
}
|
||
|
||
strcpy( header->VersionUser, dcb->VersionUser );
|
||
|
||
RtlCopyMemory( &block[DH_PHYSICAL_MEMORY_BLOCK],
|
||
dcb->MemoryDescriptor,
|
||
sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) +
|
||
((dcb->MemoryDescriptor->NumberOfRuns - 1) *
|
||
sizeof( PHYSICAL_MEMORY_RUN )) );
|
||
|
||
RtlCopyMemory( &block[DH_CONTEXT_RECORD],
|
||
context,
|
||
sizeof( CONTEXT ) );
|
||
|
||
exception.ExceptionCode = STATUS_BREAKPOINT;
|
||
exception.ExceptionRecord = (PEXCEPTION_RECORD) NULL;
|
||
exception.NumberParameters = 0;
|
||
exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
|
||
|
||
#if defined(i386)
|
||
|
||
exception.ExceptionAddress = (PVOID) context->Eip;
|
||
|
||
#elif defined(MIPS)
|
||
|
||
exception.ExceptionAddress = (PVOID) context->Fir;
|
||
|
||
#elif defined(ALPHA)
|
||
|
||
exception.ExceptionAddress = (PVOID) context->Fir;
|
||
|
||
#elif defined(_PPC_)
|
||
|
||
exception.ExceptionAddress = (PVOID) context->Iar;
|
||
|
||
#else
|
||
|
||
#error( "unknown processor type" )
|
||
|
||
#endif
|
||
|
||
RtlCopyMemory( &block[DH_EXCEPTION_RECORD],
|
||
&exception,
|
||
sizeof( EXCEPTION_RECORD ) );
|
||
|
||
//
|
||
// All of the pieces of the header file have been generated. Before
|
||
// mapping or writing anything to the disk, the I- & D-stream caches
|
||
// must be flushed so that page color coherency is kept. Sweep both
|
||
// caches now.
|
||
//
|
||
|
||
KeSweepCurrentDcache();
|
||
KeSweepCurrentIcache();
|
||
|
||
//
|
||
// Create MDL for dump.
|
||
//
|
||
|
||
mdl = (PMDL) &localMdl[0];
|
||
MmCreateMdl( mdl, NULL, PAGE_SIZE );
|
||
mdl->MdlFlags |= MDL_PAGES_LOCKED;
|
||
|
||
mcb = dcb->FileDescriptorArray;
|
||
|
||
page = (PULONG) (mdl + 1);
|
||
*page = dcb->HeaderPfn;
|
||
mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
|
||
|
||
bytesRemaining = PAGE_SIZE;
|
||
memoryAddress = (ULONG) dcb->HeaderPage;
|
||
|
||
//
|
||
// All of the pieces of the header file have been generated. Write
|
||
// the header page to the paging file, using the appropriate drivers,
|
||
// etc.
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint( "IoWriteCrashDump: Writing dump header to disk\n" );
|
||
#endif
|
||
while (bytesRemaining) {
|
||
|
||
if (mcb[0].QuadPart <= bytesRemaining) {
|
||
byteCount = mcb[0].LowPart;
|
||
} else {
|
||
byteCount = bytesRemaining;
|
||
}
|
||
|
||
mdl->ByteCount = byteCount;
|
||
mdl->ByteOffset = memoryAddress & (PAGE_SIZE - 1);
|
||
mdl->MappedSystemVa = (PVOID) memoryAddress;
|
||
|
||
//
|
||
// Write to disk.
|
||
//
|
||
|
||
if (!NT_SUCCESS( write( &mcb[1], mdl ) )) {
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Adjust bytes remaining.
|
||
//
|
||
|
||
bytesRemaining -= byteCount;
|
||
memoryAddress += byteCount;
|
||
mcb[0].QuadPart = mcb[0].QuadPart - byteCount;
|
||
mcb[1].QuadPart = mcb[1].QuadPart + byteCount;
|
||
|
||
if (!mcb[0].QuadPart) {
|
||
mcb += 2;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
DbgPrint( "IoWriteCrashDump: Header page written\n" );
|
||
#endif
|
||
//
|
||
// The header page has been written to the paging file. If a full dump
|
||
// of all of physical memory is to be written, write it now.
|
||
//
|
||
|
||
if (dcb->Flags & DCB_DUMP_ENABLED) {
|
||
|
||
ULONG pagesDoneSoFar = 0;
|
||
ULONG currentPercentage = 0;
|
||
ULONG maximumPercentage = 0;
|
||
|
||
#if DBG
|
||
DbgPrint( "IoWriteCrashDump: Writing memory dump\n" );
|
||
#endif
|
||
//
|
||
// Set the virtual file offset and initialize loop variables and
|
||
// constants.
|
||
//
|
||
|
||
//mdl->MdlFlags &= ~MDL_MAPPED_TO_SYSTEM_VA;
|
||
memoryAddress = dcb->MemoryDescriptor->Run[0].BasePage * PAGE_SIZE;
|
||
|
||
//
|
||
// Now loop, writing all of physical memory to the paging file.
|
||
//
|
||
|
||
while (mcb[0].QuadPart) {
|
||
|
||
diskByteOffset = mcb[1];
|
||
|
||
//
|
||
// Calculate byte offset;
|
||
//
|
||
|
||
byteOffset = memoryAddress & (PAGE_SIZE - 1);
|
||
|
||
if (32768 <= mcb[0].QuadPart) {
|
||
byteCount = 32768 - byteOffset;
|
||
} else {
|
||
byteCount = mcb[0].LowPart;
|
||
}
|
||
|
||
pagesDoneSoFar += byteCount / PAGE_SIZE;
|
||
|
||
currentPercentage =
|
||
(pagesDoneSoFar * 100) /
|
||
dcb->MemoryDescriptor->NumberOfPages;
|
||
|
||
if (currentPercentage > maximumPercentage) {
|
||
|
||
maximumPercentage = currentPercentage;
|
||
//
|
||
// Update message on screen.
|
||
//
|
||
|
||
sprintf( messageBuffer, "%Z: %3d\r", &dcb->PssProgressMsg, maximumPercentage );
|
||
HalDisplayString( messageBuffer );
|
||
|
||
}
|
||
|
||
//
|
||
// Map the physical memory and write it to the
|
||
// current segment of the file.
|
||
//
|
||
|
||
MapPhysicalMemory( mdl,
|
||
memoryAddress,
|
||
&dcb->MemoryDescriptor->Run[0],
|
||
byteCount );
|
||
|
||
//
|
||
// Write the next segment.
|
||
//
|
||
|
||
if (!NT_SUCCESS( write( &diskByteOffset, mdl ) )) {
|
||
IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Adjust pointers for next part.
|
||
//
|
||
|
||
memoryAddress += byteCount;
|
||
mcb[0].QuadPart = mcb[0].QuadPart - byteCount;
|
||
mcb[1].QuadPart = mcb[1].QuadPart + byteCount;
|
||
|
||
if (!mcb[0].QuadPart) {
|
||
mcb += 2;
|
||
}
|
||
|
||
if (pagesDoneSoFar >= dcb->MemoryDescriptor->NumberOfPages) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
#if DBG
|
||
DbgPrint( "IoWriteCrashDump: Memory dump written\n" );
|
||
#endif
|
||
}
|
||
|
||
sprintf( messageBuffer, "%Z", &dcb->PssDoneMsg );
|
||
HalDisplayString( messageBuffer );
|
||
|
||
//
|
||
// Sweep the cache so the debugger will work.
|
||
//
|
||
|
||
KeSweepCurrentDcache();
|
||
KeSweepCurrentIcache();
|
||
|
||
//
|
||
// Have the dump flush the adapter and disk caches.
|
||
//
|
||
finishUp();
|
||
|
||
//
|
||
// Indicate to the debugger that the dump has been successfully
|
||
// written.
|
||
//
|
||
|
||
IopFinalCrashDumpStatus = STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Check to see whether or not auto-reboots are enabled and, if so,
|
||
// reboot now.
|
||
//
|
||
|
||
if (dcb->Flags & DCB_AUTO_REBOOT) {
|
||
|
||
#if DBG
|
||
DbgPrint( "IoWriteCrashDump: Autorebooting\n" );
|
||
#endif
|
||
KeReturnToFirmware( HalRebootRoutine );
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static
|
||
VOID
|
||
MapPhysicalMemory(
|
||
IN OUT PMDL Mdl,
|
||
IN ULONG MemoryAddress,
|
||
IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to fill in the specified MDL (Memory Descriptor
|
||
List) w/the appropriate information to map the specified memory address
|
||
range.
|
||
|
||
Arguments:
|
||
|
||
Mdl - Address of the MDL to be filled in.
|
||
|
||
MemoryAddress - Pseudo-virtual address being mapped.
|
||
|
||
PhysicalMemoryRun - Base address of the physical memory run list.
|
||
|
||
Length - Length of transfer to be mapped.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPHYSICAL_MEMORY_RUN pmr = PhysicalMemoryRun;
|
||
PULONG page;
|
||
ULONG pages;
|
||
ULONG base;
|
||
ULONG currentBase;
|
||
|
||
//
|
||
// Begin by determining the base physical page of the start of the address
|
||
// range and filling in the MDL appropriately.
|
||
//
|
||
|
||
Mdl->StartVa = (PVOID) (MemoryAddress);
|
||
Mdl->ByteOffset = MemoryAddress & (PAGE_SIZE - 1);
|
||
Mdl->ByteCount = Length;
|
||
|
||
//
|
||
// Get the page frame index for the base address.
|
||
//
|
||
|
||
base = (ULONG) Mdl->StartVa >> PAGE_SHIFT;
|
||
pages = COMPUTE_PAGES_SPANNED( (ULONG) MemoryAddress, Length );
|
||
currentBase = pmr->BasePage;
|
||
page = (PULONG) (Mdl + 1);
|
||
|
||
//
|
||
// Map all of the pages for this transfer until there are no more remaining
|
||
// to be mapped.
|
||
//
|
||
|
||
while (pages) {
|
||
|
||
//
|
||
// Find the memory run that maps the beginning of this transfer.
|
||
//
|
||
|
||
while (currentBase + pmr->PageCount <= base) {
|
||
currentBase += pmr->PageCount;
|
||
pmr++;
|
||
}
|
||
|
||
//
|
||
// The current memory run maps the start of this transfer. Capture
|
||
// the base page for the start of the transfer.
|
||
//
|
||
|
||
*page++ = pmr->BasePage + (base++ - currentBase);
|
||
pages--;
|
||
}
|
||
|
||
//
|
||
// All of the PFNs for the address range have been filled in so map the
|
||
// physical memory into virtual address space.
|
||
//
|
||
|
||
MmMapMemoryDumpMdl( Mdl );
|
||
}
|