<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">
Hi Daisuke,<br class="">
<br class="">
<blockquote type="cite" class="">On Oct 28, 2020, at 4:37 AM, <a href="mailto:d.hatayama@fujitsu.com" class="">
d.hatayama@fujitsu.com</a> wrote:<br class="">
<br class="">
<blockquote type="cite" class="">/*<br class="">
+ * Find virtual (VA) and physical (PA) addresses of kernel start<br class="">
+ *<br class="">
+ * va:<br class="">
+ *   Actual address of the kernel start (_stext) placed<br class="">
+ *   randomly by kaslr feature. To be more accurate,<br class="">
+ *   VA = _stext(from vmlinux) + kaslr_offset<br class="">
+ *<br class="">
+ * pa:<br class="">
+ *   Physical address where the kerenel is placed.<br class="">
+ *<br class="">
+ * In nokaslr case, VA = _stext (from vmlinux)<br class="">
+ * In kaslr case, virtual address of the kernel placement goes<br class="">
+ * in this range: ffffffff80000000..ffffffff9fffffff, or<br class="">
+ * __START_KERNEL_map..+512MB<br class="">
+ *<br class="">
+ * <a href="https://nam04.safelinks.protection.outlook.com/?" class="">https://nam04.safelinks.protection.outlook.com/?</a>url=https%3A%2F%<a href="http://2Fwww.kernel.org" class="">2Fwww.kernel.org</a>%2Fdoc%2FDocumentation%2Fx86%2Fx86_64%2Fmm.txt&amp;data=04%7C01%7Camakhalov%<a href="http://40vmware.com" class="">40vmware.com</a>%7C426ba673d45a4fb69de408d87b35d0f7%7Cb39138ca3cee4b4aa4d6cd83d9dd62f0%7C0%7C0%7C637394818358089889%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=ujyld4sSOtwS8EvY0Onni%2FYc9oCbl63nBOM4hLf6pL8%3D&amp;reserved=0<br class="">
+ *<br class="">
+ * Randomized VA will be the first valid page starting from<br class="">
+ * ffffffff80000000 (__START_KERNEL_map). Page tree entry of<br class="">
+ * this page will contain the PA of the kernel start.<br class="">
</blockquote>
<br class="">
I didn't come up with this natural idea, which is better in that<br class="">
IDTR is unnecessary.<br class="">
<br class="">
<blockquote type="cite" class="">+ *<br class="">
+ * NOTES:<br class="">
+ * 1. This method does not support PTI (Page Table Isolation)<br class="">
+ * case where CR3 points to the isolated page tree.<br class="">
</blockquote>
<br class="">
calc_kaslr_offset() already deals with PTI here:<br class="">
<br class="">
       if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)<br class="">
               pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);<br class="">
       else<br class="">
               pgd = cr3 & ~CR3_PCID_MASK;<br class="">
<br class="">
Thus it's OK to think that the CR3 points at the kernel counterpart.<br class="">
</blockquote>
<div class="">Good point, thanks!</div>
<br class="">
<blockquote type="cite" class=""><br class="">
<blockquote type="cite" class="">+ * 2. 4-level paging support only, as caller (calc_kaslr_offset)<br class="">
+ * does not support 5-level paging.<br class="">
</blockquote>
<br class="">
According to the mm.txt the address range for kernel text appears<br class="">
same in 5-level paging. What is the reason not to cover 5-level<br class="">
paging in this patch? Is there something that cannot be assumed on<br class="">
5-level paging?<br class="">
</blockquote>
There are no technical challenges. I just do not have Ice lake machine to test it.
<div class="">Do you know how I can get dump/vmlinux with 5-level paging enabled?<br class="">
<div class="">Once 5-level paging support is done, this method can be used as default, as there are</div>
<div class="">no limitations. <br class="">
<div class=""><br class="">
<blockquote type="cite" class=""><br class="">
<blockquote type="cite" class="">+ */<br class="">
+static int<br class="">
+find_kernel_start(ulong *va, ulong *pa)<br class="">
+{<br class="">
+       int i, pgd_idx, pud_idx, pmd_idx, pte_idx;<br class="">
+       uint64_t pgd_pte, pud_pte, pmd_pte, pte;<br class="">
+<br class="">
+       pgd_idx = pgd_index(__START_KERNEL_map);<br class="">
+       pud_idx = pud_index(__START_KERNEL_map);<br class="">
+       pmd_idx = pmd_index(__START_KERNEL_map);<br class="">
+       pte_idx = pte_index(__START_KERNEL_map);<br class="">
+<br class="">
+       for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {<br class="">
+               pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));<br class="">
</blockquote>
<br class="">
machdep->pgd is not guaranteed to be aligned by PAGE_SIZE.<br class="">
This could refer to the pgd for userland that resides in the next page.<br class="">
I guess it's necessary to get the 1st pgd entry in the page machdep->pgd belongs to.<br class="">
Like this?<br class="">
<br class="">
   pgd_pte = ULONG((machdep->pgd & PHYSICAL_PAGE_MASK) + pgd_idx * sizeof(uint64_t));<br class="">
</blockquote>
<div class="">As I understand machdep->pgd is a buffer, cached value of some pgd table from the dump.</div>
<div class="">machdep->pgd does not have to be aligned in the memory.</div>
<div class="">We just need to read at specific offset "pgd_idx * sizeof(uint64_t)” to get our pgd_pte.</div>
<div class="">I think " & PHYSICAL_PAGE_MASK” is not needed here.</div>
<div class="">Let me know if I wrong.</div>
<div class=""><br class="">
</div>
<div class="">But i’m going to introduce pgd prefetch from inside find_kernel_start() to do not depend on</div>
<div class="">prefetch from the caller. So caller must provide top pgd physical address</div>
<div class=""><br class="">
</div>
@@ -350,7 +3<u class="">50</u>,7 @@ quit:<br class="">
  * does not support 5-level paging.<br class="">
  */<br class="">
 static int<br class="">
-find_kernel_start(ulong *va, ulong *pa)<br class="">
+find_kernel_start(uint64_t pgd, ulong *va, ulong *pa)<br class="">
 {<br class="">
        int i, pgd_idx, pud_idx, pmd_idx, pte_idx;<br class="">
        uint64_t pgd_pte, pud_pte, pmd_pte, pte;<br class="">
@@ -361,6 +358,7 @@ find_kernel_start(ulong *va, ulong *pa)<br class="">
        pmd_idx = pmd_index(__START_KERNEL_map);<br class="">
        pte_idx = pte_index(__START_KERNEL_map);<br class="">
<br class="">
+       FILL_PGD(pgd & PHYSICAL_PAGE_MASK, PHYSADDR, PAGESIZE());<br class="">
        for (; pgd_idx < PTRS_PER_PGD; pgd_idx++) {<br class="">
                pgd_pte = ULONG(machdep->pgd + pgd_idx * sizeof(uint64_t));<br class="">
                if (pgd_pte & _PAGE_PRESENT)</div>
</div>
</div>
<div class=""><br class="">
</div>
<div class="">Thanks for review. Again will wait for 5-level paging dump/machine availability and send the improved patch.</div>
<div class="">Do you want me to switch to this method as default (to use it before IDTR method)?</div>
<div class=""><br class="">
</div>
<div class="">Regards,</div>
<div class="">—Alexey</div>
</body>
</html>