]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
efi: Disable interrupts around EFI calls, not in the epilog/prolog calls
authorIngo Molnar <mingo@kernel.org>
Tue, 3 Mar 2015 06:34:33 +0000 (07:34 +0100)
committerLuis Henriques <luis.henriques@canonical.com>
Mon, 25 Jan 2016 10:43:30 +0000 (10:43 +0000)
commit 23a0d4e8fa6d3a1d7fb819f79bcc0a3739c30ba9 upstream.

Tapasweni Pathak reported that we do a kmalloc() in efi_call_phys_prolog()
on x86-64 while having interrupts disabled, which is a big no-no, as
kmalloc() can sleep.

Solve this by removing the irq disabling from the prolog/epilog calls
around EFI calls: it's unnecessary, as in this stage we are single
threaded in the boot thread, and we don't ever execute this from
interrupt contexts.

Reported-by: Tapasweni Pathak <tapaswenipathak@gmail.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c

index 5bbb477f5c2a83fb3ce4631c0dd1b2210c2f0afa..09c8ac286cd56a5a29b97e98a019844a431a1c29 100644 (file)
@@ -236,12 +236,19 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
        efi_memory_desc_t *virtual_map)
 {
        efi_status_t status;
+       unsigned long flags;
 
        efi_call_phys_prelog();
+
+       /* Disable interrupts around EFI calls: */
+       local_irq_save(flags);
        status = efi_call_phys(efi_phys.set_virtual_address_map,
                               memory_map_size, descriptor_size,
                               descriptor_version, virtual_map);
+       local_irq_restore(flags);
+
        efi_call_phys_epilog();
+
        return status;
 }
 
index 9ee3491e31fbab7f6643462395d31c6f9f36f1b4..be4e7eb41674125bca32fab1c40ae1a8e40644f0 100644 (file)
 
 /*
  * To make EFI call EFI runtime service in physical addressing mode we need
- * prelog/epilog before/after the invocation to disable interrupt, to
- * claim EFI runtime service handler exclusively and to duplicate a memory in
- * low memory space say 0 - 3G.
+ * prolog/epilog before/after the invocation to claim the EFI runtime service
+ * handler exclusively and to duplicate a memory mapping in low memory space,
+ * say 0 - 3G.
  */
-static unsigned long efi_rt_eflags;
 
 void efi_sync_low_kernel_mappings(void) {}
 void __init efi_dump_pagetable(void) {}
@@ -59,8 +58,6 @@ void efi_call_phys_prelog(void)
 {
        struct desc_ptr gdt_descr;
 
-       local_irq_save(efi_rt_eflags);
-
        load_cr3(initial_page_table);
        __flush_tlb_all();
 
@@ -79,8 +76,6 @@ void efi_call_phys_epilog(void)
 
        load_cr3(swapper_pg_dir);
        __flush_tlb_all();
-
-       local_irq_restore(efi_rt_eflags);
 }
 
 void __init efi_runtime_mkexec(void)
index 290d397e1dd9125e408a1ee140fe4d3ced51a33d..8139b48584037e1e5e9218e70853b882408ac158 100644 (file)
@@ -42,7 +42,6 @@
 #include <asm/time.h>
 
 static pgd_t *save_pgd __initdata;
-static unsigned long efi_flags __initdata;
 
 /*
  * We allocate runtime services regions bottom-up, starting from -4G, i.e.
@@ -89,7 +88,6 @@ void __init efi_call_phys_prelog(void)
                return;
 
        early_code_mapping_set_exec(1);
-       local_irq_save(efi_flags);
 
        n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
        save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
@@ -117,7 +115,6 @@ void __init efi_call_phys_epilog(void)
                set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]);
        kfree(save_pgd);
        __flush_tlb_all();
-       local_irq_restore(efi_flags);
        early_code_mapping_set_exec(0);
 }