mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
880 lines
21 KiB
880 lines
21 KiB
/*++
|
|
|
|
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);
|
|
}
|