/* I) IA-32 Virtual Address: 3 2 2 1 1 0 1 2 1 2 1 0 +-----------------+------------+-------------+ | Directory | Table | Offset | +-----------------+------------+-------------+ Mapping PDE, PTE to memory: PDE: 1) VirtualAddress >> 22 - we get offset to an entry in Page Directory 2) Entry size is 4Bytes ( (*4) == (<<2) 3) Base Address in Windows is: 0xC030 0000 4) PDE_BASE = 0xC0300000 5) PDE_END = 0xC0300FFF (1024PDE * 4B = 4KB) PDE_Address(VirtualAddress) = ((VirtualAddress>>22)<<2) + PDE_BASE; PTE: 1) VirtualAddress >> 12 - we get offset to an entry in PageTable Directory 2) Entry size is 4Bytes ( (*4) == (<<2)) 3) Base Address in Windows is: 0xC0000000 4) PTE_BASE = 0xC0000000 5) PTE_END = 0xC03FFFFF (1024PDE * 1024PTE *4B = 4MB) PTE_Address(VirtualAddress) = ((VirtualAddress>>12)<<2) + PTE_BASE; Page Size - 4KB, 4MB (no PTE) We want read something from VirtualAddress (VA): 1) ULONG PageDirectoryOffset = (VA >> 22)*4; - ( VA >> 22 ) - give us offset to entry in a PageDirectory - *4 - each entry have 4Bytes 2) ULONG PDE_BASE_Physical = GetCR3(); ULONG GetCR3(VOID) { ULONG base; _asm { push eax mov eax, cr3 mov base, eax pop eax } return base; } 3) Now we need map this to Virtual Memory (Windows alread map this memory to address 0xC0300000) #define PDE_TABLE_SIZE 4096 PDE pde; PVOID PDE_BASE_Virtual; PHYSICAL_ADDRESS physical; physical.LowPart = PDE_BASE_Physical; physical.HighPart = 0; /* PDE_BASE_Virtual is a PageDirectory Virtual Memory address now */ PDE_BASE_Virtual = MmMapIoSpace(physical, PDE_TABLE_SIZE, MmNonCached); /* now we can read Page Director Entry */ pde = *((PPDE) ( ((ULONG) PDE_BASE_Virtual) + PageDirectoryOffset )); /* Now we can check is a entry valid */ if( pde.valid ) { if(pde.LargePage) { /* In such case we can read whole page - 4MB */ } else { /* Now we should map PTE */ PTE pte; PVOID PTE_Virtual; PHYSICAL_ADDRESS PTE_Physical; ULONG PageTableOffset; PTE_Physical.LowPart = (pde.page_table_base_address<<12); PTE_Physical.HighPart = 0; PageTableOffset = ( (VA>>12) & 0x3FF ); PTE_Virtual = MmMapIoSpace(PTE_Physical, PTE_TABLE_SIZE, MmNonCached); /* now we can read Page Table Entry */ pte = *((PPTE)(((ULONG) PTE_Virtual) + PageTableOffset)); if( pte.Valid ) { /* We can read such page now */ } MmUnmapIoSpace(PTE_Virtual, PTE_TABLE_SIZE); } } MmUnmapIoSpace(PDE_BASE_Virtual, PDE_TABLE_SIZE); /* We need remember about some kind of locking this memory */ /* From other side such MmMapIoSpace/MmUnmapIoSpace cost some resources, so good idea is have map whole Physical memory during boot process */ 4) Because Windows have already maped such Page Directory and Page Tables in Virtual Memory, we can use NT map, and also NT locks (for secure access for such Tables). See secure memory reading (that is a better idea). II) IA-32 PAE Virtual Address: 3 3 2 2 2 1 1 0 1 0 9 1 0 2 1 0 +--------+--------------+----------+-----------+ | DirPtr | Directory | Table | Offset | +--------+--------------+----------+-----------+ Mapping PDE, PTE to memory: PDE: 0) CR0.PG == 1 - paging enabled CR4.PAE == 1 - PAE enabled CR3 - Page Directory Pointer Table Base Address 1) VirtualAddress >> 21 - we get offset to an entry in Page Directory 2) Entry size is 4Bytes ( (*8) == (<<3) 3) Base Address in Windows is: 0xC060 0000 4) PDE_BASE = 0xC0600000 5) PDE_END = 0xC0603FFF (4DPE * 512PDE * 8B = 16KB) PDE_Address(VirtualAddress) = ((VirtualAddress>>21)<<3) + PDE_BASE; PTE: 1) VirtualAddress >> 12 - we get offset to an entry in PageTable Directory 2) Entry size is 8Bytes ( (*8) == (<<3)) 3) Base Address in Windows is: 0xC0000000 4) PDE_BASE = 0xC0000000 5) PDE_END = 0xC07FFFFF (4DPE * 512PDE * 512PTE * 8B = 8MB) PTE_Address(VirtualAddress) = ((VirtualAddress>>12)<<3) + PTE_BASE; Page Size - 4KB, 2MB (no PTE) Test: PTE_Address(PTE_BASE)== PDE_BASE */