Skip to content

Instantly share code, notes, and snippets.

@doug65536
Created June 29, 2021 04:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doug65536/0d584c5d8a546f08651b0d652199dc85 to your computer and use it in GitHub Desktop.
Save doug65536/0d584c5d8a546f08651b0d652199dc85 to your computer and use it in GitHub Desktop.
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