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();
--
2.20.1