Hi Rui,
You may need to do a rebase on the latest upstream. I merged a patch
[1] and noticed yours conflicts with it.
[1]:
https://www.mail-archive.com/devel@lists.crash-utility.osci.io/msg02260.html
Thanks,
Tao Liu
On Wed, Sep 2, 2026 at 2:34 PM Rui Qi <qirui.001(a)bytedance.com> wrote:
On 9/1/26 10:15 AM, Rui Qi wrote:
> RISC-V page table entries at any level may be leaf entries when V is
> set and any of R/W/X is set. The riscv64 vtop walkers currently treat
> non-zero intermediate entries as pointers to the next page table, so a
> PMD leaf can be used as a page table address and make vtop fail with a
> physical seek error.
>
> Detect leaf entries at PGD/P4D/PUD/PMD levels and translate them using
> the page size implied by that level. Continue walking only for non-leaf
> table entries.
>
> Signed-off-by: Rui Qi <qirui.001(a)bytedance.com>
> ---
> riscv64.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 54 insertions(+)
>
> diff --git a/riscv64.c b/riscv64.c
> index 4dcecc2f6b2c..ca26965421d7 100644
> --- a/riscv64.c
> +++ b/riscv64.c
> @@ -602,6 +602,33 @@ riscv64_translate_pte(ulong pte, void *physaddr, ulonglong
unused)
> return page_present;
> }
>
> +static int
> +riscv64_pte_is_leaf(ulong pte)
> +{
> + return ((pte & _PAGE_PRESENT) &&
> + (pte & (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)));
> +}
> +
> +static int
> +riscv64_handle_leaf_pte(ulong pte, ulong vaddr, int shift,
> + physaddr_t *paddr, int verbose)
> +{
> + physaddr_t paddr_base, page_mask;
> +
> + pte &= PTE_PFN_PROT_MASK;
> + paddr_base = PTOB(pte >> _PAGE_PFN_SHIFT);
> + page_mask = ~(((physaddr_t)1 << shift) - 1);
> + *paddr = (paddr_base & page_mask) + (vaddr & ~page_mask);
> +
> + if (verbose) {
> + fprintf(fp, " PAGE: %016llx\n\n",
> + (ulonglong)(*paddr & page_mask));
> + riscv64_translate_pte(pte, 0, 0);
> + }
> +
> + return TRUE;
> +}
> +
> static void
> riscv64_page_type_init(void)
> {
> @@ -655,6 +682,9 @@ riscv64_vtop_3level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr,
pgd_val);
> if (!pgd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pgd_val))
> + return riscv64_handle_leaf_pte(pgd_val, vaddr,
> + PGD_SHIFT_L3, paddr, verbose);
> pgd_val &= PTE_PFN_PROT_MASK;
> pmd_base = (pgd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -666,6 +696,9 @@ riscv64_vtop_3level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PMD: %016lx => %016lx\n", pmd_addr,
pmd_val);
> if (!pmd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pmd_val))
> + return riscv64_handle_leaf_pte(pmd_val, vaddr,
> + PMD_SHIFT, paddr, verbose);
> pmd_val &= PTE_PFN_PROT_MASK;
> pte_base = (pmd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1237,6 +1270,9 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr,
pgd_val);
> if (!pgd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pgd_val))
> + return riscv64_handle_leaf_pte(pgd_val, vaddr,
> + PGD_SHIFT_L4, paddr, verbose);
> pgd_val &= PTE_PFN_PROT_MASK;
> pud_base = (pgd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1248,6 +1284,9 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PUD: %016lx => %016lx\n", pud_addr,
pud_val);
> if (!pud_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pud_val))
> + return riscv64_handle_leaf_pte(pud_val, vaddr,
> + PUD_SHIFT, paddr, verbose);
> pud_val &= PTE_PFN_PROT_MASK;
> pmd_base = (pud_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1259,6 +1298,9 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PMD: %016lx => %016lx\n", pmd_addr,
pmd_val);
> if (!pmd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pmd_val))
> + return riscv64_handle_leaf_pte(pmd_val, vaddr,
> + PMD_SHIFT, paddr, verbose);
> pmd_val &= PTE_PFN_PROT_MASK;
> pte_base = (pmd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1316,6 +1358,9 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr,
pgd_val);
> if (!pgd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pgd_val))
> + return riscv64_handle_leaf_pte(pgd_val, vaddr,
> + PGD_SHIFT_L5, paddr, verbose);
> pgd_val &= PTE_PFN_PROT_MASK;
> p4d_base = (pgd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1327,6 +1372,9 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " P4D: %016lx => %016lx\n", p4d_addr,
p4d_val);
> if (!p4d_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(p4d_val))
> + return riscv64_handle_leaf_pte(p4d_val, vaddr,
> + P4D_SHIFT, paddr, verbose);
> p4d_val &= PTE_PFN_PROT_MASK;
> pud_base = (p4d_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1338,6 +1386,9 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PUD: %016lx => %016lx\n", pud_addr,
pud_val);
> if (!pud_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pud_val))
> + return riscv64_handle_leaf_pte(pud_val, vaddr,
> + PUD_SHIFT, paddr, verbose);
> pud_val &= PTE_PFN_PROT_MASK;
> pmd_base = (pud_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
> @@ -1349,6 +1400,9 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t
*paddr, int verbose)
> fprintf(fp, " PMD: %016lx => %016lx\n", pmd_addr,
pmd_val);
> if (!pmd_val)
> goto no_page;
> + if (riscv64_pte_is_leaf(pmd_val))
> + return riscv64_handle_leaf_pte(pmd_val, vaddr,
> + PMD_SHIFT, paddr, verbose);
> pmd_val &= PTE_PFN_PROT_MASK;
> pte_base = (pmd_val >> _PAGE_PFN_SHIFT) << PAGESHIFT();
>
Hi,
This patch fixes a crash utility issue on RISC-V where `vtop -k` may
fail to translate valid vmalloc/vmap addresses.
The issue was observed while analyzing a RISC-V system running the
6.12.95 kernel. For some vmalloc addresses, `vtop` failed with:
crash> vtop -k ffff8f8044680000
VIRTUAL
PHYSICAL
vtop: seek error: physical address
However, `kmem -v` showed that the same address belonged to a valid vmap
area.
Further investigation showed that the address was mapped by a leaf PTE at
an intermediate page table level, such as PMD. On RISC-V, a PTE at any
level may be a leaf entry when the V bit is set and at least one of the
R/W/X bits is set. Leaf PTEs are therefore not limited to the last page
table level.
The existing crash RISC-V page table walkers only handled leaf entries at
the final PTE level. For PGD/P4D/PUD/PMD entries, any non-zero entry was
treated as a pointer to the next-level page table. When such an entry was
actually a leaf PTE, crash incorrectly used its PFN as a page-table-page
address, which led to a physical seek error.
This patch fixes the issue by detecting leaf PTEs during the Sv39, Sv48,
and Sv57 page table walks. When a leaf entry is found at PGD/P4D/PUD/PMD
level, crash now translates the virtual address using the page size
implied by that level. Non-leaf entries continue to be handled by walking
to the next page table level.
After the fix, the previously failing address can be translated correctly,
for example:
crash> vtop -k ffff8f803c000000
VIRTUAL PHYSICAL
ffff8f803c000000 b003c000000
Addresses with an offset inside the same large mapping are also handled
correctly:
crash> vtop -k ffff8f803c123456
VIRTUAL PHYSICAL
ffff8f803c123456 b003c123456
The normal 4KB PTE mapping path was also verified to continue working.
This is a crash utility bug fix only. No kernel change is required.