Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/mm: Replace compile-time checks for 5-level paging with runtime-time checks

This patch converts the of CONFIG_X86_5LEVEL check to runtime checks for
p4d folding.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-mm@kvack.org
Link: http://lkml.kernel.org/r/20180214182542.69302-9-kirill.shutemov@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Kirill A. Shutemov and committed by
Ingo Molnar
91f606a8 98219dda

+46 -45
+10 -13
arch/x86/include/asm/pgtable_64.h
··· 217 217 218 218 static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) 219 219 { 220 - #if defined(CONFIG_PAGE_TABLE_ISOLATION) && !defined(CONFIG_X86_5LEVEL) 221 - p4dp->pgd = pti_set_user_pgd(&p4dp->pgd, p4d.pgd); 222 - #else 223 - *p4dp = p4d; 224 - #endif 220 + pgd_t pgd; 221 + 222 + if (pgtable_l5_enabled || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) { 223 + *p4dp = p4d; 224 + return; 225 + } 226 + 227 + pgd = native_make_pgd(p4d_val(p4d)); 228 + pgd = pti_set_user_pgd((pgd_t *)p4dp, pgd); 229 + *p4dp = native_make_p4d(pgd_val(pgd)); 225 230 } 226 231 227 232 static inline void native_p4d_clear(p4d_t *p4d) 228 233 { 229 - #ifdef CONFIG_X86_5LEVEL 230 234 native_set_p4d(p4d, native_make_p4d(0)); 231 - #else 232 - native_set_p4d(p4d, (p4d_t) { .pgd = native_make_pgd(0)}); 233 - #endif 234 235 } 235 236 236 237 static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) 237 238 { 238 - #ifdef CONFIG_PAGE_TABLE_ISOLATION 239 239 *pgdp = pti_set_user_pgd(pgdp, pgd); 240 - #else 241 - *pgdp = pgd; 242 - #endif 243 240 } 244 241 245 242 static inline void native_pgd_clear(pgd_t *pgd)
+1 -3
arch/x86/mm/dump_pagetables.c
··· 348 348 void *pt) 349 349 { 350 350 if (__pa(pt) == __pa(kasan_zero_pmd) || 351 - #ifdef CONFIG_X86_5LEVEL 352 - __pa(pt) == __pa(kasan_zero_p4d) || 353 - #endif 351 + (pgtable_l5_enabled && __pa(pt) == __pa(kasan_zero_p4d)) || 354 352 __pa(pt) == __pa(kasan_zero_pud)) { 355 353 pgprotval_t prot = pte_flags(kasan_zero_pte[0]); 356 354 note_page(m, st, __pgprot(prot), 5);
+2 -2
arch/x86/mm/fault.c
··· 439 439 if (pgd_none(*pgd_ref)) 440 440 return -1; 441 441 442 - if (CONFIG_PGTABLE_LEVELS > 4) { 442 + if (pgtable_l5_enabled) { 443 443 if (pgd_none(*pgd)) { 444 444 set_pgd(pgd, *pgd_ref); 445 445 arch_flush_lazy_mmu_mode(); ··· 454 454 if (p4d_none(*p4d_ref)) 455 455 return -1; 456 456 457 - if (p4d_none(*p4d) && CONFIG_PGTABLE_LEVELS == 4) { 457 + if (p4d_none(*p4d) && !pgtable_l5_enabled) { 458 458 set_p4d(p4d, *p4d_ref); 459 459 arch_flush_lazy_mmu_mode(); 460 460 } else {
+1 -1
arch/x86/mm/ident_map.c
··· 120 120 result = ident_p4d_init(info, p4d, addr, next); 121 121 if (result) 122 122 return result; 123 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) { 123 + if (pgtable_l5_enabled) { 124 124 set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag)); 125 125 } else { 126 126 /*
+18 -12
arch/x86/mm/init_64.c
··· 88 88 } 89 89 __setup("noexec32=", nonx32_setup); 90 90 91 - /* 92 - * When memory was added make sure all the processes MM have 93 - * suitable PGD entries in the local PGD level page. 94 - */ 95 - #ifdef CONFIG_X86_5LEVEL 96 - void sync_global_pgds(unsigned long start, unsigned long end) 91 + static void sync_global_pgds_l5(unsigned long start, unsigned long end) 97 92 { 98 93 unsigned long addr; 99 94 ··· 124 129 spin_unlock(&pgd_lock); 125 130 } 126 131 } 127 - #else 128 - void sync_global_pgds(unsigned long start, unsigned long end) 132 + 133 + static void sync_global_pgds_l4(unsigned long start, unsigned long end) 129 134 { 130 135 unsigned long addr; 131 136 ··· 168 173 spin_unlock(&pgd_lock); 169 174 } 170 175 } 171 - #endif 176 + 177 + /* 178 + * When memory was added make sure all the processes MM have 179 + * suitable PGD entries in the local PGD level page. 180 + */ 181 + void sync_global_pgds(unsigned long start, unsigned long end) 182 + { 183 + if (pgtable_l5_enabled) 184 + sync_global_pgds_l5(start, end); 185 + else 186 + sync_global_pgds_l4(start, end); 187 + } 172 188 173 189 /* 174 190 * NOTE: This function is marked __ref because it calls __init function ··· 638 632 unsigned long vaddr = (unsigned long)__va(paddr); 639 633 int i = p4d_index(vaddr); 640 634 641 - if (!IS_ENABLED(CONFIG_X86_5LEVEL)) 635 + if (!pgtable_l5_enabled) 642 636 return phys_pud_init((pud_t *) p4d_page, paddr, paddr_end, page_size_mask); 643 637 644 638 for (; i < PTRS_PER_P4D; i++, paddr = paddr_next) { ··· 718 712 page_size_mask); 719 713 720 714 spin_lock(&init_mm.page_table_lock); 721 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) 715 + if (pgtable_l5_enabled) 722 716 pgd_populate(&init_mm, pgd, p4d); 723 717 else 724 718 p4d_populate(&init_mm, p4d_offset(pgd, vaddr), (pud_t *) p4d); ··· 1099 1093 * 5-level case we should free them. This code will have to change 1100 1094 * to adapt for boot-time switching between 4 and 5 level page tables. 1101 1095 */ 1102 - if (CONFIG_PGTABLE_LEVELS == 5) 1096 + if (pgtable_l5_enabled) 1103 1097 free_pud_table(pud_base, p4d, altmap); 1104 1098 } 1105 1099
+6 -6
arch/x86/mm/kasan_init_64.c
··· 176 176 * With folded p4d, pgd_clear() is nop, use p4d_clear() 177 177 * instead. 178 178 */ 179 - if (CONFIG_PGTABLE_LEVELS < 5) 180 - p4d_clear(p4d_offset(pgd, start)); 181 - else 179 + if (pgtable_l5_enabled) 182 180 pgd_clear(pgd); 181 + else 182 + p4d_clear(p4d_offset(pgd, start)); 183 183 } 184 184 185 185 pgd = pgd_offset_k(start); ··· 191 191 { 192 192 unsigned long p4d; 193 193 194 - if (!IS_ENABLED(CONFIG_X86_5LEVEL)) 194 + if (!pgtable_l5_enabled) 195 195 return (p4d_t *)pgd; 196 196 197 197 p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK; ··· 272 272 for (i = 0; i < PTRS_PER_PUD; i++) 273 273 kasan_zero_pud[i] = __pud(pud_val); 274 274 275 - for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++) 275 + for (i = 0; pgtable_l5_enabled && i < PTRS_PER_P4D; i++) 276 276 kasan_zero_p4d[i] = __p4d(p4d_val); 277 277 278 278 kasan_map_early_shadow(early_top_pgt); ··· 303 303 * bunch of things like kernel code, modules, EFI mapping, etc. 304 304 * We need to take extra steps to not overwrite them. 305 305 */ 306 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) { 306 + if (pgtable_l5_enabled) { 307 307 void *ptr; 308 308 309 309 ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
+3 -3
arch/x86/mm/kaslr.c
··· 124 124 */ 125 125 entropy = remain_entropy / (ARRAY_SIZE(kaslr_regions) - i); 126 126 prandom_bytes_state(&rand_state, &rand, sizeof(rand)); 127 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) 127 + if (pgtable_l5_enabled) 128 128 entropy = (rand % (entropy + 1)) & P4D_MASK; 129 129 else 130 130 entropy = (rand % (entropy + 1)) & PUD_MASK; ··· 136 136 * randomization alignment. 137 137 */ 138 138 vaddr += get_padding(&kaslr_regions[i]); 139 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) 139 + if (pgtable_l5_enabled) 140 140 vaddr = round_up(vaddr + 1, P4D_SIZE); 141 141 else 142 142 vaddr = round_up(vaddr + 1, PUD_SIZE); ··· 212 212 return; 213 213 } 214 214 215 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) 215 + if (pgtable_l5_enabled) 216 216 init_trampoline_p4d(); 217 217 else 218 218 init_trampoline_pud();
+1 -1
arch/x86/mm/tlb.c
··· 157 157 unsigned long sp = current_stack_pointer; 158 158 pgd_t *pgd = pgd_offset(mm, sp); 159 159 160 - if (CONFIG_PGTABLE_LEVELS > 4) { 160 + if (pgtable_l5_enabled) { 161 161 if (unlikely(pgd_none(*pgd))) { 162 162 pgd_t *pgd_ref = pgd_offset_k(sp); 163 163
+1 -1
arch/x86/platform/efi/efi_64.c
··· 227 227 228 228 pud = pud_alloc(&init_mm, p4d, EFI_VA_END); 229 229 if (!pud) { 230 - if (CONFIG_PGTABLE_LEVELS > 4) 230 + if (pgtable_l5_enabled) 231 231 free_page((unsigned long) pgd_page_vaddr(*pgd)); 232 232 free_page((unsigned long)efi_pgd); 233 233 return -ENOMEM;
+3 -3
arch/x86/power/hibernate_64.c
··· 50 50 { 51 51 pmd_t *pmd; 52 52 pud_t *pud; 53 - p4d_t *p4d; 53 + p4d_t *p4d = NULL; 54 54 55 55 /* 56 56 * The new mapping only has to cover the page containing the image ··· 66 66 * tables used by the image kernel. 67 67 */ 68 68 69 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) { 69 + if (pgtable_l5_enabled) { 70 70 p4d = (p4d_t *)get_safe_page(GFP_ATOMIC); 71 71 if (!p4d) 72 72 return -ENOMEM; ··· 84 84 __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC)); 85 85 set_pud(pud + pud_index(restore_jump_address), 86 86 __pud(__pa(pmd) | _KERNPG_TABLE)); 87 - if (IS_ENABLED(CONFIG_X86_5LEVEL)) { 87 + if (p4d) { 88 88 set_p4d(p4d + p4d_index(restore_jump_address), __p4d(__pa(pud) | _KERNPG_TABLE)); 89 89 set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(p4d) | _KERNPG_TABLE)); 90 90 } else {