mirror of https://github.com/lianthony/NT4.0
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.
426 lines
9.9 KiB
426 lines
9.9 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pte.c
|
|
|
|
Abstract:
|
|
|
|
WinDbg Extension Api
|
|
|
|
Author:
|
|
|
|
Lou Perazzoli (LouP) 15-Feb-1992
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
moved to windbg format
|
|
Ramon J San Andres (ramonsa) 8-Nov-1993
|
|
|
|
--*/
|
|
|
|
#define NUMBER_OF_PTE_TO_READ 100
|
|
|
|
#ifndef MM_PTE_LARGE_PAGE_MASK
|
|
#define MM_PTE_LARGE_PAGE_MASK 0
|
|
#endif
|
|
|
|
typedef struct _SYS_PTE_LIST {
|
|
ULONG Next;
|
|
ULONG Previous;
|
|
ULONG Value;
|
|
ULONG Count;
|
|
} SYS_PTE_LIST, *PSYS_PTE_LIST;
|
|
|
|
|
|
ULONG MmKseg2Frame;
|
|
|
|
ULONG
|
|
MiGetFrameFromPte (
|
|
IN ULONG lpte
|
|
);
|
|
|
|
ULONG
|
|
MiGetFrameFromPte (
|
|
ULONG lpte
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the PTE is valid, returns the page frame number that
|
|
the PTE maps. Zero is returned otherwise.
|
|
|
|
Arguments:
|
|
|
|
lpte - the PTE to examine.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
MMPTE Pte1;
|
|
|
|
Pte1.u.Long = lpte;
|
|
|
|
if (Pte1.u.Hard.Valid) {
|
|
return (Pte1.u.Hard.PageFrameNumber);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
ULONG
|
|
MiGetFreeCountFromPteList (
|
|
IN PULONG Pte
|
|
);
|
|
|
|
ULONG
|
|
MiGetFreeCountFromPteList (
|
|
IN PULONG Pte
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified PTE points to a free list header in the
|
|
system PTE pool. It returns the number of free entries
|
|
in this block.
|
|
|
|
Arguments:
|
|
|
|
Pte - the PTE to examine.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE Pte1;
|
|
MMPTE Pte2;
|
|
|
|
|
|
Pte1.u.Long = *Pte;
|
|
Pte2.u.Long = *(Pte + 1);
|
|
return (( Pte1.u.List.OneEntry) ?
|
|
1 :
|
|
Pte2.u.List.NextEntry);
|
|
}
|
|
|
|
ULONG
|
|
MiGetNextFromPteList (
|
|
IN ULONG Pte
|
|
);
|
|
|
|
ULONG
|
|
MiGetNextFromPteList (
|
|
ULONG Pte
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The specified PTE points to a free list header in the
|
|
system PTE pool. It returns the next entry in the block.
|
|
|
|
Arguments:
|
|
|
|
Pte - the PTE to examine.
|
|
|
|
--*/
|
|
|
|
{
|
|
MMPTE xyz;
|
|
|
|
xyz.u.Long = Pte;
|
|
return(xyz.u.List.NextEntry);
|
|
}
|
|
|
|
|
|
DECLARE_API( sysptes )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps all vads for process.
|
|
|
|
Arguments:
|
|
|
|
args - Flags
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG result;
|
|
ULONG Flags;
|
|
ULONG next;
|
|
PMMPTE PteBase;
|
|
PMMPTE PteEnd;
|
|
PMMPTE IndexBias;
|
|
ULONG FreeStart;
|
|
ULONG NumberOfPtes;
|
|
PMMPTE PteArray;
|
|
HANDLE PteHandle;
|
|
ULONG PageCount;
|
|
ULONG ReadCount;
|
|
PMMPTE Pte;
|
|
ULONG IndexBase;
|
|
ULONG free;
|
|
ULONG totalFree;
|
|
ULONG largeFree;
|
|
ULONG i;
|
|
ULONG Page;
|
|
ULONG first;
|
|
PSYS_PTE_LIST List;
|
|
ULONG FreeSysPteListBySize [MM_SYS_PTE_TABLES_MAX];
|
|
ULONG SysPteIndex [MM_SYS_PTE_TABLES_MAX];
|
|
|
|
|
|
Flags = 0;
|
|
sscanf(args,"%lx",&Flags);
|
|
dprintf("\n\nSystem PTE Information\n");
|
|
|
|
PteBase = (PMMPTE)GetUlongValue ("MmSystemPtesStart");
|
|
PteEnd = (PMMPTE)GetUlongValue ("MmSystemPtesEnd");
|
|
IndexBias = (PMMPTE)GetUlongValue ("MmSystemPteBase");
|
|
|
|
dprintf(" Total System Ptes %ld\n", 1 + (PteEnd - PteBase));
|
|
free = GetExpression( "MmSysPteIndex" );
|
|
|
|
if ( !ReadMemory( (DWORD)free,
|
|
&SysPteIndex[0],
|
|
sizeof(ULONG) * MM_SYS_PTE_TABLES_MAX,
|
|
&result) ) {
|
|
dprintf("%08lx: Unable to get PTE index\n",free);
|
|
} else {
|
|
|
|
free = GetExpression( "MmSysPteListBySizeCount" );
|
|
|
|
if ( !ReadMemory( (DWORD)free,
|
|
&FreeSysPteListBySize[0],
|
|
sizeof(ULONG) * MM_SYS_PTE_TABLES_MAX,
|
|
&result) ) {
|
|
dprintf("%08lx: Unable to get free PTE index\n",free);
|
|
} else {
|
|
for (i = 0; i < MM_SYS_PTE_TABLES_MAX; i++ ) {
|
|
dprintf(" SysPtes list of size %3ld has %3ld free\n",
|
|
SysPteIndex[i],
|
|
FreeSysPteListBySize[i]);
|
|
}
|
|
}
|
|
}
|
|
dprintf(" \n");
|
|
FreeStart = GetUlongValue ("MmFirstFreeSystemPte");
|
|
FreeStart = MiGetNextFromPteList (FreeStart);
|
|
NumberOfPtes = 1 + PteEnd - PteBase;
|
|
|
|
dprintf(" starting PTE: %8lx\n", PteBase);
|
|
dprintf(" ending PTE: %8lx\n",PteEnd);
|
|
|
|
PteHandle = LocalAlloc(LMEM_MOVEABLE,
|
|
NumberOfPtes * sizeof(MMPTE));
|
|
if (!PteHandle) {
|
|
dprintf("Unable to get allocate memory of %ld bytes\n",
|
|
NumberOfPtes * sizeof(MMPTE));
|
|
} else {
|
|
PteArray = LocalLock(PteHandle);
|
|
dprintf(" loading ");
|
|
for (PageCount = 0;
|
|
PageCount < NumberOfPtes;
|
|
PageCount += NUMBER_OF_PTE_TO_READ) {
|
|
|
|
if ( CheckControlC() ) {
|
|
LocalUnlock(PteArray);
|
|
LocalFree((void *)PteHandle);
|
|
return;
|
|
}
|
|
|
|
dprintf(".");
|
|
ReadCount = NumberOfPtes - PageCount > NUMBER_OF_PTE_TO_READ ?
|
|
NUMBER_OF_PTE_TO_READ :
|
|
NumberOfPtes - PageCount + 1;
|
|
|
|
ReadCount *= sizeof (MMPTE);
|
|
|
|
Pte = (PMMPTE)((ULONG)PteBase + PageCount * sizeof (MMPTE));
|
|
|
|
if ( !ReadMemory( (DWORD)Pte,
|
|
&PteArray[PageCount],
|
|
ReadCount,
|
|
&result) ) {
|
|
dprintf("Unable to get system pte block - "
|
|
"address %lx - count %lu - page %lu\n",
|
|
Pte, ReadCount, PageCount);
|
|
return;
|
|
}
|
|
}
|
|
|
|
dprintf("\n");
|
|
|
|
// Now we have a local copy: let's take a look
|
|
|
|
// walk the free list.
|
|
|
|
IndexBase = PteBase - IndexBias;
|
|
|
|
totalFree = 0;
|
|
i = 0;
|
|
largeFree = 0;
|
|
next = FreeStart;
|
|
|
|
while (next < 0xfffff) {
|
|
|
|
if ( CheckControlC() ) {
|
|
LocalUnlock(PteArray);
|
|
LocalFree((void *)PteHandle);
|
|
return;
|
|
}
|
|
|
|
free = MiGetFreeCountFromPteList ((PULONG)&PteArray[next - IndexBase]);
|
|
|
|
if (Flags & 1) {
|
|
dprintf(" free ptes: %8lx number free: %5ld.\n",
|
|
&PteBase[next - IndexBase],
|
|
free);
|
|
}
|
|
if (free > largeFree) {
|
|
largeFree = free;
|
|
}
|
|
totalFree += free;
|
|
i += 1;
|
|
next = MiGetNextFromPteList ((ULONG)PteArray[next - IndexBase].u.Long);
|
|
}
|
|
dprintf("\n free blocks: %ld total free: %ld largest free block: %ld\n\n",
|
|
i, totalFree, largeFree);
|
|
|
|
//
|
|
// Walk through the array and sum up the usage on a per physical
|
|
// page basis.
|
|
//
|
|
|
|
List = VirtualAlloc (NULL,
|
|
NumberOfPtes * sizeof(SYS_PTE_LIST),
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (List == NULL) {
|
|
dprintf("alloc failed %lx\n",GetLastError());
|
|
LocalUnlock(PteArray);
|
|
LocalFree((void *)PteHandle);
|
|
return;
|
|
}
|
|
|
|
free = 0;
|
|
next = 0;
|
|
List[0].Value = 0xffffffff;
|
|
List[0].Previous = 0xffffff;
|
|
first = 0;
|
|
|
|
for (i = 0; i < NumberOfPtes ; i++) {
|
|
if (Page = MiGetFrameFromPte ((ULONG)PteArray[i].u.Long)) {
|
|
next = first;
|
|
while (Page > List[next].Value) {
|
|
next = List[next].Next;
|
|
}
|
|
if (List[next].Value == Page) {
|
|
List[next].Count += 1;
|
|
} else {
|
|
free += 1;
|
|
List[free].Next = next;
|
|
List[free].Value = Page;
|
|
List[free].Count = 1;
|
|
List[free].Previous = List[next].Previous;
|
|
if (next == first) {
|
|
first = free;
|
|
} else {
|
|
List[List[next].Previous].Next = free;
|
|
}
|
|
List[next].Previous = free;
|
|
}
|
|
}
|
|
|
|
if ( CheckControlC() ) {
|
|
LocalUnlock(PteArray);
|
|
LocalFree((void *)PteHandle);
|
|
VirtualFree (List, 0, MEM_RELEASE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
next = first;
|
|
dprintf (" Page Count\n");
|
|
while (List[next].Value != 0xffffffff) {
|
|
if ((Flags & 2) || (List[next].Count > 1)) {
|
|
dprintf (" %8lx %5ld.\n", List[next].Value, List[next].Count);
|
|
}
|
|
next = List[next].Next;
|
|
}
|
|
|
|
LocalUnlock(PteArray);
|
|
LocalFree((void *)PteHandle);
|
|
VirtualFree (List, 0, MEM_RELEASE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
GetAddressState(
|
|
IN PVOID VirtualAddress
|
|
)
|
|
|
|
{
|
|
ULONG Address;
|
|
ULONG result;
|
|
ULONG flags = 0;
|
|
PMMPTE Pte;
|
|
PMMPTE Pde;
|
|
ULONG PdeContents;
|
|
ULONG PteContents;
|
|
|
|
if (MI_IS_PHYSICAL_ADDRESS (VirtualAddress)) {
|
|
return ADDRESS_VALID;
|
|
}
|
|
Address = (ULONG)VirtualAddress;
|
|
|
|
Pde = (PMMPTE)MiGetPdeAddress (Address);
|
|
Pte = (PMMPTE)MiGetPteAddress (Address);
|
|
|
|
if ( !ReadMemory( (DWORD)Pde,
|
|
&PdeContents,
|
|
sizeof(ULONG),
|
|
&result) ) {
|
|
dprintf("%08lx: Unable to get PDE\n",Pde);
|
|
return ADDRESS_NOT_VALID;
|
|
}
|
|
|
|
if (PdeContents & MM_PTE_VALID_MASK) {
|
|
if (PdeContents & MM_PTE_LARGE_PAGE_MASK) {
|
|
return ADDRESS_VALID;
|
|
}
|
|
if ( !ReadMemory( (DWORD)Pte,
|
|
&PteContents,
|
|
sizeof(ULONG),
|
|
&result) ) {
|
|
dprintf("%08lx: Unable to get PTE\n",Pte);
|
|
return ADDRESS_NOT_VALID;
|
|
}
|
|
if (PteContents & MM_PTE_VALID_MASK) {
|
|
return ADDRESS_VALID;
|
|
}
|
|
if (PteContents & MM_PTE_TRANSITION_MASK) {
|
|
if (!(PteContents & MM_PTE_PROTOTYPE_MASK)) {
|
|
return ADDRESS_TRANSITION;
|
|
}
|
|
}
|
|
}
|
|
return ADDRESS_NOT_VALID;
|
|
}
|