arm64: mm: add param to force create_pgd_mapping() to use page mappings
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 29 Jun 2016 12:51:26 +0000 (14:51 +0200)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 1 Jul 2016 10:56:26 +0000 (11:56 +0100)
Add a bool parameter 'allow_block_mappings' to create_pgd_mapping() and
the various helper functions that it descends into, to give the caller
control over whether block entries may be used to create the mapping.

The UEFI runtime mapping routines will use this to avoid creating block
entries that would need to split up into page entries when applying the
permissions listed in the Memory Attributes firmware table.

This also replaces the block_mappings_allowed() helper function that was
added for DEBUG_PAGEALLOC functionality, but the resulting code is
functionally equivalent (given that debug_page_alloc does not operate on
EFI page table entries anyway)

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/mmu.h
arch/arm64/kernel/efi.c
arch/arm64/mm/mmu.c

index 97b1d8f26b9c8aeedba43bd489b91f58e4fae76c..8d9fce037b2fccd53e4a4340b1d9b4b3c99dff90 100644 (file)
@@ -34,7 +34,7 @@ extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
 extern void init_mem_pgprot(void);
 extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
                               unsigned long virt, phys_addr_t size,
-                              pgprot_t prot);
+                              pgprot_t prot, bool allow_block_mappings);
 extern void *fixmap_remap_fdt(phys_addr_t dt_phys);
 
 #endif
index 78f52488f9ff82461f2933689b44e7b0fcf74b80..98160494852101905773fc0be1472f5a41cf343e 100644 (file)
@@ -65,7 +65,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 
        create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
                           md->num_pages << EFI_PAGE_SHIFT,
-                          __pgprot(prot_val | PTE_NG));
+                          __pgprot(prot_val | PTE_NG), true);
        return 0;
 }
 
index 0c95d6ec873db22f445390dba466b7acfac3525b..a289d66121b69d0fc2644dae633d3a33a5e23c17 100644 (file)
@@ -155,29 +155,10 @@ static void split_pud(pud_t *old_pud, pmd_t *pmd)
        } while (pmd++, i++, i < PTRS_PER_PMD);
 }
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
-static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
-{
-
-       /*
-        * If debug_page_alloc is enabled we must map the linear map
-        * using pages. However, other mappings created by
-        * create_mapping_noalloc must use sections in some cases. Allow
-        * sections to be used in those cases, where no pgtable_alloc
-        * function is provided.
-        */
-       return !pgtable_alloc || !debug_pagealloc_enabled();
-}
-#else
-static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
-{
-       return true;
-}
-#endif
-
 static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
                                  phys_addr_t phys, pgprot_t prot,
-                                 phys_addr_t (*pgtable_alloc)(void))
+                                 phys_addr_t (*pgtable_alloc)(void),
+                                 bool allow_block_mappings)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -208,7 +189,7 @@ static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
                next = pmd_addr_end(addr, end);
                /* try section mapping first */
                if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
-                     block_mappings_allowed(pgtable_alloc)) {
+                     allow_block_mappings) {
                        pmd_t old_pmd =*pmd;
                        pmd_set_huge(pmd, phys, prot);
                        /*
@@ -247,7 +228,8 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next,
 
 static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                                  phys_addr_t phys, pgprot_t prot,
-                                 phys_addr_t (*pgtable_alloc)(void))
+                                 phys_addr_t (*pgtable_alloc)(void),
+                                 bool allow_block_mappings)
 {
        pud_t *pud;
        unsigned long next;
@@ -267,8 +249,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                /*
                 * For 4K granule only, attempt to put down a 1GB block
                 */
-               if (use_1G_block(addr, next, phys) &&
-                   block_mappings_allowed(pgtable_alloc)) {
+               if (use_1G_block(addr, next, phys) && allow_block_mappings) {
                        pud_t old_pud = *pud;
                        pud_set_huge(pud, phys, prot);
 
@@ -289,7 +270,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                        }
                } else {
                        alloc_init_pmd(pud, addr, next, phys, prot,
-                                      pgtable_alloc);
+                                      pgtable_alloc, allow_block_mappings);
                }
                phys += next - addr;
        } while (pud++, addr = next, addr != end);
@@ -303,7 +284,8 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
  */
 static void init_pgd(pgd_t *pgd, phys_addr_t phys, unsigned long virt,
                                    phys_addr_t size, pgprot_t prot,
-                                   phys_addr_t (*pgtable_alloc)(void))
+                                   phys_addr_t (*pgtable_alloc)(void),
+                                   bool allow_block_mappings)
 {
        unsigned long addr, length, end, next;
 
@@ -321,7 +303,8 @@ static void init_pgd(pgd_t *pgd, phys_addr_t phys, unsigned long virt,
        end = addr + length;
        do {
                next = pgd_addr_end(addr, end);
-               alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc);
+               alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc,
+                              allow_block_mappings);
                phys += next - addr;
        } while (pgd++, addr = next, addr != end);
 }
@@ -339,9 +322,11 @@ static phys_addr_t late_pgtable_alloc(void)
 static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
                                 unsigned long virt, phys_addr_t size,
                                 pgprot_t prot,
-                                phys_addr_t (*alloc)(void))
+                                phys_addr_t (*alloc)(void),
+                                bool allow_block_mappings)
 {
-       init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc);
+       init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc,
+                allow_block_mappings);
 }
 
 /*
@@ -357,16 +342,15 @@ static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
                        &phys, virt);
                return;
        }
-       __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
-                            NULL);
+       __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, true);
 }
 
 void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
                               unsigned long virt, phys_addr_t size,
-                              pgprot_t prot)
+                              pgprot_t prot, bool allow_block_mappings)
 {
        __create_pgd_mapping(mm->pgd, phys, virt, size, prot,
-                            late_pgtable_alloc);
+                            late_pgtable_alloc, allow_block_mappings);
 }
 
 static void create_mapping_late(phys_addr_t phys, unsigned long virt,
@@ -379,7 +363,7 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
        }
 
        __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
-                            late_pgtable_alloc);
+                            late_pgtable_alloc, !debug_pagealloc_enabled());
 }
 
 static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
@@ -396,7 +380,8 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
        if (end < kernel_start || start >= kernel_end) {
                __create_pgd_mapping(pgd, start, __phys_to_virt(start),
                                     end - start, PAGE_KERNEL,
-                                    early_pgtable_alloc);
+                                    early_pgtable_alloc,
+                                    !debug_pagealloc_enabled());
                return;
        }
 
@@ -408,12 +393,14 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
                __create_pgd_mapping(pgd, start,
                                     __phys_to_virt(start),
                                     kernel_start - start, PAGE_KERNEL,
-                                    early_pgtable_alloc);
+                                    early_pgtable_alloc,
+                                    !debug_pagealloc_enabled());
        if (kernel_end < end)
                __create_pgd_mapping(pgd, kernel_end,
                                     __phys_to_virt(kernel_end),
                                     end - kernel_end, PAGE_KERNEL,
-                                    early_pgtable_alloc);
+                                    early_pgtable_alloc,
+                                    !debug_pagealloc_enabled());
 
        /*
         * Map the linear alias of the [_text, __init_begin) interval as
@@ -423,7 +410,7 @@ static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end
         */
        __create_pgd_mapping(pgd, kernel_start, __phys_to_virt(kernel_start),
                             kernel_end - kernel_start, PAGE_KERNEL_RO,
-                            early_pgtable_alloc);
+                            early_pgtable_alloc, !debug_pagealloc_enabled());
 }
 
 static void __init map_mem(pgd_t *pgd)
@@ -480,7 +467,7 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
        BUG_ON(!PAGE_ALIGNED(size));
 
        __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot,
-                            early_pgtable_alloc);
+                            early_pgtable_alloc, !debug_pagealloc_enabled());
 
        vma->addr       = va_start;
        vma->phys_addr  = pa_start;