arm64: efi: always map runtime services code and data regions down to pages
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 29 Jun 2016 12:51:27 +0000 (14:51 +0200)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 1 Jul 2016 10:56:26 +0000 (11:56 +0100)
To avoid triggering diagnostics in the MMU code that are finicky about
splitting block mappings into more granular mappings, ensure that regions
that are likely to appear in the Memory Attributes table as well as the
UEFI memory map are always mapped down to pages. This way, we can use
apply_to_page_range() instead of create_pgd_mapping() for the second pass,
which cannot split or merge block entries, and operates strictly on PTEs.

Note that this aligns the arm64 Memory Attributes table handling code with
the ARM code, which already uses apply_to_page_range() to set the strict
permissions.

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

index 622db3c6474e2d5c51b3a1689869534cf16019ee..8b13476cdf9617c2d71a7e518b0301eb317c95f6 100644 (file)
@@ -14,8 +14,7 @@ extern void efi_init(void);
 #endif
 
 int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
-
-#define efi_set_mapping_permissions    efi_create_mapping
+int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
 
 #define arch_efi_call_virt_setup()                                     \
 ({                                                                     \
index 98160494852101905773fc0be1472f5a41cf343e..4aef89f37049a77f154c211f5ae41875d1a701a1 100644 (file)
@@ -62,13 +62,47 @@ struct screen_info screen_info __section(.data);
 int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
 {
        pteval_t prot_val = create_mapping_protection(md);
+       bool allow_block_mappings = (md->type != EFI_RUNTIME_SERVICES_CODE &&
+                                    md->type != EFI_RUNTIME_SERVICES_DATA);
 
        create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
                           md->num_pages << EFI_PAGE_SHIFT,
-                          __pgprot(prot_val | PTE_NG), true);
+                          __pgprot(prot_val | PTE_NG), allow_block_mappings);
        return 0;
 }
 
+static int __init set_permissions(pte_t *ptep, pgtable_t token,
+                                 unsigned long addr, void *data)
+{
+       efi_memory_desc_t *md = data;
+       pte_t pte = *ptep;
+
+       if (md->attribute & EFI_MEMORY_RO)
+               pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
+       if (md->attribute & EFI_MEMORY_XP)
+               pte = set_pte_bit(pte, __pgprot(PTE_PXN));
+       set_pte(ptep, pte);
+       return 0;
+}
+
+int __init efi_set_mapping_permissions(struct mm_struct *mm,
+                                      efi_memory_desc_t *md)
+{
+       BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
+              md->type != EFI_RUNTIME_SERVICES_DATA);
+
+       /*
+        * Calling apply_to_page_range() is only safe on regions that are
+        * guaranteed to be mapped down to pages. Since we are only called
+        * for regions that have been mapped using efi_create_mapping() above
+        * (and this is checked by the generic Memory Attributes table parsing
+        * routines), there is no need to check that again here.
+        */
+       return apply_to_page_range(mm, md->virt_addr,
+                                  md->num_pages << EFI_PAGE_SHIFT,
+                                  set_permissions, md);
+}
+
 static int __init arm64_dmi_init(void)
 {
        /*