Page Directory Entry and Page Table Entry i386 Windows XP (SP2)



Virtual Memory - Intel official documentation

Virtual Memory - Intel


WinDbg and !pte analyze


kd> !pte 0
               VA 00000000
PDE at   C0300000        PTE at C0000000
contains 027A0067      contains 00000000
pfn 27a0 ---DA--UWEV    

kd> !pte 1000
               VA 00001000
PDE at   C0300000        PTE at C0000004
contains 027A0067      contains 00000000
pfn 27a0 ---DA--UWEV    

kd> !pte 50001
               VA 00050001
PDE at   C0300000        PTE at C0000140
contains 027A0067      contains 00000000
pfn 27a0 ---DA--UWEV    

kd> !pte 150002
               VA 00150002
PDE at   C0300000        PTE at C0000540
contains 027A0067      contains 00000000
pfn 27a0 ---DA--UWEV    

kd> !pte 01150022
               VA 01150022
PDE at   C0300010        PTE at C0004540
contains 00000000

kd> !pte 150022
               VA 00150022
PDE at   C0300000        PTE at C0000540
contains 027A0067      contains 00000000
pfn 27a0 ---DA--UWEV    

kd> !pte 1150022
               VA 01150022
PDE at   C0300010        PTE at C0004540
contains 00000000

kd> !pte 2150022
               VA 02150022
PDE at   C0300020        PTE at C0008540
contains 00000000

kd> !pte 2350022
               VA 02350022
PDE at   C0300020        PTE at C0008D40
contains 00000000

kd> !pte FFFFFFF
               VA FFFFFFFF
PDE at   C0300FFC        PTE at C03FFFFC
contains 00000000




Windows XP (sp2 - i386) Page Table address (WinDbg analyze, Windows Internals MS press)

Page Directory starts at 0xC030 0000 virtual address on i386.
Page Table starts at 0xC000 0000 virtual address on i386.

Conversion VirtualAddress -> PDE, PTE address


PDEaddress = ((VirtualAddress>>20) & (~0x3) ) + 0xC0300000
PTEaddress = ((VirtualAddress>>10) & (~0x3) )+ 0xC0000000

 ~0x3 - correction from !pte FFFFFFFF and correct aligment (4Bytes)



Intel Page Directory Entry and Page Table Entry structures


Page Directory structure

The "C" structure:



typedef struct _PTE
{
    ULONG Present           :1;
    ULONG Writable          :1;
    ULONG Owner             :1;
    ULONG WriteThrough      :1;
    ULONG CacheDisable      :1;
    ULONG Accessed          :1;
    ULONG Dirty             :1;
    ULONG LargePage         :1;
    ULONG Global            :1;
    ULONG ForUse1           :1;
    ULONG ForUse2           :1;
    ULONG ForUse3           :1;
    ULONG PageFrameNumber   :20;
} PTE, *PPTE;

IsAddressValid - kernel mode function



#define PDE_OFFSET 0xC0300000
#define PTE_OFFSET 0xC0000000

#add correction (~0x3) also here!
#define PDEaddr(VirtualAddress) ( (PPTE) (( ((ULONG) VirtualAddress) >> 20) + PDE_OFFSET) )
#define PTEaddr(VirtualAddress) ( (PPTE) (( ((ULONG) VirtualAddress) >> 10) + PTE_OFFSET) )

BOOLEAN
IsAddressValid(PVOID VirtualAddress)
{
	PPTE ptr;
	
	ptr = PDEaddr(VirtualAddress);
	if( ptr->Present == 0 )
	{
		return FALSE;
	}
	
	if( ptr->LargePage != 0 )
	{
		return TRUE;
	}
	
	ptr = PTEaddr(VirtualAddress);
	if( ptr->Present == 0)
	{
		return FALSE;
	}
	
	return TRUE;
}

try
{
// try will work for UserMode memory and PagedPool
// Page fault will raise an exception in that case.
//
// For nonpaged memory we should use IsAddressValid
// function - PAGE_FAULT_IN_NONPAGED_AREA protection

	if( KeNumberProcessor == 1 )
	{
	  KeRaiseIrql(HIGH_LEVEL, &oldIrql); 
	  if( IsAddressValid( address ) )
	  {
		// Read memory
		status = *( (ULONG*) address );
	  }
	  KeLowerIrql(oldIrql);
	}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
	KeLowerIrql(oldIrql);
	status = GetExceptionCode();
}




Copyrights (c) by Janusz Dziedzic