]> Git Repo - linux.git/commitdiff
Merge branch 'x86-boot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 26 Jul 2016 00:32:28 +0000 (17:32 -0700)
committerLinus Torvalds <[email protected]>
Tue, 26 Jul 2016 00:32:28 +0000 (17:32 -0700)
Pull x86 boot updates from Ingo Molnar:
 "The main changes:

   - add initial commits to randomize kernel memory section virtual
     addresses, enabled via a new kernel option: RANDOMIZE_MEMORY
     (Thomas Garnier, Kees Cook, Baoquan He, Yinghai Lu)

   - enhance KASLR (RANDOMIZE_BASE) physical memory randomization (Kees
     Cook)

   - EBDA/BIOS region boot quirk cleanups (Andy Lutomirski, Ingo Molnar)

   - misc cleanups/fixes"

* 'x86-boot-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/boot: Simplify EBDA-vs-BIOS reservation logic
  x86/boot: Clarify what x86_legacy_features.reserve_bios_regions does
  x86/boot: Reorganize and clean up the BIOS area reservation code
  x86/mm: Do not reference phys addr beyond kernel
  x86/mm: Add memory hotplug support for KASLR memory randomization
  x86/mm: Enable KASLR for vmalloc memory regions
  x86/mm: Enable KASLR for physical mapping memory regions
  x86/mm: Implement ASLR for kernel memory regions
  x86/mm: Separate variable for trampoline PGD
  x86/mm: Add PUD VA support for physical mapping
  x86/mm: Update physical mapping variable names
  x86/mm: Refactor KASLR entropy functions
  x86/KASLR: Fix boot crash with certain memory configurations
  x86/boot/64: Add forgotten end of function marker
  x86/KASLR: Allow randomization below the load address
  x86/KASLR: Extend kernel image physical address randomization to addresses larger than 4G
  x86/KASLR: Randomize virtual address separately
  x86/KASLR: Clarify identity map interface
  x86/boot: Refuse to build with data relocations
  x86/KASLR, x86/power: Remove x86 hibernation restrictions

1  2 
arch/x86/Kconfig
arch/x86/include/asm/pgtable.h
arch/x86/lib/Makefile
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c

diff --combined arch/x86/Kconfig
index df884a522c396527ba76aeca4781ba3b0c10557c,703413fb233a184941bbb702b01ea662b1f9af8b..51b028c1ca96402fd95a6ca9dcaddd0b99b94eda
@@@ -294,6 -294,11 +294,6 @@@ config X86_32_LAZY_G
        def_bool y
        depends on X86_32 && !CC_STACKPROTECTOR
  
 -config ARCH_HWEIGHT_CFLAGS
 -      string
 -      default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
 -      default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
 -
  config ARCH_SUPPORTS_UPROBES
        def_bool y
  
@@@ -1929,21 -1934,26 +1929,26 @@@ config RANDOMIZE_BAS
          attempts relying on knowledge of the location of kernel
          code internals.
  
-         The kernel physical and virtual address can be randomized
-         from 16MB up to 1GB on 64-bit and 512MB on 32-bit. (Note that
-         using RANDOMIZE_BASE reduces the memory space available to
-         kernel modules from 1.5GB to 1GB.)
+         On 64-bit, the kernel physical and virtual addresses are
+         randomized separately. The physical address will be anywhere
+         between 16MB and the top of physical memory (up to 64TB). The
+         virtual address will be randomized from 16MB up to 1GB (9 bits
+         of entropy). Note that this also reduces the memory space
+         available to kernel modules from 1.5GB to 1GB.
+         On 32-bit, the kernel physical and virtual addresses are
+         randomized together. They will be randomized from 16MB up to
+         512MB (8 bits of entropy).
  
          Entropy is generated using the RDRAND instruction if it is
          supported. If RDTSC is supported, its value is mixed into
          the entropy pool as well. If neither RDRAND nor RDTSC are
-         supported, then entropy is read from the i8254 timer.
-         Since the kernel is built using 2GB addressing, and
-         PHYSICAL_ALIGN must be at a minimum of 2MB, only 10 bits of
-         entropy is theoretically possible. Currently, with the
-         default value for PHYSICAL_ALIGN and due to page table
-         layouts, 64-bit uses 9 bits of entropy and 32-bit uses 8 bits.
+         supported, then entropy is read from the i8254 timer. The
+         usable entropy is limited by the kernel being built using
+         2GB addressing, and that PHYSICAL_ALIGN must be at a
+         minimum of 2MB. As a result, only 10 bits of entropy are
+         theoretically possible, but the implementations are further
+         limited due to memory layouts.
  
          If CONFIG_HIBERNATE is also enabled, KASLR is disabled at boot
          time. To enable it, boot with "kaslr" on the kernel command
@@@ -1983,6 -1993,38 +1988,38 @@@ config PHYSICAL_ALIG
  
          Don't change this unless you know what you are doing.
  
+ config RANDOMIZE_MEMORY
+       bool "Randomize the kernel memory sections"
+       depends on X86_64
+       depends on RANDOMIZE_BASE
+       default RANDOMIZE_BASE
+       ---help---
+          Randomizes the base virtual address of kernel memory sections
+          (physical memory mapping, vmalloc & vmemmap). This security feature
+          makes exploits relying on predictable memory locations less reliable.
+          The order of allocations remains unchanged. Entropy is generated in
+          the same way as RANDOMIZE_BASE. Current implementation in the optimal
+          configuration have in average 30,000 different possible virtual
+          addresses for each memory section.
+          If unsure, say N.
+ config RANDOMIZE_MEMORY_PHYSICAL_PADDING
+       hex "Physical memory mapping padding" if EXPERT
+       depends on RANDOMIZE_MEMORY
+       default "0xa" if MEMORY_HOTPLUG
+       default "0x0"
+       range 0x1 0x40 if MEMORY_HOTPLUG
+       range 0x0 0x40
+       ---help---
+          Define the padding in terabytes added to the existing physical
+          memory size during kernel memory randomization. It is useful
+          for memory hotplug support but reduces the entropy available for
+          address randomization.
+          If unsure, leave at the default value.
  config HOTPLUG_CPU
        bool "Support for hot-pluggable CPUs"
        depends on SMP
index 2815d268af8bb797f21b0acee2cd16fd8874eec4,5472682a307f53abcf476a94d8b75384477b7bf5..437feb436efa666dbe13732c7d4269160fed49e3
@@@ -480,7 -480,7 +480,7 @@@ pte_t *populate_extra_pte(unsigned lon
  
  static inline int pte_none(pte_t pte)
  {
 -      return !pte.pte;
 +      return !(pte.pte & ~(_PAGE_KNL_ERRATUM_MASK));
  }
  
  #define __HAVE_ARCH_PTE_SAME
@@@ -552,8 -552,7 +552,8 @@@ static inline int pmd_none(pmd_t pmd
  {
        /* Only check low word on 32-bit platforms, since it might be
           out of sync with upper half. */
 -      return (unsigned long)native_pmd_val(pmd) == 0;
 +      unsigned long val = native_pmd_val(pmd);
 +      return (val & ~_PAGE_KNL_ERRATUM_MASK) == 0;
  }
  
  static inline unsigned long pmd_page_vaddr(pmd_t pmd)
@@@ -617,7 -616,7 +617,7 @@@ static inline unsigned long pages_to_mb
  #if CONFIG_PGTABLE_LEVELS > 2
  static inline int pud_none(pud_t pud)
  {
 -      return native_pud_val(pud) == 0;
 +      return (native_pud_val(pud) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0;
  }
  
  static inline int pud_present(pud_t pud)
@@@ -695,12 -694,6 +695,12 @@@ static inline int pgd_bad(pgd_t pgd
  
  static inline int pgd_none(pgd_t pgd)
  {
 +      /*
 +       * There is no need to do a workaround for the KNL stray
 +       * A/D bit erratum here.  PGDs only point to page tables
 +       * except on 32-bit non-PAE which is not supported on
 +       * KNL.
 +       */
        return !native_pgd_val(pgd);
  }
  #endif        /* CONFIG_PGTABLE_LEVELS > 3 */
@@@ -736,6 -729,23 +736,23 @@@ extern int direct_gbpages
  void init_mem_mapping(void);
  void early_alloc_pgt_buf(void);
  
+ #ifdef CONFIG_X86_64
+ /* Realmode trampoline initialization. */
+ extern pgd_t trampoline_pgd_entry;
+ static inline void __meminit init_trampoline_default(void)
+ {
+       /* Default trampoline pgd value */
+       trampoline_pgd_entry = init_level4_pgt[pgd_index(__PAGE_OFFSET)];
+ }
+ # ifdef CONFIG_RANDOMIZE_MEMORY
+ void __meminit init_trampoline(void);
+ # else
+ #  define init_trampoline init_trampoline_default
+ # endif
+ #else
+ static inline void init_trampoline(void) { }
+ #endif
  /* local pte updates need not use xchg for locking */
  static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
  {
diff --combined arch/x86/lib/Makefile
index ec969cc3eb20e9c03c24b90130cbe78c5969e9a4,cfa6d076f4f22b0fa0f9657b5a29cd3aed9edb45..34a74131a12c58ef9f38712261900093b53220f1
@@@ -24,8 -24,9 +24,9 @@@ lib-y += usercopy_$(BITS).o usercopy.o 
  lib-y += memcpy_$(BITS).o
  lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
  lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
+ lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o
  
 -obj-y += msr.o msr-reg.o msr-reg-export.o
 +obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o
  
  ifeq ($(CONFIG_X86_32),y)
          obj-y += atomic64_32.o
diff --combined arch/x86/mm/init_64.c
index e14f87057c3f807a49faf45d5259fdfff18cf7dd,7bf1ddb54537472db71bd7913ce26f5d8da76f33..53cc2256cf239a54be55f3b552b788350ddf3a25
@@@ -328,22 -328,30 +328,30 @@@ void __init cleanup_highmap(void
        }
  }
  
+ /*
+  * Create PTE level page table mapping for physical addresses.
+  * It returns the last physical address mapped.
+  */
  static unsigned long __meminit
- phys_pte_init(pte_t *pte_page, unsigned long addr, unsigned long end,
+ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end,
              pgprot_t prot)
  {
-       unsigned long pages = 0, next;
-       unsigned long last_map_addr = end;
+       unsigned long pages = 0, paddr_next;
+       unsigned long paddr_last = paddr_end;
+       pte_t *pte;
        int i;
  
-       pte_t *pte = pte_page + pte_index(addr);
+       pte = pte_page + pte_index(paddr);
+       i = pte_index(paddr);
  
-       for (i = pte_index(addr); i < PTRS_PER_PTE; i++, addr = next, pte++) {
-               next = (addr & PAGE_MASK) + PAGE_SIZE;
-               if (addr >= end) {
+       for (; i < PTRS_PER_PTE; i++, paddr = paddr_next, pte++) {
+               paddr_next = (paddr & PAGE_MASK) + PAGE_SIZE;
+               if (paddr >= paddr_end) {
                        if (!after_bootmem &&
-                           !e820_any_mapped(addr & PAGE_MASK, next, E820_RAM) &&
-                           !e820_any_mapped(addr & PAGE_MASK, next, E820_RESERVED_KERN))
+                           !e820_any_mapped(paddr & PAGE_MASK, paddr_next,
+                                            E820_RAM) &&
+                           !e820_any_mapped(paddr & PAGE_MASK, paddr_next,
+                                            E820_RESERVED_KERN))
                                set_pte(pte, __pte(0));
                        continue;
                }
                 * pagetable pages as RO. So assume someone who pre-setup
                 * these mappings are more intelligent.
                 */
 -              if (pte_val(*pte)) {
 +              if (!pte_none(*pte)) {
                        if (!after_bootmem)
                                pages++;
                        continue;
                }
  
                if (0)
-                       printk("   pte=%p addr=%lx pte=%016lx\n",
-                              pte, addr, pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL).pte);
+                       pr_info("   pte=%p addr=%lx pte=%016lx\n", pte, paddr,
+                               pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL).pte);
                pages++;
-               set_pte(pte, pfn_pte(addr >> PAGE_SHIFT, prot));
-               last_map_addr = (addr & PAGE_MASK) + PAGE_SIZE;
+               set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, prot));
+               paddr_last = (paddr & PAGE_MASK) + PAGE_SIZE;
        }
  
        update_page_count(PG_LEVEL_4K, pages);
  
-       return last_map_addr;
+       return paddr_last;
  }
  
+ /*
+  * Create PMD level page table mapping for physical addresses. The virtual
+  * and physical address have to be aligned at this level.
+  * It returns the last physical address mapped.
+  */
  static unsigned long __meminit
- phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
+ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end,
              unsigned long page_size_mask, pgprot_t prot)
  {
-       unsigned long pages = 0, next;
-       unsigned long last_map_addr = end;
+       unsigned long pages = 0, paddr_next;
+       unsigned long paddr_last = paddr_end;
  
-       int i = pmd_index(address);
+       int i = pmd_index(paddr);
  
-       for (; i < PTRS_PER_PMD; i++, address = next) {
-               pmd_t *pmd = pmd_page + pmd_index(address);
+       for (; i < PTRS_PER_PMD; i++, paddr = paddr_next) {
+               pmd_t *pmd = pmd_page + pmd_index(paddr);
                pte_t *pte;
                pgprot_t new_prot = prot;
  
-               next = (address & PMD_MASK) + PMD_SIZE;
-               if (address >= end) {
+               paddr_next = (paddr & PMD_MASK) + PMD_SIZE;
+               if (paddr >= paddr_end) {
                        if (!after_bootmem &&
-                           !e820_any_mapped(address & PMD_MASK, next, E820_RAM) &&
-                           !e820_any_mapped(address & PMD_MASK, next, E820_RESERVED_KERN))
+                           !e820_any_mapped(paddr & PMD_MASK, paddr_next,
+                                            E820_RAM) &&
+                           !e820_any_mapped(paddr & PMD_MASK, paddr_next,
+                                            E820_RESERVED_KERN))
                                set_pmd(pmd, __pmd(0));
                        continue;
                }
  
 -              if (pmd_val(*pmd)) {
 +              if (!pmd_none(*pmd)) {
                        if (!pmd_large(*pmd)) {
                                spin_lock(&init_mm.page_table_lock);
                                pte = (pte_t *)pmd_page_vaddr(*pmd);
-                               last_map_addr = phys_pte_init(pte, address,
-                                                               end, prot);
+                               paddr_last = phys_pte_init(pte, paddr,
+                                                          paddr_end, prot);
                                spin_unlock(&init_mm.page_table_lock);
                                continue;
                        }
                        if (page_size_mask & (1 << PG_LEVEL_2M)) {
                                if (!after_bootmem)
                                        pages++;
-                               last_map_addr = next;
+                               paddr_last = paddr_next;
                                continue;
                        }
                        new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
                        set_pte((pte_t *)pmd,
-                               pfn_pte((address & PMD_MASK) >> PAGE_SHIFT,
+                               pfn_pte((paddr & PMD_MASK) >> PAGE_SHIFT,
                                        __pgprot(pgprot_val(prot) | _PAGE_PSE)));
                        spin_unlock(&init_mm.page_table_lock);
-                       last_map_addr = next;
+                       paddr_last = paddr_next;
                        continue;
                }
  
                pte = alloc_low_page();
-               last_map_addr = phys_pte_init(pte, address, end, new_prot);
+               paddr_last = phys_pte_init(pte, paddr, paddr_end, new_prot);
  
                spin_lock(&init_mm.page_table_lock);
                pmd_populate_kernel(&init_mm, pmd, pte);
                spin_unlock(&init_mm.page_table_lock);
        }
        update_page_count(PG_LEVEL_2M, pages);
-       return last_map_addr;
+       return paddr_last;
  }
  
+ /*
+  * Create PUD level page table mapping for physical addresses. The virtual
+  * and physical address do not have to be aligned at this level. KASLR can
+  * randomize virtual addresses up to this level.
+  * It returns the last physical address mapped.
+  */
  static unsigned long __meminit
- phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
-                        unsigned long page_size_mask)
+ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end,
+             unsigned long page_size_mask)
  {
-       unsigned long pages = 0, next;
-       unsigned long last_map_addr = end;
-       int i = pud_index(addr);
+       unsigned long pages = 0, paddr_next;
+       unsigned long paddr_last = paddr_end;
+       unsigned long vaddr = (unsigned long)__va(paddr);
+       int i = pud_index(vaddr);
  
-       for (; i < PTRS_PER_PUD; i++, addr = next) {
-               pud_t *pud = pud_page + pud_index(addr);
+       for (; i < PTRS_PER_PUD; i++, paddr = paddr_next) {
+               pud_t *pud;
                pmd_t *pmd;
                pgprot_t prot = PAGE_KERNEL;
  
-               next = (addr & PUD_MASK) + PUD_SIZE;
-               if (addr >= end) {
+               vaddr = (unsigned long)__va(paddr);
+               pud = pud_page + pud_index(vaddr);
+               paddr_next = (paddr & PUD_MASK) + PUD_SIZE;
+               if (paddr >= paddr_end) {
                        if (!after_bootmem &&
-                           !e820_any_mapped(addr & PUD_MASK, next, E820_RAM) &&
-                           !e820_any_mapped(addr & PUD_MASK, next, E820_RESERVED_KERN))
+                           !e820_any_mapped(paddr & PUD_MASK, paddr_next,
+                                            E820_RAM) &&
+                           !e820_any_mapped(paddr & PUD_MASK, paddr_next,
+                                            E820_RESERVED_KERN))
                                set_pud(pud, __pud(0));
                        continue;
                }
  
 -              if (pud_val(*pud)) {
 +              if (!pud_none(*pud)) {
                        if (!pud_large(*pud)) {
                                pmd = pmd_offset(pud, 0);
-                               last_map_addr = phys_pmd_init(pmd, addr, end,
-                                                        page_size_mask, prot);
+                               paddr_last = phys_pmd_init(pmd, paddr,
+                                                          paddr_end,
+                                                          page_size_mask,
+                                                          prot);
                                __flush_tlb_all();
                                continue;
                        }
                        if (page_size_mask & (1 << PG_LEVEL_1G)) {
                                if (!after_bootmem)
                                        pages++;
-                               last_map_addr = next;
+                               paddr_last = paddr_next;
                                continue;
                        }
                        prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
                        pages++;
                        spin_lock(&init_mm.page_table_lock);
                        set_pte((pte_t *)pud,
-                               pfn_pte((addr & PUD_MASK) >> PAGE_SHIFT,
+                               pfn_pte((paddr & PUD_MASK) >> PAGE_SHIFT,
                                        PAGE_KERNEL_LARGE));
                        spin_unlock(&init_mm.page_table_lock);
-                       last_map_addr = next;
+                       paddr_last = paddr_next;
                        continue;
                }
  
                pmd = alloc_low_page();
-               last_map_addr = phys_pmd_init(pmd, addr, end, page_size_mask,
-                                             prot);
+               paddr_last = phys_pmd_init(pmd, paddr, paddr_end,
+                                          page_size_mask, prot);
  
                spin_lock(&init_mm.page_table_lock);
                pud_populate(&init_mm, pud, pmd);
  
        update_page_count(PG_LEVEL_1G, pages);
  
-       return last_map_addr;
+       return paddr_last;
  }
  
+ /*
+  * Create page table mapping for the physical memory for specific physical
+  * addresses. The virtual and physical addresses have to be aligned on PMD level
+  * down. It returns the last physical address mapped.
+  */
  unsigned long __meminit
- kernel_physical_mapping_init(unsigned long start,
-                            unsigned long end,
+ kernel_physical_mapping_init(unsigned long paddr_start,
+                            unsigned long paddr_end,
                             unsigned long page_size_mask)
  {
        bool pgd_changed = false;
-       unsigned long next, last_map_addr = end;
-       unsigned long addr;
+       unsigned long vaddr, vaddr_start, vaddr_end, vaddr_next, paddr_last;
  
-       start = (unsigned long)__va(start);
-       end = (unsigned long)__va(end);
-       addr = start;
+       paddr_last = paddr_end;
+       vaddr = (unsigned long)__va(paddr_start);
+       vaddr_end = (unsigned long)__va(paddr_end);
+       vaddr_start = vaddr;
  
-       for (; start < end; start = next) {
-               pgd_t *pgd = pgd_offset_k(start);
+       for (; vaddr < vaddr_end; vaddr = vaddr_next) {
+               pgd_t *pgd = pgd_offset_k(vaddr);
                pud_t *pud;
  
-               next = (start & PGDIR_MASK) + PGDIR_SIZE;
+               vaddr_next = (vaddr & PGDIR_MASK) + PGDIR_SIZE;
  
                if (pgd_val(*pgd)) {
                        pud = (pud_t *)pgd_page_vaddr(*pgd);
-                       last_map_addr = phys_pud_init(pud, __pa(start),
-                                                __pa(end), page_size_mask);
+                       paddr_last = phys_pud_init(pud, __pa(vaddr),
+                                                  __pa(vaddr_end),
+                                                  page_size_mask);
                        continue;
                }
  
                pud = alloc_low_page();
-               last_map_addr = phys_pud_init(pud, __pa(start), __pa(end),
-                                                page_size_mask);
+               paddr_last = phys_pud_init(pud, __pa(vaddr), __pa(vaddr_end),
+                                          page_size_mask);
  
                spin_lock(&init_mm.page_table_lock);
                pgd_populate(&init_mm, pgd, pud);
        }
  
        if (pgd_changed)
-               sync_global_pgds(addr, end - 1, 0);
+               sync_global_pgds(vaddr_start, vaddr_end - 1, 0);
  
        __flush_tlb_all();
  
-       return last_map_addr;
+       return paddr_last;
  }
  
  #ifndef CONFIG_NUMA
@@@ -673,7 -708,7 +708,7 @@@ static void __meminit free_pte_table(pt
  
        for (i = 0; i < PTRS_PER_PTE; i++) {
                pte = pte_start + i;
 -              if (pte_val(*pte))
 +              if (!pte_none(*pte))
                        return;
        }
  
@@@ -691,7 -726,7 +726,7 @@@ static void __meminit free_pmd_table(pm
  
        for (i = 0; i < PTRS_PER_PMD; i++) {
                pmd = pmd_start + i;
 -              if (pmd_val(*pmd))
 +              if (!pmd_none(*pmd))
                        return;
        }
  
        spin_unlock(&init_mm.page_table_lock);
  }
  
 -/* Return true if pgd is changed, otherwise return false. */
 -static bool __meminit free_pud_table(pud_t *pud_start, pgd_t *pgd)
 -{
 -      pud_t *pud;
 -      int i;
 -
 -      for (i = 0; i < PTRS_PER_PUD; i++) {
 -              pud = pud_start + i;
 -              if (pud_val(*pud))
 -                      return false;
 -      }
 -
 -      /* free a pud table */
 -      free_pagetable(pgd_page(*pgd), 0);
 -      spin_lock(&init_mm.page_table_lock);
 -      pgd_clear(pgd);
 -      spin_unlock(&init_mm.page_table_lock);
 -
 -      return true;
 -}
 -
  static void __meminit
  remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
                 bool direct)
@@@ -892,6 -948,7 +927,6 @@@ remove_pagetable(unsigned long start, u
        unsigned long addr;
        pgd_t *pgd;
        pud_t *pud;
 -      bool pgd_changed = false;
  
        for (addr = start; addr < end; addr = next) {
                next = pgd_addr_end(addr, end);
  
                pud = (pud_t *)pgd_page_vaddr(*pgd);
                remove_pud_table(pud, addr, next, direct);
 -              if (free_pud_table(pud, pgd))
 -                      pgd_changed = true;
        }
  
 -      if (pgd_changed)
 -              sync_global_pgds(start, end - 1, 1);
 -
        flush_tlb_all();
  }
  
diff --combined arch/x86/mm/pageattr.c
index 47870a534877c59e0580c74f54095d6db0ccfc83,379b5111ac6b904915086e735b9502855cb04f3d..849dc09fa4f0b803b7139015de6b98f7778165bd
@@@ -101,7 -101,8 +101,8 @@@ static inline unsigned long highmap_sta
  
  static inline unsigned long highmap_end_pfn(void)
  {
-       return __pa_symbol(roundup(_brk_end, PMD_SIZE)) >> PAGE_SHIFT;
+       /* Do not reference physical address outside the kernel. */
+       return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT;
  }
  
  #endif
@@@ -112,6 -113,12 +113,12 @@@ within(unsigned long addr, unsigned lon
        return addr >= start && addr < end;
  }
  
+ static inline int
+ within_inclusive(unsigned long addr, unsigned long start, unsigned long end)
+ {
+       return addr >= start && addr <= end;
+ }
  /*
   * Flushing functions
   */
@@@ -746,6 -753,18 +753,6 @@@ static bool try_to_free_pmd_page(pmd_t 
        return true;
  }
  
 -static bool try_to_free_pud_page(pud_t *pud)
 -{
 -      int i;
 -
 -      for (i = 0; i < PTRS_PER_PUD; i++)
 -              if (!pud_none(pud[i]))
 -                      return false;
 -
 -      free_page((unsigned long)pud);
 -      return true;
 -}
 -
  static bool unmap_pte_range(pmd_t *pmd, unsigned long start, unsigned long end)
  {
        pte_t *pte = pte_offset_kernel(pmd, start);
@@@ -859,6 -878,16 +866,6 @@@ static void unmap_pud_range(pgd_t *pgd
         */
  }
  
 -static void unmap_pgd_range(pgd_t *root, unsigned long addr, unsigned long end)
 -{
 -      pgd_t *pgd_entry = root + pgd_index(addr);
 -
 -      unmap_pud_range(pgd_entry, addr, end);
 -
 -      if (try_to_free_pud_page((pud_t *)pgd_page_vaddr(*pgd_entry)))
 -              pgd_clear(pgd_entry);
 -}
 -
  static int alloc_pte_page(pmd_t *pmd)
  {
        pte_t *pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_NOTRACK);
@@@ -1091,12 -1120,7 +1098,12 @@@ static int populate_pgd(struct cpa_dat
  
        ret = populate_pud(cpa, addr, pgd_entry, pgprot);
        if (ret < 0) {
 -              unmap_pgd_range(cpa->pgd, addr,
 +              /*
 +               * Leave the PUD page in place in case some other CPU or thread
 +               * already found it, but remove any useless entries we just
 +               * added to it.
 +               */
 +              unmap_pud_range(pgd_entry, addr,
                                addr + (cpa->numpages << PAGE_SHIFT));
                return ret;
        }
@@@ -1168,7 -1192,7 +1175,7 @@@ repeat
                return __cpa_process_fault(cpa, address, primary);
  
        old_pte = *kpte;
 -      if (!pte_val(old_pte))
 +      if (pte_none(old_pte))
                return __cpa_process_fault(cpa, address, primary);
  
        if (level == PG_LEVEL_4K) {
@@@ -1299,7 -1323,8 +1306,8 @@@ static int cpa_process_alias(struct cpa
         * to touch the high mapped kernel as well:
         */
        if (!within(vaddr, (unsigned long)_text, _brk_end) &&
-           within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn())) {
+           within_inclusive(cpa->pfn, highmap_start_pfn(),
+                            highmap_end_pfn())) {
                unsigned long temp_cpa_vaddr = (cpa->pfn << PAGE_SHIFT) +
                                               __START_KERNEL_map - phys_base;
                alias_cpa = *cpa;
@@@ -1974,6 -1999,12 +1982,6 @@@ out
        return retval;
  }
  
 -void kernel_unmap_pages_in_pgd(pgd_t *root, unsigned long address,
 -                             unsigned numpages)
 -{
 -      unmap_pgd_range(root, address, address + (numpages << PAGE_SHIFT));
 -}
 -
  /*
   * The testcases use internal knowledge of the implementation that shouldn't
   * be exposed to the rest of the kernel. Include these directly here.
This page took 0.09985 seconds and 4 git commands to generate.