881 lines
21 KiB
C
881 lines
21 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
crashdmp.c
|
||
|
||
Abstract:
|
||
|
||
This module contains routines which provide support for writing out
|
||
a crashdump on system failure.
|
||
|
||
Author:
|
||
|
||
Landy Wang (landyw) 04-Oct-2000
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "mi.h"
|
||
|
||
LOGICAL
|
||
MiIsAddressRangeValid (
|
||
IN PVOID VirtualAddress,
|
||
IN SIZE_T Length
|
||
)
|
||
{
|
||
PUCHAR Va;
|
||
PUCHAR EndVa;
|
||
ULONG Pages;
|
||
|
||
Va = PAGE_ALIGN (VirtualAddress);
|
||
Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES (VirtualAddress, Length);
|
||
EndVa = Va + (Pages << PAGE_SHIFT);
|
||
|
||
while (Va < EndVa) {
|
||
|
||
if (!MmIsAddressValid (Va)) {
|
||
return FALSE;
|
||
}
|
||
|
||
Va += PAGE_SIZE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
MiRemoveFreePoolMemoryFromDump (
|
||
IN PMM_KERNEL_DUMP_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes all memory from the nonpaged pool free page lists to reduce the size
|
||
of a kernel memory dump.
|
||
|
||
Because the entries in these structures are destroyed by errant drivers
|
||
that modify pool after freeing it, the entries are carefully
|
||
validated prior to any dereferences.
|
||
|
||
Arguments:
|
||
|
||
Context - Supplies the dump context pointer that must be passed to
|
||
IoFreeDumpRange.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Environment:
|
||
|
||
Kernel-mode, post-bugcheck.
|
||
|
||
For use by crashdump routines ONLY.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY Entry;
|
||
PLIST_ENTRY List;
|
||
PLIST_ENTRY ListEnd;
|
||
PMMFREE_POOL_ENTRY PoolEntry;
|
||
ULONG LargePageMapped;
|
||
|
||
List = &MmNonPagedPoolFreeListHead[0];
|
||
ListEnd = List + MI_MAX_FREE_LIST_HEADS;
|
||
|
||
for ( ; List < ListEnd; List += 1) {
|
||
|
||
for (Entry = List->Flink; Entry != List; Entry = Entry->Flink) {
|
||
|
||
PoolEntry = CONTAINING_RECORD (Entry,
|
||
MMFREE_POOL_ENTRY,
|
||
List);
|
||
|
||
//
|
||
// Check for corrupted values.
|
||
//
|
||
|
||
if (BYTE_OFFSET(PoolEntry) != 0) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Check that the entry has not been corrupted.
|
||
//
|
||
|
||
if (MiIsAddressRangeValid (PoolEntry, sizeof (MMFREE_POOL_ENTRY)) == FALSE) {
|
||
break;
|
||
}
|
||
|
||
if (PoolEntry->Size == 0) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Signature is only maintained in checked builds.
|
||
//
|
||
|
||
ASSERT (PoolEntry->Signature == MM_FREE_POOL_SIGNATURE);
|
||
|
||
//
|
||
// Verify that the element's flinks and blinks are valid.
|
||
//
|
||
|
||
if ((!MiIsAddressRangeValid (Entry->Flink, sizeof (LIST_ENTRY))) ||
|
||
(!MiIsAddressRangeValid (Entry->Blink, sizeof (LIST_ENTRY))) ||
|
||
(Entry->Blink->Flink != Entry) ||
|
||
(Entry->Flink->Blink != Entry)) {
|
||
|
||
break;
|
||
}
|
||
|
||
//
|
||
// The list entry is valid, remove it from the dump.
|
||
//
|
||
|
||
if (MI_IS_PHYSICAL_ADDRESS (PoolEntry)) {
|
||
LargePageMapped = 1;
|
||
}
|
||
else {
|
||
LargePageMapped = 0;
|
||
}
|
||
|
||
Context->FreeDumpRange (Context,
|
||
PoolEntry,
|
||
PoolEntry->Size,
|
||
LargePageMapped);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
LOGICAL
|
||
MiIsPhysicalMemoryAddress (
|
||
IN PFN_NUMBER PageFrameIndex,
|
||
IN OUT PULONG Hint,
|
||
IN LOGICAL PfnLockNeeded
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if a given address is backed by RAM or IO space.
|
||
|
||
Arguments:
|
||
|
||
PageFrameIndex - Supplies a page frame number to check.
|
||
|
||
Hint - Supplies a hint at which memory run we should start
|
||
searching for this pfn. The hint is updated on success
|
||
and failure.
|
||
|
||
PfnLockNeeded - Supplies TRUE if the caller needs this routine to
|
||
acquire the PFN lock. FALSE if not (ie: the caller
|
||
already holds the PFN lock or we are crashing the system
|
||
and so the PFN lock may already be held by someone else).
|
||
|
||
Return Value:
|
||
|
||
TRUE - If the address is backed by RAM.
|
||
|
||
FALSE - If the address is IO mapped memory.
|
||
|
||
Environment:
|
||
|
||
Kernel-mode, post-bugcheck.
|
||
|
||
For use by crash dump and other Mm internal routines.
|
||
|
||
--*/
|
||
{
|
||
ULONG Index;
|
||
KIRQL OldIrql;
|
||
PPHYSICAL_MEMORY_RUN Run;
|
||
PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock;
|
||
|
||
//
|
||
// Initializing OldIrql is not needed for correctness, but without it
|
||
// the compiler cannot compile this code W4 to check for use of
|
||
// uninitialized variables.
|
||
//
|
||
|
||
OldIrql = PASSIVE_LEVEL;
|
||
|
||
if (PfnLockNeeded) {
|
||
LOCK_PFN2 (OldIrql);
|
||
}
|
||
|
||
PhysicalMemoryBlock = MmPhysicalMemoryBlock;
|
||
|
||
if (PageFrameIndex > MmHighestPhysicalPage) {
|
||
if (PfnLockNeeded) {
|
||
UNLOCK_PFN2 (OldIrql);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
if (*Hint < PhysicalMemoryBlock->NumberOfRuns) {
|
||
|
||
Run = &PhysicalMemoryBlock->Run[*Hint];
|
||
|
||
if ((PageFrameIndex >= Run->BasePage) &&
|
||
(PageFrameIndex < Run->BasePage + Run->PageCount)) {
|
||
|
||
if (PfnLockNeeded) {
|
||
UNLOCK_PFN2 (OldIrql);
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
for (Index = 0; Index < PhysicalMemoryBlock->NumberOfRuns; Index += 1) {
|
||
|
||
Run = &PhysicalMemoryBlock->Run[Index];
|
||
|
||
if ((PageFrameIndex >= Run->BasePage) &&
|
||
(PageFrameIndex < Run->BasePage + Run->PageCount)) {
|
||
|
||
*Hint = Index;
|
||
if (PfnLockNeeded) {
|
||
UNLOCK_PFN2 (OldIrql);
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Since the physical memory block is ordered by increasing
|
||
// base page PFN number, if this PFN is smaller, then bail.
|
||
//
|
||
|
||
if (Run->BasePage + Run->PageCount > PageFrameIndex) {
|
||
*Hint = Index;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (PfnLockNeeded) {
|
||
UNLOCK_PFN2 (OldIrql);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
VOID
|
||
MiAddPagesWithNoMappings (
|
||
IN PMM_KERNEL_DUMP_CONTEXT Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add pages to a kernel memory crashdump that do not have a
|
||
virtual mapping in this process context.
|
||
|
||
This includes entries that are wired directly into the TB.
|
||
|
||
Arguments:
|
||
|
||
Context - Crashdump context pointer.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Environment:
|
||
|
||
Kernel-mode, post-bugcheck.
|
||
|
||
For use by crash dump routines ONLY.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if defined (_X86_)
|
||
|
||
ULONG LargePageMapped;
|
||
PVOID Va;
|
||
PHYSICAL_ADDRESS DirBase;
|
||
|
||
//
|
||
// Add the current page directory table page - don't use the directory
|
||
// table base for the crashing process as we have switched cr3 on
|
||
// stack overflow crashes, etc.
|
||
//
|
||
|
||
_asm {
|
||
mov eax, cr3
|
||
mov DirBase.LowPart, eax
|
||
}
|
||
|
||
//
|
||
// cr3 is always located below 4gb physical.
|
||
//
|
||
|
||
DirBase.HighPart = 0;
|
||
|
||
Va = MmGetVirtualForPhysical (DirBase);
|
||
|
||
if (MI_IS_PHYSICAL_ADDRESS (Va)) {
|
||
LargePageMapped = 1;
|
||
}
|
||
else {
|
||
LargePageMapped = 0;
|
||
}
|
||
|
||
Context->SetDumpRange (Context,
|
||
Va,
|
||
1,
|
||
LargePageMapped);
|
||
|
||
#elif defined(_AMD64_)
|
||
|
||
ULONG LargePageMapped;
|
||
PVOID Va;
|
||
PHYSICAL_ADDRESS DirBase;
|
||
|
||
//
|
||
// Add the current page directory table page - don't use the directory
|
||
// table base for the crashing process as we have switched cr3 on
|
||
// stack overflow crashes, etc.
|
||
//
|
||
|
||
DirBase.QuadPart = ReadCR3 ();
|
||
|
||
Va = MmGetVirtualForPhysical (DirBase);
|
||
|
||
if (MI_IS_PHYSICAL_ADDRESS (Va)) {
|
||
LargePageMapped = 1;
|
||
}
|
||
else {
|
||
LargePageMapped = 0;
|
||
}
|
||
|
||
Context->SetDumpRange (Context,
|
||
Va,
|
||
1,
|
||
LargePageMapped);
|
||
|
||
#elif defined(_IA64_)
|
||
|
||
if (MiKseg0Mapping == TRUE) {
|
||
Context->SetDumpRange (
|
||
Context,
|
||
MiKseg0Start,
|
||
(((ULONG_PTR)MiKseg0End - (ULONG_PTR)MiKseg0Start) >> PAGE_SHIFT) + 1,
|
||
1);
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
|
||
LOGICAL
|
||
MiAddRangeToCrashDump (
|
||
IN PMM_KERNEL_DUMP_CONTEXT Context,
|
||
IN PVOID Va,
|
||
IN SIZE_T NumberOfBytes
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Adds the specified range of memory to the crashdump.
|
||
|
||
Arguments:
|
||
|
||
Context - Supplies the crashdump context pointer.
|
||
|
||
Va - Supplies the starting virtual address.
|
||
|
||
NumberOfBytes - Supplies the number of bytes to dump. Note that for IA64,
|
||
this must not cause the range to cross a region boundary.
|
||
|
||
Return Value:
|
||
|
||
TRUE if all valid pages were added to the crashdump, FALSE otherwise.
|
||
|
||
Environment:
|
||
|
||
Kernel mode, post-bugcheck.
|
||
|
||
For use by crash dump routines ONLY.
|
||
|
||
--*/
|
||
|
||
{
|
||
LOGICAL Status;
|
||
LOGICAL AddThisPage;
|
||
ULONG Hint;
|
||
PVOID EndingAddress;
|
||
PMMPTE PointerPte;
|
||
PMMPTE PointerPde;
|
||
PMMPTE PointerPpe;
|
||
PMMPTE PointerPxe;
|
||
PFN_NUMBER PageFrameIndex;
|
||
#if defined (_X86_) || defined (_AMD64_)
|
||
PFN_NUMBER NumberOfPages;
|
||
#endif
|
||
|
||
Hint = 0;
|
||
Status = TRUE;
|
||
|
||
EndingAddress = (PVOID)((ULONG_PTR)Va + NumberOfBytes - 1);
|
||
|
||
#if defined(_IA64_)
|
||
|
||
//
|
||
// IA64 has a separate page directory parent for each region and
|
||
// unimplemented address bits are ignored by the processor (as
|
||
// long as they are canonical), but we must watch for them
|
||
// here so the incrementing PPE walk doesn't go off the end.
|
||
// This is done by truncating any given region request so it does
|
||
// not go past the end of the specified region. Note this
|
||
// automatically will include the page maps which are sign extended
|
||
// because the PPEs would just wrap anyway.
|
||
//
|
||
|
||
if (((ULONG_PTR)EndingAddress & ~VRN_MASK) >= MM_VA_MAPPED_BY_PPE * PDE_PER_PAGE) {
|
||
EndingAddress = (PVOID)(((ULONG_PTR)EndingAddress & VRN_MASK) |
|
||
((MM_VA_MAPPED_BY_PPE * PDE_PER_PAGE) - 1));
|
||
}
|
||
|
||
#endif
|
||
|
||
Va = PAGE_ALIGN (Va);
|
||
|
||
PointerPxe = MiGetPxeAddress (Va);
|
||
PointerPpe = MiGetPpeAddress (Va);
|
||
PointerPde = MiGetPdeAddress (Va);
|
||
PointerPte = MiGetPteAddress (Va);
|
||
|
||
do {
|
||
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
restart:
|
||
#endif
|
||
|
||
KdCheckForDebugBreak ();
|
||
|
||
#if (_MI_PAGING_LEVELS >= 4)
|
||
while (PointerPxe->u.Hard.Valid == 0) {
|
||
|
||
//
|
||
// This extended page directory parent entry is empty,
|
||
// go to the next one.
|
||
//
|
||
|
||
PointerPxe += 1;
|
||
PointerPpe = MiGetVirtualAddressMappedByPte (PointerPxe);
|
||
PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
|
||
PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
|
||
Va = MiGetVirtualAddressMappedByPte (PointerPte);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
|
||
//
|
||
// All done, return.
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
ASSERT (MiGetPpeAddress(Va) == PointerPpe);
|
||
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
while (PointerPpe->u.Hard.Valid == 0) {
|
||
|
||
//
|
||
// This page directory parent entry is empty, go to the next one.
|
||
//
|
||
|
||
PointerPpe += 1;
|
||
PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe);
|
||
PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
|
||
Va = MiGetVirtualAddressMappedByPte (PointerPte);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
|
||
//
|
||
// All done, return.
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
#if (_MI_PAGING_LEVELS >= 4)
|
||
if (MiIsPteOnPdeBoundary (PointerPpe)) {
|
||
PointerPxe += 1;
|
||
ASSERT (PointerPxe == MiGetPteAddress (PointerPpe));
|
||
goto restart;
|
||
}
|
||
#endif
|
||
|
||
}
|
||
#endif
|
||
|
||
while (PointerPde->u.Hard.Valid == 0) {
|
||
|
||
//
|
||
// This page directory entry is empty, go to the next one.
|
||
//
|
||
|
||
PointerPde += 1;
|
||
PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
|
||
Va = MiGetVirtualAddressMappedByPte (PointerPte);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
|
||
//
|
||
// All done, return.
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
#if (_MI_PAGING_LEVELS >= 3)
|
||
if (MiIsPteOnPdeBoundary (PointerPde)) {
|
||
PointerPpe += 1;
|
||
ASSERT (PointerPpe == MiGetPteAddress (PointerPde));
|
||
PointerPxe = MiGetPteAddress (PointerPpe);
|
||
goto restart;
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// A valid PDE has been located, examine each PTE.
|
||
//
|
||
|
||
ASSERT64 (PointerPpe->u.Hard.Valid == 1);
|
||
ASSERT (PointerPde->u.Hard.Valid == 1);
|
||
ASSERT (Va <= EndingAddress);
|
||
|
||
#if defined (_X86_) || defined (_AMD64_)
|
||
|
||
if (PointerPde->u.Hard.LargePage == 1) {
|
||
|
||
//
|
||
// Large pages are always backed by RAM, not mapped to
|
||
// I/O space, so always add them to the dump.
|
||
//
|
||
|
||
NumberOfPages = (((ULONG_PTR)MiGetVirtualAddressMappedByPde (PointerPde + 1) - (ULONG_PTR)Va) / PAGE_SIZE);
|
||
|
||
Status = Context->SetDumpRange (Context,
|
||
Va,
|
||
NumberOfPages,
|
||
1);
|
||
|
||
if (!NT_SUCCESS (Status)) {
|
||
#if DBG
|
||
DbgPrint ("Adding large VA %p to crashdump failed\n", Va);
|
||
DbgBreakPoint ();
|
||
#endif
|
||
Status = FALSE;
|
||
}
|
||
|
||
PointerPde += 1;
|
||
Va = MiGetVirtualAddressMappedByPde (PointerPde);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
return Status;
|
||
}
|
||
|
||
PointerPte = MiGetPteAddress (Va);
|
||
PointerPpe = MiGetPpeAddress (Va);
|
||
PointerPxe = MiGetPxeAddress (Va);
|
||
|
||
//
|
||
// March on to the next page directory.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Exclude memory that is mapped in the system cache.
|
||
// Note the system cache starts and ends on page directory boundaries
|
||
// and is never mapped with large pages.
|
||
//
|
||
|
||
if (MI_IS_SYSTEM_CACHE_ADDRESS (Va)) {
|
||
PointerPde += 1;
|
||
Va = MiGetVirtualAddressMappedByPde (PointerPde);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
return Status;
|
||
}
|
||
|
||
PointerPte = MiGetPteAddress (Va);
|
||
PointerPpe = MiGetPpeAddress (Va);
|
||
PointerPxe = MiGetPxeAddress (Va);
|
||
|
||
//
|
||
// March on to the next page directory.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
do {
|
||
|
||
AddThisPage = FALSE;
|
||
PageFrameIndex = 0;
|
||
|
||
if (PointerPte->u.Hard.Valid == 1) {
|
||
|
||
PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
|
||
AddThisPage = TRUE;
|
||
}
|
||
else if ((PointerPte->u.Soft.Prototype == 0) &&
|
||
(PointerPte->u.Soft.Transition == 1)) {
|
||
|
||
PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerPte);
|
||
AddThisPage = TRUE;
|
||
}
|
||
|
||
if (AddThisPage == TRUE) {
|
||
|
||
//
|
||
// Include only addresses that are backed by RAM, not mapped to
|
||
// I/O space.
|
||
//
|
||
|
||
if (MiIsPhysicalMemoryAddress (PageFrameIndex, &Hint, FALSE)) {
|
||
|
||
//
|
||
// Add this page to the dump.
|
||
//
|
||
|
||
Status = Context->SetDumpRange (Context,
|
||
(PVOID) PageFrameIndex,
|
||
1,
|
||
2);
|
||
|
||
if (!NT_SUCCESS (Status)) {
|
||
#if DBG
|
||
DbgPrint ("Adding VA %p to crashdump failed\n", Va);
|
||
DbgBreakPoint ();
|
||
#endif
|
||
Status = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
Va = (PVOID)((ULONG_PTR)Va + PAGE_SIZE);
|
||
PointerPte += 1;
|
||
|
||
ASSERT64 (PointerPpe->u.Hard.Valid == 1);
|
||
ASSERT (PointerPde->u.Hard.Valid == 1);
|
||
|
||
if ((Va > EndingAddress) || (Va == NULL)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// If not at the end of a page table and still within the specified
|
||
// range, just march directly on to the next PTE.
|
||
//
|
||
// Otherwise, if the virtual address is on a page directory boundary
|
||
// then attempt to leap forward skipping over empty mappings
|
||
// where possible.
|
||
//
|
||
|
||
} while (!MiIsVirtualAddressOnPdeBoundary(Va));
|
||
|
||
ASSERT (PointerPte == MiGetPteAddress (Va));
|
||
PointerPde = MiGetPdeAddress (Va);
|
||
PointerPpe = MiGetPpeAddress (Va);
|
||
PointerPxe = MiGetPxeAddress (Va);
|
||
|
||
} while (TRUE);
|
||
|
||
// NEVER REACHED
|
||
}
|
||
|
||
|
||
VOID
|
||
MiAddActivePageDirectories (
|
||
IN PMM_KERNEL_DUMP_CONTEXT Context
|
||
)
|
||
{
|
||
UCHAR i;
|
||
PKPRCB Prcb;
|
||
PKPROCESS Process;
|
||
PFN_NUMBER PageFrameIndex;
|
||
|
||
#if defined (_X86PAE_)
|
||
PMMPTE PointerPte;
|
||
ULONG j;
|
||
#endif
|
||
|
||
for (i = 0; i < KeNumberProcessors; i += 1) {
|
||
|
||
Prcb = KiProcessorBlock[i];
|
||
|
||
Process = Prcb->CurrentThread->ApcState.Process;
|
||
|
||
#if defined (_X86PAE_)
|
||
|
||
//
|
||
// Note that on PAE systems, the idle and system process have
|
||
// NULL initialized PaeTop fields. Thus this field must be
|
||
// explicitly checked for before being referenced here.
|
||
//
|
||
|
||
//
|
||
// Add the 4 top level page directory pages to the dump.
|
||
//
|
||
|
||
PointerPte = (PMMPTE) ((PEPROCESS)Process)->PaeTop;
|
||
|
||
if (PointerPte == NULL) {
|
||
PointerPte = &MiSystemPaeVa.PteEntry[0];
|
||
}
|
||
|
||
for (j = 0; j < PD_PER_SYSTEM; j += 1) {
|
||
PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE(PointerPte);
|
||
PointerPte += 1;
|
||
Context->SetDumpRange (Context, (PVOID) PageFrameIndex, 1, 2);
|
||
}
|
||
|
||
//
|
||
// Add the real cr3 page to the dump, note that the value stored in the
|
||
// directory table base is really a physical address (not a frame).
|
||
//
|
||
|
||
PageFrameIndex = Process->DirectoryTableBase[0];
|
||
PageFrameIndex = (PageFrameIndex >> PAGE_SHIFT);
|
||
|
||
#else
|
||
|
||
PageFrameIndex =
|
||
MI_GET_DIRECTORY_FRAME_FROM_PROCESS ((PEPROCESS)(Process));
|
||
|
||
#endif
|
||
|
||
//
|
||
// Add this physical page to the dump.
|
||
//
|
||
|
||
Context->SetDumpRange (Context, (PVOID) PageFrameIndex, 1, 2);
|
||
}
|
||
|
||
#if defined(_IA64_)
|
||
|
||
//
|
||
// The first processor's PCR is mapped in region 4 which is not (and cannot)
|
||
// be scanned later, so explicitly add it to the dump here.
|
||
//
|
||
|
||
Prcb = KiProcessorBlock[0];
|
||
|
||
Context->SetDumpRange (Context, (PVOID) Prcb->PcrPage, 1, 2);
|
||
#endif
|
||
}
|
||
|
||
|
||
VOID
|
||
MmGetKernelDumpRange (
|
||
IN PMM_KERNEL_DUMP_CONTEXT Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Add (and subtract) ranges of system memory to the crashdump.
|
||
|
||
Arguments:
|
||
|
||
Context - Crashdump context pointer.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Environment:
|
||
|
||
Kernel mode, post-bugcheck.
|
||
|
||
For use by crash dump routines ONLY.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Va;
|
||
SIZE_T NumberOfBytes;
|
||
|
||
ASSERT ((Context != NULL) &&
|
||
(Context->SetDumpRange != NULL) &&
|
||
(Context->FreeDumpRange != NULL));
|
||
|
||
MiAddActivePageDirectories (Context);
|
||
|
||
#if defined(_IA64_)
|
||
|
||
//
|
||
// Note each IA64 region must be passed separately to MiAddRange...
|
||
//
|
||
|
||
Va = (PVOID) ALT4KB_PERMISSION_TABLE_START;
|
||
NumberOfBytes = PDE_UTBASE + PAGE_SIZE - (ULONG_PTR) Va;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
Va = (PVOID) MM_SESSION_SPACE_DEFAULT;
|
||
NumberOfBytes = PDE_STBASE + PAGE_SIZE - (ULONG_PTR) Va;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
Va = (PVOID) KADDRESS_BASE;
|
||
NumberOfBytes = PDE_KTBASE + PAGE_SIZE - (ULONG_PTR) Va;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
#elif defined(_AMD64_)
|
||
|
||
Va = (PVOID) MM_SYSTEM_RANGE_START;
|
||
NumberOfBytes = MM_KSEG0_BASE - (ULONG_PTR) Va;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
Va = (PVOID) MM_KSEG2_BASE;
|
||
NumberOfBytes = MM_SYSTEM_SPACE_START - (ULONG_PTR) Va;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
Va = (PVOID) MM_PAGED_POOL_START;
|
||
NumberOfBytes = MM_SYSTEM_SPACE_END - (ULONG_PTR) Va + 1;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
#else
|
||
|
||
Va = MmSystemRangeStart;
|
||
NumberOfBytes = MM_SYSTEM_SPACE_END - (ULONG_PTR) Va + 1;
|
||
MiAddRangeToCrashDump (Context, Va, NumberOfBytes);
|
||
|
||
#endif
|
||
|
||
//
|
||
// Add any memory that is a part of the kernel space, but does not
|
||
// have a virtual mapping (hence was not collected above).
|
||
//
|
||
|
||
MiAddPagesWithNoMappings (Context);
|
||
|
||
//
|
||
// Remove nonpaged pool that is not in use.
|
||
//
|
||
|
||
MiRemoveFreePoolMemoryFromDump (Context);
|
||
}
|