Skip to content

Commit

Permalink
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/tip/tip

Pull EFI updates from Ingo Molnar:
 "The main EFI changes in this cycle were:

   - Fix the apple-properties code (Andy Shevchenko)

   - Add WARN() on arm64 if UEFI Runtime Services corrupt the reserved
     x18 register (Ard Biesheuvel)

   - Use efi_switch_mm() on x86 instead of manipulating %cr3 directly
     (Sai Praneeth)

   - Fix early memremap leak in ESRT code (Ard Biesheuvel)

   - Switch to L"xxx" notation for wide string literals (Ard Biesheuvel)

   - ... plus misc other cleanups and bugfixes"

* 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/efi: Use efi_switch_mm() rather than manually twiddling with %cr3
  x86/efi: Replace efi_pgd with efi_mm.pgd
  efi: Use string literals for efi_char16_t variable initializers
  efi/esrt: Fix handling of early ESRT table mapping
  efi: Use efi_mm in x86 as well as ARM
  efi: Make const array 'apple' static
  efi/apple-properties: Use memremap() instead of ioremap()
  efi: Reorder pr_notice() with add_device_randomness() call
  x86/efi: Replace GFP_ATOMIC with GFP_KERNEL in efi_query_variable_store()
  efi/arm64: Check whether x18 is preserved by runtime services calls
  efi/arm*: Stop printing addresses of virtual mappings
  efi/apple-properties: Remove redundant attribute initialization from unmarshal_key_value_pairs()
  efi/arm*: Only register page tables when they exist
  • Loading branch information
torvalds committed Apr 3, 2018
2 parents 2fcd2b3 + 03781e4 commit bc16d40
Show file tree
Hide file tree
Showing 18 changed files with 141 additions and 108 deletions.
4 changes: 3 additions & 1 deletion arch/arm64/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
({ \
efi_##f##_t *__f; \
__f = p->f; \
__f(args); \
__efi_rt_asm_wrapper(__f, #f, args); \
})

#define arch_efi_call_virt_teardown() \
Expand All @@ -40,6 +40,8 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
efi_virtmap_unload(); \
})

efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);

#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)

/* arch specific definitions used by the stub code */
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o \
efi-rt-wrapper.o
arm64-obj-$(CONFIG_PCI) += pci.o
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
arm64-obj-$(CONFIG_ACPI) += acpi.o
Expand Down
41 changes: 41 additions & 0 deletions arch/arm64/kernel/efi-rt-wrapper.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2018 Linaro Ltd <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/

#include <linux/linkage.h>

ENTRY(__efi_rt_asm_wrapper)
stp x29, x30, [sp, #-32]!
mov x29, sp

/*
* Register x18 is designated as the 'platform' register by the AAPCS,
* which means firmware running at the same exception level as the OS
* (such as UEFI) should never touch it.
*/
stp x1, x18, [sp, #16]

/*
* We are lucky enough that no EFI runtime services take more than
* 5 arguments, so all are passed in registers rather than via the
* stack.
*/
mov x8, x0
mov x0, x2
mov x1, x3
mov x2, x4
mov x3, x5
mov x4, x6
blr x8

ldp x1, x2, [sp, #16]
cmp x2, x18
ldp x29, x30, [sp], #32
b.ne 0f
ret
0: b efi_handle_corrupted_x18 // tail call
ENDPROC(__efi_rt_asm_wrapper)
6 changes: 6 additions & 0 deletions arch/arm64/kernel/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,9 @@ bool efi_poweroff_required(void)
{
return efi_enabled(EFI_RUNTIME_SERVICES);
}

asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)
{
pr_err_ratelimited(FW_BUG "register x18 corrupted by EFI %s\n", f);
return s;
}
3 changes: 2 additions & 1 deletion arch/x86/boot/compressed/eboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,9 +421,10 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
}
}

static const efi_char16_t apple[] = L"Apple";

static void setup_quirks(struct boot_params *boot_params)
{
efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
efi_table_attr(efi_system_table, fw_vendor, sys_table);

Expand Down
26 changes: 11 additions & 15 deletions arch/x86/include/asm/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <asm/processor-flags.h>
#include <asm/tlb.h>
#include <asm/nospec-branch.h>
#include <asm/mmu_context.h>

/*
* We map the EFI regions needed for runtime services non-contiguously,
Expand Down Expand Up @@ -69,14 +70,13 @@ extern asmlinkage u64 efi_call(void *fp, ...);
#define efi_call_phys(f, args...) efi_call((f), args)

/*
* Scratch space used for switching the pagetable in the EFI stub
* struct efi_scratch - Scratch space used while switching to/from efi_mm
* @phys_stack: stack used during EFI Mixed Mode
* @prev_mm: store/restore stolen mm_struct while switching to/from efi_mm
*/
struct efi_scratch {
u64 r15;
u64 prev_cr3;
pgd_t *efi_pgt;
bool use_pgd;
u64 phys_stack;
u64 phys_stack;
struct mm_struct *prev_mm;
} __packed;

#define arch_efi_call_virt_setup() \
Expand All @@ -86,22 +86,17 @@ struct efi_scratch {
__kernel_fpu_begin(); \
firmware_restrict_branch_speculation_start(); \
\
if (efi_scratch.use_pgd) { \
efi_scratch.prev_cr3 = __read_cr3(); \
write_cr3((unsigned long)efi_scratch.efi_pgt); \
__flush_tlb_all(); \
} \
if (!efi_enabled(EFI_OLD_MEMMAP)) \
efi_switch_mm(&efi_mm); \
})

#define arch_efi_call_virt(p, f, args...) \
efi_call((void *)p->f, args) \

#define arch_efi_call_virt_teardown() \
({ \
if (efi_scratch.use_pgd) { \
write_cr3(efi_scratch.prev_cr3); \
__flush_tlb_all(); \
} \
if (!efi_enabled(EFI_OLD_MEMMAP)) \
efi_switch_mm(efi_scratch.prev_mm); \
\
firmware_restrict_branch_speculation_end(); \
__kernel_fpu_end(); \
Expand Down Expand Up @@ -144,6 +139,7 @@ extern void __init efi_dump_pagetable(void);
extern void __init efi_apply_memmap_quirks(void);
extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_switch_mm(struct mm_struct *mm);

struct efi_setup_data {
u64 fw_vendor;
Expand Down
6 changes: 3 additions & 3 deletions arch/x86/mm/debug_pagetables.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <linux/debugfs.h>
#include <linux/efi.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <asm/pgtable.h>
Expand Down Expand Up @@ -73,13 +74,12 @@ static const struct file_operations ptdump_curusr_fops = {
#endif

#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
extern pgd_t *efi_pgd;
static struct dentry *pe_efi;

static int ptdump_show_efi(struct seq_file *m, void *v)
{
if (efi_pgd)
ptdump_walk_pgd_level_debugfs(m, efi_pgd, false);
if (efi_mm.pgd)
ptdump_walk_pgd_level_debugfs(m, efi_mm.pgd, false);
return 0;
}

Expand Down
60 changes: 33 additions & 27 deletions arch/x86/platform/efi/efi_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/ucs2_string.h>
#include <linux/mem_encrypt.h>
#include <linux/sched/task.h>

#include <asm/setup.h>
#include <asm/page.h>
Expand Down Expand Up @@ -82,9 +83,8 @@ pgd_t * __init efi_call_phys_prolog(void)
int n_pgds, i, j;

if (!efi_enabled(EFI_OLD_MEMMAP)) {
save_pgd = (pgd_t *)__read_cr3();
write_cr3((unsigned long)efi_scratch.efi_pgt);
goto out;
efi_switch_mm(&efi_mm);
return NULL;
}

early_code_mapping_set_exec(1);
Expand Down Expand Up @@ -156,8 +156,7 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
pud_t *pud;

if (!efi_enabled(EFI_OLD_MEMMAP)) {
write_cr3((unsigned long)save_pgd);
__flush_tlb_all();
efi_switch_mm(efi_scratch.prev_mm);
return;
}

Expand Down Expand Up @@ -191,8 +190,7 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
early_code_mapping_set_exec(0);
}

pgd_t *efi_pgd;
EXPORT_SYMBOL_GPL(efi_pgd);
EXPORT_SYMBOL_GPL(efi_mm);

/*
* We need our own copy of the higher levels of the page tables
Expand All @@ -205,7 +203,7 @@ EXPORT_SYMBOL_GPL(efi_pgd);
*/
int __init efi_alloc_page_tables(void)
{
pgd_t *pgd;
pgd_t *pgd, *efi_pgd;
p4d_t *p4d;
pud_t *pud;
gfp_t gfp_mask;
Expand Down Expand Up @@ -233,6 +231,10 @@ int __init efi_alloc_page_tables(void)
return -ENOMEM;
}

efi_mm.pgd = efi_pgd;
mm_init_cpumask(&efi_mm);
init_new_context(NULL, &efi_mm);

return 0;
}

Expand All @@ -245,6 +247,7 @@ void efi_sync_low_kernel_mappings(void)
pgd_t *pgd_k, *pgd_efi;
p4d_t *p4d_k, *p4d_efi;
pud_t *pud_k, *pud_efi;
pgd_t *efi_pgd = efi_mm.pgd;

if (efi_enabled(EFI_OLD_MEMMAP))
return;
Expand Down Expand Up @@ -338,19 +341,11 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
unsigned long pfn, text, pf;
struct page *page;
unsigned npages;
pgd_t *pgd;
pgd_t *pgd = efi_mm.pgd;

if (efi_enabled(EFI_OLD_MEMMAP))
return 0;

/*
* Since the PGD is encrypted, set the encryption mask so that when
* this value is loaded into cr3 the PGD will be decrypted during
* the pagetable walk.
*/
efi_scratch.efi_pgt = (pgd_t *)__sme_pa(efi_pgd);
pgd = efi_pgd;

/*
* It can happen that the physical address of new_memmap lands in memory
* which is not mapped in the EFI page table. Therefore we need to go
Expand All @@ -364,8 +359,6 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
return 1;
}

efi_scratch.use_pgd = true;

/*
* Certain firmware versions are way too sentimential and still believe
* they are exclusive and unquestionable owners of the first physical page,
Expand Down Expand Up @@ -419,7 +412,7 @@ static void __init __map_region(efi_memory_desc_t *md, u64 va)
{
unsigned long flags = _PAGE_RW;
unsigned long pfn;
pgd_t *pgd = efi_pgd;
pgd_t *pgd = efi_mm.pgd;

if (!(md->attribute & EFI_MEMORY_WB))
flags |= _PAGE_PCD;
Expand Down Expand Up @@ -523,7 +516,7 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len)
static int __init efi_update_mappings(efi_memory_desc_t *md, unsigned long pf)
{
unsigned long pfn;
pgd_t *pgd = efi_pgd;
pgd_t *pgd = efi_mm.pgd;
int err1, err2;

/* Update the 1:1 mapping */
Expand Down Expand Up @@ -620,10 +613,26 @@ void __init efi_dump_pagetable(void)
if (efi_enabled(EFI_OLD_MEMMAP))
ptdump_walk_pgd_level(NULL, swapper_pg_dir);
else
ptdump_walk_pgd_level(NULL, efi_pgd);
ptdump_walk_pgd_level(NULL, efi_mm.pgd);
#endif
}

/*
* Makes the calling thread switch to/from efi_mm context. Can be used
* for SetVirtualAddressMap() i.e. current->active_mm == init_mm as well
* as during efi runtime calls i.e current->active_mm == current_mm.
* We are not mm_dropping()/mm_grabbing() any mm, because we are not
* losing/creating any references.
*/
void efi_switch_mm(struct mm_struct *mm)
{
task_lock(current);
efi_scratch.prev_mm = current->active_mm;
current->active_mm = mm;
switch_mm(efi_scratch.prev_mm, mm, NULL);
task_unlock(current);
}

#ifdef CONFIG_EFI_MIXED
extern efi_status_t efi64_thunk(u32, ...);

Expand Down Expand Up @@ -677,16 +686,13 @@ efi_status_t efi_thunk_set_virtual_address_map(
efi_sync_low_kernel_mappings();
local_irq_save(flags);

efi_scratch.prev_cr3 = __read_cr3();
write_cr3((unsigned long)efi_scratch.efi_pgt);
__flush_tlb_all();
efi_switch_mm(&efi_mm);

func = (u32)(unsigned long)phys_set_virtual_address_map;
status = efi64_thunk(func, memory_map_size, descriptor_size,
descriptor_version, virtual_map);

write_cr3(efi_scratch.prev_cr3);
__flush_tlb_all();
efi_switch_mm(efi_scratch.prev_mm);
local_irq_restore(flags);

return status;
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/platform/efi/efi_thunk_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ENTRY(efi64_thunk)
* Switch to 1:1 mapped 32-bit stack pointer.
*/
movq %rsp, efi_saved_sp(%rip)
movq efi_scratch+25(%rip), %rsp
movq efi_scratch(%rip), %rsp

/*
* Calculate the physical address of the kernel text.
Expand Down
10 changes: 6 additions & 4 deletions arch/x86/platform/efi/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct quark_security_header {
u32 rsvd[2];
};

static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
static const efi_char16_t efi_dummy_name[] = L"DUMMY";

static bool efi_no_storage_paranoia;

Expand Down Expand Up @@ -105,7 +105,8 @@ early_param("efi_no_storage_paranoia", setup_storage_paranoia);
*/
void efi_delete_dummy_variable(void)
{
efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
efi.set_variable((efi_char16_t *)efi_dummy_name,
&EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
Expand Down Expand Up @@ -177,12 +178,13 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size,
* that by attempting to use more space than is available.
*/
unsigned long dummy_size = remaining_size + 1024;
void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
void *dummy = kzalloc(dummy_size, GFP_KERNEL);

if (!dummy)
return EFI_OUT_OF_RESOURCES;

status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
status = efi.set_variable((efi_char16_t *)efi_dummy_name,
&EFI_DUMMY_GUID,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
Expand Down
Loading

0 comments on commit bc16d40

Please sign in to comment.