arm64: efi: avoid block mappings for unaligned UEFI memory regions
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 29 Jun 2016 12:51:28 +0000 (14:51 +0200)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 1 Jul 2016 10:56:26 +0000 (11:56 +0100)
When running the OS with a page size > 4 KB, we need to round up mappings
for regions that are not aligned to the OS's page size. We already avoid
block mappings for EfiRuntimeServicesCode/Data regions for other reasons,
but in the unlikely event that other unaliged regions exists that have the
EFI_MEMORY_RUNTIME attribute set, ensure that unaligned regions are always
mapped down to pages. This way, the overlapping page is guaranteed not to
be covered by a block mapping that needs to be split.

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

index 4aef89f..ba9bee3 100644 (file)
@@ -65,6 +65,20 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
        bool allow_block_mappings = (md->type != EFI_RUNTIME_SERVICES_CODE &&
                                     md->type != EFI_RUNTIME_SERVICES_DATA);
 
+       if (!PAGE_ALIGNED(md->phys_addr) ||
+           !PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT)) {
+               /*
+                * If the end address of this region is not aligned to page
+                * size, the mapping is rounded up, and may end up sharing a
+                * page frame with the next UEFI memory region. If we create
+                * a block entry now, we may need to split it again when mapping
+                * the next region, and support for that is going to be removed
+                * from the MMU routines. So avoid block mappings altogether in
+                * that case.
+                */
+               allow_block_mappings = false;
+       }
+
        create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
                           md->num_pages << EFI_PAGE_SHIFT,
                           __pgprot(prot_val | PTE_NG), allow_block_mappings);