calc_kaslr_offset() already deals with PTI here:
if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
else
pgd = cr3 & ~CR3_PCID_MASK;
Thus it's OK to think that the CR3 points at the kernel counterpart.
Good point, thanks!
And also this logic is based on the kernel logic that such pgt pair
is generated even when PTI is disabled at runtime. But I think you should test
with PTI disabled for in case.
+ * 2. 4-level paging support only, as caller (calc_kaslr_offset)
+ * does not support 5-level paging.
According to the mm.txt the address range for kernel text appears
same in 5-level paging. What is the reason not to cover 5-level
paging in this patch? Is there something that cannot be assumed on
5-level paging?
There are no technical challenges. I just do not have Ice lake machine to test it.
I see.
Do you know how I can get dump/vmlinux with 5-level paging enabled?
At least I don't have Ice Lake machine and I cannot share such crash dump.
Once 5-level paging support is done, this method can be used as
default, as there are
no limitations.
+ */
+static int
+find_kernel_start(ulong *va, ulong *pa)
+{
+ int i, pgd_idx, pud_idx, pmd_idx, pte_idx;
+ uint64_t pgd_pte, pud_pte, pmd_pte, pte;
+
+ pgd_idx = pgd_index(__START_KERNEL_map);
+ pud_idx = pud_index(__START_KERNEL_map);
+ pmd_idx = pmd_index(__START_KERNEL_map);
+ pte_idx = pte_index(__START_KERNEL_map);
+
+ for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {
+ pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));
machdep->pgd is not guaranteed to be aligned by PAGE_SIZE.
This could refer to the pgd for userland that resides in the next page.
I guess it's necessary to get the 1st pgd entry in the page machdep->pgd belongs
to.
Like this?
pgd_pte = ULONG((machdep->pgd & PHYSICAL_PAGE_MASK) + pgd_idx *
sizeof(uint64_t));
As I understand machdep->pgd is a buffer, cached value of some pgd table from the
dump.
machdep->pgd does not have to be aligned in the memory.
We just need to read at specific offset "pgd_idx * sizeof(uint64_t)” to get our
pgd_pte.
I think " & PHYSICAL_PAGE_MASK” is not needed here.
Let me know if I wrong.
As I said in another mail, the comment from me was wrong; I was confused by pgd.
But i’m going to introduce pgd prefetch from inside find_kernel_start() to do not depend
on
prefetch from the caller. So caller must provide top pgd physical address
@@ -350,7 +350,7 @@ quit:
* does not support 5-level paging.
*/
static int
-find_kernel_start(ulong *va, ulong *pa)
+find_kernel_start(uint64_t pgd, ulong *va, ulong *pa)
{
int i, pgd_idx, pud_idx, pmd_idx, pte_idx;
uint64_t pgd_pte, pud_pte, pmd_pte, pte;
@@ -361,6 +358,7 @@ find_kernel_start(ulong *va, ulong *pa)
pmd_idx = pmd_index(__START_KERNEL_map);
pte_idx = pte_index(__START_KERNEL_map);
+ FILL_PGD(pgd & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());
for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {
pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));
if (pgd_pte & _PAGE_PRESENT)
Thanks for review. Again will wait for 5-level paging dump/machine availability and send
the improved patch.
Do you want me to switch to this method as default (to use it before IDTR method)?
Yes. Please remove the condition idtr == 0. By this, we can calculate kaslr_offset
in earlier kernel boot phase where IDTR is not configured.
Also,
+ if (idtr == 0 && st->_stext_vmlinux &&
(st->_stext_vmlinux != UNINITIALIZED)) {
+ ulong va, pa;
+ ret = find_kernel_start(&va, &pa);
+ if (ret == FALSE)
+ goto quit;
this gives up the search immediately. Please keep searching remaining registers,
at least for sadump format.
+ kaslr_offset = va - st->_stext_vmlinux;
+ phys_base = pa - (va - __START_KERNEL_map);
+
+ goto found;
+ }
Please do linux_banner sanity check for in case at least for sadump format.
Thanks.
HATAYAMA, Daisuke