NT4/private/ntos/mm/dmpaddr.c
2020-09-30 17:12:29 +02:00

880 lines
23 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
dmpaddr.c
Abstract:
Temporary routine to print valid addresses within an
address space.
Author:
Lou Perazzoli (loup) 20-Mar-1989
Environment:
Kernel Mode.
Revision History:
--*/
#include "mi.h"
#if DBG
BOOLEAN
MiFlushUnusedSectionInternal (
IN PCONTROL_AREA ControlArea
);
#endif //DBG
#if DBG
VOID
MiDumpValidAddresses (
)
{
ULONG va = 0;
ULONG i,j;
PMMPTE PointerPde;
PMMPTE PointerPte;
PointerPde = MiGetPdeAddress (va);
for (i = 0; i < PDE_PER_PAGE; i++) {
if (PointerPde->u.Hard.Valid) {
DbgPrint(" **valid PDE, element %ld %lx %lx\n",i,i,
PointerPde->u.Long);
PointerPte = MiGetPteAddress (va);
for (j = 0 ; j < PTE_PER_PAGE; j++) {
if (PointerPte->u.Hard.Valid) {
DbgPrint("Valid address at %lx pte %lx\n", (ULONG)va,
PointerPte->u.Long);
}
va += PAGE_SIZE;
PointerPte++;
}
} else {
va += (ULONG)PDE_PER_PAGE * (ULONG)PAGE_SIZE;
}
PointerPde++;
}
return;
}
#endif //DBG
#if DBG
VOID
MiFormatPte (
IN PMMPTE PointerPte
)
{
// int j;
// unsigned long pte;
PMMPTE proto_pte;
PSUBSECTION subsect;
// struct a_bit {
// unsigned long biggies : 31;
// unsigned long bitties : 1;
// };
//
// struct a_bit print_pte;
proto_pte = MiPteToProto(PointerPte);
subsect = MiGetSubsectionAddress(PointerPte);
DbgPrint("***DumpPTE at %lx contains %lx protoaddr %lx subsect %lx\n\n",
(ULONG)PointerPte, PointerPte->u.Long, (ULONG)proto_pte,
(ULONG)subsect);
return;
// DbgPrint("page frame number 0x%lx proto PTE address 0x%lx\n",
//
// DbgPrint("PTE is 0x%lx\n", PTETOULONG(the_pte));
//
// proto_pte = MiPteToProto(PointerPte);
//
// DbgPrint("page frame number 0x%lx proto PTE address 0x%lx\n",
// PointerPte->u.Hard.PageFrameNumber,*(PULONG)&proto_pte);
//
// DbgPrint(" 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 \n");
// DbgPrint(" +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \n");
// DbgPrint(" | pfn |c|p|t|r|r|d|a|c|p|o|w|v| \n");
// DbgPrint(" | |o|r|r|s|s|t|c|a|b|w|r|l| \n");
// DbgPrint(" | |w|o|n|v|v|y|c|c|o|n|t|d| \n");
// DbgPrint(" +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \n ");
// pte = PTETOULONG(the_pte);
//
// for (j = 0; j < 32; j++) {
// *(PULONG)& print_pte = pte;
// DbgPrint(" %lx",print_pte.bitties);
// pte = pte << 1;
// }
// DbgPrint("\n");
//
}
#endif //DBG
#if DBG
VOID
MiDumpWsl ( )
{
ULONG i;
PMMWSLE wsle;
DbgPrint("***WSLE cursize %lx frstfree %lx Min %lx Max %lx\n",
PsGetCurrentProcess()->Vm.WorkingSetSize,
MmWorkingSetList->FirstFree,
PsGetCurrentProcess()->Vm.MinimumWorkingSetSize,
PsGetCurrentProcess()->Vm.MaximumWorkingSetSize);
DbgPrint(" quota %lx firstdyn %lx last ent %lx next slot %lx\n",
MmWorkingSetList->Quota,
MmWorkingSetList->FirstDynamic,
MmWorkingSetList->LastEntry,
MmWorkingSetList->NextSlot);
wsle = MmWsle;
for (i = 0; i < MmWorkingSetList->LastEntry; i++) {
DbgPrint(" index %lx %lx\n",i,wsle->u1.Long);
wsle++;
}
return;
}
#endif //DBG
#if 0 //COMMENTED OUT!!!
VOID
MiFlushUnusedSections (
VOID
)
/*++
Routine Description:
This routine rumages through the PFN database and attempts
to close any unused sections.
Arguments:
None.
Return Value:
None.
--*/
{
PMMPFN LastPfn;
PMMPFN Pfn1;
PSUBSECTION Subsection;
KIRQL OldIrql;
LOCK_PFN (OldIrql);
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage + 1);
LastPfn = MI_PFN_ELEMENT(MmHighestPhysicalPage);
while (Pfn1 < LastPfn) {
if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
(Pfn1->u3.e1.PageLocation == StandbyPageList)) {
//
// Make sure the PTE is not waiting for I/O to complete.
//
if (MI_IS_PFN_DELETED (Pfn1)) {
Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
MiFlushUnusedSectionInternal (Subsection->ControlArea);
}
}
}
Pfn1++;
}
UNLOCK_PFN (OldIrql);
return;
}
BOOLEAN
MiFlushUnusedSectionInternal (
IN PCONTROL_AREA ControlArea
)
{
BOOLEAN result;
KIRQL OldIrql = APC_LEVEL;
if ((ControlArea->NumberOfMappedViews != 0) ||
(ControlArea->NumberOfSectionReferences != 0)) {
//
// The segment is currently in use.
//
return FALSE;
}
//
// The segment has no references, delete it. If the segment
// is already being deleted, set the event field in the control
// area and wait on the event.
//
if ((ControlArea->u.Flags.BeingDeleted) ||
(ControlArea->u.Flags.BeingCreated)) {
return TRUE;
}
//
// Set the being deleted flag and up the number of mapped views
// for the segment. Upping the number of mapped views prevents
// the segment from being deleted and passed to the deletion thread
// while we are forcing a delete.
//
ControlArea->u.Flags.BeingDeleted = 1;
ControlArea->NumberOfMappedViews = 1;
//
// This is a page file backed or image Segment. The Segment is being
// deleted, remove all references to the paging file and physical memory.
//
UNLOCK_PFN (OldIrql);
MiCleanSection (ControlArea);
LOCK_PFN (OldIrql);
return TRUE;
}
#endif //0
#if DBG
#define ALLOC_SIZE ((ULONG)8*1024)
#define MM_SAVED_CONTROL 64
#define MM_KERN_MAP_SIZE 64
#define MM_NONPAGED_POOL_MARK ((PUCHAR)0xfffff123)
#define MM_PAGED_POOL_MARK ((PUCHAR)0xfffff124)
#define MM_KERNEL_STACK_MARK ((PUCHAR)0xfffff125)
extern ULONG MmSystemPtesStart[MaximumPtePoolTypes];
extern ULONG MmSystemPtesEnd[MaximumPtePoolTypes];
typedef struct _KERN_MAP {
ULONG StartVa;
ULONG EndVa;
PLDR_DATA_TABLE_ENTRY Entry;
} KERN_MAP, *PKERN_MAP;
ULONG
MiBuildKernelMap (
IN ULONG NumberOfElements,
IN OUT PKERN_MAP KernelMap
);
NTSTATUS
MmMemoryUsage (
IN PVOID Buffer,
IN ULONG Size,
IN ULONG Type,
OUT PULONG OutLength
)
/*++
Routine Description:
This routine (debugging only) dumps the current memory usage by
walking the PFN database.
Arguments:
Buffer - Supplies a buffer in which to copy the data.
Size - Supplies the size of the buffer.
Type - Supplies a value of 0 to dump everything,
a value of 1 to dump only valid pages.
OutLength - Returns how much data was written into the buffer.
Return Value:
None.
--*/
{
PMMPFN LastPfn;
PMMPFN Pfn1;
PMMPFN Pfn2;
PSUBSECTION Subsection;
KIRQL OldIrql;
PSYSTEM_MEMORY_INFORMATION MemInfo;
PSYSTEM_MEMORY_INFO Info;
PSYSTEM_MEMORY_INFO InfoStart;
PSYSTEM_MEMORY_INFO InfoEnd;
PUCHAR String;
PUCHAR Master;
PCONTROL_AREA ControlArea;
BOOLEAN Found;
BOOLEAN FoundMap;
PMDL Mdl;
NTSTATUS status = STATUS_SUCCESS;
ULONG Length;
PEPROCESS Process;
PUCHAR End;
PCONTROL_AREA SavedControl[MM_SAVED_CONTROL];
PSYSTEM_MEMORY_INFO SavedInfo[MM_SAVED_CONTROL];
ULONG j;
ULONG ControlCount = 0;
PUCHAR PagedSection = NULL;
ULONG Failed;
UCHAR PageFileMapped[] = "PageFile Mapped";
UCHAR MetaFile[] = "Fs Meta File";
UCHAR NoName[] = "No File Name";
UCHAR NonPagedPool[] = "NonPagedPool";
UCHAR PagedPool[] = "PagedPool";
UCHAR KernelStack[] = "Kernel Stack";
PUCHAR NameString;
KERN_MAP KernMap[MM_KERN_MAP_SIZE];
ULONG KernSize;
ULONG VirtualAddress;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
Mdl = MmCreateMdl (NULL, Buffer, Size);
try {
MmProbeAndLockPages (Mdl, KeGetPreviousMode(), IoWriteAccess);
} except (EXCEPTION_EXECUTE_HANDLER) {
ExFreePool (Mdl);
return GetExceptionCode();
}
MemInfo = MmGetSystemAddressForMdl (Mdl);
InfoStart = &MemInfo->Memory[0];
InfoEnd = InfoStart;
End = (PUCHAR)MemInfo + Size;
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage + 1);
LastPfn = MI_PFN_ELEMENT(MmHighestPhysicalPage);
KernSize = MiBuildKernelMap (MM_KERN_MAP_SIZE, &KernMap[0]);
LOCK_PFN (OldIrql);
while (Pfn1 < LastPfn) {
Info = InfoStart;
FoundMap = FALSE;
if ((Pfn1->u3.e1.PageLocation != FreePageList) &&
(Pfn1->u3.e1.PageLocation != ZeroedPageList) &&
(Pfn1->u3.e1.PageLocation != BadPageList)) {
if (Type == 1) {
if (Pfn1->u3.e1.PageLocation != ActiveAndValid) {
Pfn1++;
continue;
}
}
if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {
Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
Master = (PUCHAR)Subsection->ControlArea;
ControlArea = Subsection->ControlArea;
if (!MmIsAddressValid(ControlArea)) {
DbgPrint ("Pfnp %lx not found %lx\n",Pfn1 - MmPfnDatabase,
(ULONG)Pfn1->PteAddress);
Pfn1++;
continue;
}
if (ControlArea->FilePointer != NULL) {
if (!MmIsAddressValid(ControlArea->FilePointer)) {
Pfn1++;
continue;
}
}
} else {
FoundMap = TRUE;
VirtualAddress = (ULONG)MiGetVirtualAddressMappedByPte (Pfn1->PteAddress);
if ((VirtualAddress >= (ULONG)MmPagedPoolStart) &&
(VirtualAddress <= (ULONG)MmPagedPoolEnd)) {
//
// This is paged pool, put it in the paged pool cell.
//
Master = MM_PAGED_POOL_MARK;
} else if ((VirtualAddress >= (ULONG)MmNonPagedPoolStart) &&
(VirtualAddress <= (ULONG)MmNonPagedPoolEnd)) {
//
// This is nonpaged pool, put it in the nonpaged pool cell.
//
Master = MM_NONPAGED_POOL_MARK;
} else {
FoundMap = FALSE;
for (j=0; j < KernSize; j++) {
if ((VirtualAddress >= KernMap[j].StartVa) &&
(VirtualAddress < KernMap[j].EndVa)) {
Master = (PUCHAR)&KernMap[j];
FoundMap = TRUE;
break;
}
}
}
if (!FoundMap) {
if (((ULONG)Pfn1->PteAddress >= MmSystemPtesStart[SystemPteSpace]) &&
((ULONG)Pfn1->PteAddress <= MmSystemPtesEnd[SystemPteSpace])) {
//
// This is kernel stack.
//
Master = MM_KERNEL_STACK_MARK;
} else {
Pfn2 = MI_PFN_ELEMENT (Pfn1->PteFrame);
Master = (PUCHAR)Pfn2->PteFrame;
if (((ULONG)Master == 0) || ((ULONG)Master > MmHighestPhysicalPage)) {
DbgPrint ("Pfn %lx not found %lx\n",Pfn1 - MmPfnDatabase,
(ULONG)Pfn1->PteAddress);
Pfn1++;
continue;
}
}
}
}
//
// See if there is already a master info block.
//
Found = FALSE;
while (Info < InfoEnd) {
if (Info->StringOffset == Master) {
Found = TRUE;
break;
}
Info += 1;
}
if (!Found) {
Info = InfoEnd;
InfoEnd += 1;
if ((PUCHAR)Info >= ((PUCHAR)InfoStart + Size) - sizeof(SYSTEM_MEMORY_INFO)) {
status = STATUS_DATA_OVERRUN;
goto Done;
}
RtlZeroMemory (Info, sizeof(*Info));
Info->StringOffset = Master;
}
if ((Pfn1->u3.e1.PageLocation == StandbyPageList) ||
(Pfn1->u3.e1.PageLocation == TransitionPage)) {
Info->TransitionCount += 1;
} else if ((Pfn1->u3.e1.PageLocation == ModifiedPageList) ||
(Pfn1->u3.e1.PageLocation == ModifiedNoWritePageList)) {
Info->ModifiedCount += 1;
} else {
Info->ValidCount += 1;
if (Type == 1) {
if ((Pfn1->PteAddress >= MiGetPdeAddress (0x0)) &&
(Pfn1->PteAddress <= MiGetPdeAddress (0xFFFFFFFF))) {
Info->PageTableCount += 1;
}
}
}
if (Type != 1) {
if ((Pfn1->PteAddress >= MiGetPdeAddress (0x0)) &&
(Pfn1->PteAddress <= MiGetPdeAddress (0xFFFFFFFF))) {
Info->PageTableCount += 1;
}
}
}
Pfn1++;
}
MemInfo->StringStart = (ULONG)Buffer + (PUCHAR)InfoEnd - (PUCHAR)MemInfo;
String = (PUCHAR)InfoEnd;
//
// Process strings...
//
Info = InfoStart;
while (Info < InfoEnd) {
if (Info->StringOffset > (PUCHAR)0x80000000) {
//
// Make sure this is not stacks or other areas.
//
Length = 0;
ControlArea = NULL;
if (Info->StringOffset == MM_NONPAGED_POOL_MARK) {
Length = 14;
NameString = NonPagedPool;
} else if (Info->StringOffset == MM_PAGED_POOL_MARK) {
Length = 14;
NameString = PagedPool;
} else if (Info->StringOffset == MM_KERNEL_STACK_MARK) {
Length = 14;
NameString = KernelStack;
} else if (((PUCHAR)Info->StringOffset >= (PUCHAR)&KernMap[0]) &&
((PUCHAR)Info->StringOffset <= (PUCHAR)&KernMap[MM_KERN_MAP_SIZE])) {
DataTableEntry = ((PKERN_MAP)Info->StringOffset)->Entry;
NameString = (PUCHAR)DataTableEntry->BaseDllName.Buffer;
Length = DataTableEntry->BaseDllName.Length;
} else {
//
// This points to a control area.
// Get the file name.
//
ControlArea = (PCONTROL_AREA)(Info->StringOffset);
NameString = (PUCHAR)&ControlArea->FilePointer->FileName.Buffer[0];
}
Info->StringOffset = NULL;
Failed = TRUE;
if (Length == 0) {
if (MmIsAddressValid (&ControlArea->FilePointer->FileName.Length)) {
Length = ControlArea->FilePointer->FileName.Length;
if (Length == 0) {
if (ControlArea->u.Flags.NoModifiedWriting) {
Length = 14;
NameString = MetaFile;
} else if (ControlArea->u.Flags.File == 0) {
NameString = PageFileMapped;
Length = 16;
} else {
NameString = NoName;
Length = 14;
}
}
}
}
if ((String+Length+2) >= End) {
status = STATUS_DATA_OVERRUN;
goto Done;
}
if (MmIsAddressValid (&NameString[0]) &&
MmIsAddressValid (&NameString[Length - 1])) {
RtlMoveMemory (String,
NameString,
Length );
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
String[Length] = 0;
String[Length + 1] = 0;
String += Length + 2;
Failed = FALSE;
}
if (Failed && ControlArea) {
if (!(ControlArea->u.Flags.BeingCreated ||
ControlArea->u.Flags.BeingDeleted) &&
(ControlCount < MM_SAVED_CONTROL)) {
SavedControl[ControlCount] = ControlArea;
SavedInfo[ControlCount] = Info;
ControlArea->NumberOfSectionReferences += 1;
ControlCount += 1;
}
}
} else {
//
// Process...
//
Pfn1 = MI_PFN_ELEMENT (Info->StringOffset);
Info->StringOffset = NULL;
if ((String+16) >= End) {
status = STATUS_DATA_OVERRUN;
goto Done;
}
Process = (PEPROCESS)Pfn1->u1.Event;
if (Pfn1->PteAddress == MiGetPteAddress (PDE_BASE)) {
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
RtlMoveMemory (String,
&Process->ImageFileName[0],
16);
String += 16;
} else {
Info->StringOffset = PagedSection;
if (PagedSection == NULL) {
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
RtlMoveMemory (String,
&PageFileMapped,
16);
PagedSection = Info->StringOffset;
String += 16;
}
}
}
Info += 1;
}
Done:
UNLOCK_PFN (OldIrql);
while (ControlCount != 0) {
//
// Process all the pagable name strings.
//
ControlCount -= 1;
ControlArea = SavedControl[ControlCount];
Info = SavedInfo[ControlCount];
NameString = (PUCHAR)&ControlArea->FilePointer->FileName.Buffer[0];
Length = ControlArea->FilePointer->FileName.Length;
if (Length == 0) {
if (ControlArea->u.Flags.NoModifiedWriting) {
Length = 12;
NameString = MetaFile;
} else if (ControlArea->u.Flags.File == 0) {
NameString = PageFileMapped;
Length = 16;
} else {
NameString = NoName;
Length = 12;
}
}
if ((String+Length+2) >= End) {
status = STATUS_DATA_OVERRUN;
}
if (status != STATUS_DATA_OVERRUN) {
RtlMoveMemory (String,
NameString,
Length );
Info->StringOffset = (PUCHAR)Buffer + ((PUCHAR)String - (PUCHAR)MemInfo);
String[Length] = 0;
String[Length + 1] = 0;
String += Length + 2;
}
LOCK_PFN (OldIrql);
ControlArea->NumberOfSectionReferences -= 1;
MiCheckForControlAreaDeletion (ControlArea);
UNLOCK_PFN (OldIrql);
}
*OutLength = ((PUCHAR)String - (PUCHAR)MemInfo);
MmUnlockPages (Mdl);
ExFreePool (Mdl);;
return status;
}
#else //DBG
NTSTATUS
MmMemoryUsage (
IN PVOID Buffer,
IN ULONG Size,
IN ULONG Type,
OUT PULONG OutLength
)
{
return STATUS_NOT_IMPLEMENTED;
}
#endif //DBG
#if DBG
ULONG
MiBuildKernelMap (
IN ULONG NumberOfElements,
IN OUT PKERN_MAP KernelMap
)
{
PLIST_ENTRY Next;
PLIST_ENTRY NextEntry;
PLDR_DATA_TABLE_ENTRY DataTableEntry;
ULONG i = 0;
KeEnterCriticalRegion();
ExAcquireResourceShared (&PsLoadedModuleResource, TRUE);
NextEntry = PsLoadedModuleList.Flink;
do {
DataTableEntry = CONTAINING_RECORD(NextEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
KernelMap[i].Entry = DataTableEntry;
KernelMap[i].StartVa = (ULONG)DataTableEntry->DllBase;
KernelMap[i].EndVa = KernelMap[i].StartVa +
(ULONG)DataTableEntry->SizeOfImage;
i += 1;
if (i == NumberOfElements) {
break;
}
Next = DataTableEntry->InLoadOrderLinks.Flink;
NextEntry = NextEntry->Flink;
} while (NextEntry != &PsLoadedModuleList);
ExReleaseResource (&PsLoadedModuleResource);
KeLeaveCriticalRegion();
return i;
}
#endif //DBG
#if DBG
VOID
MiFlushCache (
VOID
)
/*++
Routine Description:
This routine (debugging only) flushes the "cache" by moving
all pages from the standby list to the free list. Modified
pages are not effected.
Arguments:
None.
Return Value:
None.
--*/
{
KIRQL OldIrql;
ULONG Page;
LOCK_PFN (OldIrql);
while (MmPageLocationList[StandbyPageList]->Total != 0) {
Page = MiRemovePageFromList (MmPageLocationList[StandbyPageList]);
//
// A page has been removed from the standby list. The
// PTE which refers to this page is currently in the transtion
// state and must have its original contents restored to free
// the the last reference to this physical page.
//
MiRestoreTransitionPte (Page);
//
// Put the page into the free list.
//
MiInsertPageInList (MmPageLocationList[FreePageList], Page);
}
UNLOCK_PFN (OldIrql);
return;
}
VOID
MiDumpReferencedPages (
VOID
)
/*++
Routine Description:
This routine (debugging only) dumps all PFN entries which appear
to be locked in memory for i/o.
Arguments:
None.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PMMPFN Pfn1;
PMMPFN PfnLast;
LOCK_PFN (OldIrql);
Pfn1 = MI_PFN_ELEMENT (MmLowestPhysicalPage);
PfnLast = MI_PFN_ELEMENT (MmHighestPhysicalPage);
while (Pfn1 <= PfnLast) {
if ((Pfn1->u2.ShareCount == 0) && (Pfn1->u3.e2.ReferenceCount != 0)) {
MiFormatPfn (Pfn1);
}
if (Pfn1->u3.e2.ReferenceCount > 1) {
MiFormatPfn (Pfn1);
}
Pfn1 += 1;
}
UNLOCK_PFN (OldIrql);
return;
}
#endif //DBG