Created
June 29, 2021 04:47
-
-
Save doug65536/0d584c5d8a546f08651b0d652199dc85 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void bx_dbg_dump_table(Bit64u *st_ptr, Bit64u *en_ptr) | |
{ | |
if (! BX_CPU(dbg_cpu)->cr0.get_PG()) { | |
printf("paging off\n"); | |
return; | |
} | |
Bit64u st = st_ptr ? *st_ptr : 0; | |
Bit64u en = en_ptr ? *en_ptr : ~Bit64u(0); | |
bx_address cr3 = BX_CPU(dbg_cpu)->cr3; | |
bx_address pd = cr3 & -4096; | |
printf("cr3: 0x" FMT_PHY_ADDRX "\n", (bx_phy_address)BX_CPU(dbg_cpu)->cr3); | |
bx_cr4_t const &cr4 = BX_CPU(dbg_cpu)->cr4; | |
// Physical address extension and long mode active | |
bx_bool pae = cr4.get_PAE(); | |
bx_bool lma = BX_CPU(dbg_cpu)->efer.get_LMA(); | |
// 4-level paging in long mode, else 3 level in PAE, else 2 level | |
// Note that LMA implies PAE | |
int levels = lma ? 4 : pae ? 3 : 2; | |
// 512 entries per page in PAE, else 1024 entries | |
int log2_ent = pae ? 9 : 10; | |
int ent = 1 << log2_ent; | |
// The top level page table only has 4 entries in 32 bit PAE | |
int topent = levels == 3 ? 4 : ent; | |
// Page table entries are 64 bits in PAE | |
int ptesz = pae ? sizeof(Bit64u) : sizeof(Bit32u); | |
// Linear addresses are 16 hex digits in long mode, else 8 digits | |
int lindigits = lma ? 16 : 8; | |
// Physical addresses are 13 hex digits in PAE, else 8 digits | |
int phydigits = pae ? 13 : 8; | |
// Support 40 bit physical address for non-PAE 4MB pages | |
int pse36 = !!BX_CPU(dbg_cpu)->cpuid_support_isa_extension(BX_ISA_PSE36); | |
Bit8u pte_bytes[8]; | |
Bit64u pte; | |
Bit64u linaddr[5]; | |
Bit64u phyaddr[5]; | |
Bit64u lvl[4]; | |
Bit64u ent_addr; | |
// bx_dbg_dump_table_flags buffer, example: NXG-DA-----W | |
char flags[16]; | |
if (!lma && (cr3 >> 32)) { | |
dbg_printf("32 bit PAE page directory physical address" | |
" not within first 4GB!\n"); | |
} | |
phyaddr[0] = pd; | |
for (lvl[0] = 0; lvl[0] < topent; ++lvl[0]) { | |
linaddr[0] = lvl[0] << (12 + (levels * log2_ent - log2_ent)); | |
ent_addr = phyaddr[0] + ptesz * lvl[0]; | |
// Read PTE | |
BX_MEM(0)->dbg_fetch_mem( | |
BX_CPU(dbg_cpu), ent_addr, ptesz, pte_bytes); | |
// Decode bytes into PTE | |
if (ptesz == 8) | |
pte = conv_8xBit8u_to_Bit64u(pte_bytes); | |
else | |
pte = conv_4xBit8u_to_Bit32u(pte_bytes); | |
// Ignore entry that is not present | |
if (!(pte & 1)) | |
continue; | |
// Mapping is huge if page size enabled is set and PS bit is set | |
int huge0 = cr4.get_PSE() && !!(pte & (1<<7)); | |
if (!pae && huge0) { | |
// 4MB page | |
phyaddr[1] = (pte & (~(Bit64u)0 << 22)) & ~(~(Bit64u)0 << 32); | |
if (pse36) { | |
// Bit 39:32 of physical address from PTE bits 16:13 | |
phyaddr[1] |= (pte & (0xFU << 13)) << 32; | |
} | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 4MB %s\n", | |
phydigits, ent_addr, | |
lindigits, lma ? bx_canonical(linaddr[0]) : linaddr[0], | |
phydigits, phyaddr[1], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 0)); | |
continue; | |
} | |
if (pae && huge0) { | |
// Invalid PAE huge page at level 0 | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" Reserved huge page bit set! %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, lma ? bx_canonical(linaddr[0]) : linaddr[0], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 0)); | |
continue; | |
} | |
phyaddr[1] = (pte & (~(Bit64u)0 << 12)) & ~(~(Bit64u)0 << 52); | |
for (lvl[1] = 0; lvl[1] < ent; ++lvl[1]) { | |
if (pae) | |
// Second highest 9 bits of linear address | |
linaddr[1] = linaddr[0] + (lvl[1] << (12 + (levels * 9 - 18))); | |
else | |
// Second highest 10 bits of linear address | |
linaddr[1] = linaddr[0] + (lvl[1] << 12); | |
ent_addr = phyaddr[1] + ptesz * lvl[1]; | |
// Read PTE | |
BX_MEM(0)->dbg_fetch_mem( | |
BX_CPU(dbg_cpu), ent_addr, ptesz, pte_bytes); | |
// Decode bytes into PTE | |
if (ptesz == 8) | |
pte = conv_8xBit8u_to_Bit64u(pte_bytes); | |
else | |
pte = conv_4xBit8u_to_Bit32u(pte_bytes); | |
if (!(pte & 1)) | |
continue; | |
if (!pae) { | |
// 32 bit 4KB page | |
phyaddr[2] = pte & (~(Bit64u)0 << 12); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 4KB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, bx_canonical(linaddr[1]), | |
phydigits, (Bit64u)phyaddr[2], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 1)); | |
continue; | |
} | |
int huge1 = !!(pte & (1<<7)); | |
if (huge1 && !lma) { | |
// 32 bit PAE 2MB page | |
phyaddr[2] = pte & (~(Bit64u)0 << 21) & ~(~(Bit64u)0 << 52); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 2MB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, bx_canonical(linaddr[1]), | |
phydigits, (Bit64u)phyaddr[2], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 1)); | |
continue; | |
} | |
if (huge1) { | |
// 64 bit PAE 1GB page | |
phyaddr[2] = pte & (~(Bit64u)0 << 30) & ~(~(Bit64u)0 << 52); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 1GB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, bx_canonical(linaddr[1]), | |
phydigits, (Bit64u)phyaddr[2], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 1)); | |
continue; | |
} | |
assert(ptesz == 8); | |
phyaddr[2] = (pte & (~(Bit64u)0 << 12)) & ~(~(Bit64u)0 << 52); | |
for (lvl[2] = 0; lvl[2] < ent; ++lvl[2]) { | |
linaddr[2] = linaddr[1] + (lvl[2] << (12 + (levels * 9 - 27))); | |
ent_addr = phyaddr[2] + ptesz * lvl[2]; | |
// Read PTE | |
BX_MEM(0)->dbg_fetch_mem( | |
BX_CPU(dbg_cpu), ent_addr, ptesz, pte_bytes); | |
// Decode bytes into PTE | |
pte = conv_8xBit8u_to_Bit64u(pte_bytes); | |
if (!(pte & 1)) | |
continue; | |
int huge2 = (levels == 4) && !!(pte & (1<<7)); | |
if (huge2) { | |
phyaddr[3] = pte & (~(Bit64u)0 << 21) & ~(~(Bit64u)0 << 52); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 2MB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, bx_canonical(linaddr[2]), | |
phydigits, (Bit64u)phyaddr[3], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 2)); | |
continue; | |
} | |
if (!lma) { | |
phyaddr[3] = pte & (~(Bit64u)0 << 12) & ~(~(Bit64u)0 << 52); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 4KB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, linaddr[2], | |
phydigits, (Bit64u)phyaddr[3], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 2)); | |
continue; | |
} | |
assert(lma); | |
phyaddr[3] = (pte & (~(Bit64u)0 << 12)) & ~(~(Bit64u)0 << 52); | |
for (lvl[3] = 0; lvl[3] < ent; ++lvl[3]) { | |
linaddr[3] = linaddr[2] + (lvl[3] << 12); | |
ent_addr = phyaddr[3] + ptesz * lvl[3]; | |
assert(ptesz == sizeof(Bit64u)); | |
// Read PTE | |
BX_MEM(0)->dbg_fetch_mem( | |
BX_CPU(dbg_cpu), ent_addr, ptesz, pte_bytes); | |
// Decode bytes into PTE | |
pte = conv_8xBit8u_to_Bit64u(pte_bytes); | |
if (!(pte & 1)) | |
continue; | |
phyaddr[4] = pte & (~(Bit64u)0 << 12) & ~(~(Bit64u)0 << 52); | |
dbg_printf("0x%0*" FMT_64 "x:" | |
" 0x%0*" FMT_64 "x ->" | |
" 0x%0*" FMT_64 "x 4KB %s\n", | |
phydigits, (Bit64u)ent_addr, | |
lindigits, bx_canonical(linaddr[3]), | |
phydigits, (Bit64u)phyaddr[4], | |
bx_dbg_dump_table_flags(flags, sizeof(flags), pte, 3)); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment