/*---------------------------------------------------------------------------- PAGING.C: DJGPP program to dump the CPU page tables. Chris Giese http://SisAndHappy.com/ChrisGiese This code is public domain (no copyright). You can do whatever you want with it. Build with CWSDPR0.EXE instead of CWSDPMI.EXE: gcc -o paging.exe -O2 -Wall -W -g paging.c stubedit paging.exe dpmi=cwsdpr0.exe Run under plain DOS (no Windows or EMM386.EXE). page directory entry unused PDE page table entry (PTE) (PDE) for 4MB page normal PDE or PTE ---------------------- -------------------- ---------------- ---------- b31-22 =page addr =b31-22 of page addr =page table addr =AVAILABLE b21 =page addr =RESERVED=0 =page table addr =AVAILABLE b20-13 =page addr =b39-32 of page addr =page table addr =AVAILABLE b12 =page addr =PAT =page table addr =AVAILABLE b11-9 =AVAILABLE =AVAILABLE =AVAILABLE =AVAILABLE b8 G=global G=global =AVAILABLE =AVAILABLE b7 =PAT =page size=1 =page size=0 =AVAILABLE b6 D=dirty D=dirty =AVAILABLE =AVAILABLE b5 A=accessed A=accessed A=accessed =AVAILABLE b4 =cache disable =cache disable =cache disable =AVAILABLE b3 =write-through =write-through =write-through =AVAILABLE b2 U=user U=user U=user =AVAILABLE b1 W=writable W=writable W=writable =AVAILABLE b0 P=present=1 P=present=1 P=present=1 present=0 PAT: page attribute table (?)(Pentium III CPU or newer) page size: 0=4K page, 1=4M page (? CPU or newer). b39-b32 valid only if PAE enabled global: page mapping not invalidated by reloading register CR3 (P6 CPU or newer) dirty: page was modified (written to) accessed: page was read from or written to cache disable: page is uncached (486 CPU or newer) write-through: "write-through" caching is enabled (486 CPU or newer) user: page can be accessed by code running at ring 3 writable: page can be written to present: other bits are valid PAE: Physical Address Extension (>4 GB memory). Pentium Pro CPU or newer. INVLPG addr: This instruction invalidates one page table entry corresponding to memory location addr (486 CPU or newer) Reloading CR3 register invalidates all page table entries except for those with the G bit set ----------------------------------------------------------------------------*/ #include /* printf() */ #if defined(__DJGPP__) #include /* __djgpp_conventional_base */ #include /* _CRT0_FLAG_NEARPTR, _crt0_startup_flags */ #define PTR2LINEAR(P) ((uint32_t)(P) - __djgpp_conventional_base) #define LINEAR2PTR(L) (void *)((L) + __djgpp_conventional_base) /* Doesn't work with Watcom C, sorry. I tried. */ #elif defined(__WATCOMC__) && defined(__386__) #define PTR2LINEAR(P) ((uint32_t)(P)) #define LINEAR2PTR(L) (void *)(L) unsigned get_cr3(void); #pragma aux get_cr3 = \ "mov eax,cr3" \ value [ eax ]; #else #error Sorry, unsupported compiler #endif #define HIBITS(N) ((N) & 0xFFFFF000L) typedef unsigned long uint32_t; /****************************************************************************/ int main(void) { /* PD=Page Directory, PDE=PD Entry, PT=Page Table, PTE=PT Entry, v=virtual address, p=physical address, v2p=virtual-to-physical conversion value, pv2p=previous V2P */ uint32_t cr3, *pd, pde, *pt, pte, v, p, v2p, pv2p; /* Page Directory Index, Page Table Index */ unsigned pdi, pti; #if defined(__DJGPP__) /* turn off data segment limit, for nearptr access */ if(!(_crt0_startup_flags & _CRT0_FLAG_NEARPTR)) { if(!__djgpp_nearptr_enable()) { printf("Error: can not enable near pointer " "access (WinNT/2k/XP?)\n"); return 1; } } /* get pointer to page directory */ __asm__("mov %%cr3,%%eax\n" : "=a"(cr3)); #else /* defined(__WATCOMC__) */ cr3 = get_cr3(); #endif pd = LINEAR2PTR(HIBITS(cr3)); /* virtaddr of main() is different because of segmentation; not paging */ printf( "address of main()=0x%p, virtaddr of main()=0x%lX\n" "CR3 (page directory pointer)=0x%lX\n" "PDI=Page Directory Index, PTI=Page Table Index\n" "D=Dirty, A=Accessed, U=User (Ring 3), W=Writable\n" "PDI PTI D A U W virtaddr physaddr virt2phys\n" "---- ---- - - - - -------- -------- --------\n", main, PTR2LINEAR(main), cr3); pv2p = -1uL; /* Walk page directory. PDI = bits 31-22 of virtual address. */ for(pdi = 0; pdi < 1024; pdi++) { if(((pde = pd[pdi]) & 1) == 0) /* Present bit = 0 */ continue; pt = LINEAR2PTR(HIBITS(pde)); /* Walk page table. PTI = bits 21-12 of virtual address. */ for(pti = 0; pti < 1024; pti++) { if(((pte = pt[pti]) & 1) == 0) continue; v = ((pdi << 10L) | pti) << 12L; p = HIBITS(pte); printf("%4u %4u %c %c %c %c %8lX %8lX", pdi, pti, (pte & 0x40) ? 'D' : ' ', (pte & 0x20) ? 'A' : ' ', (pte & 0x04) ? 'U' : ' ', (pte & 0x02) ? 'W' : ' ', v, p); if((v2p = v - p) != pv2p) { printf(" %8lX", v2p); pv2p = v2p; } printf("\n"); } } return 0; }