Adds ARM64 support for 3-level page tables with 64K pages and 48 VA bits.
---
 arm64.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 defs.h  |  28 +++++++++++----
 2 files changed, 133 insertions(+), 21 deletions(-)

diff --git a/arm64.c b/arm64.c
index f6ea7a1..d1c9c3e 100644
--- a/arm64.c
+++ b/arm64.c
@@ -34,6 +34,7 @@ static void arm64_init_kernel_pgd(void);
 static int arm64_kvtop(struct task_context *, ulong, physaddr_t *, int);
 static int arm64_uvtop(struct task_context *, ulong, physaddr_t *, int);
 static int arm64_vtop_2level_64k(ulong, ulong, physaddr_t *, int);
+static int arm64_vtop_3level_64k(ulong, ulong, physaddr_t *, int);
 static int arm64_vtop_3level_4k(ulong, ulong, physaddr_t *, int);
 static ulong arm64_get_task_pgd(ulong);
 static void arm64_irq_stack_init(void);
@@ -188,15 +189,29 @@ arm64_init(int when)
                        break;
 
                case 65536:
-                       machdep->flags |= VM_L2_64K;
-                       machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K;
-                       if ((machdep->pgd = 
-                           (char *)malloc(PTRS_PER_PGD_L2_64K * 8)) == NULL)
-                               error(FATAL, "cannot malloc pgd space.");
-                       if ((machdep->ptbl = 
-                           (char *)malloc(PTRS_PER_PTE_L2_64K * 8)) == NULL)
-                               error(FATAL, "cannot malloc ptbl space.");
-                       machdep->pmd = NULL;  /* not used */
+                       if (machdep->machspec->VA_BITS > PGDIR_SHIFT_L3_64K) {
+                               machdep->flags |= VM_L3_64K;
+                               machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K;
+                               if ((machdep->pgd =
+                                   (char *)malloc(PTRS_PER_PGD_L3_64K * 8)) == 
NULL)
+                                       error(FATAL, "cannot malloc pgd 
space.");
+                               if ((machdep->pmd =
+                                   (char *)malloc(PTRS_PER_PMD_L3_64K * 8)) == 
NULL)
+                                       error(FATAL, "cannot malloc pmd 
space.");
+                               if ((machdep->ptbl =
+                                   (char *)malloc(PTRS_PER_PTE_L3_64K * 8)) == 
NULL)
+                                       error(FATAL, "cannot malloc ptbl 
space.");
+                       } else {
+                               machdep->flags |= VM_L2_64K;
+                               machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K;
+                               if ((machdep->pgd =
+                                   (char *)malloc(PTRS_PER_PGD_L2_64K * 8)) == 
NULL)
+                                       error(FATAL, "cannot malloc pgd 
space.");
+                               if ((machdep->ptbl =
+                                   (char *)malloc(PTRS_PER_PTE_L2_64K * 8)) == 
NULL)
+                                       error(FATAL, "cannot malloc ptbl 
space.");
+                               machdep->pmd = NULL;  /* not used */
+                       }
                        machdep->pud = NULL;  /* not used */
                        break;
 
@@ -379,6 +394,8 @@ arm64_dump_machdep_table(ulong arg)
                fprintf(fp, "%sPHYS_OFFSET", others++ ? "|" : "");
        if (machdep->flags & VM_L2_64K)
                fprintf(fp, "%sVM_L2_64K", others++ ? "|" : "");
+       if (machdep->flags & VM_L3_64K)
+               fprintf(fp, "%sVM_L3_64K", others++ ? "|" : "");
        if (machdep->flags & VM_L3_4K)
                fprintf(fp, "%sVM_L3_4K", others++ ? "|" : "");
        if (machdep->flags & VMEMMAP)
@@ -410,10 +427,14 @@ arm64_dump_machdep_table(ulong arg)
        fprintf(fp, "     processor_speed: arm64_processor_speed()\n");
        fprintf(fp, "               uvtop: arm64_uvtop()->%s()\n",
                machdep->flags & VM_L3_4K ? 
-               "arm64_vtop_3level_4k" : "arm64_vtop_2level_64k");
+               "arm64_vtop_3level_4k" :
+               machdep->flags & VM_L3_64K ?
+               "arm64_vtop_3level_64k" : "arm64_vtop_2level_64k");
        fprintf(fp, "               kvtop: arm64_kvtop()->%s()\n",
                machdep->flags & VM_L3_4K ? 
-               "arm64_vtop_3level_4k" : "arm64_vtop_2level_64k");
+               "arm64_vtop_3level_4k" :
+               machdep->flags & VM_L3_64K ?
+               "arm64_vtop_3level_64k" : "arm64_vtop_2level_64k");
        fprintf(fp, "        get_task_pgd: arm64_get_task_pgd()\n");
        fprintf(fp, "            dump_irq: generic_dump_irq()\n");
        fprintf(fp, "     get_stack_frame: arm64_get_stack_frame()\n");
@@ -719,10 +740,12 @@ arm64_kvtop(struct task_context *tc, ulong kvaddr, 
physaddr_t *paddr, int verbos
        kernel_pgd = vt->kernel_pgd[0];
        *paddr = 0;
 
-       switch (machdep->flags & (VM_L2_64K|VM_L3_4K))
+       switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K))
        {
        case VM_L2_64K:
                return arm64_vtop_2level_64k(kernel_pgd, kvaddr, paddr, 
verbose);
+       case VM_L3_64K:
+               return arm64_vtop_3level_64k(kernel_pgd, kvaddr, paddr, 
verbose);
        case VM_L3_4K:
                return arm64_vtop_3level_4k(kernel_pgd, kvaddr, paddr, verbose);
        default:
@@ -740,10 +763,12 @@ arm64_uvtop(struct task_context *tc, ulong uvaddr, 
physaddr_t *paddr, int verbos
 
        *paddr = 0;
 
-       switch (machdep->flags & (VM_L2_64K|VM_L3_4K))
+       switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K))
        {
        case VM_L2_64K:
                return arm64_vtop_2level_64k(user_pgd, uvaddr, paddr, verbose);
+       case VM_L3_64K:
+               return arm64_vtop_3level_64k(user_pgd, uvaddr, paddr, verbose);
        case VM_L3_4K:
                return arm64_vtop_3level_4k(user_pgd, uvaddr, paddr, verbose);
        default:
@@ -820,6 +845,78 @@ no_page:
        return FALSE;
 }
 
+static int
+arm64_vtop_3level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose)
+{
+       ulong *pgd_base, *pgd_ptr, pgd_val;
+       ulong *pmd_base, *pmd_ptr, pmd_val;
+       ulong *pte_base, *pte_ptr, pte_val;
+
+        if (verbose)
+                fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd);
+
+       pgd_base = (ulong *)pgd;
+       FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L3_64K * sizeof(ulong));
+       pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_64K) & 
(PTRS_PER_PGD_L3_64K - 1));
+        pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr));
+        if (verbose)
+                fprintf(fp, "   PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val);
+       if (!pgd_val)
+               goto no_page;
+
+       /*
+        * #define __PAGETABLE_PUD_FOLDED
+        */
+
+       pmd_base = (ulong *)PTOV(pgd_val & PHYS_MASK & (s32)machdep->pagemask);
+       FILL_PMD(pmd_base, KVADDR, PTRS_PER_PMD_L3_64K * sizeof(ulong));
+       pmd_ptr = pmd_base + (((vaddr) >> PMD_SHIFT_L3_64K) & 
(PTRS_PER_PMD_L3_64K - 1));
+        pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_ptr));
+        if (verbose)
+                fprintf(fp, "   PMD: %lx => %lx\n", (ulong)pmd_ptr, pmd_val);
+       if (!pmd_val)
+               goto no_page;
+
+       if ((pmd_val & PMD_TYPE_MASK) == PMD_TYPE_SECT) {
+               ulong sectionbase = (pmd_val & SECTION_PAGE_MASK_512MB) & 
PHYS_MASK;
+               if (verbose) {
+                       fprintf(fp, "  PAGE: %lx  (512MB)\n\n", sectionbase);
+                       arm64_translate_pte(pmd_val, 0, 0);
+               }
+               *paddr = sectionbase + (vaddr & ~SECTION_PAGE_MASK_512MB);
+               return TRUE;
+       }
+
+       pte_base = (ulong *)PTOV(pmd_val & PHYS_MASK & (s32)machdep->pagemask);
+       FILL_PTBL(pte_base, KVADDR, PTRS_PER_PTE_L3_64K * sizeof(ulong));
+       pte_ptr = pte_base + (((vaddr) >> machdep->pageshift) & 
(PTRS_PER_PTE_L3_64K - 1));
+        pte_val = ULONG(machdep->ptbl + PAGEOFFSET(pte_ptr));
+        if (verbose)
+                fprintf(fp, "   PTE: %lx => %lx\n", (ulong)pte_ptr, pte_val);
+       if (!pte_val)
+               goto no_page;
+
+       if (pte_val & PTE_VALID) {
+               *paddr = (PAGEBASE(pte_val) & PHYS_MASK) + PAGEOFFSET(vaddr);
+               if (verbose) {
+                       fprintf(fp, "  PAGE: %lx\n\n", PAGEBASE(*paddr));
+                       arm64_translate_pte(pte_val, 0, 0);
+               }
+       } else {
+               if (IS_UVADDR(vaddr, NULL))
+                       *paddr = pte_val;
+               if (verbose) {
+                       fprintf(fp, "\n");
+                       arm64_translate_pte(pte_val, 0, 0);
+               }
+               goto no_page;
+       }
+
+       return TRUE;
+no_page:
+       return FALSE;
+}
+
 static int 
 arm64_vtop_3level_4k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose)
 {
@@ -2348,9 +2445,10 @@ arm64_calc_virtual_memory_ranges(void)
 
        STRUCT_SIZE_INIT(page, "page");
 
-        switch (machdep->flags & (VM_L2_64K|VM_L3_4K))
+        switch (machdep->flags & (VM_L2_64K|VM_L3_64K|VM_L3_4K))
         {
         case VM_L2_64K:
+        case VM_L3_64K:
                PUD_SIZE = PGDIR_SIZE_L2_64K;
                break;
         case VM_L3_4K:
diff --git a/defs.h b/defs.h
index 56ae06c..d1b49d0 100644
--- a/defs.h
+++ b/defs.h
@@ -2815,7 +2815,7 @@ typedef u64 pte_t;
 
 typedef signed int s32;
 
-/* 
+/*
  * 3-levels / 4K pages
  */
 #define PTRS_PER_PGD_L3_4K   (512)
@@ -2823,10 +2823,23 @@ typedef signed int s32;
 #define PTRS_PER_PTE_L3_4K   (512)
 #define PGDIR_SHIFT_L3_4K    (30)
 #define PGDIR_SIZE_L3_4K     ((1UL) << PGDIR_SHIFT_L3_4K)
-#define PGDIR_MASK_L3 4K     (~(PGDIR_SIZE_L3_4K-1))
+#define PGDIR_MASK_L3_4K     (~(PGDIR_SIZE_L3_4K-1))
 #define PMD_SHIFT_L3_4K      (21)
-#define PMD_SIZE_L3_4K       (1UL << PMD_SHIFT_4K)
-#define PMD_MASK_L3 4K       (~(PMD_SIZE_4K-1))
+#define PMD_SIZE_L3_4K       (1UL << PMD_SHIFT_L3_4K)
+#define PMD_MASK_L3_4K       (~(PMD_SIZE_L3_4K-1))
+
+/*
+ * 3-levels / 64K pages
+ */
+#define PTRS_PER_PGD_L3_64K  (64)
+#define PTRS_PER_PMD_L3_64K  (8192)
+#define PTRS_PER_PTE_L3_64K  (8192)
+#define PGDIR_SHIFT_L3_64K   (42)
+#define PGDIR_SIZE_L3_64K    ((1UL) << PGDIR_SHIFT_L3_64K)
+#define PGDIR_MASK_L3_64K    (~(PGDIR_SIZE_L3_64K-1))
+#define PMD_SHIFT_L3_64K     (29)
+#define PMD_SIZE_L3_64K      (1UL << PMD_SHIFT_L3_64K)
+#define PMD_MASK_L3_64K      (~(PMD_SIZE_L3_64K-1))
 
 /*
  * 2-levels / 64K pages
@@ -2868,9 +2881,10 @@ typedef signed int s32;
 #define KSYMS_START   (0x1)
 #define PHYS_OFFSET   (0x2)
 #define VM_L2_64K     (0x4)
-#define VM_L3_4K      (0x8)
-#define KDUMP_ENABLED (0x10)
-#define IRQ_STACKS    (0x20)
+#define VM_L3_64K     (0x8)
+#define VM_L3_4K      (0x10)
+#define KDUMP_ENABLED (0x20)
+#define IRQ_STACKS    (0x40)
 
 /* 
  * sources: Documentation/arm64/memory.txt 
-- 
2.1.4

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to