From: Dou Liyang <douly.f...@cn.fujitsu.com>

Now, kernel can use 5-level page tables in x86_64 system.

Add the 5-level paging support for makedumpfile.

Signed-off-by: Dou Liyang <douly.f...@cn.fujitsu.com>
---
 arch/x86_64.c  | 76 ++++++++++++++++++++++++++++++++++++++++++----------------
 makedumpfile.h | 17 +++++++++++++
 2 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/arch/x86_64.c b/arch/x86_64.c
index e88ee0b..b242f36 100644
--- a/arch/x86_64.c
+++ b/arch/x86_64.c
@@ -112,6 +112,8 @@ get_page_offset_x86_64(void)
 
        if (info->kernel_version < KERNEL_VERSION(2, 6, 27)) {
                info->page_offset = __PAGE_OFFSET_ORIG;
+       } else if(check_5level_paging()) {
+               info->page_offset = __PAGE_OFFSET_5LEVEL;
        } else {
                info->page_offset = __PAGE_OFFSET_2_6_27;
        }
@@ -243,6 +245,8 @@ get_versiondep_info_x86_64(void)
                info->max_physmem_bits  = _MAX_PHYSMEM_BITS_ORIG;
        else if (info->kernel_version < KERNEL_VERSION(2, 6, 31))
                info->max_physmem_bits  = _MAX_PHYSMEM_BITS_2_6_26;
+       else if(check_5level_paging())
+               info->max_physmem_bits  = _MAX_PHYSMEM_BITS_5LEVEL;
        else
                info->max_physmem_bits  = _MAX_PHYSMEM_BITS_2_6_31;
 
@@ -252,6 +256,9 @@ get_versiondep_info_x86_64(void)
        if (info->kernel_version < KERNEL_VERSION(2, 6, 31)) {
                info->vmemmap_start = VMEMMAP_START_ORIG;
                info->vmemmap_end   = VMEMMAP_END_ORIG;
+       } else if(check_5level_paging()) {
+               info->vmemmap_start = VMEMMAP_START_5LEVEL;
+               info->vmemmap_end   = VMEMMAP_END_5LEVEL;
        } else {
                info->vmemmap_start = VMEMMAP_START_2_6_31;
                info->vmemmap_end   = VMEMMAP_END_2_6_31;
@@ -268,6 +275,7 @@ __vtop4_x86_64(unsigned long vaddr, unsigned long pagetable)
 {
        unsigned long page_dir, pgd, pud_paddr, pud_pte, pmd_paddr, pmd_pte;
        unsigned long pte_paddr, pte;
+       unsigned long p4d_paddr, p4d_pte;
 
        /*
         * Get PGD.
@@ -278,23 +286,56 @@ __vtop4_x86_64(unsigned long vaddr, unsigned long 
pagetable)
                if (page_dir == NOT_PADDR)
                        return NOT_PADDR;
        }
-       page_dir += pgd_index(vaddr) * sizeof(unsigned long);
-       if (!readmem(PADDR, page_dir, &pgd, sizeof pgd)) {
-               ERRMSG("Can't get pgd (page_dir:%lx).\n", page_dir);
-               return NOT_PADDR;
-       }
-       if (info->vaddr_for_vtop == vaddr)
-               MSG("  PGD : %16lx => %16lx\n", page_dir, pgd);
 
-       if (!(pgd & _PAGE_PRESENT)) {
-               ERRMSG("Can't get a valid pgd.\n");
-               return NOT_PADDR;
+       if (check_5level_paging()) {
+               page_dir += pgd5_index(vaddr) * sizeof(unsigned long);
+               if (!readmem(PADDR, page_dir, &pgd, sizeof pgd)) {
+                       ERRMSG("Can't get pgd (page_dir:%lx).\n", page_dir);
+                       return NOT_PADDR;
+               }
+               if (info->vaddr_for_vtop == vaddr)
+                       MSG("  PGD : %16lx => %16lx\n", page_dir, pgd);
+
+               if (!(pgd & _PAGE_PRESENT)) {
+                       ERRMSG("Can't get a valid pgd.\n");
+                       return NOT_PADDR;
+               }
+               /*
+                * Get P4D.
+                */
+               p4d_paddr  = pgd & ENTRY_MASK;
+               p4d_paddr += p4d_index(vaddr) * sizeof(unsigned long);
+               if (!readmem(PADDR, p4d_paddr, &p4d_pte, sizeof p4d_pte)) {
+                       ERRMSG("Can't get p4d_pte (p4d_paddr:%lx).\n", 
p4d_paddr);
+                       return NOT_PADDR;
+               }
+               if (info->vaddr_for_vtop == vaddr)
+                       MSG("  P4D : %16lx => %16lx\n", p4d_paddr, p4d_pte);
+
+               if (!(p4d_pte & _PAGE_PRESENT)) {
+                       ERRMSG("Can't get a valid p4d_pte.\n");
+                       return NOT_PADDR;
+               }
+               pud_paddr  = p4d_pte & ENTRY_MASK;
+       }else {
+               page_dir += pgd_index(vaddr) * sizeof(unsigned long);
+               if (!readmem(PADDR, page_dir, &pgd, sizeof pgd)) {
+                       ERRMSG("Can't get pgd (page_dir:%lx).\n", page_dir);
+                       return NOT_PADDR;
+               }
+               if (info->vaddr_for_vtop == vaddr)
+                       MSG("  PGD : %16lx => %16lx\n", page_dir, pgd);
+
+               if (!(pgd & _PAGE_PRESENT)) {
+                       ERRMSG("Can't get a valid pgd.\n");
+                       return NOT_PADDR;
+               }
+               pud_paddr  = pgd & ENTRY_MASK;
        }
 
        /*
         * Get PUD.
         */
-       pud_paddr  = pgd & ENTRY_MASK;
        pud_paddr += pud_index(vaddr) * sizeof(unsigned long);
        if (!readmem(PADDR, pud_paddr, &pud_pte, sizeof pud_pte)) {
                ERRMSG("Can't get pud_pte (pud_paddr:%lx).\n", pud_paddr);
@@ -361,12 +402,7 @@ vtop4_x86_64(unsigned long vaddr)
        else if (SYMBOL(init_top_pgt) != NOT_FOUND_SYMBOL)
                init_level4_pgt = SYMBOL(init_top_pgt);
        else {
-               ERRMSG("Can't get the symbol of init_level4_pgt.\n");
-               return NOT_PADDR;
-       }
-
-       if (SYMBOL(level4_kernel_pgt) != NOT_FOUND_SYMBOL) {
-               ERRMSG("Kernel is built with 5-level page tables\n");
+               ERRMSG("Can't get the symbol of 
init_level4_pgt/init_top_pgt.\n");
                return NOT_PADDR;
        }
 
@@ -605,10 +641,6 @@ find_vmemmap_x86_64()
                return FAILED;
        }
 
-       if (SYMBOL(level4_kernel_pgt) != NOT_FOUND_SYMBOL) {
-               ERRMSG("kernel is configured for 5-level page tables\n");
-               return FAILED;
-       }
        pagestructsize = size_table.page;
        hugepagesize = PTRS_PER_PMD * info->page_size;
        vaddr_base = info->vmemmap_start;
@@ -630,12 +662,14 @@ find_vmemmap_x86_64()
        /* outer loop is for pud entries in the pgd */
        for (pgdindex = 0, pgdp = (unsigned long *)pgd_addr; pgdindex < 
num_puds;
                                                                pgdindex++, 
pgdp++) {
+
                /* read the pgd one word at a time, into pud_addr */
                if (!readmem(PADDR, (unsigned long long)pgdp, (void *)&pud_addr,
                                                                sizeof(unsigned 
long))) {
                        ERRMSG("Can't get pgd entry for slot %d.\n", pgd_index);
                        return FAILED;
                }
+
                /* mask the pgd entry for the address of the pud page */
                pud_addr &= PMASK;
                if (pud_addr == 0)
diff --git a/makedumpfile.h b/makedumpfile.h
index a0d1c13..d26c30b 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -581,16 +581,21 @@ unsigned long get_kvbase_arm64(void);
 #ifdef __x86_64__
 #define __PAGE_OFFSET_ORIG     (0xffff810000000000) /* 2.6.26, or former */
 #define __PAGE_OFFSET_2_6_27   (0xffff880000000000) /* 2.6.27, or later  */
+#define __PAGE_OFFSET_5LEVEL   (0xff10000000000000) /* 5-level page table */
 
 #define VMALLOC_START_ORIG     (0xffffc20000000000) /* 2.6.30, or former */
 #define VMALLOC_START_2_6_31   (0xffffc90000000000) /* 2.6.31, or later  */
+#define VMALLOC_START_5LEVEL   (0xffa0000000000000) /* 5-level page table */
 #define VMALLOC_END_ORIG       (0xffffe1ffffffffff) /* 2.6.30, or former */
 #define VMALLOC_END_2_6_31     (0xffffe8ffffffffff) /* 2.6.31, or later  */
+#define VMALLOC_END_5LEVEL     (0xffd1ffffffffffff) /* 5-level page table */
 
 #define VMEMMAP_START_ORIG     (0xffffe20000000000) /* 2.6.30, or former */
 #define VMEMMAP_START_2_6_31   (0xffffea0000000000) /* 2.6.31, or later  */
+#define VMEMMAP_START_5LEVEL   (0xffd4000000000000) /* 5-level page table */
 #define VMEMMAP_END_ORIG       (0xffffe2ffffffffff) /* 2.6.30, or former */
 #define VMEMMAP_END_2_6_31     (0xffffeaffffffffff) /* 2.6.31, or later  */
+#define VMEMMAP_END_5LEVEL     (0xffd5ffffffffffff) /* 5-level page table */
 
 #define __START_KERNEL_map     (0xffffffff80000000)
 #define KVBASE                 PAGE_OFFSET
@@ -598,6 +603,7 @@ unsigned long get_kvbase_arm64(void);
 #define _MAX_PHYSMEM_BITS_ORIG         (40)
 #define _MAX_PHYSMEM_BITS_2_6_26       (44)
 #define _MAX_PHYSMEM_BITS_2_6_31       (46)
+#define _MAX_PHYSMEM_BITS_5LEVEL       (52)
 
 /*
  * 4 Levels paging
@@ -617,7 +623,18 @@ unsigned long get_kvbase_arm64(void);
 #define PMD_SIZE               (1UL << PMD_SHIFT)
 #define PMD_MASK               (~(PMD_SIZE - 1))
 
+/*
+ * 5 Levels paging
+ */
+#define PGD_SHIFT_5LEVEL       (48)
+#define P4D_SHIFT              (39)
+
+#define PTRS_PER_PGD_5LEVEL    (512)
+#define PTRS_PER_P4D           (512)
+
+#define pgd5_index(address)  (((address) >> PGD_SHIFT_5LEVEL) & 
(PTRS_PER_PGD_5LEVEL - 1))
 #define pgd_index(address)  (((address) >> PGD_SHIFT) & (PTRS_PER_PGD - 1))
+#define p4d_index(address)  (((address) >> P4D_SHIFT) & (PTRS_PER_P4D - 1))
 #define pud_index(address)  (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
 #define pmd_index(address)  (((address) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
 #define pte_index(address)  (((address) >> PTE_SHIFT) & (PTRS_PER_PTE - 1))
-- 
2.13.6


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to