arm64: use non-global mappings for UEFI runtime regions
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 17 Nov 2015 08:53:31 +0000 (09:53 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 18 Nov 2015 09:40:20 +0000 (09:40 +0000)
As pointed out by Russell King in response to the proposed ARM version
of this code, the sequence to switch between the UEFI runtime mapping
and current's actual userland mapping (and vice versa) is potentially
unsafe, since it leaves a time window between the switch to the new
page tables and the TLB flush where speculative accesses may hit on
stale global TLB entries.

So instead, use non-global mappings, and perform the switch via the
ordinary ASID-aware context switch routines.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/mmu_context.h
arch/arm64/kernel/efi.c

index c0e87898ba96b04f2e5b847a0dacf01f4eb1dff1..24165784b8038b732ea568d1e74fd8c0a699b914 100644 (file)
@@ -101,7 +101,7 @@ static inline void cpu_set_default_tcr_t0sz(void)
 #define destroy_context(mm)            do { } while(0)
 void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
 
-#define init_new_context(tsk,mm)       ({ atomic64_set(&mm->context.id, 0); 0; })
+#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.id, 0); 0; })
 
 /*
  * This is called when "tsk" is about to enter lazy TLB mode.
index de46b50f4cdf952087e77d473314e75728efeec0..fc5508e0df57ff8a132894d091c94938d299ee02 100644 (file)
@@ -224,6 +224,8 @@ static bool __init efi_virtmap_init(void)
 {
        efi_memory_desc_t *md;
 
+       init_new_context(NULL, &efi_mm);
+
        for_each_efi_memory_desc(&memmap, md) {
                u64 paddr, npages, size;
                pgprot_t prot;
@@ -254,7 +256,8 @@ static bool __init efi_virtmap_init(void)
                else
                        prot = PAGE_KERNEL;
 
-               create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot);
+               create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size,
+                                  __pgprot(pgprot_val(prot) | PTE_NG));
        }
        return true;
 }
@@ -329,14 +332,7 @@ core_initcall(arm64_dmi_init);
 
 static void efi_set_pgd(struct mm_struct *mm)
 {
-       if (mm == &init_mm)
-               cpu_set_reserved_ttbr0();
-       else
-               cpu_switch_mm(mm->pgd, mm);
-
-       local_flush_tlb_all();
-       if (icache_is_aivivt())
-               __local_flush_icache_all();
+       switch_mm(NULL, mm, NULL);
 }
 
 void efi_virtmap_load(void)