Understanding virtual memory translation in AMD64/UEFI
Posted: Fri Oct 23, 2020 7:56 am
Hi all,
Trying to see if my understanding of page tables is correct. I am currently using UEFI, so I thought to inspect the page tables set up for it and see if my understanding is correct. From what I understand, all addresses in UEFI are identity mapped. I looped through the memory map descriptors and all virtual addresses are set to 0, so I am thinking this is true.
So want to know how virtual addresses are translated starting from CR3. So as an example I am using the RIP value which in this case is 0x65F_6A39. From reading the AMD64 manual, it looks like this address should be translated into the following offsets:
address -> 0x65F_6A39
PML4T -> bits 39-47 -> entry 0
PDPT -> bits 30 - 38 -> entry 0
PDT -> bits 21 - 29 -> entry 0x32 -> byte offset 0x32*8
PT -> bits 12 - 20 -> entry 0x1F6 -> byte offset 0x1F6*8
Do my offset calculations look correct?
From here, I now chase pointers starting from CR3. I assume all addresses are identity mapped because of what I’ve stated in the first paragraph. If they are not identity mapped, that’s the issue here. Below I have what I see when start pointer chasing.
It seems everything looks reasonable up until I reach the PDE, which is the first time I have a non-zero offset. The entry I am pulling from the PDT looks invalid (especially since the present bit is 0). Am I chasing pointers incorrectly? Am I applying the offset incorrectly?
Thank you!
Trying to see if my understanding of page tables is correct. I am currently using UEFI, so I thought to inspect the page tables set up for it and see if my understanding is correct. From what I understand, all addresses in UEFI are identity mapped. I looped through the memory map descriptors and all virtual addresses are set to 0, so I am thinking this is true.
So want to know how virtual addresses are translated starting from CR3. So as an example I am using the RIP value which in this case is 0x65F_6A39. From reading the AMD64 manual, it looks like this address should be translated into the following offsets:
address -> 0x65F_6A39
PML4T -> bits 39-47 -> entry 0
PDPT -> bits 30 - 38 -> entry 0
PDT -> bits 21 - 29 -> entry 0x32 -> byte offset 0x32*8
PT -> bits 12 - 20 -> entry 0x1F6 -> byte offset 0x1F6*8
Do my offset calculations look correct?
From here, I now chase pointers starting from CR3. I assume all addresses are identity mapped because of what I’ve stated in the first paragraph. If they are not identity mapped, that’s the issue here. Below I have what I see when start pointer chasing.
It seems everything looks reasonable up until I reach the PDE, which is the first time I have a non-zero offset. The entry I am pulling from the PDT looks invalid (especially since the present bit is 0). Am I chasing pointers incorrectly? Am I applying the offset incorrectly?
Thank you!
Code: Select all
CR3 -> 0x7C0_1000
PML4E -> 0x7C0_1000 + 0 -> {is_present = true,
is_writable = true,
is_user_accessible = false,
is_write_through_enabled = false,
is_cache_disabled = false,
was_accessed = true,
ignored = 0,
page_size_control_bit = 0,
must_be_zero = 0,
unused1 = 0,
table_address = 0x7C02,
unused0 = 0,
no_execute = false,
}
PDPE -> 0x7C0_2000 + 0 -> {is_present = true,
is_writable = true,
is_user_accessible = false,
is_write_through_enabled = false,
is_cache_disabled = false,
was_accessed = true,
ignored = 0,
page_size_control_bit = 0,
must_be_zero = 0,
unused1 = 0,
table_address = 0x7C03,
unused0 = 0,
no_execute = false,
}
PDE -> 0x7C0_3000 + 0x32*8 -> {is_present = false,
is_writable = false,
is_user_accessible = false,
is_write_through_enabled = false,
is_cache_disabled = false,
was_accessed = false,
ignored = 0,
page_size_control_bit = 0,
must_be_zero = 0x1,
unused1 = 0x3,
table_address = 0x30_0000_0000,
unused0 = 0xE,
no_execute = false,
}