x86/kexec: Add 5-level paging support
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Fri, 17 Mar 2017 18:55:10 +0000 (21:55 +0300)
committerIngo Molnar <mingo@kernel.org>
Mon, 27 Mar 2017 06:56:13 +0000 (08:56 +0200)
Handle additional page table level in the kexec code.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-arch@vger.kernel.org
Cc: linux-mm@kvack.org
Link: http://lkml.kernel.org/r/20170317185515.8636-2-kirill.shutemov@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/kexec.h
arch/x86/kernel/machine_kexec_32.c
arch/x86/kernel/machine_kexec_64.c

index 282630e4c6ea4696e54c6ea650751d913ce49c11..70ef205489f00e53ff568180c4dcbf6fb9e6ded1 100644 (file)
@@ -164,6 +164,7 @@ struct kimage_arch {
 };
 #else
 struct kimage_arch {
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
index 469b23d6acc272b2113878182582d9fa7532f189..5f43cec296c5c38dc28a2a0c0e43aee91ee89934 100644 (file)
@@ -103,6 +103,7 @@ static void machine_kexec_page_table_set_one(
        pgd_t *pgd, pmd_t *pmd, pte_t *pte,
        unsigned long vaddr, unsigned long paddr)
 {
+       p4d_t *p4d;
        pud_t *pud;
 
        pgd += pgd_index(vaddr);
@@ -110,7 +111,8 @@ static void machine_kexec_page_table_set_one(
        if (!(pgd_val(*pgd) & _PAGE_PRESENT))
                set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT));
 #endif
-       pud = pud_offset(pgd, vaddr);
+       p4d = p4d_offset(pgd, vaddr);
+       pud = pud_offset(p4d, vaddr);
        pmd = pmd_offset(pud, vaddr);
        if (!(pmd_val(*pmd) & _PAGE_PRESENT))
                set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE));
index 857cdbd028675716afad71c0b48974399889e622..085c3b300d32e15faeb297028ad45ddb14513dd3 100644 (file)
@@ -36,6 +36,7 @@ static struct kexec_file_ops *kexec_file_loaders[] = {
 
 static void free_transition_pgtable(struct kimage *image)
 {
+       free_page((unsigned long)image->arch.p4d);
        free_page((unsigned long)image->arch.pud);
        free_page((unsigned long)image->arch.pmd);
        free_page((unsigned long)image->arch.pte);
@@ -43,6 +44,7 @@ static void free_transition_pgtable(struct kimage *image)
 
 static int init_transition_pgtable(struct kimage *image, pgd_t *pgd)
 {
+       p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
@@ -53,13 +55,21 @@ static int init_transition_pgtable(struct kimage *image, pgd_t *pgd)
        paddr = __pa(page_address(image->control_code_page)+PAGE_SIZE);
        pgd += pgd_index(vaddr);
        if (!pgd_present(*pgd)) {
+               p4d = (p4d_t *)get_zeroed_page(GFP_KERNEL);
+               if (!p4d)
+                       goto err;
+               image->arch.p4d = p4d;
+               set_pgd(pgd, __pgd(__pa(p4d) | _KERNPG_TABLE));
+       }
+       p4d = p4d_offset(pgd, vaddr);
+       if (!p4d_present(*p4d)) {
                pud = (pud_t *)get_zeroed_page(GFP_KERNEL);
                if (!pud)
                        goto err;
                image->arch.pud = pud;
-               set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
+               set_p4d(p4d, __p4d(__pa(pud) | _KERNPG_TABLE));
        }
-       pud = pud_offset(pgd, vaddr);
+       pud = pud_offset(p4d, vaddr);
        if (!pud_present(*pud)) {
                pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL);
                if (!pmd)