[tip:core/efi] efi: Add support for EFI_MEMORY_RO attribute introduced by UEFIv2.5
Commit-ID: 87db73aebf4fefaa3eade0a28f282a1511b8 Gitweb: http://git.kernel.org/tip/87db73aebf4fefaa3eade0a28f282a1511b8 Author: Ard Biesheuvel ard.biesheu...@linaro.org AuthorDate: Fri, 7 Aug 2015 09:36:54 +0100 Committer: Ingo Molnar mi...@kernel.org CommitDate: Sat, 8 Aug 2015 10:37:38 +0200 efi: Add support for EFI_MEMORY_RO attribute introduced by UEFIv2.5 The UEFI spec v2.5 introduces a new memory attribute EFI_MEMORY_RO, which is now the preferred attribute to convey that the nature of the contents of such a region allows it to be mapped read-only (i.e., it contains .text and .rodata only). The specification of the existing EFI_MEMORY_WP attribute has been updated to align more closely with its common use as a cacheability attribute rather than a permission attribute. Add the #define and add the attribute to the memory map dumping routine. Signed-off-by: Ard Biesheuvel ard.biesheu...@linaro.org Signed-off-by: Matt Fleming matt.flem...@intel.com Reviewed-by: Laszlo Ersek ler...@redhat.com Cc: H. Peter Anvin h...@zytor.com Cc: Thomas Gleixner t...@linutronix.de Link: http://lkml.kernel.org/r/1438936621-5215-1-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar mi...@kernel.org --- drivers/firmware/efi/efi.c | 8 +--- include/linux/efi.h| 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index d6144e3..d7a9160 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -588,16 +588,18 @@ char * __init efi_md_typeattr_format(char *buf, size_t size, attr = md-attribute; if (attr ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | -EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | -EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) +EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO | +EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP | +EFI_MEMORY_RUNTIME)) snprintf(pos, size, |attr=0x%016llx], (unsigned long long)attr); else - snprintf(pos, size, |%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s], + snprintf(pos, size, |%3s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s], attr EFI_MEMORY_RUNTIME ? RUN : , attr EFI_MEMORY_XP ? XP : , attr EFI_MEMORY_RP ? RP : , attr EFI_MEMORY_WP ? WP : , +attr EFI_MEMORY_RO ? RO : , attr EFI_MEMORY_UCE ? UCE : , attr EFI_MEMORY_WB ? WB : , attr EFI_MEMORY_WT ? WT : , diff --git a/include/linux/efi.h b/include/linux/efi.h index 85ef051..26ca9e2 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -99,6 +99,7 @@ typedef struct { #define EFI_MEMORY_XP ((u64)0x4000ULL)/* execute-protect */ #define EFI_MEMORY_MORE_RELIABLE \ ((u64)0x0001ULL)/* higher reliability */ +#define EFI_MEMORY_RO ((u64)0x0002ULL)/* read-only */ #define EFI_MEMORY_RUNTIME ((u64)0x8000ULL)/* range requires runtime mapping */ #define EFI_MEMORY_DESCRIPTOR_VERSION 1 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[tip:core/efi] efi: Use correct type for struct efi_memory_map:: phys_map
Commit-ID: 44511fb9e55ada760822b0b0d7be9d150576f17f Gitweb: http://git.kernel.org/tip/44511fb9e55ada760822b0b0d7be9d150576f17f Author: Ard BiesheuvelAuthorDate: Fri, 23 Oct 2015 11:48:16 +0200 Committer: Ingo Molnar CommitDate: Wed, 28 Oct 2015 12:28:06 +0100 efi: Use correct type for struct efi_memory_map::phys_map We have been getting away with using a void* for the physical address of the UEFI memory map, since, even on 32-bit platforms with 64-bit physical addresses, no truncation takes place if the memory map has been allocated by the firmware (which only uses 1:1 virtually addressable memory), which is usually the case. However, commit: 0f96a99dab36 ("efi: Add "efi_fake_mem" boot option") adds code that clones and modifies the UEFI memory map, and the clone may live above 4 GB on 32-bit platforms. This means our use of void* for struct efi_memory_map::phys_map has graduated from 'incorrect but working' to 'incorrect and broken', and we need to fix it. So redefine struct efi_memory_map::phys_map as phys_addr_t, and get rid of a bunch of casts that are now unneeded. Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: izumi.t...@jp.fujitsu.com Cc: kamezawa.hir...@jp.fujitsu.com Cc: linux-...@vger.kernel.org Cc: matt.flem...@intel.com Link: http://lkml.kernel.org/r/1445593697-1342-1-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm64/kernel/efi.c | 4 ++-- arch/x86/platform/efi/efi.c | 4 ++-- drivers/firmware/efi/efi.c | 8 include/linux/efi.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 4b7df34..61eb1d1 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -208,7 +208,7 @@ void __init efi_init(void) memblock_reserve(params.mmap & PAGE_MASK, PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); - memmap.phys_map = (void *)params.mmap; + memmap.phys_map = params.mmap; memmap.map = early_memremap(params.mmap, params.mmap_size); memmap.map_end = memmap.map + params.mmap_size; memmap.desc_size = params.desc_size; @@ -282,7 +282,7 @@ static int __init arm64_enable_runtime_services(void) pr_info("Remapping and enabling EFI services.\n"); mapsize = memmap.map_end - memmap.map; - memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, + memmap.map = (__force void *)ioremap_cache(memmap.phys_map, mapsize); if (!memmap.map) { pr_err("Failed to remap EFI memory map\n"); diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 3e1d09e..ad28540 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -194,7 +194,7 @@ static void __init do_add_efi_memmap(void) int __init efi_memblock_x86_reserve_range(void) { struct efi_info *e = _params.efi_info; - unsigned long pmap; + phys_addr_t pmap; if (efi_enabled(EFI_PARAVIRT)) return 0; @@ -209,7 +209,7 @@ int __init efi_memblock_x86_reserve_range(void) #else pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32)); #endif - memmap.phys_map = (void *)pmap; + memmap.phys_map = pmap; memmap.nr_map = e->efi_memmap_size / e->efi_memdesc_size; memmap.desc_size= e->efi_memdesc_size; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 31fc864..027ca21 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -254,7 +254,7 @@ subsys_initcall(efisubsys_init); int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) { struct efi_memory_map *map = efi.memmap; - void *p, *e; + phys_addr_t p, e; if (!efi_enabled(EFI_MEMMAP)) { pr_err_once("EFI_MEMMAP is not enabled.\n"); @@ -286,10 +286,10 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) * So just always get our own virtual map on the CPU. * */ - md = early_memremap((phys_addr_t)p, sizeof (*md)); + md = early_memremap(p, sizeof (*md)); if (!md) { - pr_err_once("early_memremap(%p, %zu) failed.\n", - p, sizeof (*md)); + pr_err_once("early_memremap(%pa, %zu) failed.\n", + , sizeof (*md)); return -ENOMEM; } diff --git a/include/linux/efi.h
[tip:core/urgent] arm64/efi: Fix boot crash by not padding between EFI_MEMORY_RUNTIME regions
Commit-ID: 0ce3cc008ec04258b6a6314b09f1a6012810881a Gitweb: http://git.kernel.org/tip/0ce3cc008ec04258b6a6314b09f1a6012810881a Author: Ard BiesheuvelAuthorDate: Fri, 25 Sep 2015 23:02:19 +0100 Committer: Ingo Molnar CommitDate: Thu, 1 Oct 2015 12:51:28 +0200 arm64/efi: Fix boot crash by not padding between EFI_MEMORY_RUNTIME regions The new Properties Table feature introduced in UEFIv2.5 may split memory regions that cover PE/COFF memory images into separate code and data regions. Since these regions only differ in the type (runtime code vs runtime data) and the permission bits, but not in the memory type attributes (UC/WC/WT/WB), the spec does not require them to be aligned to 64 KB. Since the relative offset of PE/COFF .text and .data segments cannot be changed on the fly, this means that we can no longer pad out those regions to be mappable using 64 KB pages. Unfortunately, there is no annotation in the UEFI memory map that identifies data regions that were split off from a code region, so we must apply this logic to all adjacent runtime regions whose attributes only differ in the permission bits. So instead of rounding each memory region to 64 KB alignment at both ends, only round down regions that are not directly preceded by another runtime region with the same type attributes. Since the UEFI spec does not mandate that the memory map be sorted, this means we also need to sort it first. Note that this change will result in all EFI_MEMORY_RUNTIME regions whose start addresses are not aligned to the OS page size to be mapped with executable permissions (i.e., on kernels compiled with 64 KB pages). However, since these mappings are only active during the time that UEFI Runtime Services are being invoked, the window for abuse is rather small. Tested-by: Mark Salter Tested-by: Mark Rutland [UEFI 2.4 only] Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Mark Salter Reviewed-by: Mark Rutland Cc: # v4.0+ Cc: Catalin Marinas Cc: Leif Lindholm Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/1443218539-7610-3-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm64/kernel/efi.c | 3 +- drivers/firmware/efi/libstub/arm-stub.c | 88 +++-- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index e8ca6ea..13671a9 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -258,7 +258,8 @@ static bool __init efi_virtmap_init(void) */ if (!is_normal_ram(md)) prot = __pgprot(PROT_DEVICE_nGnRE); - else if (md->type == EFI_RUNTIME_SERVICES_CODE) + else if (md->type == EFI_RUNTIME_SERVICES_CODE || +!PAGE_ALIGNED(md->phys_addr)) prot = PAGE_KERNEL_EXEC; else prot = PAGE_KERNEL; diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index e29560e..950c87f 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -13,6 +13,7 @@ */ #include +#include #include #include "efistub.h" @@ -305,6 +306,44 @@ fail: */ #define EFI_RT_VIRTUAL_BASE0x4000 +static int cmp_mem_desc(const void *l, const void *r) +{ + const efi_memory_desc_t *left = l, *right = r; + + return (left->phys_addr > right->phys_addr) ? 1 : -1; +} + +/* + * Returns whether region @left ends exactly where region @right starts, + * or false if either argument is NULL. + */ +static bool regions_are_adjacent(efi_memory_desc_t *left, +efi_memory_desc_t *right) +{ + u64 left_end; + + if (left == NULL || right == NULL) + return false; + + left_end = left->phys_addr + left->num_pages * EFI_PAGE_SIZE; + + return left_end == right->phys_addr; +} + +/* + * Returns whether region @left and region @right have compatible memory type + * mapping attributes, and are both EFI_MEMORY_RUNTIME regions. + */ +static bool regions_have_compatible_memory_type_attrs(efi_memory_desc_t *left, + efi_memory_desc_t *right) +{ + static const u64 mem_type_mask = EFI_MEMORY_WB | EFI_MEMORY_WT | +EFI_MEMORY_WC | EFI_MEMORY_UC | +
[tip:efi/core] efi/runtime-wrappers: Remove out of date comment regarding in_nmi()
Commit-ID: 774846defceb16dcab2f0215cfc467f7c93f1c26 Gitweb: http://git.kernel.org/tip/774846defceb16dcab2f0215cfc467f7c93f1c26 Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:06:59 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:04 +0100 efi/runtime-wrappers: Remove out of date comment regarding in_nmi() This code is long gone, so remove the comment as well. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1454364428-494-6-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/runtime-wrappers.c | 26 -- 1 file changed, 26 deletions(-) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index e9f2867..311f415 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -62,32 +62,6 @@ static DEFINE_SPINLOCK(efi_runtime_lock); /* - * Some runtime services calls can be reentrant under NMI, even if the table - * above says they are not. (source: UEFI Specification v2.4A) - * - * Table 32. Functions that may be called after Machine Check, INIT and NMI - * ++--+ - * | Function | Called after Machine Check, INIT and NMI | - * ++--+ - * | GetTime() | Yes, even if previously busy.| - * | GetVariable() | Yes, even if previously busy | - * | GetNextVariableName() | Yes, even if previously busy | - * | QueryVariableInfo() | Yes, even if previously busy | - * | SetVariable() | Yes, even if previously busy | - * | UpdateCapsule() | Yes, even if previously busy | - * | QueryCapsuleCapabilities()| Yes, even if previously busy | - * | ResetSystem() | Yes, even if previously busy | - * ++--+ - * - * In order to prevent deadlocks under NMI, the wrappers for these functions - * may only grab the efi_runtime_lock or rtc_lock spinlocks if !efi_in_nmi(). - * However, not all of the services listed are reachable through NMI code paths, - * so the the special handling as suggested by the UEFI spec is only implemented - * for QueryVariableInfo() and SetVariable(), as these can be reached in NMI - * context through efi_pstore_write(). - */ - -/* * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), * the EFI specification requires that callers of the time related runtime * functions serialize with other CMOS accesses in the kernel, as the EFI time
[tip:efi/core] efi: Remove redundant efi_set_variable_nonblocking () prototype
Commit-ID: 70d2a3cf2f4ae2e93b7a661842d84c2b5132cee7 Gitweb: http://git.kernel.org/tip/70d2a3cf2f4ae2e93b7a661842d84c2b5132cee7 Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:06:56 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:02 +0100 efi: Remove redundant efi_set_variable_nonblocking() prototype There is no need for a separate nonblocking prototype definition for the SetVariable() UEFI Runtime Service, since it is identical to the blocking version. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1454364428-494-3-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- include/linux/efi.h | 8 ++-- 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/include/linux/efi.h b/include/linux/efi.h index 569b5a8..8706e0a 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -507,10 +507,6 @@ typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 attr, unsigned long data_size, void *data); -typedef efi_status_t -efi_set_variable_nonblocking_t(efi_char16_t *name, efi_guid_t *vendor, - u32 attr, unsigned long data_size, void *data); - typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); typedef void efi_reset_system_t (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data); @@ -851,7 +847,7 @@ extern struct efi { efi_get_variable_t *get_variable; efi_get_next_variable_t *get_next_variable; efi_set_variable_t *set_variable; - efi_set_variable_nonblocking_t *set_variable_nonblocking; + efi_set_variable_t *set_variable_nonblocking; efi_query_variable_info_t *query_variable_info; efi_update_capsule_t *update_capsule; efi_query_capsule_caps_t *query_capsule_caps; @@ -1091,7 +1087,7 @@ struct efivar_operations { efi_get_variable_t *get_variable; efi_get_next_variable_t *get_next_variable; efi_set_variable_t *set_variable; - efi_set_variable_nonblocking_t *set_variable_nonblocking; + efi_set_variable_t *set_variable_nonblocking; efi_query_variable_store_t *query_variable_store; };
[tip:efi/core] efi: Add nonblocking option to efi_query_variable_store()
Commit-ID: ca0e30dcaa53a3fcb2dfdf74252d30bc40603eea Gitweb: http://git.kernel.org/tip/ca0e30dcaa53a3fcb2dfdf74252d30bc40603eea Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:06:58 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:04 +0100 efi: Add nonblocking option to efi_query_variable_store() The function efi_query_variable_store() may be invoked by efivar_entry_set_nonblocking(), which itself takes care to only call a non-blocking version of the SetVariable() runtime wrapper. However, efi_query_variable_store() may call the SetVariable() wrapper directly, as well as the wrapper for QueryVariableInfo(), both of which could deadlock in the same way we are trying to prevent by calling efivar_entry_set_nonblocking() in the first place. So instead, modify efi_query_variable_store() to use the non-blocking variants of QueryVariableInfo() (and give up rather than free up space if the available space is below EFI_MIN_RESERVE) if invoked with the 'nonblocking' argument set to true. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1454364428-494-5-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/quirks.c | 33 - drivers/firmware/efi/vars.c| 16 ++-- include/linux/efi.h| 12 +--- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 4535046..2326bf5 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -57,13 +57,41 @@ void efi_delete_dummy_variable(void) } /* + * In the nonblocking case we do not attempt to perform garbage + * collection if we do not have enough free space. Rather, we do the + * bare minimum check and give up immediately if the available space + * is below EFI_MIN_RESERVE. + * + * This function is intended to be small and simple because it is + * invoked from crash handler paths. + */ +static efi_status_t +query_variable_store_nonblocking(u32 attributes, unsigned long size) +{ + efi_status_t status; + u64 storage_size, remaining_size, max_size; + + status = efi.query_variable_info_nonblocking(attributes, _size, +_size, +_size); + if (status != EFI_SUCCESS) + return status; + + if (remaining_size - size < EFI_MIN_RESERVE) + return EFI_OUT_OF_RESOURCES; + + return EFI_SUCCESS; +} + +/* * Some firmware implementations refuse to boot if there's insufficient space * in the variable store. Ensure that we never use more than a safe limit. * * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable * store. */ -efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) +efi_status_t efi_query_variable_store(u32 attributes, unsigned long size, + bool nonblocking) { efi_status_t status; u64 storage_size, remaining_size, max_size; @@ -71,6 +99,9 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size) if (!(attributes & EFI_VARIABLE_NON_VOLATILE)) return 0; + if (nonblocking) + return query_variable_store_nonblocking(attributes, size); + status = efi.query_variable_info(attributes, _size, _size, _size); if (status != EFI_SUCCESS) diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 70a0fb1..d2a4962 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -234,7 +234,18 @@ check_var_size(u32 attributes, unsigned long size) if (!fops->query_variable_store) return EFI_UNSUPPORTED; - return fops->query_variable_store(attributes, size); + return fops->query_variable_store(attributes, size, false); +} + +static efi_status_t +check_var_size_nonblocking(u32 attributes, unsigned long size) +{ + const struct efivar_operations *fops = __efivars->ops; + + if (!fops->query_variable_store) + return EFI_UNSUPPORTED; + + return fops->query_variable_store(attributes, size, true); } static int efi_status_to_err(efi_status_t status) @@ -615,7 +626,8 @@ efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, if (!spin_trylock_irqsave(&__efivars->lock, flags)) return
[tip:efi/core] efi: Runtime-wrapper: Get rid of the rtc_lock spinlock
Commit-ID: 1bb6936473c07b5a7c8daced1000893b7145bb14 Gitweb: http://git.kernel.org/tip/1bb6936473c07b5a7c8daced1000893b7145bb14 Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:07:00 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:05 +0100 efi: Runtime-wrapper: Get rid of the rtc_lock spinlock The rtc_lock spinlock aims to serialize access to the CMOS RTC between the UEFI firmware and the kernel drivers that use it directly. However, x86 is the only arch that performs such direct accesses, and that never uses the time related UEFI runtime services. Since no other UEFI enlightened architectures have a legcay CMOS RTC anyway, we can remove the rtc_lock spinlock entirely. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1454364428-494-7-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/runtime-wrappers.c | 32 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 311f415..7b8b2f2 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -61,24 +61,14 @@ */ static DEFINE_SPINLOCK(efi_runtime_lock); -/* - * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), - * the EFI specification requires that callers of the time related runtime - * functions serialize with other CMOS accesses in the kernel, as the EFI time - * functions may choose to also use the legacy CMOS RTC. - */ -__weak DEFINE_SPINLOCK(rtc_lock); - static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { unsigned long flags; efi_status_t status; - spin_lock_irqsave(_lock, flags); - spin_lock(_runtime_lock); + spin_lock_irqsave(_runtime_lock, flags); status = efi_call_virt(get_time, tm, tc); - spin_unlock(_runtime_lock); - spin_unlock_irqrestore(_lock, flags); + spin_unlock_irqrestore(_runtime_lock, flags); return status; } @@ -87,11 +77,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) unsigned long flags; efi_status_t status; - spin_lock_irqsave(_lock, flags); - spin_lock(_runtime_lock); + spin_lock_irqsave(_runtime_lock, flags); status = efi_call_virt(set_time, tm); - spin_unlock(_runtime_lock); - spin_unlock_irqrestore(_lock, flags); + spin_unlock_irqrestore(_runtime_lock, flags); return status; } @@ -102,11 +90,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, unsigned long flags; efi_status_t status; - spin_lock_irqsave(_lock, flags); - spin_lock(_runtime_lock); + spin_lock_irqsave(_runtime_lock, flags); status = efi_call_virt(get_wakeup_time, enabled, pending, tm); - spin_unlock(_runtime_lock); - spin_unlock_irqrestore(_lock, flags); + spin_unlock_irqrestore(_runtime_lock, flags); return status; } @@ -115,11 +101,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) unsigned long flags; efi_status_t status; - spin_lock_irqsave(_lock, flags); - spin_lock(_runtime_lock); + spin_lock_irqsave(_runtime_lock, flags); status = efi_call_virt(set_wakeup_time, enabled, tm); - spin_unlock(_runtime_lock); - spin_unlock_irqrestore(_lock, flags); + spin_unlock_irqrestore(_runtime_lock, flags); return status; }
[tip:efi/core] efi: Expose non-blocking set_variable() wrapper to efivars
Commit-ID: 9c6672ac9c91f7eb1ec436be1442b8c26d098e55 Gitweb: http://git.kernel.org/tip/9c6672ac9c91f7eb1ec436be1442b8c26d098e55 Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:06:55 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:01 +0100 efi: Expose non-blocking set_variable() wrapper to efivars Commit 6d80dba1c9fe ("efi: Provide a non-blocking SetVariable() operation") implemented a non-blocking alternative for the UEFI SetVariable() invocation performed by efivars, since it may occur in atomic context. However, this version of the function was never exposed via the efivars struct, so the non-blocking versions was not actually callable. Fix that. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Fixes: 6d80dba1c9fe ("efi: Provide a non-blocking SetVariable() operation") Link: http://lkml.kernel.org/r/1454364428-494-2-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/efi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 9b815c8..20451c2 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -182,6 +182,7 @@ static int generic_ops_register(void) { generic_ops.get_variable = efi.get_variable; generic_ops.set_variable = efi.set_variable; + generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking; generic_ops.get_next_variable = efi.get_next_variable; generic_ops.query_variable_store = efi_query_variable_store;
[tip:efi/core] efi/runtime-wrappers: Add a nonblocking version of QueryVariableInfo()
Commit-ID: d3cac1f83c631b9fe5edaebcba49f6989bfff089 Gitweb: http://git.kernel.org/tip/d3cac1f83c631b9fe5edaebcba49f6989bfff089 Author: Ard BiesheuvelAuthorDate: Mon, 1 Feb 2016 22:06:57 + Committer: Ingo Molnar CommitDate: Wed, 3 Feb 2016 11:31:03 +0100 efi/runtime-wrappers: Add a nonblocking version of QueryVariableInfo() This introduces a new runtime wrapper for the QueryVariableInfo() UEFI Runtime Service, which gives up immediately rather than spins on failure to grab the efi_runtime spinlock. This is required in the non-blocking path of the efi-pstore code. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1454364428-494-4-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/runtime-wrappers.c | 22 ++ include/linux/efi.h | 1 + 2 files changed, 23 insertions(+) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 228bbf9..e9f2867 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -230,6 +230,27 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, return status; } +static efi_status_t +virt_efi_query_variable_info_nonblocking(u32 attr, +u64 *storage_space, +u64 *remaining_space, +u64 *max_variable_size) +{ + unsigned long flags; + efi_status_t status; + + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) + return EFI_UNSUPPORTED; + + if (!spin_trylock_irqsave(_runtime_lock, flags)) + return EFI_NOT_READY; + + status = efi_call_virt(query_variable_info, attr, storage_space, + remaining_space, max_variable_size); + spin_unlock_irqrestore(_runtime_lock, flags); + return status; +} + static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) { unsigned long flags; @@ -300,6 +321,7 @@ void efi_native_runtime_setup(void) efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; efi.reset_system = virt_efi_reset_system; efi.query_variable_info = virt_efi_query_variable_info; + efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; efi.update_capsule = virt_efi_update_capsule; efi.query_capsule_caps = virt_efi_query_capsule_caps; } diff --git a/include/linux/efi.h b/include/linux/efi.h index 8706e0a..ad1e177 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -849,6 +849,7 @@ extern struct efi { efi_set_variable_t *set_variable; efi_set_variable_t *set_variable_nonblocking; efi_query_variable_info_t *query_variable_info; + efi_query_variable_info_t *query_variable_info_nonblocking; efi_update_capsule_t *update_capsule; efi_query_capsule_caps_t *query_capsule_caps; efi_get_next_high_mono_count_t *get_next_high_mono_count;
[tip:efi/core] efi/arm64: Check for h/w support before booting a >4 KB granular kernel
Commit-ID: 42b55734030c1f724d5f47aeb872e2cccd650d79 Gitweb: http://git.kernel.org/tip/42b55734030c1f724d5f47aeb872e2cccd650d79 Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:36:02 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:27 +0100 efi/arm64: Check for h/w support before booting a >4 KB granular kernel A kernel built with support for a page size that is not supported by the hardware it runs on cannot boot to a state where it can inform the user about the failure. If we happen to be booting via UEFI, we can fail gracefully so check if the currently configured page size is supported by the hardware before entering the kernel proper. Note that UEFI mandates support for 4 KB pages, so in that case, no check is needed. Tested-by: Suzuki K Poulose Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Jeremy Linton Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-10-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm64-stub.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 9e03427..047fc34 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -12,6 +12,26 @@ #include #include #include +#include + +efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) +{ + u64 tg; + + /* UEFI mandates support for 4 KB granularity, no need to check */ + if (IS_ENABLED(CONFIG_ARM64_4K_PAGES)) + return EFI_SUCCESS; + + tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf; + if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) { + if (IS_ENABLED(CONFIG_ARM64_64K_PAGES)) + pr_efi_err(sys_table_arg, "This 64 KB granular kernel is not supported by your CPU\n"); + else + pr_efi_err(sys_table_arg, "This 16 KB granular kernel is not supported by your CPU\n"); + return EFI_UNSUPPORTED; + } + return EFI_SUCCESS; +} efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, unsigned long *image_addr,
[tip:efi/core] efi/arm-init: Use read-only early mappings
Commit-ID: 2eec5dedf770dc85c1fdf6b86873165e61bb1fff Gitweb: http://git.kernel.org/tip/2eec5dedf770dc85c1fdf6b86873165e61bb1fff Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:36:00 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:27 +0100 efi/arm-init: Use read-only early mappings The early mappings of the EFI system table contents and the UEFI memory map are read-only from the OS point of view. So map them read-only to protect them from inadvertent modification. Tested-by: Mark Rutland Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-8-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 9e15d57..aa1f743 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -61,8 +61,8 @@ static int __init uefi_init(void) char vendor[100] = "unknown"; int i, retval; - efi.systab = early_memremap(efi_system_table, - sizeof(efi_system_table_t)); + efi.systab = early_memremap_ro(efi_system_table, + sizeof(efi_system_table_t)); if (efi.systab == NULL) { pr_warn("Unable to map EFI system table.\n"); return -ENOMEM; @@ -86,8 +86,8 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0x); /* Show what we know for posterity */ - c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), -sizeof(vendor) * sizeof(efi_char16_t)); + c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor), + sizeof(vendor) * sizeof(efi_char16_t)); if (c16) { for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) vendor[i] = c16[i]; @@ -100,8 +100,8 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0x, vendor); table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; - config_tables = early_memremap(efi_to_phys(efi.systab->tables), - table_size); + config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables), + table_size); if (config_tables == NULL) { pr_warn("Unable to map EFI config table array.\n"); retval = -ENOMEM; @@ -185,7 +185,7 @@ void __init efi_init(void) efi_system_table = params.system_table; memmap.phys_map = params.mmap; - memmap.map = early_memremap(params.mmap, params.mmap_size); + memmap.map = early_memremap_ro(params.mmap, params.mmap_size); if (memmap.map == NULL) { /* * If we are booting via UEFI, the UEFI memory map is the only
[tip:efi/core] efi/arm*: Perform hardware compatibility check
Commit-ID: b9d6769b5678dbd6cb328d20716561d35b2b1510 Gitweb: http://git.kernel.org/tip/b9d6769b5678dbd6cb328d20716561d35b2b1510 Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:36:03 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:27 +0100 efi/arm*: Perform hardware compatibility check Before proceeding with relocating the kernel and parsing the command line, insert a call to check_platform_features() to allow an arch specific check to be performed whether the current kernel can execute on the current hardware. Tested-by: Suzuki K Poulose Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Jeremy Linton Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-11-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 4 drivers/firmware/efi/libstub/efistub.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 3397902..6086a87 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -190,6 +190,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, pr_efi(sys_table, "Booting Linux Kernel...\n"); + status = check_platform_features(sys_table); + if (status != EFI_SUCCESS) + goto fail; + /* * Get a handle to the loaded image protocol. This is used to get * information about the running image, such as size and the command diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 86ff7bf..981c603 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -53,4 +53,6 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, efi_memory_desc_t *runtime_map, int *count); +efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); + #endif
[tip:efi/core] efi/arm: Check for LPAE support before booting a LPAE kernel
Commit-ID: 2ec0f0a3a4bfab90eda8b81656f62e07abf2321f Gitweb: http://git.kernel.org/tip/2ec0f0a3a4bfab90eda8b81656f62e07abf2321f Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:36:01 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:27 +0100 efi/arm: Check for LPAE support before booting a LPAE kernel A kernel built with support for LPAE cannot boot to a state where it can inform the user about if it has to fail due to missing LPAE support in the hardware. If we happen to be booting via UEFI, we can fail gracefully so check for LPAE support in the hardware on CONFIG_ARM_LPAE builds before entering the kernel proper. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Jeremy Linton Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-9-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm32-stub.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index 495ebd6..6f42be4 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -9,6 +9,23 @@ #include #include +efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) +{ + int block; + + /* non-LPAE kernels can run anywhere */ + if (!IS_ENABLED(CONFIG_ARM_LPAE)) + return EFI_SUCCESS; + + /* LPAE kernels need compatible hardware */ + block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); + if (block < 5) { + pr_efi_err(sys_table_arg, "This LPAE kernel is not supported by your CPU\n"); + return EFI_UNSUPPORTED; + } + return EFI_SUCCESS; +} + efi_status_t handle_kernel_image(efi_system_table_t *sys_table, unsigned long *image_addr, unsigned long *image_size,
[tip:efi/core] arm64/vmlinux.lds.S: Handle .init.rodata.xxx and .init.bss sections
Commit-ID: 1ce99bf45306ba889faadced6baabebf7770c546 Gitweb: http://git.kernel.org/tip/1ce99bf45306ba889faadced6baabebf7770c546 Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:35:58 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:26 +0100 arm64/vmlinux.lds.S: Handle .init.rodata.xxx and .init.bss sections The EFI stub is typically built into the decompressor (x86, ARM) so none of its symbols are annotated as __init. However, on arm64, the stub is linked into the kernel proper, and the code is __init annotated at the section level by prepending all names of SHF_ALLOC sections with '.init'. This results in section names like .init.rodata.str1.8 (for string literals) and .init.bss (which is tiny), both of which can be moved into the .init.data output section. Tested-by: Mark Rutland Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Will Deacon Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-6-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm64/kernel/vmlinux.lds.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index e3928f5..cbf4db4 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -134,6 +134,7 @@ SECTIONS CON_INITCALL SECURITY_INITCALL INIT_RAM_FS + *(.init.rodata.* .init.bss) /* from the EFI stub */ } .exit.data : { ARM_EXIT_KEEP(EXIT_DATA)
[tip:efi/core] efi/arm64: Drop __init annotation from handle_kernel_image()
Commit-ID: dae31fd2b74c35cc84128733bc210bf6b26ae408 Gitweb: http://git.kernel.org/tip/dae31fd2b74c35cc84128733bc210bf6b26ae408 Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:35:57 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:26 +0100 efi/arm64: Drop __init annotation from handle_kernel_image() After moving arm64-stub.c to libstub/, all of its sections are emitted as .init.xxx sections automatically, and the __init annotation of handle_kernel_image() causes it to end up in .init.init.text, which is not recognized as an __init section by the linker scripts. So drop the annotation. Tested-by: Mark Rutland Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Will Deacon Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-5-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm64-stub.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 78dfbd3..9e03427 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -13,13 +13,13 @@ #include #include -efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, - unsigned long *image_addr, - unsigned long *image_size, - unsigned long *reserve_addr, - unsigned long *reserve_size, - unsigned long dram_base, - efi_loaded_image_t *image) +efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, +unsigned long *image_addr, +unsigned long *image_size, +unsigned long *reserve_addr, +unsigned long *reserve_size, +unsigned long dram_base, +efi_loaded_image_t *image) { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0;
[tip:efi/core] efi/runtime-wrappers: Run UEFI Runtime Services with interrupts enabled
Commit-ID: fe3244945c47161e2486412d6412c87ba279305d Gitweb: http://git.kernel.org/tip/fe3244945c47161e2486412d6412c87ba279305d Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:35:55 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:25 +0100 efi/runtime-wrappers: Run UEFI Runtime Services with interrupts enabled The UEFI spec allows Runtime Services to be invoked with interrupts enabled. The only reason we were disabling interrupts was to prevent recursive calls into the services on the same CPU, which will lead to deadlock. However, the only context where such invocations may occur legally is from efi-pstore via efivars, and that code has been updated to call a non-blocking alternative when invoked from a non-interruptible context. So instead, update the ordinary, blocking UEFI Runtime Services wrappers to execute with interrupts enabled. This aims to prevent excessive interrupt latencies on uniprocessor platforms with slow variable stores. Note that other OSes such as Windows call UEFI Runtime Services with interrupts enabled as well. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Andy Lutomirski Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-3-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/runtime-wrappers.c | 71 + 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 7b8b2f2..de69530 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -63,23 +63,21 @@ static DEFINE_SPINLOCK(efi_runtime_lock); static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(get_time, tm, tc); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } static efi_status_t virt_efi_set_time(efi_time_t *tm) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(set_time, tm); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } @@ -87,23 +85,21 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(get_wakeup_time, enabled, pending, tm); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(set_wakeup_time, enabled, tm); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } @@ -113,13 +109,12 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, unsigned long *data_size, void *data) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(get_variable, name, vendor, attr, data_size, data); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } @@ -127,12 +122,11 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) { - unsigned long flags; efi_status_t status; - spin_lock_irqsave(_runtime_lock, flags); + spin_lock(_runtime_lock); status = efi_call_virt(get_next_variable, name_size, name, vendor); - spin_unlock_irqrestore(_runtime_lock, flags); + spin_unlock(_runtime_lock); return status; } @@ -142,13 +136,12 @@ static efi_status_t
[tip:efi/core] efi/efistub: Prevent __init annotations from being used
Commit-ID: 07e83dbb75865b016f6493c119a30aac7c25051a Gitweb: http://git.kernel.org/tip/07e83dbb75865b016f6493c119a30aac7c25051a Author: Ard BiesheuvelAuthorDate: Wed, 17 Feb 2016 12:35:59 + Committer: Ingo Molnar CommitDate: Mon, 22 Feb 2016 08:26:26 +0100 efi/efistub: Prevent __init annotations from being used __init annotations should not be used in the EFI stub, since the code is either included in the decompressor (x86, ARM) where they have no effect, or the whole stub is __init annotated at the section level (arm64), by renaming the sections. In the second case the __init annotations will be redundant, and will result in section names like .init.init.text, and our linker script does not expect that. So un-#define __init so that its inadvertent use will force a build error. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1455712566-16727-7-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/efistub.h | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 6b6548f..86ff7bf 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -5,6 +5,16 @@ /* error code which can't be mistaken for valid address */ #define EFI_ERROR (~0UL) +/* + * __init annotations should not be used in the EFI stub, since the code is + * either included in the decompressor (x86, ARM) where they have no effect, + * or the whole stub is __init annotated at the section level (arm64), by + * renaming the sections, in which case the __init annotation will be + * redundant, and will result in section names like .init.init.text, and our + * linker script does not expect that. + */ +#undef __init + void efi_char16_printk(efi_system_table_t *, efi_char16_t *); efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
[tip:efi/core] efifb: Enable the efi-framebuffer platform driver for ARM and arm64
Commit-ID: 9822504c1fa5c557ea8776765f03fd16eb4de4c9 Gitweb: http://git.kernel.org/tip/9822504c1fa5c557ea8776765f03fd16eb4de4c9 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:56 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:34:01 +0200 efifb: Enable the efi-framebuffer platform driver for ARM and arm64 Allows the efifb driver to be built for ARM and arm64. This simply involves updating the Kconfig dependency expression, and supplying dummy versions of efifb_setup_from_dmi(). Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-25-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h | 4 arch/arm64/include/asm/efi.h | 4 drivers/video/fbdev/Kconfig | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index 25f8b11..b45fe39 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -67,6 +67,10 @@ void efi_virtmap_unload(void); struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg); void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si); +static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) +{ +} + /* * A reasonable upper bound for the uncompressed kernel size is 32 MBytes, * so we will reserve that amount of memory. We have no easy way to tell what diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index fa09886..79dc8c2 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -59,6 +59,10 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); #define alloc_screen_info(x...)_info #define free_screen_info(x...) +static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) +{ +} + #define EFI_ALLOC_ALIGNSZ_64K /* diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 983280e..e5a391a 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -761,7 +761,7 @@ config FB_VESA config FB_EFI bool "EFI-based Framebuffer Support" - depends on (FB = y) && X86 && EFI + depends on (FB = y) && !IA64 && EFI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT
[tip:efi/core] efifb: Use builtin_platform_driver and drop unused includes
Commit-ID: 07ea7ec5df3ee4a9fedb3d81dc69c2f8d07d44c0 Gitweb: http://git.kernel.org/tip/07ea7ec5df3ee4a9fedb3d81dc69c2f8d07d44c0 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:51 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:58 +0200 efifb: Use builtin_platform_driver and drop unused includes Since efifb can only be built directly into the kernel, drop the module specific includes and definitions. Drop some other includes we don't need as well. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Peter Jones Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-20-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/video/fbdev/efifb.c | 6 +- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index dd59436..f4c045c 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -6,15 +6,12 @@ * */ -#include #include #include #include #include #include #include -#include -#include #include #include @@ -331,5 +328,4 @@ static struct platform_driver efifb_driver = { .remove = efifb_remove, }; -module_platform_driver(efifb_driver); -MODULE_LICENSE("GPL"); +builtin_platform_driver(efifb_driver);
[tip:efi/core] efi/arm*: Wire up 'struct screen_info' to efi-framebuffer platform device
Commit-ID: e3271c96ca7d01957b03b5f1e2bdc00e08fd7160 Gitweb: http://git.kernel.org/tip/e3271c96ca7d01957b03b5f1e2bdc00e08fd7160 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:55 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:34:01 +0200 efi/arm*: Wire up 'struct screen_info' to efi-framebuffer platform device This adds code to the ARM and arm64 EFI init routines to expose a platform device of type 'efi-framebuffer' if 'struct screen_info' has been populated appropriately from the GOP protocol by the stub. Since the framebuffer may potentially be located in system RAM, make sure that the region is reserved and marked MEMBLOCK_NOMAP. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-24-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index ac95dd8..7a3318d 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -78,6 +79,10 @@ static void __init init_screen_info(void) screen_info.orig_video_cols = 80; screen_info.orig_video_lines = 25; } + + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && + memblock_is_map_memory(screen_info.lfb_base)) + memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); } static int __init uefi_init(void) @@ -256,3 +261,16 @@ void __init efi_init(void) init_screen_info(); } + +static int __init register_gop_device(void) +{ + void *pd; + + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + return 0; + + pd = platform_device_register_data(NULL, "efi-framebuffer", 0, + _info, sizeof(screen_info)); + return PTR_ERR_OR_ZERO(pd); +} +subsys_initcall(register_gop_device);
[tip:efi/core] efi/arm/libstub: Make screen_info accessible to the UEFI stub
Commit-ID: 801820bee9bccb7c156af2b95c7208f428a06ae7 Gitweb: http://git.kernel.org/tip/801820bee9bccb7c156af2b95c7208f428a06ae7 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:53 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:59 +0200 efi/arm/libstub: Make screen_info accessible to the UEFI stub In order to hand over the framebuffer described by the GOP protocol and discovered by the UEFI stub, make struct screen_info accessible by the stub. This involves allocating a loader data buffer and passing it to the kernel proper via a UEFI Configuration Table, since the UEFI stub executes in the context of the decompressor, and cannot access the kernel's copy of struct screen_info directly. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-22-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h| 3 +++ arch/arm/kernel/setup.c | 3 ++- drivers/firmware/efi/arm-init.c | 34 +++- drivers/firmware/efi/efi.c| 5 +++-- drivers/firmware/efi/libstub/arm32-stub.c | 37 +++ include/linux/efi.h | 11 - 6 files changed, 88 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index dc30d89..25f8b11 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -64,6 +64,9 @@ void efi_virtmap_unload(void); #define __efi_call_early(f, ...) f(__VA_ARGS__) #define efi_is_64bit() (false) +struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg); +void free_screen_info(efi_system_table_t *sys_table, struct screen_info *si); + /* * A reasonable upper bound for the uncompressed kernel size is 32 MBytes, * so we will reserve that amount of memory. We have no easy way to tell what diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 2c4bea3..7d4e285 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -883,7 +883,8 @@ static void __init request_standard_resources(const struct machine_desc *mdesc) request_resource(_resource, ); } -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) +#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) || \ +defined(CONFIG_EFI) struct screen_info screen_info = { .orig_video_lines = 30, .orig_video_cols = 80, diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 909d974..ac95dd8 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -11,12 +11,15 @@ * */ +#define pr_fmt(fmt)"efi: " fmt + #include #include #include #include #include #include +#include #include @@ -51,6 +54,32 @@ static phys_addr_t efi_to_phys(unsigned long addr) return addr; } +static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR; + +static __initdata efi_config_table_type_t arch_tables[] = { + {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, _info_table}, + {NULL_GUID, NULL, NULL} +}; + +static void __init init_screen_info(void) +{ + struct screen_info *si; + + if (screen_info_table != EFI_INVALID_TABLE_ADDR) { + si = early_memremap_ro(screen_info_table, sizeof(*si)); + if (!si) { + pr_err("Could not map screen_info config table\n"); + return; + } + screen_info = *si; + early_memunmap(si, sizeof(*si)); + + /* dummycon on ARM needs non-zero values for columns/lines */ + screen_info.orig_video_cols = 80; + screen_info.orig_video_lines = 25; + } +} + static int __init uefi_init(void) { efi_char16_t *c16; @@ -108,7 +137,8 @@ static int __init uefi_init(void) goto out; } retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, -sizeof(efi_config_table_t), NULL); +sizeof(efi_config_table_t), +arch_tables); early_memunmap(config_tables, table_size); out: @@ -223,4 +253,6 @@ void __init efi_init(void) PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); } + +
[tip:efi/core] efi/arm*/libstub: Wire up GOP protocol to 'struct screen_info'
Commit-ID: f0827e18a7a1da574ba8201a8b18f63778451aae Gitweb: http://git.kernel.org/tip/f0827e18a7a1da574ba8201a8b18f63778451aae Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:54 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:34:00 +0200 efi/arm*/libstub: Wire up GOP protocol to 'struct screen_info' This adds the code to the ARM and arm64 versions of the UEFI stub to populate struct screen_info based on the information received from the firmware via the GOP protocol. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-23-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 1286325..993aa56 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -169,6 +169,25 @@ void efi_char16_printk(efi_system_table_t *sys_table_arg, out->output_string(out, str); } +static struct screen_info *setup_graphics(efi_system_table_t *sys_table_arg) +{ + efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + efi_status_t status; + unsigned long size; + void **gop_handle = NULL; + struct screen_info *si = NULL; + + size = 0; + status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL, + _proto, NULL, , gop_handle); + if (status == EFI_BUFFER_TOO_SMALL) { + si = alloc_screen_info(sys_table_arg); + if (!si) + return NULL; + efi_setup_gop(sys_table_arg, si, _proto, size); + } + return si; +} /* * This function handles the architcture specific differences between arm and @@ -208,6 +227,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, unsigned long reserve_addr = 0; unsigned long reserve_size = 0; int secure_boot = 0; + struct screen_info *si; /* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) @@ -260,6 +280,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, __nokaslr = true; } + si = setup_graphics(sys_table); + status = handle_kernel_image(sys_table, image_addr, _size, _addr, _size, @@ -341,6 +363,7 @@ fail_free_image: efi_free(sys_table, image_size, *image_addr); efi_free(sys_table, reserve_size, reserve_addr); fail_free_cmdline: + free_screen_info(sys_table, si); efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); fail: return EFI_ERROR;
[tip:efi/core] efi: Get rid of the EFI_SYSTEM_TABLES status bit
Commit-ID: c5b591e96db9d99d0126acf93f24e1fb8b368343 Gitweb: http://git.kernel.org/tip/c5b591e96db9d99d0126acf93f24e1fb8b368343 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:33 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:46 +0200 efi: Get rid of the EFI_SYSTEM_TABLES status bit The EFI_SYSTEM_TABLES status bit is set by all EFI supporting architectures upon discovery of the EFI system table, but the bit is never tested in any code we have in the tree. So remove it. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Leif Lindholm Cc: Luck, Tony Cc: Mark Rutland Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-2-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/ia64/kernel/efi.c | 2 -- arch/x86/platform/efi/efi.c| 2 -- drivers/firmware/efi/arm-runtime.c | 1 - include/linux/efi.h| 1 - 4 files changed, 6 deletions(-) diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 300dac3..bf0865c 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -531,8 +531,6 @@ efi_init (void) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0x, vendor); - set_bit(EFI_SYSTEM_TABLES, ); - palo_phys = EFI_INVALID_TABLE_ADDR; if (efi_config_init(arch_tables) != 0) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 994a7df8..df393ea 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -352,8 +352,6 @@ static int __init efi_systab_init(void *phys) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0x); - set_bit(EFI_SYSTEM_TABLES, ); - return 0; } diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 6ae21e4..16c7d2a 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -105,7 +105,6 @@ static int __init arm_enable_runtime_services(void) pr_err("Failed to remap EFI System Table\n"); return -ENOMEM; } - set_bit(EFI_SYSTEM_TABLES, ); if (!efi_virtmap_init()) { pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); diff --git a/include/linux/efi.h b/include/linux/efi.h index 1626474..1545098 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1000,7 +1000,6 @@ extern int __init efi_setup_pcdp_console(char *); * possible, remove EFI-related code altogether. */ #define EFI_BOOT 0 /* Were we booted from EFI? */ -#define EFI_SYSTEM_TABLES 1 /* Can we use EFI system tables? */ #define EFI_CONFIG_TABLES 2 /* Can we use EFI config tables? */ #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */
[tip:efi/core] efi/arm-init: Reserve rather than unmap the memory map for ARM as well
Commit-ID: 249f7632162980b286f30166436471f8ba81fc1e Gitweb: http://git.kernel.org/tip/249f7632162980b286f30166436471f8ba81fc1e Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:07:02 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:34:05 +0200 efi/arm-init: Reserve rather than unmap the memory map for ARM as well Now that ARM has a fully functional memremap() implementation, there is no longer a need to remove the UEFI memory map from the linear mapping in order to be able to create a permanent mapping for it using generic code. So remove the 'IS_ENABLED(CONFIG_ARM)' conditional we added in: 7cc8cbcf82d1 ("efi/arm64: Don't apply MEMBLOCK_NOMAP to UEFI memory map mapping") ... and revert to using memblock_reserve() for both ARM and arm64. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Leif Lindholm Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-31-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c | 17 +++-- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 7a3318d..ef90f0c 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -244,20 +244,9 @@ void __init efi_init(void) efi_memattr_init(); early_memunmap(efi.memmap.map, params.mmap_size); - if (IS_ENABLED(CONFIG_ARM)) { - /* -* ARM currently does not allow ioremap_cache() to be called on -* memory regions that are covered by struct page. So remove the -* UEFI memory map from the linear mapping. -*/ - memblock_mark_nomap(params.mmap & PAGE_MASK, - PAGE_ALIGN(params.mmap_size + - (params.mmap & ~PAGE_MASK))); - } else { - memblock_reserve(params.mmap & PAGE_MASK, -PAGE_ALIGN(params.mmap_size + - (params.mmap & ~PAGE_MASK))); - } + memblock_reserve(params.mmap & PAGE_MASK, +PAGE_ALIGN(params.mmap_size + + (params.mmap & ~PAGE_MASK))); init_screen_info(); }
[tip:efi/core] ARM/efi: Apply strict permissions for UEFI Runtime Services regions
Commit-ID: 9fc68b717c24a215a32c1b4e05b30433cafb2599 Gitweb: http://git.kernel.org/tip/9fc68b717c24a215a32c1b4e05b30433cafb2599 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:42 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:53 +0200 ARM/efi: Apply strict permissions for UEFI Runtime Services regions Recent UEFI versions expose permission attributes for runtime services memory regions, either in the UEFI memory map or in the separate memory attributes table. This allows the kernel to map these regions with stricter permissions, rather than the RWX permissions that are used by default. So wire this up in our mapping routine. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Catalin Marinas Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Russell King Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-11-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h | 1 + arch/arm/kernel/efi.c | 41 + 2 files changed, 42 insertions(+) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index e0eea72..b0c341d 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -22,6 +22,7 @@ void efi_init(void); int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); +int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); #define efi_call_virt(f, ...) \ ({ \ diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c index ff8a9d8..9f43ba0 100644 --- a/arch/arm/kernel/efi.c +++ b/arch/arm/kernel/efi.c @@ -11,6 +11,41 @@ #include #include +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(L_PTE_RDONLY)); + if (md->attribute & EFI_MEMORY_XP) + pte = set_pte_bit(pte, __pgprot(L_PTE_XN)); + set_pte_ext(ptep, pte, PTE_EXT_NG); + return 0; +} + +int __init efi_set_mapping_permissions(struct mm_struct *mm, + efi_memory_desc_t *md) +{ + unsigned long base, size; + + base = md->virt_addr; + size = md->num_pages << EFI_PAGE_SHIFT; + + /* +* We can only use apply_to_page_range() if we can guarantee that the +* entire region was mapped using pages. This should be the case if the +* region does not cover any naturally aligned SECTION_SIZE sized +* blocks. +*/ + if (round_down(base + size, SECTION_SIZE) < + round_up(base, SECTION_SIZE) + SECTION_SIZE) + return apply_to_page_range(mm, base, size, set_permissions, md); + + return 0; +} + int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) { struct map_desc desc = { @@ -34,5 +69,11 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) desc.type = MT_DEVICE; create_mapping_late(mm, , true); + + /* +* If stricter permissions were specified, apply them now. +*/ + if (md->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP)) + return efi_set_mapping_permissions(mm, md); return 0; }
[tip:efi/core] efi: Add support for the EFI_MEMORY_ATTRIBUTES_TABLE config table
Commit-ID: a604af075a3226adaff84b7026876f0c6dfe9f52 Gitweb: http://git.kernel.org/tip/a604af075a3226adaff84b7026876f0c6dfe9f52 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:44 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:54 +0200 efi: Add support for the EFI_MEMORY_ATTRIBUTES_TABLE config table This declares the GUID and struct typedef for the new memory attributes table which contains the permissions that can be used to apply stricter permissions to UEFI Runtime Services memory regions. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Catalin Marinas Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-13-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/efi.c | 2 ++ include/linux/efi.h| 13 + 2 files changed, 15 insertions(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index f7d36c6..583e647 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -43,6 +43,7 @@ struct efi __read_mostly efi = { .config_table = EFI_INVALID_TABLE_ADDR, .esrt = EFI_INVALID_TABLE_ADDR, .properties_table = EFI_INVALID_TABLE_ADDR, + .mem_attr_table = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -338,6 +339,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {UGA_IO_PROTOCOL_GUID, "UGA", }, {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", }, {EFI_PROPERTIES_TABLE_GUID, "PROP", _table}, + {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", _attr_table}, {NULL_GUID, NULL, NULL}, }; diff --git a/include/linux/efi.h b/include/linux/efi.h index c2c0da4..81af5fe 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -623,6 +623,10 @@ void efi_native_runtime_setup(void); EFI_GUID(0x3152bca5, 0xeade, 0x433d, \ 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) +#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID \ + EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, \ +0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) + typedef struct { efi_guid_t guid; u64 table; @@ -847,6 +851,14 @@ typedef struct { #define EFI_INVALID_TABLE_ADDR (~0UL) +typedef struct { + u32 version; + u32 num_entries; + u32 desc_size; + u32 reserved; + efi_memory_desc_t entry[0]; +} efi_memory_attributes_table_t; + /* * All runtime access to EFI goes through this structure: */ @@ -868,6 +880,7 @@ extern struct efi { unsigned long config_table; /* config tables */ unsigned long esrt; /* ESRT table */ unsigned long properties_table; /* properties table */ + unsigned long mem_attr_table; /* memory attributes table */ efi_get_time_t *get_time; efi_set_time_t *set_time; efi_get_wakeup_time_t *get_wakeup_time;
[tip:efi/core] efi: Implement generic support for the Memory Attributes table
Commit-ID: 10f0d2f57705350bbbe5f28e9292ae3905823c3c Gitweb: http://git.kernel.org/tip/10f0d2f57705350bbbe5f28e9292ae3905823c3c Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:45 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:54 +0200 efi: Implement generic support for the Memory Attributes table This implements shared support for discovering the presence of the Memory Attributes table, and for parsing and validating its contents. The table is validated against the construction rules in the UEFI spec. Since this is a new table, it makes sense to complain if we encounter a table that does not follow those rules. The parsing and validation routine takes a callback that can be specified per architecture, that gets passed each unique validated region, with the virtual address retrieved from the ordinary memory map. Signed-off-by: Ard Biesheuvel [ Trim pr_*() strings to 80 cols and use EFI consistently. ] Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Catalin Marinas Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-14-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/Makefile | 2 +- drivers/firmware/efi/memattr.c | 182 + include/linux/efi.h| 13 +++ 3 files changed, 196 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 62e654f..d5be623 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -9,7 +9,7 @@ # KASAN_SANITIZE_runtime-wrappers.o := n -obj-$(CONFIG_EFI) += efi.o vars.o reboot.o +obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_ESRT) += esrt.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c new file mode 100644 index 000..236004b --- /dev/null +++ b/drivers/firmware/efi/memattr.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2016 Linaro Ltd. + * + * 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. + */ + +#define pr_fmt(fmt)"efi: memattr: " fmt + +#include +#include +#include +#include + +#include + +static int __initdata tbl_size; + +/* + * Reserve the memory associated with the Memory Attributes configuration + * table, if it exists. + */ +int __init efi_memattr_init(void) +{ + efi_memory_attributes_table_t *tbl; + + if (efi.mem_attr_table == EFI_INVALID_TABLE_ADDR) + return 0; + + tbl = early_memremap(efi.mem_attr_table, sizeof(*tbl)); + if (!tbl) { + pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n", + efi.mem_attr_table); + return -ENOMEM; + } + + if (tbl->version > 1) { + pr_warn("Unexpected EFI Memory Attributes table version %d\n", + tbl->version); + goto unmap; + } + + tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size; + memblock_reserve(efi.mem_attr_table, tbl_size); + +unmap: + early_memunmap(tbl, sizeof(*tbl)); + return 0; +} + +/* + * Returns a copy @out of the UEFI memory descriptor @in if it is covered + * entirely by a UEFI memory map entry with matching attributes. The virtual + * address of @out is set according to the matching entry that was found. + */ +static bool entry_is_valid(const efi_memory_desc_t *in, efi_memory_desc_t *out) +{ + u64 in_paddr = in->phys_addr; + u64 in_size = in->num_pages << EFI_PAGE_SHIFT; + efi_memory_desc_t *md; + + *out = *in; + + if (in->type != EFI_RUNTIME_SERVICES_CODE && + in->type != EFI_RUNTIME_SERVICES_DATA) { + pr_warn("Entry type should be RuntimeServiceCode/Data\n"); + return false; + } + + if (!(in->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))) { + pr_warn("Entry attributes invalid: RO and XP bits both cleared\n"); + return false; + } + + if (PAGE_SIZE > EFI_PAGE_SIZE && + (!PAGE_ALIGNED(in->phys_addr) || +!PAGE_ALIGNED(in->num_pages << EFI_PAGE_SHIFT))) { + /* +* Since
[tip:efi/core] arm64/efi: Apply strict permissions to UEFI Runtime Services regions
Commit-ID: 1fd55a9a09b0293af95ab4299b108f030fef4464 Gitweb: http://git.kernel.org/tip/1fd55a9a09b0293af95ab4299b108f030fef4464 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:43 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:53 +0200 arm64/efi: Apply strict permissions to UEFI Runtime Services regions Recent UEFI versions expose permission attributes for runtime services memory regions, either in the UEFI memory map or in the separate memory attributes table. This allows the kernel to map these regions with stricter permissions, rather than the RWX permissions that are used by default. So wire this up in our mapping routine. Note that in the absence of permission attributes, we still only map regions of type EFI_RUNTIME_SERVICE_CODE with the executable bit set. Also, we base the mapping attributes of EFI_MEMORY_MAPPED_IO on the type directly rather than on the absence of the EFI_MEMORY_WB attribute. This is more correct, but is also required for compatibility with the upcoming support for the Memory Attributes Table, which only carries permission attributes, not memory type attributes. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Catalin Marinas Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-12-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm64/kernel/efi.c | 54 - 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index b6abc85..33a6da1 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -17,22 +17,48 @@ #include -int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) +/* + * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be + * executable, everything else can be mapped with the XN bits + * set. Also take the new (optional) RO/XP bits into account. + */ +static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) { - pteval_t prot_val; + u64 attr = md->attribute; + u32 type = md->type; - /* -* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be -* executable, everything else can be mapped with the XN bits -* set. -*/ - if ((md->attribute & EFI_MEMORY_WB) == 0) - prot_val = PROT_DEVICE_nGnRE; - else if (md->type == EFI_RUNTIME_SERVICES_CODE || -!PAGE_ALIGNED(md->phys_addr)) - prot_val = pgprot_val(PAGE_KERNEL_EXEC); - else - prot_val = pgprot_val(PAGE_KERNEL); + if (type == EFI_MEMORY_MAPPED_IO) + return PROT_DEVICE_nGnRE; + + if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr), + "UEFI Runtime regions are not aligned to 64 KB -- buggy firmware?")) + /* +* If the region is not aligned to the page size of the OS, we +* can not use strict permissions, since that would also affect +* the mapping attributes of the adjacent regions. +*/ + return pgprot_val(PAGE_KERNEL_EXEC); + + /* R-- */ + if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) == + (EFI_MEMORY_XP | EFI_MEMORY_RO)) + return pgprot_val(PAGE_KERNEL_RO); + + /* R-X */ + if (attr & EFI_MEMORY_RO) + return pgprot_val(PAGE_KERNEL_ROX); + + /* RW- */ + if (attr & EFI_MEMORY_XP || type != EFI_RUNTIME_SERVICES_CODE) + return pgprot_val(PAGE_KERNEL); + + /* RWX */ + return pgprot_val(PAGE_KERNEL_EXEC); +} + +int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) +{ + pteval_t prot_val = create_mapping_protection(md); create_pgd_mapping(mm, md->phys_addr, md->virt_addr, md->num_pages << EFI_PAGE_SHIFT,
[tip:efi/core] efi: Check EFI_MEMORY_DESCRIPTOR version explicitly
Commit-ID: 0d054ad96e97dcd8966e9333eabcc7a466672f70 Gitweb: http://git.kernel.org/tip/0d054ad96e97dcd8966e9333eabcc7a466672f70 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:40 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:51 +0200 efi: Check EFI_MEMORY_DESCRIPTOR version explicitly Our efi_memory_desc_t type is based on EFI_MEMORY_DESCRIPTOR version 1 in the UEFI spec. No version updates are expected, but since we are about to introduce support for new firmware tables that use the same descriptor type, it makes sense to at least warn if we encounter other versions. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-9-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/efi.c | 4 drivers/firmware/efi/arm-init.c | 4 2 files changed, 8 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 88d2fb2..dde46cd 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -211,6 +211,10 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_size= e->efi_memdesc_size; efi.memmap.desc_version = e->efi_memdesc_version; + WARN(efi.memmap.desc_version != 1, +"Unexpected EFI_MEMORY_DESCRIPTOR version %ld", +efi.memmap.desc_version); + memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); return 0; diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 90a9b47..a84dddb 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -198,6 +198,10 @@ void __init efi_init(void) efi.memmap.desc_size = params.desc_size; efi.memmap.desc_version = params.desc_ver; + WARN(efi.memmap.desc_version != 1, +"Unexpected EFI_MEMORY_DESCRIPTOR version %ld", + efi.memmap.desc_version); + if (uefi_init() < 0) return;
[tip:efi/core] efi/arm*: Use memremap() to create the persistent memmap mapping
Commit-ID: 24d45d1dc275b818093fe1d0055a230ce5e8c4c7 Gitweb: http://git.kernel.org/tip/24d45d1dc275b818093fe1d0055a230ce5e8c4c7 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:41 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:52 +0200 efi/arm*: Use memremap() to create the persistent memmap mapping Instead of using ioremap_cache(), which is slightly inappropriate for mapping firmware tables, and is not even allowed on ARM for mapping regions that are covered by a struct page, use memremap(), which was invented for this purpose, and will also reuse the existing kernel direct mapping if the requested region is covered by it. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-10-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-runtime.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 55a9ea0..19283de 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -105,8 +105,7 @@ static int __init arm_enable_runtime_services(void) mapsize = efi.memmap.map_end - efi.memmap.map; - efi.memmap.map = (__force void *)ioremap_cache(efi.memmap.phys_map, - mapsize); + efi.memmap.map = memremap(efi.memmap.phys_map, mapsize, MEMREMAP_WB); if (!efi.memmap.map) { pr_err("Failed to remap EFI memory map\n"); return -ENOMEM;
[tip:efi/core] efi/arm*: Take the Memory Attributes table into account
Commit-ID: 789957ef72f976cb325e9057225fc4e9c4513060 Gitweb: http://git.kernel.org/tip/789957ef72f976cb325e9057225fc4e9c4513060 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:46 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:55 +0200 efi/arm*: Take the Memory Attributes table into account Call into the generic memory attributes table support code at the appropriate times during the init sequence so that the UEFI Runtime Services region are mapped according to the strict permissions it specifies. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Catalin Marinas Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Sai Praneeth Prakhya Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-15-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/efi.h | 2 ++ drivers/firmware/efi/arm-init.c| 1 + drivers/firmware/efi/arm-runtime.c | 10 -- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 8e88a69..4dafc89 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -14,6 +14,8 @@ extern void efi_init(void); int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); +#define efi_set_mapping_permissionsefi_create_mapping + #define efi_call_virt(f, ...) \ ({ \ efi_##f##_t *__f; \ diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index a84dddb..909d974 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -206,6 +206,7 @@ void __init efi_init(void) return; reserve_regions(); + efi_memattr_init(); early_memunmap(efi.memmap.map, params.mmap_size); if (IS_ENABLED(CONFIG_ARM)) { diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 19283de..17ccf0a 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -77,9 +77,15 @@ static bool __init efi_virtmap_init(void) systab_found = true; } } - if (!systab_found) + if (!systab_found) { pr_err("No virtual mapping found for the UEFI System Table\n"); - return systab_found; + return false; + } + + if (efi_memattr_apply_permissions(_mm, efi_set_mapping_permissions)) + return false; + + return true; } /*
[tip:efi/core] x86/efi/efifb: Move DMI based quirks handling out of generic code
Commit-ID: 21289ec02b41c4b928a0b3de1778b325d714eea3 Gitweb: http://git.kernel.org/tip/21289ec02b41c4b928a0b3de1778b325d714eea3 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:50 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:57 +0200 x86/efi/efifb: Move DMI based quirks handling out of generic code The efifb quirks handling based on DMI identification of the platform is specific to x86, so move it to x86 arch code. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: David Herrmann Acked-by: Peter Jones Cc: Borislav Petkov Cc: Mark Rutland Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-19-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/include/asm/efi.h | 2 ++ arch/x86/kernel/sysfb_efi.c | 15 +++ drivers/video/fbdev/efifb.c | 15 --- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 10e4407..8747abe 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -180,6 +180,8 @@ static inline bool efi_runtime_supported(void) extern struct console early_efi_console; extern void parse_efi_setup(u64 phys_addr, u32 data_len); +extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt); + #ifdef CONFIG_EFI_MIXED extern void efi_thunk_runtime_setup(void); extern efi_status_t efi_thunk_set_virtual_address_map( diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c index b285d4e..e21a8a7 100644 --- a/arch/x86/kernel/sysfb_efi.c +++ b/arch/x86/kernel/sysfb_efi.c @@ -68,6 +68,21 @@ struct efifb_dmi_info efifb_dmi_list[] = { [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE } }; +void efifb_setup_from_dmi(struct screen_info *si, const char *opt) +{ + int i; + + for (i = 0; i < M_UNKNOWN; i++) { + if (efifb_dmi_list[i].base != 0 && + !strcmp(opt, efifb_dmi_list[i].optname)) { + si->lfb_base = efifb_dmi_list[i].base; + si->lfb_linelength = efifb_dmi_list[i].stride; + si->lfb_width = efifb_dmi_list[i].width; + si->lfb_height = efifb_dmi_list[i].height; + } + } +} + #define choose_value(dmivalue, fwvalue, field, flags) ({ \ typeof(fwvalue) _ret_ = fwvalue;\ if ((flags) & (field)) \ diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 95d293b..dd59436 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -15,7 +16,7 @@ #include #include #include -#include +#include static bool request_mem_succeeded = false; @@ -85,21 +86,13 @@ static struct fb_ops efifb_ops = { static int efifb_setup(char *options) { char *this_opt; - int i; if (options && *options) { while ((this_opt = strsep(, ",")) != NULL) { if (!*this_opt) continue; - for (i = 0; i < M_UNKNOWN; i++) { - if (efifb_dmi_list[i].base != 0 && - !strcmp(this_opt, efifb_dmi_list[i].optname)) { - screen_info.lfb_base = efifb_dmi_list[i].base; - screen_info.lfb_linelength = efifb_dmi_list[i].stride; - screen_info.lfb_width = efifb_dmi_list[i].width; - screen_info.lfb_height = efifb_dmi_list[i].height; - } - } + efifb_setup_from_dmi(_info, this_opt); + if (!strncmp(this_opt, "base:", 5)) screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "stride:", 7))
[tip:efi/core] arm64/efi/libstub: Make screen_info accessible to the UEFI stub
Commit-ID: 57fdb89aeb7b0e3aab19847ab7399e5d76f11e6f Gitweb: http://git.kernel.org/tip/57fdb89aeb7b0e3aab19847ab7399e5d76f11e6f Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:52 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:59 +0200 arm64/efi/libstub: Make screen_info accessible to the UEFI stub Unlike on 32-bit ARM, where we need to pass the stub's version of struct screen_info to the kernel proper via a configuration table, on 64-bit ARM it simply involves making the core kernel's copy of struct screen_info visible to the stub by exposing an __efistub_ alias for it. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Will Deacon Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-21-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi.c | 3 +++ arch/arm64/kernel/image.h| 1 + 3 files changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index af40baa..fa09886 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -56,6 +56,9 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); #define __efi_call_early(f, ...) f(__VA_ARGS__) #define efi_is_64bit() (true) +#define alloc_screen_info(x...)_info +#define free_screen_info(x...) + #define EFI_ALLOC_ALIGNSZ_64K /* diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 33a6da1..78f5248 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -56,6 +56,9 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) return pgprot_val(PAGE_KERNEL_EXEC); } +/* we will fill this structure from the stub, so don't put it in .bss */ +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); diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h index 5e360ce..1428849a 100644 --- a/arch/arm64/kernel/image.h +++ b/arch/arm64/kernel/image.h @@ -112,6 +112,7 @@ __efistub___memset = KALLSYMS_HIDE(__pi_memset); __efistub__text= KALLSYMS_HIDE(_text); __efistub__end = KALLSYMS_HIDE(_end); __efistub__edata = KALLSYMS_HIDE(_edata); +__efistub_screen_info = KALLSYMS_HIDE(screen_info); #endif
[tip:efi/core] x86/efi: Prepare GOP handling code for reuse as generic code
Commit-ID: 2c23b73c2d0249c499c4784b6db08dcfc6b7b3b0 Gitweb: http://git.kernel.org/tip/2c23b73c2d0249c499c4784b6db08dcfc6b7b3b0 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:48 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:56 +0200 x86/efi: Prepare GOP handling code for reuse as generic code In preparation of moving this code to drivers/firmware/efi and reusing it on ARM and arm64, apply any changes that will be required to make this code build for other architectures. This should make it easier to track down problems that this move may cause to its operation on x86. Note that the generic version uses slightly different ways of casting the protocol methods and some other variables to the correct types, since such method calls are not loosely typed on ARM and arm64 as they are on x86. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-17-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 58 arch/x86/boot/compressed/eboot.h | 4 +++ arch/x86/include/asm/efi.h | 5 include/linux/efi.h | 5 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 583d539..10516e2 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -622,19 +622,22 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, } static efi_status_t -__gop_query32(struct efi_graphics_output_protocol_32 *gop32, +__gop_query32(efi_system_table_t *sys_table_arg, + struct efi_graphics_output_protocol_32 *gop32, struct efi_graphics_output_mode_info **info, unsigned long *size, u64 *fb_base) { struct efi_graphics_output_protocol_mode_32 *mode; + efi_graphics_output_protocol_query_mode query_mode; efi_status_t status; unsigned long m; m = gop32->mode; mode = (struct efi_graphics_output_protocol_mode_32 *)m; + query_mode = (void *)(unsigned long)gop32->query_mode; - status = efi_early->call(gop32->query_mode, gop32, -mode->mode, size, info); + status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size, + info); if (status != EFI_SUCCESS) return status; @@ -643,8 +646,8 @@ __gop_query32(struct efi_graphics_output_protocol_32 *gop32, } static efi_status_t -setup_gop32(struct screen_info *si, efi_guid_t *proto, - unsigned long size, void **gop_handle) +setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, +efi_guid_t *proto, unsigned long size, void **gop_handle) { struct efi_graphics_output_protocol_32 *gop32, *first_gop; unsigned long nr_gops; @@ -654,7 +657,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; - efi_status_t status; + efi_status_t status = EFI_NOT_FOUND; u32 *handles = (u32 *)(unsigned long)gop_handle; int i; @@ -667,7 +670,7 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; bool conout_found = false; void *dummy = NULL; - u32 h = handles[i]; + efi_handle_t h = (efi_handle_t)(unsigned long)handles[i]; u64 current_fb_base; status = efi_call_early(handle_protocol, h, @@ -680,7 +683,8 @@ setup_gop32(struct screen_info *si, efi_guid_t *proto, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query32(gop32, , , _fb_base); + status = __gop_query32(sys_table_arg, gop32, , , + _fb_base); if (status == EFI_SUCCESS && (!first_gop || conout_found)) { /* * Systems that use the UEFI Console Splitter may @@ -735,19 +739,22 @@ out: } static efi_status_t -__gop_query64(struct efi_graphics_output_protocol_64 *gop64, +__gop_query64(efi_system_table_t *sys_table_arg, + struct efi_graphics_output_protocol_64 *gop64, struct efi_graphics_output_mode_info **info, unsigned long *size, u64 *fb_base) {
[tip:efi/core] efi/libstub: Move Graphics Output Protocol handling to generic code
Commit-ID: fc37206427ce38eafbeff48099d873235e878450 Gitweb: http://git.kernel.org/tip/fc37206427ce38eafbeff48099d873235e878450 Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:49 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:57 +0200 efi/libstub: Move Graphics Output Protocol handling to generic code The Graphics Output Protocol code executes in the stub, so create a generic version based on the x86 version in libstub so that we can move other archs to it in subsequent patches. The new source file gop.c is added to the libstub build for all architectures, but only wired up for x86. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: David Herrmann Cc: Mark Rutland Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-18-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h| 4 +- arch/arm64/include/asm/efi.h | 4 +- arch/x86/boot/compressed/eboot.c | 318 -- arch/x86/boot/compressed/eboot.h | 78 drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/gop.c| 354 ++ include/linux/efi.h | 81 +++- 7 files changed, 441 insertions(+), 400 deletions(-) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index b0c341d..dc30d89 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -60,7 +60,9 @@ void efi_virtmap_unload(void); /* arch specific definitions used by the stub code */ -#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define __efi_call_early(f, ...) f(__VA_ARGS__) +#define efi_is_64bit() (false) /* * A reasonable upper bound for the uncompressed kernel size is 32 MBytes, diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 4dafc89..af40baa 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -52,7 +52,9 @@ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); #define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */ #define MAX_FDT_OFFSET SZ_512M -#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) +#define __efi_call_early(f, ...) f(__VA_ARGS__) +#define efi_is_64bit() (true) #define EFI_ALLOC_ALIGNSZ_64K diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 10516e2..52fef60 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -571,324 +571,6 @@ free_handle: efi_call_early(free_pool, pci_handle); } -static void -setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, -struct efi_pixel_bitmask pixel_info, int pixel_format) -{ - if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { - si->lfb_depth = 32; - si->lfb_linelength = pixels_per_scan_line * 4; - si->red_size = 8; - si->red_pos = 0; - si->green_size = 8; - si->green_pos = 8; - si->blue_size = 8; - si->blue_pos = 16; - si->rsvd_size = 8; - si->rsvd_pos = 24; - } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) { - si->lfb_depth = 32; - si->lfb_linelength = pixels_per_scan_line * 4; - si->red_size = 8; - si->red_pos = 16; - si->green_size = 8; - si->green_pos = 8; - si->blue_size = 8; - si->blue_pos = 0; - si->rsvd_size = 8; - si->rsvd_pos = 24; - } else if (pixel_format == PIXEL_BIT_MASK) { - find_bits(pixel_info.red_mask, >red_pos, >red_size); - find_bits(pixel_info.green_mask, >green_pos, - >green_size); - find_bits(pixel_info.blue_mask, >blue_pos, >blue_size); - find_bits(pixel_info.reserved_mask, >rsvd_pos, - >rsvd_size); - si->lfb_depth = si->red_size + si->green_size + - si->blue_size + si->rsvd_size; - si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; - } else { - si->lfb_depth = 4; - si->lfb_linelength =
[tip:efi/core] efi/arm*: Drop writable mapping of the UEFI System table
Commit-ID: 14c43be60166981f0b1f034ad9c59252c6f99e0d Gitweb: http://git.kernel.org/tip/14c43be60166981f0b1f034ad9c59252c6f99e0d Author: Ard BiesheuvelAuthorDate: Mon, 25 Apr 2016 21:06:34 +0100 Committer: Ingo Molnar CommitDate: Thu, 28 Apr 2016 11:33:47 +0200 efi/arm*: Drop writable mapping of the UEFI System table Commit: 2eec5dedf770 ("efi/arm-init: Use read-only early mappings") updated the early ARM UEFI init code to create the temporary, early mapping of the UEFI System table using read-only attributes, as a hardening measure against inadvertent modification. However, this still leaves the permanent, writable mapping of the UEFI System table, which is only ever referenced during invocations of UEFI Runtime Services, at which time the UEFI virtual mapping is available, which also covers the system table. (This is guaranteed by the fact that SetVirtualAddressMap(), which is a runtime service itself, converts various entries in the table to their virtual equivalents, which implies that the table must be covered by a RuntimeServicesData region that has the EFI_MEMORY_RUNTIME attribute.) So instead of creating this permanent mapping, record the virtual address of the system table inside the UEFI virtual mapping, and dereference that when accessing the table. This protects the contents of the system table from inadvertent (or deliberate) modification when no UEFI Runtime Services calls are in progress. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Cc: Borislav Petkov Cc: Leif Lindholm Cc: Mark Rutland Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1461614832-17633-3-git-send-email-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c| 2 ++ drivers/firmware/efi/arm-runtime.c | 27 --- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 8714f8c..008ed19 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -85,6 +85,8 @@ static int __init uefi_init(void) efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0x); + efi.runtime_version = efi.systab->hdr.revision; + /* Show what we know for posterity */ c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor), sizeof(vendor) * sizeof(efi_char16_t)); diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 16c7d2a..771750d 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -42,10 +42,12 @@ static struct mm_struct efi_mm = { static bool __init efi_virtmap_init(void) { efi_memory_desc_t *md; + bool systab_found; efi_mm.pgd = pgd_alloc(_mm); init_new_context(NULL, _mm); + systab_found = false; for_each_efi_memory_desc(, md) { phys_addr_t phys = md->phys_addr; int ret; @@ -64,8 +66,20 @@ static bool __init efi_virtmap_init(void) , ret); return false; } + /* +* If this entry covers the address of the UEFI system table, +* calculate and record its virtual address. +*/ + if (efi_system_table >= phys && + efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) { + efi.systab = (void *)(unsigned long)(efi_system_table - +phys + md->virt_addr); + systab_found = true; + } } - return true; + if (!systab_found) + pr_err("No virtual mapping found for the UEFI System Table\n"); + return systab_found; } /* @@ -99,15 +113,8 @@ static int __init arm_enable_runtime_services(void) memmap.map_end = memmap.map + mapsize; efi.memmap = - efi.systab = (__force void *)ioremap_cache(efi_system_table, - sizeof(efi_system_table_t)); - if (!efi.systab) { - pr_err("Failed to remap EFI System Table\n"); - return -ENOMEM; - } - if (!efi_virtmap_init()) { - pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); + pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n"); return -ENOMEM; } @@ -115,8 +122,6 @@ static int __init arm_enable_runtime_services(void)
[tip:efi/urgent] efi/fdt: Avoid FDT manipulation after ExitBootServices()
Commit-ID: c8f325a59cfc718d13a50fbc746ed9b415c25e92 Gitweb: http://git.kernel.org/tip/c8f325a59cfc718d13a50fbc746ed9b415c25e92 Author: Ard BiesheuvelAuthorDate: Wed, 1 Feb 2017 17:45:02 + Committer: Ingo Molnar CommitDate: Wed, 1 Feb 2017 21:17:49 +0100 efi/fdt: Avoid FDT manipulation after ExitBootServices() Some AArch64 UEFI implementations disable the MMU in ExitBootServices(), after which unaligned accesses to RAM are no longer supported. Commit: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") fixed an issue in the memory map handling of the stub FDT code, but inadvertently created an issue with such firmware, by moving some of the FDT manipulation to after the invocation of ExitBootServices(). Given that the stub's libfdt implementation uses the ordinary, accelerated string functions, which rely on hardware handling of unaligned accesses, manipulating the FDT with the MMU off may result in alignment faults. So fix the situation by moving the update_fdt_memmap() call into the callback function invoked by efi_exit_boot_services() right before it calls the ExitBootServices() UEFI service (which is arguably a better place for it anyway) Note that disabling the MMU in ExitBootServices() is not compliant with the UEFI spec, and carries great risk due to the fact that switching from cached to uncached memory accesses halfway through compiler generated code (i.e., involving a stack) can never be done in a way that is architecturally safe. Fixes: abfb7b686a3e ("efi/libstub/arm*: Pass latest memory map to the kernel") Signed-off-by: Ard Biesheuvel Tested-by: Riku Voipio Cc: Cc: mark.rutl...@arm.com Cc: linux-...@vger.kernel.org Cc: m...@codeblueprint.co.uk Cc: leif.lindh...@linaro.org Cc: linux-arm-ker...@lists.infradead.org Link: http://lkml.kernel.org/r/1485971102-23330-2-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/fdt.c | 14 +++--- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 921dfa0..260c4b4 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -187,6 +187,7 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map) struct exit_boot_struct { efi_memory_desc_t *runtime_map; int *runtime_entry_count; + void *new_fdt_addr; }; static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, @@ -202,7 +203,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, efi_get_virtmap(*map->map, *map->map_size, *map->desc_size, p->runtime_map, p->runtime_entry_count); - return EFI_SUCCESS; + return update_fdt_memmap(p->new_fdt_addr, map); } /* @@ -300,22 +301,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, priv.runtime_map = runtime_map; priv.runtime_entry_count = _entry_count; + priv.new_fdt_addr = (void *)*new_fdt_addr; status = efi_exit_boot_services(sys_table, handle, , , exit_boot_func); if (status == EFI_SUCCESS) { efi_set_virtual_address_map_t *svam; - status = update_fdt_memmap((void *)*new_fdt_addr, ); - if (status != EFI_SUCCESS) { - /* -* The kernel won't get far without the memory map, but -* may still be able to print something meaningful so -* return success here. -*/ - return EFI_SUCCESS; - } - /* Install the new virtual address map */ svam = sys_table->runtime->set_virtual_address_map; status = svam(runtime_entry_count * desc_size, desc_size,
[tip:efi/core] efi/libstub: Preserve .debug sections after absolute relocation check
Commit-ID: 696204faa6e8a318320ebb49d9fa69bc8275644d Gitweb: http://git.kernel.org/tip/696204faa6e8a318320ebb49d9fa69bc8275644d Author: Ard BiesheuvelAuthorDate: Tue, 31 Jan 2017 13:21:42 + Committer: Ingo Molnar CommitDate: Wed, 1 Feb 2017 08:45:47 +0100 efi/libstub: Preserve .debug sections after absolute relocation check The build commands for the ARM and arm64 EFI stubs strip the .debug sections and other sections that may legally contain absolute relocations, in order to inspect the remaining sections for the presence of such relocations. This leaves us without debugging symbols in the stub for no good reason, considering that these sections are omitted from the kernel binary anyway, and that these relocations are thus only consumed by users of the ELF binary, such as debuggers. So move to 'strip' for performing the relocation check, and if it succeeds, invoke objcopy as before, but leaving the .debug sections in place. Note that these sections may refer to ksymtab/kcrctab contents, so leave those in place as well. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1485868902-20401-11-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/Makefile | 24 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index d564d25..33e0e2f 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -mno-mmx -mno-sse cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \ +cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ -fno-builtin -fpic -mno-single-pic-base cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt @@ -60,7 +60,7 @@ CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) extra-$(CONFIG_EFI_ARMSTUB):= $(lib-y) lib-$(CONFIG_EFI_ARMSTUB) := $(patsubst %.o,%.stub.o,$(lib-y)) -STUBCOPY_FLAGS-y := -R .debug* -R *ksymtab* -R *kcrctab* +STUBCOPY_RM-y := -R *ksymtab* -R *kcrctab* STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \ --prefix-symbols=__efistub_ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS @@ -68,17 +68,25 @@ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS $(obj)/%.stub.o: $(obj)/%.o FORCE $(call if_changed,stubcopy) +# +# Strip debug sections and some other sections that may legally contain +# absolute relocations, so that we can inspect the remaining sections for +# such relocations. If none are found, regenerate the output object, but +# this time, use objcopy and leave all sections in place. +# quiet_cmd_stubcopy = STUBCPY $@ - cmd_stubcopy = if $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; then \ -$(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y)\ -&& (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ -rm -f $@; /bin/false); else /bin/false; fi + cmd_stubcopy = if $(STRIP) --strip-debug $(STUBCOPY_RM-y) -o $@ $<; \ +then if $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y); \ +then (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ + rm -f $@; /bin/false); \ +else $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; fi\ +else /bin/false; fi # # ARM discards the .data section because it disallows r/w data in the # decompressor. So move our .data to .data.efistub, which is preserved # explicitly by the decompressor linker script. # -STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \ - -R ___ksymtab+sort -R ___kcrctab+sort +STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub +STUBCOPY_RM-$(CONFIG_ARM) += -R ___ksymtab+sort -R ___kcrctab+sort STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
[tip:efi/core] efi: Use typed function pointers for the runtime services table
Commit-ID: c4c39c70c5fef43655019236bec8ba5e7273b868 Gitweb: http://git.kernel.org/tip/c4c39c70c5fef43655019236bec8ba5e7273b868 Author: Ard BiesheuvelAuthorDate: Tue, 31 Jan 2017 13:21:39 + Committer: Ingo Molnar CommitDate: Wed, 1 Feb 2017 08:45:45 +0100 efi: Use typed function pointers for the runtime services table Instead of using void pointers, and casting them to correctly typed function pointers upon use, declare the runtime services pointers as function pointers using their respective prototypes, for which typedefs are already available. Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1485868902-20401-8-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- include/linux/efi.h | 36 ++-- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/linux/efi.h b/include/linux/efi.h index 5f632bf..85e9fda 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -509,24 +509,6 @@ typedef struct { u64 query_variable_info; } efi_runtime_services_64_t; -typedef struct { - efi_table_hdr_t hdr; - void *get_time; - void *set_time; - void *get_wakeup_time; - void *set_wakeup_time; - void *set_virtual_address_map; - void *convert_pointer; - void *get_variable; - void *get_next_variable; - void *set_variable; - void *get_next_high_mono_count; - void *reset_system; - void *update_capsule; - void *query_capsule_caps; - void *query_variable_info; -} efi_runtime_services_t; - typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); typedef efi_status_t efi_set_time_t (efi_time_t *tm); typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, @@ -561,6 +543,24 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size, bool nonblocking); +typedef struct { + efi_table_hdr_t hdr; + efi_get_time_t *get_time; + efi_set_time_t *set_time; + efi_get_wakeup_time_t *get_wakeup_time; + efi_set_wakeup_time_t *set_wakeup_time; + efi_set_virtual_address_map_t *set_virtual_address_map; + void*convert_pointer; + efi_get_variable_t *get_variable; + efi_get_next_variable_t *get_next_variable; + efi_set_variable_t *set_variable; + efi_get_next_high_mono_count_t *get_next_high_mono_count; + efi_reset_system_t *reset_system; + efi_update_capsule_t*update_capsule; + efi_query_capsule_caps_t*query_capsule_caps; + efi_query_variable_info_t *query_variable_info; +} efi_runtime_services_t; + void efi_native_runtime_setup(void); /*
[tip:efi/core] efi/libstub: Make file I/O chunking x86-specific
Commit-ID: b3879a4d3a31ef14265a52e8d941cf4b0f6627ae Gitweb: http://git.kernel.org/tip/b3879a4d3a31ef14265a52e8d941cf4b0f6627ae Author: Ard BiesheuvelAuthorDate: Mon, 6 Feb 2017 11:22:46 + Committer: Ingo Molnar CommitDate: Tue, 7 Feb 2017 10:42:11 +0100 efi/libstub: Make file I/O chunking x86-specific The ARM decompressor is finicky when it comes to uninitialized variables with local linkage, the reason being that it may relocate .text and .bss independently when executing from ROM. This is only possible if all references into .bss from .text are absolute, and this happens to be the case for references emitted under -fpic to symbols with external linkage, and so all .bss references must involve symbols with external linkage. When building the ARM stub using clang, the initialized local variable __chunk_size is optimized into a zero-initialized flag that indicates whether chunking is in effect or not. This flag is therefore emitted into .bss, which triggers the ARM decompressor's diagnostics, resulting in a failed build. Under UEFI, we never execute the decompressor from ROM, so the diagnostic makes little sense here. But we can easily work around the issue by making __chunk_size global instead. However, given that the file I/O chunking that is controlled by the __chunk_size variable is intended to work around known bugs on various x86 implementations of UEFI, we can simply make the chunking an x86 specific feature. This is an improvement by itself, and also removes the need to parse the efi= options in the stub entirely. Tested-by: Arnd Bergmann Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1486380166-31868-8-git-send-email-ard.biesheu...@linaro.org [ Small readability edits. ] Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/efi-stub-helper.c | 11 ++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 6ee9164..919822b 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -414,6 +414,14 @@ efi_status_t efi_parse_options(char *cmdline) char *str; /* +* Currently, the only efi= option we look for is 'nochunk', which +* is intended to work around known issues on certain x86 UEFI +* versions. So ignore for now on other architectures. +*/ + if (!IS_ENABLED(CONFIG_X86)) + return EFI_SUCCESS; + + /* * If no EFI parameters were specified on the cmdline we've got * nothing to do. */ @@ -586,7 +594,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, size = files[j].size; while (size) { unsigned long chunksize; - if (size > __chunk_size) + + if (IS_ENABLED(CONFIG_X86) && size > __chunk_size) chunksize = __chunk_size; else chunksize = size;
[tip:efi/urgent] efi/libstub: Treat missing SecureBoot variable as Secure Boot disabled
Commit-ID: 52e51f16407b7b34e26affb500a21e250d9fce0b Gitweb: http://git.kernel.org/tip/52e51f16407b7b34e26affb500a21e250d9fce0b Author: Ard BiesheuvelAuthorDate: Wed, 1 Mar 2017 19:04:35 + Committer: Ingo Molnar CommitDate: Thu, 2 Mar 2017 08:11:18 +0100 efi/libstub: Treat missing SecureBoot variable as Secure Boot disabled The newly refactored code that infers the firmware's Secure Boot state prints the following error when the EFI variable 'SecureBoot' does not exist: EFI stub: ERROR: Could not determine UEFI Secure Boot status. However, this variable is only guaranteed to be defined on a system that is Secure Boot capable to begin with, and so it is not an error if it is missing. So report Secure Boot as being disabled in this case, without printing any error messages. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1488395076-29712-2-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/secureboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 6def402..5da36e5 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -45,6 +45,8 @@ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) size = sizeof(secboot); status = get_efi_var(efi_SecureBoot_name, _variable_guid, NULL, , ); + if (status == EFI_NOT_FOUND) + return efi_secureboot_mode_disabled; if (status != EFI_SUCCESS) goto out_efi_err; @@ -78,7 +80,5 @@ secure_boot_enabled: out_efi_err: pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n"); - if (status == EFI_NOT_FOUND) - return efi_secureboot_mode_disabled; return efi_secureboot_mode_unknown; }
[tip:efi/urgent] efi/arm: Fix boot crash with CONFIG_CPUMASK_OFFSTACK=y
Commit-ID: d1eb98143c56f24fef125f5bbed49ae0b52fb7d6 Gitweb: http://git.kernel.org/tip/d1eb98143c56f24fef125f5bbed49ae0b52fb7d6 Author: Ard BiesheuvelAuthorDate: Wed, 1 Mar 2017 19:05:54 + Committer: Ingo Molnar CommitDate: Thu, 2 Mar 2017 08:11:19 +0100 efi/arm: Fix boot crash with CONFIG_CPUMASK_OFFSTACK=y On ARM and arm64, we use a dedicated mm_struct to map the UEFI Runtime Services regions, which allows us to map those regions on demand, and in a way that is guaranteed to be compatible with incoming kernels across kexec. As it turns out, we don't fully initialize the mm_struct in the same way as process mm_structs are initialized on fork(), which results in the following crash on ARM if CONFIG_CPUMASK_OFFSTACK=y is enabled: ... EFI Variables Facility v0.08 2004-May-17 Unable to handle kernel NULL pointer dereference at virtual address [...] Process swapper/0 (pid: 1) ... __memzero() check_and_switch_context() virt_efi_get_next_variable() efivar_init() efivars_sysfs_init() do_one_initcall() ... This is due to a missing call to mm_init_cpumask(), so add it. Signed-off-by: Ard Biesheuvel Cc: # v4.5+ Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1488395154-29786-1-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-runtime.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 349dc3e..974c5a3 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -65,6 +65,7 @@ static bool __init efi_virtmap_init(void) bool systab_found; efi_mm.pgd = pgd_alloc(_mm); + mm_init_cpumask(_mm); init_new_context(NULL, _mm); systab_found = false;
[tip:efi/core] MAINTAINERS: Add myself as EFI maintainer
Commit-ID: 6026ed2fe258b61ea5aadd91a95c4f36a6dbe167 Gitweb: http://git.kernel.org/tip/6026ed2fe258b61ea5aadd91a95c4f36a6dbe167 Author: Ard BiesheuvelAuthorDate: Tue, 18 Oct 2016 15:33:11 +0100 Committer: Ingo Molnar CommitDate: Tue, 18 Oct 2016 17:11:14 +0200 MAINTAINERS: Add myself as EFI maintainer At the request of Matt, I am taking up co-maintainership of the EFI subsystem. So add my name to the EFI section in MAINTAINERS, and change the SCM tree reference to point to the new shared Git repo. Signed-off-by: Ard Biesheuvel Acked-by: Will Deacon Acked-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20161018143318.15673-2-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7..6847ba8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4620,8 +4620,9 @@ F:sound/usb/misc/ua101.c EXTENSIBLE FIRMWARE INTERFACE (EFI) M: Matt Fleming +M: Ard Biesheuvel L: linux-...@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git S: Maintained F: Documentation/efi-stub.txt F: arch/ia64/kernel/efi.c
[tip:efi/urgent] efi/arm: Fix absolute relocation detection for older toolchains
Commit-ID: b0dddf6c147e6fe61374d625c4bb2b7c52018639 Gitweb: http://git.kernel.org/tip/b0dddf6c147e6fe61374d625c4bb2b7c52018639 Author: Ard BiesheuvelAuthorDate: Tue, 18 Oct 2016 16:53:11 +0100 Committer: Ingo Molnar CommitDate: Wed, 19 Oct 2016 14:49:44 +0200 efi/arm: Fix absolute relocation detection for older toolchains When building the ARM kernel with CONFIG_EFI=y, the following build error may occur when using a less recent version of binutils (2.23 or older): STUBCPY drivers/firmware/efi/libstub/lib-sort.stub.o R_ARM_ABS32 sort 0004 R_ARM_ABS32 __ksymtab_strings drivers/firmware/efi/libstub/lib-sort.stub.o: absolute symbol references not allowed in the EFI stub (and when building with debug symbols, the list above is much longer, and contains all the internal references between the .debug sections and the actual code) This issue is caused by the fact that objcopy v2.23 or earlier does not support wildcards in its -R and -j options, which means the following line from the Makefile: STUBCOPY_FLAGS-y := -R .debug* -R *ksymtab* -R *kcrctab* fails to take effect, leaving harmless absolute relocations in the binary that are indistinguishable from relocations that may cause crashes at runtime due to the fact that these relocations are resolved at link time using the virtual address of the kernel, which is always different from the address at which the EFI firmware loads and invokes the stub. So, as a workaround, disable debug symbols explicitly when building the stub for ARM, and strip the ksymtab and kcrctab symbols for the only exported symbol we currently reuse in the stub, which is 'sort'. Tested-by: Jon Hunter Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1476805991-7160-2-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index c069451..5e23e2d 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ -mno-mmx -mno-sse cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ +cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \ -fno-builtin -fpic -mno-single-pic-base cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt @@ -79,5 +79,6 @@ quiet_cmd_stubcopy = STUBCPY $@ # decompressor. So move our .data to .data.efistub, which is preserved # explicitly by the decompressor linker script. # -STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub +STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \ + -R ___ksymtab+sort -R ___kcrctab+sort STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
[tip:efi/core] efi/libstub: Make efi_random_alloc() allocate below 4 GB on 32-bit
Commit-ID: 018edcfac4c3b140366ad51b0907f3becb5bb624 Gitweb: http://git.kernel.org/tip/018edcfac4c3b140366ad51b0907f3becb5bb624 Author: Ard BiesheuvelAuthorDate: Thu, 24 Nov 2016 18:02:23 + Committer: Ingo Molnar CommitDate: Fri, 25 Nov 2016 07:15:23 +0100 efi/libstub: Make efi_random_alloc() allocate below 4 GB on 32-bit The UEFI stub executes in the context of the firmware, which identity maps the available system RAM, which implies that only memory below 4 GB can be used for allocations on 32-bit architectures, even on [L]PAE capable hardware. So ignore any reported memory above 4 GB in efi_random_alloc(). This also fixes a reported build problem on ARM under -Os, where the 64-bit logical shift relies on a software routine that the ARM decompressor does not provide. A second [minor] issue is also fixed, where the '+ 1' is moved out of the shift, where it belongs: the reason for its presence is that a memory region where start == end should count as a single slot, given that 'end' takes the desired size and alignment of the allocation into account. To clarify the code in this regard, rename start/end to 'first_slot' and 'last_slot', respectively, and introduce 'region_end' to describe the last usable address of the current region. Reported-by: Arnd Bergmann Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/1480010543-25709-2-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/random.c | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 3a3feac..7e72954 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -45,19 +45,20 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, unsigned long align_shift) { unsigned long align = 1UL << align_shift; - u64 start, end; + u64 first_slot, last_slot, region_end; if (md->type != EFI_CONVENTIONAL_MEMORY) return 0; - start = round_up(md->phys_addr, align); - end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size, -align); + region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1); - if (start > end) + first_slot = round_up(md->phys_addr, align); + last_slot = round_down(region_end - size + 1, align); + + if (first_slot > last_slot) return 0; - return (end - start + 1) >> align_shift; + return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1; } /*
[tip:efi/core] efi/arm*/libstub: Invoke EFI_RNG_PROTOCOL to seed the UEFI RNG table
Commit-ID: 568bc4e87033d232c5fd00d5b0cd22a2ccc04944 Gitweb: http://git.kernel.org/tip/568bc4e87033d232c5fd00d5b0cd22a2ccc04944 Author: Ard BiesheuvelAuthorDate: Sat, 12 Nov 2016 21:32:33 + Committer: Ingo Molnar CommitDate: Sun, 13 Nov 2016 08:23:15 +0100 efi/arm*/libstub: Invoke EFI_RNG_PROTOCOL to seed the UEFI RNG table Invoke the EFI_RNG_PROTOCOL protocol in the context of the stub and install the Linux-specific RNG seed UEFI config table. This will be picked up by the EFI routines in the core kernel to seed the kernel entropy pool. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20161112213237.8804-6-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 2 ++ drivers/firmware/efi/libstub/efistub.h | 2 ++ drivers/firmware/efi/libstub/random.c | 48 + include/linux/efi.h | 1 + 4 files changed, 53 insertions(+) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 993aa56..b4f7d78 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -340,6 +340,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (status != EFI_SUCCESS) pr_efi_err(sys_table, "Failed initrd from command line!\n"); + efi_random_get_seed(sys_table); + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, _fdt_addr, dram_base + MAX_FDT_OFFSET, diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index fe1f225..b98824e 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -71,4 +71,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, efi_status_t check_platform_features(efi_system_table_t *sys_table_arg); +efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg); + #endif diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index f8e2e5a..3a3feac 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -143,3 +143,51 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, return status; } + +#define RANDOM_SEED_SIZE 32 + +efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) +{ + efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; + efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW; + efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; + struct efi_rng_protocol *rng; + struct linux_efi_random_seed *seed; + efi_status_t status; + + status = efi_call_early(locate_protocol, _proto, NULL, + (void **)); + if (status != EFI_SUCCESS) + return status; + + status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA, + sizeof(*seed) + RANDOM_SEED_SIZE, + (void **)); + if (status != EFI_SUCCESS) + return status; + + status = rng->get_rng(rng, _algo_raw, RANDOM_SEED_SIZE, + seed->bits); + if (status == EFI_UNSUPPORTED) + /* +* Use whatever algorithm we have available if the raw algorithm +* is not implemented. +*/ + status = rng->get_rng(rng, NULL, RANDOM_SEED_SIZE, + seed->bits); + + if (status != EFI_SUCCESS) + goto err_freepool; + + seed->size = RANDOM_SEED_SIZE; + status = efi_call_early(install_configuration_table, _table_guid, + seed); + if (status != EFI_SUCCESS) + goto err_freepool; + + return EFI_SUCCESS; + +err_freepool: + efi_call_early(free_pool, seed); + return status; +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 85e28b1..f5a821d 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -589,6 +589,7 @@ void efi_native_runtime_setup(void); #define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) #define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) #define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f,
[tip:efi/core] efi/libstub: Add random.c to ARM build
Commit-ID: a6a144698db93a2c456d1e3811140cadef1ba0e3 Gitweb: http://git.kernel.org/tip/a6a144698db93a2c456d1e3811140cadef1ba0e3 Author: Ard BiesheuvelAuthorDate: Sat, 12 Nov 2016 21:32:32 + Committer: Ingo Molnar CommitDate: Sun, 13 Nov 2016 08:23:15 +0100 efi/libstub: Add random.c to ARM build Make random.c build for ARM by moving the fallback definition of EFI_ALLOC_ALIGN to efistub.h, and replacing a division by a value we know to be a power of 2 with a right shift (this is required since ARM does not have any integer division helper routines in its decompressor) Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20161112213237.8804-5-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/Makefile | 4 ++-- drivers/firmware/efi/libstub/efi-stub-helper.c | 9 - drivers/firmware/efi/libstub/efistub.h | 9 + drivers/firmware/efi/libstub/random.c | 8 +--- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5e23e2d..6621b13 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -36,11 +36,11 @@ arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) -lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ +lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o random.o \ $(patsubst %.c,lib-%.o,$(arm-deps)) lib-$(CONFIG_ARM) += arm32-stub.o -lib-$(CONFIG_ARM64)+= arm64-stub.o random.o +lib-$(CONFIG_ARM64)+= arm64-stub.o CFLAGS_arm64-stub.o:= -DTEXT_OFFSET=$(TEXT_OFFSET) # diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 4b74bf8..757badc 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,15 +32,6 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; -/* - * Allow the platform to override the allocation granularity: this allows - * systems that have the capability to run with a larger page size to deal - * with the allocations for initrd and fdt more efficiently. - */ -#ifndef EFI_ALLOC_ALIGN -#define EFI_ALLOC_ALIGNEFI_PAGE_SIZE -#endif - #define EFI_MMAP_NR_SLACK_SLOTS8 struct file_info { diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index ee49cd2..fe1f225 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -15,6 +15,15 @@ */ #undef __init +/* + * Allow the platform to override the allocation granularity: this allows + * systems that have the capability to run with a larger page size to deal + * with the allocations for initrd and fdt more efficiently. + */ +#ifndef EFI_ALLOC_ALIGN +#define EFI_ALLOC_ALIGNEFI_PAGE_SIZE +#endif + void efi_char16_printk(efi_system_table_t *, efi_char16_t *); efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 0c9f58c..f8e2e5a 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -8,6 +8,7 @@ */ #include +#include #include #include "efistub.h" @@ -41,8 +42,9 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, */ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, unsigned long size, -unsigned long align) +unsigned long align_shift) { + unsigned long align = 1UL << align_shift; u64 start, end; if (md->type != EFI_CONVENTIONAL_MEMORY) @@ -55,7 +57,7 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md, if (start > end) return 0; - return (end - start + 1) / align; + return (end - start + 1) >> align_shift; } /* @@ -98,7 +100,7 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, efi_memory_desc_t *md = (void *)memory_map + map_offset; unsigned long slots; - slots = get_entry_num_slots(md, size, align); + slots = get_entry_num_slots(md, size, ilog2(align)); MD_NUM_SLOTS(md) = slots;
[tip:efi/core] MAINTAINERS: Add ARM and arm64 EFI specific files to EFI subsystem
Commit-ID: f135a176426fc643caf6480e3200f1733f58dbf6 Gitweb: http://git.kernel.org/tip/f135a176426fc643caf6480e3200f1733f58dbf6 Author: Ard BiesheuvelAuthorDate: Sat, 12 Nov 2016 21:32:30 + Committer: Ingo Molnar CommitDate: Sun, 13 Nov 2016 08:23:14 +0100 MAINTAINERS: Add ARM and arm64 EFI specific files to EFI subsystem Since I will be co-maintaining the EFI subsystem, it makes sense to mention the ARM and arm64 EFI bits in the EFI section in MAINTAINERS so that Matt, the list and I get cc'ed on proposed changes. Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Acked-by: Will Deacon Acked-by: Russell King Cc: Linus Torvalds Cc: M: Matthew Garrett Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20161112213237.8804-3-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- MAINTAINERS | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 851b89b..afaf24f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4631,12 +4631,14 @@ L: linux-...@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git S: Maintained F: Documentation/efi-stub.txt -F: arch/ia64/kernel/efi.c +F: arch/*/kernel/efi.c F: arch/x86/boot/compressed/eboot.[ch] -F: arch/x86/include/asm/efi.h +F: arch/*/include/asm/efi.h F: arch/x86/platform/efi/ F: drivers/firmware/efi/ F: include/linux/efi*.h +F: arch/arm/boot/compressed/efi-header.S +F: arch/arm64/kernel/efi-entry.S EFI VARIABLE FILESYSTEM M: Matthew Garrett
[tip:efi/core] efi: Add support for seeding the RNG from a UEFI config table
Commit-ID: 636259880a7e7d3446a707dddebc799da94bdd0b Gitweb: http://git.kernel.org/tip/636259880a7e7d3446a707dddebc799da94bdd0b Author: Ard BiesheuvelAuthorDate: Sat, 12 Nov 2016 21:32:31 + Committer: Ingo Molnar CommitDate: Sun, 13 Nov 2016 08:23:14 +0100 efi: Add support for seeding the RNG from a UEFI config table Specify a Linux specific UEFI configuration table that carries some random bits, and use the contents during early boot to seed the kernel's random number generator. This allows much strong random numbers to be generated early on. The entropy is fed to the kernel using add_device_randomness(), which is documented as being appropriate for being called very early. Since UEFI configuration tables may also be consumed by kexec'd kernels, register a reboot notifier that updates the seed in the table. Note that the config table could be generated by the EFI stub or by any other UEFI driver or application (e.g., GRUB), but the random seed table GUID and the associated functionality should be considered an internal kernel interface (unless it is promoted to ABI later on) Signed-off-by: Ard Biesheuvel Signed-off-by: Matt Fleming Reviewed-by: Kees Cook Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20161112213237.8804-4-m...@codeblueprint.co.uk Signed-off-by: Ingo Molnar --- drivers/firmware/efi/efi.c | 72 ++ include/linux/efi.h| 8 ++ 2 files changed, 80 insertions(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a4944e2..9291480 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -23,7 +23,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -48,6 +51,7 @@ struct efi __read_mostly efi = { .esrt = EFI_INVALID_TABLE_ADDR, .properties_table = EFI_INVALID_TABLE_ADDR, .mem_attr_table = EFI_INVALID_TABLE_ADDR, + .rng_seed = EFI_INVALID_TABLE_ADDR, }; EXPORT_SYMBOL(efi); @@ -440,6 +444,7 @@ static __initdata efi_config_table_type_t common_tables[] = { {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", }, {EFI_PROPERTIES_TABLE_GUID, "PROP", _table}, {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", _attr_table}, + {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", _seed}, {NULL_GUID, NULL, NULL}, }; @@ -501,6 +506,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, pr_cont("\n"); set_bit(EFI_CONFIG_TABLES, ); + if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) { + struct linux_efi_random_seed *seed; + u32 size = 0; + + seed = early_memremap(efi.rng_seed, sizeof(*seed)); + if (seed != NULL) { + size = seed->size; + early_memunmap(seed, sizeof(*seed)); + } else { + pr_err("Could not map UEFI random seed!\n"); + } + if (size > 0) { + seed = early_memremap(efi.rng_seed, + sizeof(*seed) + size); + if (seed != NULL) { + add_device_randomness(seed->bits, seed->size); + early_memunmap(seed, sizeof(*seed) + size); + } else { + pr_err("Could not map UEFI random seed!\n"); + } + } + } + /* Parse the EFI Properties table if it exists */ if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { efi_properties_table_t *tbl; @@ -824,3 +852,47 @@ int efi_status_to_err(efi_status_t status) return err; } + +#ifdef CONFIG_KEXEC +static int update_efi_random_seed(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct linux_efi_random_seed *seed; + u32 size = 0; + + if (!kexec_in_progress) + return NOTIFY_DONE; + + seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB); + if (seed != NULL) { + size = min(seed->size, 32U); + memunmap(seed); + } else { + pr_err("Could not map UEFI random seed!\n"); + } + if (size > 0) { + seed = memremap(efi.rng_seed, sizeof(*seed) + size, + MEMREMAP_WB); + if (seed != NULL) { + seed->size = size; + get_random_bytes(seed->bits, seed->size); +
[tip:efi/urgent] efi/libstub/arm*: Pass latest memory map to the kernel
Commit-ID: abfb7b686a3e5be27bf81db62f9c5c895b76f5d1 Gitweb: http://git.kernel.org/tip/abfb7b686a3e5be27bf81db62f9c5c895b76f5d1 Author: Ard BiesheuvelAuthorDate: Sat, 24 Dec 2016 13:59:23 + Committer: Ingo Molnar CommitDate: Wed, 28 Dec 2016 09:23:32 +0100 efi/libstub/arm*: Pass latest memory map to the kernel As reported by James Morse, the current libstub code involving the annotated memory map only works somewhat correctly by accident, due to the fact that a pool allocation happens to be reused immediately, retaining its former contents on most implementations of the UEFI boot services. Instead of juggling memory maps, which makes the code more complex than it needs to be, simply put placeholder values into the FDT for the memory map parameters, and only write the actual values after ExitBootServices() has been called. Reported-by: James Morse Signed-off-by: Ard Biesheuvel Cc: Cc: Jeffrey Hugo Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arm-ker...@lists.infradead.org Cc: linux-...@vger.kernel.org Fixes: ed9cc156c42f ("efi/libstub: Use efi_exit_boot_services() in FDT") Link: http://lkml.kernel.org/r/1482587963-20183-2-git-send-email-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/efistub.h | 8 drivers/firmware/efi/libstub/fdt.c | 87 ++ 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index b98824e..0e2a96b 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -39,14 +39,6 @@ efi_status_t efi_file_close(void *handle); unsigned long get_dram_base(efi_system_table_t *sys_table_arg); -efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, - unsigned long orig_fdt_size, - void *fdt, int new_fdt_size, char *cmdline_ptr, - u64 initrd_addr, u64 initrd_size, - efi_memory_desc_t *memory_map, - unsigned long map_size, unsigned long desc_size, - u32 desc_ver); - efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *handle, unsigned long *new_fdt_addr, diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index a6a9311..921dfa0 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -16,13 +16,10 @@ #include "efistub.h" -efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, - unsigned long orig_fdt_size, - void *fdt, int new_fdt_size, char *cmdline_ptr, - u64 initrd_addr, u64 initrd_size, - efi_memory_desc_t *memory_map, - unsigned long map_size, unsigned long desc_size, - u32 desc_ver) +static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, + unsigned long orig_fdt_size, + void *fdt, int new_fdt_size, char *cmdline_ptr, + u64 initrd_addr, u64 initrd_size) { int node, num_rsv; int status; @@ -101,25 +98,23 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, if (status) goto fdt_set_fail; - fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); + fdt_val64 = U64_MAX; /* placeholder */ status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", _val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(map_size); + fdt_val32 = U32_MAX; /* placeholder */ status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", _val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", _val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", _val32, sizeof(fdt_val32)); if (status) @@ -148,6 +143,43 @@ fdt_set_fail: return EFI_LOAD_ERROR; } +static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map) +{ + int node =
[tip:efi/urgent] efi/fb: Avoid reconfiguration of BAR that covers the framebuffer
Commit-ID: 5a8997342183bb792fe2c15cecf371665d784dd7 Gitweb: http://git.kernel.org/tip/5a8997342183bb792fe2c15cecf371665d784dd7 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 16:27:44 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:20:18 +0200 efi/fb: Avoid reconfiguration of BAR that covers the framebuffer On UEFI systems, the PCI subsystem is enumerated by the firmware, and if a graphical framebuffer is exposed via a PCI device, its base address and size are exposed to the OS via the Graphics Output Protocol (GOP). On arm64 PCI systems, the entire PCI hierarchy is reconfigured from scratch at boot. This may result in the GOP framebuffer address to become stale, if the BAR covering the framebuffer is modified. This will cause the framebuffer to become unresponsive, and may in some cases result in unpredictable behavior if the range is reassigned to another device. So add a non-x86 quirk to the EFI fb driver to find the BAR associated with the GOP base address, and claim the BAR resource so that the PCI core will not move it. Signed-off-by: Ard Biesheuvel Cc: # v4.7+ Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: lorenzo.pieral...@arm.com Fixes: 9822504c1fa5 ("efifb: Enable the efi-framebuffer platform driver ...") Link: http://lkml.kernel.org/r/20170404152744.26687-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/video/fbdev/efifb.c | 66 - 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 8c4dc1e..758960b 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +144,8 @@ static struct attribute *efifb_attrs[] = { }; ATTRIBUTE_GROUPS(efifb); +static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */ + static int efifb_probe(struct platform_device *dev) { struct fb_info *info; @@ -152,7 +155,7 @@ static int efifb_probe(struct platform_device *dev) unsigned int size_total; char *option = NULL; - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; if (fb_get_options("efifb", )) @@ -360,3 +363,64 @@ static struct platform_driver efifb_driver = { }; builtin_platform_driver(efifb_driver); + +#ifndef CONFIG_X86 + +static bool pci_bar_found; /* did we find a BAR matching the efifb base? */ + +static void claim_efifb_bar(struct pci_dev *dev, int idx) +{ + u16 word; + + pci_bar_found = true; + + pci_read_config_word(dev, PCI_COMMAND, ); + if (!(word & PCI_COMMAND_MEMORY)) { + pci_dev_disabled = true; + dev_err(>dev, + "BAR %d: assigned to efifb but device is disabled!\n", + idx); + return; + } + + if (pci_claim_resource(dev, idx)) { + pci_dev_disabled = true; + dev_err(>dev, + "BAR %d: failed to claim resource for efifb!\n", idx); + return; + } + + dev_info(>dev, "BAR %d: assigned to efifb\n", idx); +} + +static void efifb_fixup_resources(struct pci_dev *dev) +{ + u64 base = screen_info.lfb_base; + u64 size = screen_info.lfb_size; + int i; + + if (pci_bar_found || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + return; + + if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) + base |= (u64)screen_info.ext_lfb_base << 32; + + if (!base) + return; + + for (i = 0; i < PCI_STD_RESOURCE_END; i++) { + struct resource *res = >resource[i]; + + if (!(res->flags & IORESOURCE_MEM)) + continue; + + if (res->start <= base && res->end >= base + size - 1) { + claim_efifb_bar(dev, i); + break; + } + } +} +DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, + 16, efifb_fixup_resources); + +#endif
[tip:efi/core] efi/arm-stub: Correct FDT and initrd allocation rules for arm64
Commit-ID: 5e0e04e655826dce058c75a82adaa979231e6149 Gitweb: http://git.kernel.org/tip/5e0e04e655826dce058c75a82adaa979231e6149 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:37 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:48 +0200 efi/arm-stub: Correct FDT and initrd allocation rules for arm64 On arm64, we have made some changes over the past year to the way the kernel itself is allocated and to how it deals with the initrd and FDT. This patch brings the allocation logic in the EFI stub in line with that, which is necessary because the introduction of KASLR has created the possibility for the initrd to be allocated in a place where the kernel may not be able to map it. (This is mostly a theoretical scenario, since it only affects systems where the physical memory footprint exceeds the size of the linear mapping.) Since we know the kernel itself will be covered by the linear mapping, choose a suitably sized window (i.e., based on the size of the linear region) covering the kernel when allocating memory for the initrd. The FDT may be anywhere in memory on arm64 now that we map it via the fixmap, so we can lift the address restriction there completely. Tested-by: Richard Ruigrok Signed-off-by: Ard Biesheuvel Reviewed-by: Jeffrey Hugo Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-4-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h | 14 +- arch/arm64/include/asm/efi.h| 23 ++- drivers/firmware/efi/libstub/arm-stub.c | 7 --- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index e4e6a9d6..17f1f1a 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -85,6 +85,18 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) */ #define ZIMAGE_OFFSET_LIMITSZ_128M #define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE -#define MAX_FDT_OFFSET ZIMAGE_OFFSET_LIMIT + +/* on ARM, the FDT should be located in the first 128 MB of RAM */ +static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) +{ + return dram_base + ZIMAGE_OFFSET_LIMIT; +} + +/* on ARM, the initrd should be loaded in a lowmem region */ +static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, + unsigned long image_addr) +{ + return dram_base + SZ_512M; +} #endif /* _ASM_ARM_EFI_H */ diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index e744528..083a52d3 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -46,7 +46,28 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); * 2MiB so we know it won't cross a 2MiB boundary. */ #define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */ -#define MAX_FDT_OFFSET SZ_512M + +/* on arm64, the FDT may be located anywhere in system RAM */ +static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) +{ + return ULONG_MAX; +} + +/* + * On arm64, we have to ensure that the initrd ends up in the linear region, + * which is a 1 GB aligned region of size '1UL << (VA_BITS - 1)' that is + * guaranteed to cover the kernel Image. + * + * Since the EFI stub is part of the kernel Image, we can relax the + * usual requirements in Documentation/arm64/booting.txt, which still + * apply to other bootloaders, and are required for some kernel + * configurations. + */ +static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, + unsigned long image_addr) +{ + return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS - 1)); +} #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) #define __efi_call_early(f, ...) f(__VA_ARGS__) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index d4056c6..02049ff 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -213,8 +213,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (!fdt_addr) pr_efi(sys_table, "Generating empty DTB\n"); - status = handle_cmdline_files(sys_table, image, cmdline_ptr, - "initrd=", dram_base + SZ_512M, + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=", +
[tip:efi/core] efi/arm-stub: Round up FDT allocation to mapping size
Commit-ID: 05181c7c42c830e5f3fe7a0e93dfec0bd0fd8456 Gitweb: http://git.kernel.org/tip/05181c7c42c830e5f3fe7a0e93dfec0bd0fd8456 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:39 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:49 +0200 efi/arm-stub: Round up FDT allocation to mapping size The FDT is mapped via a fixmap entry that is at least 2 MB in size and 2 MB aligned on 4 KB page size kernels. On UEFI systems, the FDT allocation may share this 2 MB mapping with a reserved region (or another memory region that we should never map), unless we account for this in the size of the allocation (the alignment is already 2 MB) So instead of taking guesses at the needed space, simply allocate 2 MB immediately. The allocation will be recorded as EFI_LOADER_DATA, and the kernel only memblock_reserve()'s the actual size of the FDT, so the unused space will be released back to the kernel. Reviewed-By: Jeffrey Hugo Tested-by: Richard Ruigrok Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-6-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/efi.h | 1 + drivers/firmware/efi/libstub/fdt.c | 57 -- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 083a52d3..8f3043a 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -1,6 +1,7 @@ #ifndef _ASM_EFI_H #define _ASM_EFI_H +#include #include #include #include diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 260c4b4..41f457b 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -206,6 +206,10 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, return update_fdt_memmap(p->new_fdt_addr, map); } +#ifndef MAX_FDT_SIZE +#define MAX_FDT_SIZE SZ_2M +#endif + /* * Allocate memory for a new FDT, then add EFI, commandline, and * initrd related fields to the FDT. This routine increases the @@ -233,7 +237,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, u32 desc_ver; unsigned long mmap_key; efi_memory_desc_t *memory_map, *runtime_map; - unsigned long new_fdt_size; efi_status_t status; int runtime_entry_count = 0; struct efi_boot_memmap map; @@ -262,41 +265,29 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, "Exiting boot services and installing virtual address map...\n"); map.map = _map; + status = efi_high_alloc(sys_table, MAX_FDT_SIZE, EFI_FDT_ALIGN, + new_fdt_addr, max_addr); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, + "Unable to allocate memory for new device tree.\n"); + goto fail; + } + /* -* Estimate size of new FDT, and allocate memory for it. We -* will allocate a bigger buffer if this ends up being too -* small, so a rough guess is OK here. +* Now that we have done our final memory allocation (and free) +* we can get the memory map key needed for exit_boot_services(). */ - new_fdt_size = fdt_size + EFI_PAGE_SIZE; - while (1) { - status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN, - new_fdt_addr, max_addr); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n"); - goto fail; - } - - status = update_fdt(sys_table, - (void *)fdt_addr, fdt_size, - (void *)*new_fdt_addr, new_fdt_size, - cmdline_ptr, initrd_addr, initrd_size); + status = efi_get_memory_map(sys_table, ); + if (status != EFI_SUCCESS) + goto fail_free_new_fdt; - /* Succeeding the first time is the expected case. */ - if (status == EFI_SUCCESS) - break; + status = update_fdt(sys_table, (void *)fdt_addr, fdt_size, + (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr, + initrd_addr, initrd_size); - if (status == EFI_BUFFER_TOO_SMALL) { - /* -* We need to allocate more space for the new -
[tip:efi/core] efi/libstub/arm/arm64: Disable debug prints on 'quiet' cmdline arg
Commit-ID: b27aef2499e8c5af11aee9c239029ca4dbe162ed Gitweb: http://git.kernel.org/tip/b27aef2499e8c5af11aee9c239029ca4dbe162ed Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:09 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:55 +0200 efi/libstub/arm/arm64: Disable debug prints on 'quiet' cmdline arg The EFI stub currently prints a number of diagnostic messages that do not carry a lot of information. Since these prints are not controlled by 'loglevel' or other command line parameters, and since they appear on the EFI framebuffer as well (if enabled), it would be nice if we could turn them off. So let's add support for the 'quiet' command line parameter in the stub, and disable the non-error prints if it is passed. Signed-off-by: Ard Biesheuvel Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: b...@alien8.de Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c| 20 ++-- drivers/firmware/efi/libstub/arm32-stub.c | 2 ++ drivers/firmware/efi/libstub/efi-stub-helper.c | 9 + drivers/firmware/efi/libstub/efistub.h | 7 +++ drivers/firmware/efi/libstub/secureboot.c | 2 ++ include/linux/efi.h| 3 --- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index ac3222f..657bb72 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -116,8 +116,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) goto fail; - pr_efi(sys_table, "Booting Linux Kernel...\n"); - status = check_platform_features(sys_table); if (status != EFI_SUCCESS) goto fail; @@ -151,6 +149,16 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail; } + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline_size == 0) + efi_parse_options(CONFIG_CMDLINE); + + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) + efi_parse_options(cmdline_ptr); + + pr_efi(sys_table, "Booting Linux Kernel...\n"); + si = setup_graphics(sys_table); status = handle_kernel_image(sys_table, image_addr, _size, @@ -162,14 +170,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } - if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || - IS_ENABLED(CONFIG_CMDLINE_FORCE) || - cmdline_size == 0) - efi_parse_options(CONFIG_CMDLINE); - - if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) - efi_parse_options(cmdline_ptr); - secure_boot = efi_get_secureboot(sys_table); /* diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index 18a8b5e..becbda4 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -9,6 +9,8 @@ #include #include +#include "efistub.h" + efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { int block; diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 2e17d2b..b018436 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -33,11 +33,16 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; static int __section(.data) __nokaslr; +static int __section(.data) __quiet; int __pure nokaslr(void) { return __nokaslr; } +int __pure is_quiet(void) +{ + return __quiet; +} #define EFI_MMAP_NR_SLACK_SLOTS8 @@ -424,6 +429,10 @@ efi_status_t efi_parse_options(char const *cmdline) if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) __nokaslr = 1; + str = strstr(cmdline, "quiet"); + if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) + __quiet = 1; + /* * If no EFI parameters were specified on the cmdline we've got * nothing to do. diff --git
[tip:efi/core] ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region
Commit-ID: 170bd898f1ae1ad717d56053846f8bbd2e526045 Gitweb: http://git.kernel.org/tip/170bd898f1ae1ad717d56053846f8bbd2e526045 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:10 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:55 +0200 ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region Update the allocation logic for the virtual mapping of the UEFI runtime services to start from a randomized base address if KASLR is in effect, and if the UEFI firmware exposes an implementation of EFI_RNG_PROTOCOL. This makes it more difficult to predict the location of exploitable data structures in the runtime UEFI firmware, which increases robustness against attacks. Note that these regions are only mapped during the time a runtime service call is in progress, and only on a single CPU at a time, bit given the lack of a downside, let's enable it nonetheless. Signed-off-by: Ard Biesheuvel Cc: Borislav Petkov Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: mark.rutl...@arm.com Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 49 - 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 657bb72..1e45ec5 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,6 +18,22 @@ #include "efistub.h" +/* + * This is the base address at which to start allocating virtual memory ranges + * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use + * any allocation we choose, and eliminate the risk of a conflict after kexec. + * The value chosen is the largest non-zero power of 2 suitable for this purpose + * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can + * be mapped efficiently. + * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, + * map everything below 1 GB. (512 MB is a reasonable upper bound for the + * entire footprint of the UEFI runtime services memory regions) + */ +#define EFI_RT_VIRTUAL_BASESZ_512M +#define EFI_RT_VIRTUAL_SIZESZ_512M + +static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; + efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { @@ -213,6 +229,25 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_random_get_seed(sys_table); + if (!nokaslr()) { + /* +* Randomize the base of the UEFI runtime services region. +* Preserve the 2 MB alignment of the region by taking a +* shift of 21 bit positions into account when scaling +* the headroom value using a 32-bit random value. +*/ + u64 headroom = TASK_SIZE - EFI_RT_VIRTUAL_BASE - + EFI_RT_VIRTUAL_SIZE; + u32 rnd; + + status = efi_get_random_bytes(sys_table, sizeof(rnd), + (u8 *)); + if (status == EFI_SUCCESS) { + virtmap_base = EFI_RT_VIRTUAL_BASE + + (((headroom >> 21) * rnd) >> (32 - 21)); + } + } + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, _fdt_addr, efi_get_max_fdt_addr(dram_base), @@ -242,18 +277,6 @@ fail: return EFI_ERROR; } -/* - * This is the base address at which to start allocating virtual memory ranges - * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use - * any allocation we choose, and eliminate the risk of a conflict after kexec. - * The value chosen is the largest non-zero power of 2 suitable for this purpose - * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can - * be mapped efficiently. - * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, - * map everything below 1 GB. - */ -#define EFI_RT_VIRTUAL_BASESZ_512M - static int cmp_mem_desc(const void *l, const void *r) { const efi_memory_desc_t *left = l, *right = r; @@ -303,7 +326,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, efi_memory_desc_t
[tip:efi/core] efi/libstub: Unify command line param parsing
Commit-ID: 794e5ecb8c444bcc7e42b82e3ae7a457987949d3 Gitweb: http://git.kernel.org/tip/794e5ecb8c444bcc7e42b82e3ae7a457987949d3 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:08 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:54 +0200 efi/libstub: Unify command line param parsing Merge the parsing of the command line carried out in arm-stub.c with the handling in efi_parse_options(). Note that this also fixes the missing handling of CONFIG_CMDLINE_FORCE=y, in which case the builtin command line should supersede the one passed by the firmware. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: b...@alien8.de Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: mark.rutl...@arm.com Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-1-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c| 24 +++- drivers/firmware/efi/libstub/arm64-stub.c | 4 +--- drivers/firmware/efi/libstub/efi-stub-helper.c | 19 +++ drivers/firmware/efi/libstub/efistub.h | 2 ++ include/linux/efi.h| 2 +- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 02049ff..ac3222f 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,8 +18,6 @@ #include "efistub.h" -bool __nokaslr; - efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { @@ -153,18 +151,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail; } - /* check whether 'nokaslr' was passed on the command line */ - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - static const u8 default_cmdline[] = CONFIG_CMDLINE; - const u8 *str, *cmdline = cmdline_ptr; - - if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) - cmdline = default_cmdline; - str = strstr(cmdline, "nokaslr"); - if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) - __nokaslr = true; - } - si = setup_graphics(sys_table); status = handle_kernel_image(sys_table, image_addr, _size, @@ -176,9 +162,13 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } - status = efi_parse_options(cmdline_ptr); - if (status != EFI_SUCCESS) - pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline_size == 0) + efi_parse_options(CONFIG_CMDLINE); + + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) + efi_parse_options(cmdline_ptr); secure_boot = efi_get_secureboot(sys_table); diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index eae693e..b4c2589 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -16,8 +16,6 @@ #include "efistub.h" -extern bool __nokaslr; - efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { u64 tg; @@ -52,7 +50,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, u64 phys_seed = 0; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - if (!__nokaslr) { + if (!nokaslr()) { status = efi_get_random_bytes(sys_table_arg, sizeof(phys_seed), (u8 *)_seed); diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 3290fae..2e17d2b 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,13 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; +static int __section(.data) __nokaslr; + +int __pure nokaslr(void) +{ + return __nokaslr; +} + #define EFI_MMAP_NR_SLACK_SLOTS8 struct file_info { @@ -409,17 +416,13 @@ static efi_status_t efi_file_close(void *handle) * environments, first in the early boot environment of the EFI boot * stub, and subsequently during the kernel boot. */
[tip:efi/core] efi/arm32-stub: Allow boot-time allocations in the vmlinux region
Commit-ID: 0dee5fe386a3b51b63f5ac5aa3a23bc6ed385cae Gitweb: http://git.kernel.org/tip/0dee5fe386a3b51b63f5ac5aa3a23bc6ed385cae Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:44 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:52 +0200 efi/arm32-stub: Allow boot-time allocations in the vmlinux region The arm32 kernel decompresses itself to the base of DRAM unconditionally, and so it is the EFI stub's job to ensure that the region is available. Currently, we do this by creating an allocation there, and giving up if that fails. However, any boot services regions occupying this area are not an issue, given that the decompressor executes strictly after the stub calls ExitBootServices(). So let's try a bit harder to proceed if the initial allocation fails, and check whether any memory map entries occupying the region may be considered safe. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Eugene Cohen Reviewed-by: Roy Franz Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-11-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm32-stub.c | 148 ++ 1 file changed, 128 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index e1f0b28..18a8b5e 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -63,6 +63,132 @@ void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si) efi_call_early(free_pool, si); } +static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg, + unsigned long dram_base, + unsigned long *reserve_addr, + unsigned long *reserve_size) +{ + efi_physical_addr_t alloc_addr; + efi_memory_desc_t *memory_map; + unsigned long nr_pages, map_size, desc_size, buff_size; + efi_status_t status; + unsigned long l; + + struct efi_boot_memmap map = { + .map= _map, + .map_size = _size, + .desc_size = _size, + .desc_ver = NULL, + .key_ptr= NULL, + .buff_size = _size, + }; + + /* +* Reserve memory for the uncompressed kernel image. This is +* all that prevents any future allocations from conflicting +* with the kernel. Since we can't tell from the compressed +* image how much DRAM the kernel actually uses (due to BSS +* size uncertainty) we allocate the maximum possible size. +* Do this very early, as prints can cause memory allocations +* that may conflict with this. +*/ + alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE; + nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE; + status = efi_call_early(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS, + EFI_BOOT_SERVICES_DATA, nr_pages, _addr); + if (status == EFI_SUCCESS) { + if (alloc_addr == dram_base) { + *reserve_addr = alloc_addr; + *reserve_size = MAX_UNCOMP_KERNEL_SIZE; + return EFI_SUCCESS; + } + /* +* If we end up here, the allocation succeeded but starts below +* dram_base. This can only occur if the real base of DRAM is +* not a multiple of 128 MB, in which case dram_base will have +* been rounded up. Since this implies that a part of the region +* was already occupied, we need to fall through to the code +* below to ensure that the existing allocations don't conflict. +* For this reason, we use EFI_BOOT_SERVICES_DATA above and not +* EFI_LOADER_DATA, which we wouldn't able to distinguish from +* allocations that we want to disallow. +*/ + } + + /* +* If the allocation above failed, we may still be able to proceed: +* if the only allocations in the region are of types that will be +* released to the OS after ExitBootServices(), the decompressor can +* safely overwrite them. +*/ + status = efi_get_memory_map(sys_table_arg, ); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, + "reserve_kernel_base(): Unable to retrieve memory
[tip:efi/core] efi/libstub: Fix harmless command line parsing bug
Commit-ID: 935061e3a7de5eae398327de9f7b92588bfcf7fc Gitweb: http://git.kernel.org/tip/935061e3a7de5eae398327de9f7b92588bfcf7fc Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:45 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 09:27:53 +0200 efi/libstub: Fix harmless command line parsing bug When we parse the 'efi=' command line parameter in the stub, we fail to take spaces into account. Currently, the only way this could result in unexpected behavior is when the string 'nochunk' appears as a separate command line argument after 'efi=xxx,yyy,zzz ', so this is harmless in practice. But let's fix it nonetheless. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-12-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/efi-stub-helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 919822b..3290fae 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -436,14 +436,14 @@ efi_status_t efi_parse_options(char *cmdline) * Remember, because efi= is also used by the kernel we need to * skip over arguments we don't understand. */ - while (*str) { + while (*str && *str != ' ') { if (!strncmp(str, "nochunk", 7)) { str += strlen("nochunk"); __chunk_size = -1UL; } /* Group words together, delimited by "," */ - while (*str && *str != ',') + while (*str && *str != ' ' && *str != ',') str++; if (*str == ',')
[tip:efi/urgent] efi/fb: Avoid reconfiguration of BAR that covers the framebuffer
Commit-ID: 55d728a40d368ba80443be85c02e641fc9082a3f Gitweb: http://git.kernel.org/tip/55d728a40d368ba80443be85c02e641fc9082a3f Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 16:27:44 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:25:53 +0200 efi/fb: Avoid reconfiguration of BAR that covers the framebuffer On UEFI systems, the PCI subsystem is enumerated by the firmware, and if a graphical framebuffer is exposed via a PCI device, its base address and size are exposed to the OS via the Graphics Output Protocol (GOP). On arm64 PCI systems, the entire PCI hierarchy is reconfigured from scratch at boot. This may result in the GOP framebuffer address to become stale, if the BAR covering the framebuffer is modified. This will cause the framebuffer to become unresponsive, and may in some cases result in unpredictable behavior if the range is reassigned to another device. So add a non-x86 quirk to the EFI fb driver to find the BAR associated with the GOP base address, and claim the BAR resource so that the PCI core will not move it. Signed-off-by: Ard Biesheuvel Cc: # v4.7+ Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: lorenzo.pieral...@arm.com Fixes: 9822504c1fa5 ("efifb: Enable the efi-framebuffer platform driver ...") Link: http://lkml.kernel.org/r/20170404152744.26687-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/video/fbdev/efifb.c | 66 - 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 8c4dc1e..b827a81 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -143,6 +144,8 @@ static struct attribute *efifb_attrs[] = { }; ATTRIBUTE_GROUPS(efifb); +static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */ + static int efifb_probe(struct platform_device *dev) { struct fb_info *info; @@ -152,7 +155,7 @@ static int efifb_probe(struct platform_device *dev) unsigned int size_total; char *option = NULL; - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; if (fb_get_options("efifb", )) @@ -360,3 +363,64 @@ static struct platform_driver efifb_driver = { }; builtin_platform_driver(efifb_driver); + +#if defined(CONFIG_PCI) && !defined(CONFIG_X86) + +static bool pci_bar_found; /* did we find a BAR matching the efifb base? */ + +static void claim_efifb_bar(struct pci_dev *dev, int idx) +{ + u16 word; + + pci_bar_found = true; + + pci_read_config_word(dev, PCI_COMMAND, ); + if (!(word & PCI_COMMAND_MEMORY)) { + pci_dev_disabled = true; + dev_err(>dev, + "BAR %d: assigned to efifb but device is disabled!\n", + idx); + return; + } + + if (pci_claim_resource(dev, idx)) { + pci_dev_disabled = true; + dev_err(>dev, + "BAR %d: failed to claim resource for efifb!\n", idx); + return; + } + + dev_info(>dev, "BAR %d: assigned to efifb\n", idx); +} + +static void efifb_fixup_resources(struct pci_dev *dev) +{ + u64 base = screen_info.lfb_base; + u64 size = screen_info.lfb_size; + int i; + + if (pci_bar_found || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + return; + + if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) + base |= (u64)screen_info.ext_lfb_base << 32; + + if (!base) + return; + + for (i = 0; i < PCI_STD_RESOURCE_END; i++) { + struct resource *res = >resource[i]; + + if (!(res->flags & IORESOURCE_MEM)) + continue; + + if (res->start <= base && res->end >= base + size - 1) { + claim_efifb_bar(dev, i); + break; + } + } +} +DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY, + 16, efifb_fixup_resources); + +#endif
[tip:efi/core] efi/arm-stub: Correct FDT and initrd allocation rules for arm64
Commit-ID: 138728dd4ee30d3f35587c269c46cc829ec4d58b Gitweb: http://git.kernel.org/tip/138728dd4ee30d3f35587c269c46cc829ec4d58b Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:37 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:23 +0200 efi/arm-stub: Correct FDT and initrd allocation rules for arm64 On arm64, we have made some changes over the past year to the way the kernel itself is allocated and to how it deals with the initrd and FDT. This patch brings the allocation logic in the EFI stub in line with that, which is necessary because the introduction of KASLR has created the possibility for the initrd to be allocated in a place where the kernel may not be able to map it. (This is mostly a theoretical scenario, since it only affects systems where the physical memory footprint exceeds the size of the linear mapping.) Since we know the kernel itself will be covered by the linear mapping, choose a suitably sized window (i.e., based on the size of the linear region) covering the kernel when allocating memory for the initrd. The FDT may be anywhere in memory on arm64 now that we map it via the fixmap, so we can lift the address restriction there completely. Tested-by: Richard Ruigrok Signed-off-by: Ard Biesheuvel Reviewed-by: Jeffrey Hugo Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-4-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/include/asm/efi.h | 14 +- arch/arm64/include/asm/efi.h| 23 ++- drivers/firmware/efi/libstub/arm-stub.c | 7 --- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h index e4e6a9d6..17f1f1a 100644 --- a/arch/arm/include/asm/efi.h +++ b/arch/arm/include/asm/efi.h @@ -85,6 +85,18 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) */ #define ZIMAGE_OFFSET_LIMITSZ_128M #define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE -#define MAX_FDT_OFFSET ZIMAGE_OFFSET_LIMIT + +/* on ARM, the FDT should be located in the first 128 MB of RAM */ +static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) +{ + return dram_base + ZIMAGE_OFFSET_LIMIT; +} + +/* on ARM, the initrd should be loaded in a lowmem region */ +static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, + unsigned long image_addr) +{ + return dram_base + SZ_512M; +} #endif /* _ASM_ARM_EFI_H */ diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index e744528..083a52d3 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -46,7 +46,28 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); * 2MiB so we know it won't cross a 2MiB boundary. */ #define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */ -#define MAX_FDT_OFFSET SZ_512M + +/* on arm64, the FDT may be located anywhere in system RAM */ +static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) +{ + return ULONG_MAX; +} + +/* + * On arm64, we have to ensure that the initrd ends up in the linear region, + * which is a 1 GB aligned region of size '1UL << (VA_BITS - 1)' that is + * guaranteed to cover the kernel Image. + * + * Since the EFI stub is part of the kernel Image, we can relax the + * usual requirements in Documentation/arm64/booting.txt, which still + * apply to other bootloaders, and are required for some kernel + * configurations. + */ +static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, + unsigned long image_addr) +{ + return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS - 1)); +} #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) #define __efi_call_early(f, ...) f(__VA_ARGS__) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index d4056c6..02049ff 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -213,8 +213,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (!fdt_addr) pr_efi(sys_table, "Generating empty DTB\n"); - status = handle_cmdline_files(sys_table, image, cmdline_ptr, - "initrd=", dram_base + SZ_512M, + status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=", +
[tip:efi/core] efi/arm-stub: Round up FDT allocation to mapping size
Commit-ID: 24d7c494ce46d5bb6c8fd03e88a48ae249ec1492 Gitweb: http://git.kernel.org/tip/24d7c494ce46d5bb6c8fd03e88a48ae249ec1492 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:39 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:24 +0200 efi/arm-stub: Round up FDT allocation to mapping size The FDT is mapped via a fixmap entry that is at least 2 MB in size and 2 MB aligned on 4 KB page size kernels. On UEFI systems, the FDT allocation may share this 2 MB mapping with a reserved region (or another memory region that we should never map), unless we account for this in the size of the allocation (the alignment is already 2 MB) So instead of taking guesses at the needed space, simply allocate 2 MB immediately. The allocation will be recorded as EFI_LOADER_DATA, and the kernel only memblock_reserve()'s the actual size of the FDT, so the unused space will be released back to the kernel. Reviewed-By: Jeffrey Hugo Tested-by: Richard Ruigrok Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-6-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/efi.h | 1 + drivers/firmware/efi/libstub/fdt.c | 57 -- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 083a52d3..8f3043a 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -1,6 +1,7 @@ #ifndef _ASM_EFI_H #define _ASM_EFI_H +#include #include #include #include diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 260c4b4..41f457b 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -206,6 +206,10 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, return update_fdt_memmap(p->new_fdt_addr, map); } +#ifndef MAX_FDT_SIZE +#define MAX_FDT_SIZE SZ_2M +#endif + /* * Allocate memory for a new FDT, then add EFI, commandline, and * initrd related fields to the FDT. This routine increases the @@ -233,7 +237,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, u32 desc_ver; unsigned long mmap_key; efi_memory_desc_t *memory_map, *runtime_map; - unsigned long new_fdt_size; efi_status_t status; int runtime_entry_count = 0; struct efi_boot_memmap map; @@ -262,41 +265,29 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, "Exiting boot services and installing virtual address map...\n"); map.map = _map; + status = efi_high_alloc(sys_table, MAX_FDT_SIZE, EFI_FDT_ALIGN, + new_fdt_addr, max_addr); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, + "Unable to allocate memory for new device tree.\n"); + goto fail; + } + /* -* Estimate size of new FDT, and allocate memory for it. We -* will allocate a bigger buffer if this ends up being too -* small, so a rough guess is OK here. +* Now that we have done our final memory allocation (and free) +* we can get the memory map key needed for exit_boot_services(). */ - new_fdt_size = fdt_size + EFI_PAGE_SIZE; - while (1) { - status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN, - new_fdt_addr, max_addr); - if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n"); - goto fail; - } - - status = update_fdt(sys_table, - (void *)fdt_addr, fdt_size, - (void *)*new_fdt_addr, new_fdt_size, - cmdline_ptr, initrd_addr, initrd_size); + status = efi_get_memory_map(sys_table, ); + if (status != EFI_SUCCESS) + goto fail_free_new_fdt; - /* Succeeding the first time is the expected case. */ - if (status == EFI_SUCCESS) - break; + status = update_fdt(sys_table, (void *)fdt_addr, fdt_size, + (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr, + initrd_addr, initrd_size); - if (status == EFI_BUFFER_TOO_SMALL) { - /* -* We need to allocate more space for the new -
[tip:efi/core] efi/libstub: Fix harmless command line parsing bug
Commit-ID: 4c3f14bb87b683a2e5bbc6d6660b41893ecacfd0 Gitweb: http://git.kernel.org/tip/4c3f14bb87b683a2e5bbc6d6660b41893ecacfd0 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:45 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:27 +0200 efi/libstub: Fix harmless command line parsing bug When we parse the 'efi=' command line parameter in the stub, we fail to take spaces into account. Currently, the only way this could result in unexpected behavior is when the string 'nochunk' appears as a separate command line argument after 'efi=xxx,yyy,zzz ', so this is harmless in practice. But let's fix it nonetheless. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-12-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/efi-stub-helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 919822b..3290fae 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -436,14 +436,14 @@ efi_status_t efi_parse_options(char *cmdline) * Remember, because efi= is also used by the kernel we need to * skip over arguments we don't understand. */ - while (*str) { + while (*str && *str != ' ') { if (!strncmp(str, "nochunk", 7)) { str += strlen("nochunk"); __chunk_size = -1UL; } /* Group words together, delimited by "," */ - while (*str && *str != ',') + while (*str && *str != ' ' && *str != ',') str++; if (*str == ',')
[tip:efi/core] efi/libstub/arm/arm64: Disable debug prints on 'quiet' cmdline arg
Commit-ID: eeff7d634f4750306785be709ca444140c29b043 Gitweb: http://git.kernel.org/tip/eeff7d634f4750306785be709ca444140c29b043 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:09 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:28 +0200 efi/libstub/arm/arm64: Disable debug prints on 'quiet' cmdline arg The EFI stub currently prints a number of diagnostic messages that do not carry a lot of information. Since these prints are not controlled by 'loglevel' or other command line parameters, and since they appear on the EFI framebuffer as well (if enabled), it would be nice if we could turn them off. So let's add support for the 'quiet' command line parameter in the stub, and disable the non-error prints if it is passed. Signed-off-by: Ard Biesheuvel Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: b...@alien8.de Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c| 20 ++-- drivers/firmware/efi/libstub/arm32-stub.c | 2 ++ drivers/firmware/efi/libstub/efi-stub-helper.c | 9 + drivers/firmware/efi/libstub/efistub.h | 7 +++ drivers/firmware/efi/libstub/secureboot.c | 2 ++ include/linux/efi.h| 3 --- 6 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index ac3222f..657bb72 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -116,8 +116,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) goto fail; - pr_efi(sys_table, "Booting Linux Kernel...\n"); - status = check_platform_features(sys_table); if (status != EFI_SUCCESS) goto fail; @@ -151,6 +149,16 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail; } + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline_size == 0) + efi_parse_options(CONFIG_CMDLINE); + + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) + efi_parse_options(cmdline_ptr); + + pr_efi(sys_table, "Booting Linux Kernel...\n"); + si = setup_graphics(sys_table); status = handle_kernel_image(sys_table, image_addr, _size, @@ -162,14 +170,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } - if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || - IS_ENABLED(CONFIG_CMDLINE_FORCE) || - cmdline_size == 0) - efi_parse_options(CONFIG_CMDLINE); - - if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) - efi_parse_options(cmdline_ptr); - secure_boot = efi_get_secureboot(sys_table); /* diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index 18a8b5e..becbda4 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -9,6 +9,8 @@ #include #include +#include "efistub.h" + efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { int block; diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 2e17d2b..b018436 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -33,11 +33,16 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; static int __section(.data) __nokaslr; +static int __section(.data) __quiet; int __pure nokaslr(void) { return __nokaslr; } +int __pure is_quiet(void) +{ + return __quiet; +} #define EFI_MMAP_NR_SLACK_SLOTS8 @@ -424,6 +429,10 @@ efi_status_t efi_parse_options(char const *cmdline) if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) __nokaslr = 1; + str = strstr(cmdline, "quiet"); + if (str == cmdline || (str && str > cmdline && *(str - 1) == ' ')) + __quiet = 1; + /* * If no EFI parameters were specified on the cmdline we've got * nothing to do. diff --git
[tip:efi/core] ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region
Commit-ID: e69176d68d26d63d9214797c191ce65358ea1ecf Gitweb: http://git.kernel.org/tip/e69176d68d26d63d9214797c191ce65358ea1ecf Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:10 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:29 +0200 ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region Update the allocation logic for the virtual mapping of the UEFI runtime services to start from a randomized base address if KASLR is in effect, and if the UEFI firmware exposes an implementation of EFI_RNG_PROTOCOL. This makes it more difficult to predict the location of exploitable data structures in the runtime UEFI firmware, which increases robustness against attacks. Note that these regions are only mapped during the time a runtime service call is in progress, and only on a single CPU at a time, bit given the lack of a downside, let's enable it nonetheless. Signed-off-by: Ard Biesheuvel Cc: Borislav Petkov Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: mark.rutl...@arm.com Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 49 - 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 657bb72..1e45ec5 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,6 +18,22 @@ #include "efistub.h" +/* + * This is the base address at which to start allocating virtual memory ranges + * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use + * any allocation we choose, and eliminate the risk of a conflict after kexec. + * The value chosen is the largest non-zero power of 2 suitable for this purpose + * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can + * be mapped efficiently. + * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, + * map everything below 1 GB. (512 MB is a reasonable upper bound for the + * entire footprint of the UEFI runtime services memory regions) + */ +#define EFI_RT_VIRTUAL_BASESZ_512M +#define EFI_RT_VIRTUAL_SIZESZ_512M + +static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; + efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { @@ -213,6 +229,25 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_random_get_seed(sys_table); + if (!nokaslr()) { + /* +* Randomize the base of the UEFI runtime services region. +* Preserve the 2 MB alignment of the region by taking a +* shift of 21 bit positions into account when scaling +* the headroom value using a 32-bit random value. +*/ + u64 headroom = TASK_SIZE - EFI_RT_VIRTUAL_BASE - + EFI_RT_VIRTUAL_SIZE; + u32 rnd; + + status = efi_get_random_bytes(sys_table, sizeof(rnd), + (u8 *)); + if (status == EFI_SUCCESS) { + virtmap_base = EFI_RT_VIRTUAL_BASE + + (((headroom >> 21) * rnd) >> (32 - 21)); + } + } + new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(sys_table, handle, _fdt_addr, efi_get_max_fdt_addr(dram_base), @@ -242,18 +277,6 @@ fail: return EFI_ERROR; } -/* - * This is the base address at which to start allocating virtual memory ranges - * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use - * any allocation we choose, and eliminate the risk of a conflict after kexec. - * The value chosen is the largest non-zero power of 2 suitable for this purpose - * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can - * be mapped efficiently. - * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, - * map everything below 1 GB. - */ -#define EFI_RT_VIRTUAL_BASESZ_512M - static int cmp_mem_desc(const void *l, const void *r) { const efi_memory_desc_t *left = l, *right = r; @@ -303,7 +326,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size, unsigned long desc_size, efi_memory_desc_t
[tip:efi/core] efi/arm32-stub: Allow boot-time allocations in the vmlinux region
Commit-ID: 318532bf63cfab779d763527d8b93e48c4a96dba Gitweb: http://git.kernel.org/tip/318532bf63cfab779d763527d8b93e48c4a96dba Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:02:44 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:26 +0200 efi/arm32-stub: Allow boot-time allocations in the vmlinux region The arm32 kernel decompresses itself to the base of DRAM unconditionally, and so it is the EFI stub's job to ensure that the region is available. Currently, we do this by creating an allocation there, and giving up if that fails. However, any boot services regions occupying this area are not an issue, given that the decompressor executes strictly after the stub calls ExitBootServices(). So let's try a bit harder to proceed if the initial allocation fails, and check whether any memory map entries occupying the region may be considered safe. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Eugene Cohen Reviewed-by: Roy Franz Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170404160245.27812-11-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm32-stub.c | 148 ++ 1 file changed, 128 insertions(+), 20 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index e1f0b28..18a8b5e 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -63,6 +63,132 @@ void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si) efi_call_early(free_pool, si); } +static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg, + unsigned long dram_base, + unsigned long *reserve_addr, + unsigned long *reserve_size) +{ + efi_physical_addr_t alloc_addr; + efi_memory_desc_t *memory_map; + unsigned long nr_pages, map_size, desc_size, buff_size; + efi_status_t status; + unsigned long l; + + struct efi_boot_memmap map = { + .map= _map, + .map_size = _size, + .desc_size = _size, + .desc_ver = NULL, + .key_ptr= NULL, + .buff_size = _size, + }; + + /* +* Reserve memory for the uncompressed kernel image. This is +* all that prevents any future allocations from conflicting +* with the kernel. Since we can't tell from the compressed +* image how much DRAM the kernel actually uses (due to BSS +* size uncertainty) we allocate the maximum possible size. +* Do this very early, as prints can cause memory allocations +* that may conflict with this. +*/ + alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE; + nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE; + status = efi_call_early(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS, + EFI_BOOT_SERVICES_DATA, nr_pages, _addr); + if (status == EFI_SUCCESS) { + if (alloc_addr == dram_base) { + *reserve_addr = alloc_addr; + *reserve_size = MAX_UNCOMP_KERNEL_SIZE; + return EFI_SUCCESS; + } + /* +* If we end up here, the allocation succeeded but starts below +* dram_base. This can only occur if the real base of DRAM is +* not a multiple of 128 MB, in which case dram_base will have +* been rounded up. Since this implies that a part of the region +* was already occupied, we need to fall through to the code +* below to ensure that the existing allocations don't conflict. +* For this reason, we use EFI_BOOT_SERVICES_DATA above and not +* EFI_LOADER_DATA, which we wouldn't able to distinguish from +* allocations that we want to disallow. +*/ + } + + /* +* If the allocation above failed, we may still be able to proceed: +* if the only allocations in the region are of types that will be +* released to the OS after ExitBootServices(), the decompressor can +* safely overwrite them. +*/ + status = efi_get_memory_map(sys_table_arg, ); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, + "reserve_kernel_base(): Unable to retrieve memory
[tip:efi/core] efi/libstub: Unify command line param parsing
Commit-ID: 60f38de7a8d4e816100ceafd1b382df52527bd50 Gitweb: http://git.kernel.org/tip/60f38de7a8d4e816100ceafd1b382df52527bd50 Author: Ard BiesheuvelAuthorDate: Tue, 4 Apr 2017 17:09:08 +0100 Committer: Ingo Molnar CommitDate: Wed, 5 Apr 2017 12:27:28 +0200 efi/libstub: Unify command line param parsing Merge the parsing of the command line carried out in arm-stub.c with the handling in efi_parse_options(). Note that this also fixes the missing handling of CONFIG_CMDLINE_FORCE=y, in which case the builtin command line should supersede the one passed by the firmware. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: b...@redhat.com Cc: bhsha...@redhat.com Cc: b...@alien8.de Cc: eug...@hp.com Cc: evgeny.kalu...@intel.com Cc: jh...@codeaurora.org Cc: leif.lindh...@linaro.org Cc: linux-...@vger.kernel.org Cc: mark.rutl...@arm.com Cc: roy.fr...@cavium.com Cc: rruig...@codeaurora.org Link: http://lkml.kernel.org/r/20170404160910.28115-1-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c| 24 +++- drivers/firmware/efi/libstub/arm64-stub.c | 4 +--- drivers/firmware/efi/libstub/efi-stub-helper.c | 19 +++ drivers/firmware/efi/libstub/efistub.h | 2 ++ include/linux/efi.h| 2 +- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 02049ff..ac3222f 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -18,8 +18,6 @@ #include "efistub.h" -bool __nokaslr; - efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { @@ -153,18 +151,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail; } - /* check whether 'nokaslr' was passed on the command line */ - if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - static const u8 default_cmdline[] = CONFIG_CMDLINE; - const u8 *str, *cmdline = cmdline_ptr; - - if (IS_ENABLED(CONFIG_CMDLINE_FORCE)) - cmdline = default_cmdline; - str = strstr(cmdline, "nokaslr"); - if (str == cmdline || (str > cmdline && *(str - 1) == ' ')) - __nokaslr = true; - } - si = setup_graphics(sys_table); status = handle_kernel_image(sys_table, image_addr, _size, @@ -176,9 +162,13 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, goto fail_free_cmdline; } - status = efi_parse_options(cmdline_ptr); - if (status != EFI_SUCCESS) - pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline_size == 0) + efi_parse_options(CONFIG_CMDLINE); + + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) + efi_parse_options(cmdline_ptr); secure_boot = efi_get_secureboot(sys_table); diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index eae693e..b4c2589 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -16,8 +16,6 @@ #include "efistub.h" -extern bool __nokaslr; - efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) { u64 tg; @@ -52,7 +50,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, u64 phys_seed = 0; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { - if (!__nokaslr) { + if (!nokaslr()) { status = efi_get_random_bytes(sys_table_arg, sizeof(phys_seed), (u8 *)_seed); diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 3290fae..2e17d2b 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -32,6 +32,13 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; +static int __section(.data) __nokaslr; + +int __pure nokaslr(void) +{ + return __nokaslr; +} + #define EFI_MMAP_NR_SLACK_SLOTS8 struct file_info { @@ -409,17 +416,13 @@ static efi_status_t efi_file_close(void *handle) * environments, first in the early boot environment of the EFI boot * stub, and subsequently during the kernel boot. */
[tip:efi/core] efi/libstub/arm: Don't use TASK_SIZE when randomizing the RT space
Commit-ID: 197decefdb79d6f1350ba0316ce26ba737372d0c Gitweb: http://git.kernel.org/tip/197decefdb79d6f1350ba0316ce26ba737372d0c Author: Ard BiesheuvelAuthorDate: Mon, 17 Apr 2017 10:32:01 +0100 Committer: Ingo Molnar CommitDate: Mon, 17 Apr 2017 12:35:33 +0200 efi/libstub/arm: Don't use TASK_SIZE when randomizing the RT space As reported by James, Catalin and Mark, commit: e69176d68d26 ("ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region") ... results in a crash in the firmware, regardless of whether KASLR is in effect or not and whether the firmware implements EFI_RNG_PROTOCOL or not. Mark has identified the root cause to be the inappropriate use of TASK_SIZE in the stub, which arm64 defines as: #define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ TASK_SIZE_32 : TASK_SIZE_64) and testing thread flags at this point results in the dereference of pointers in uninitialized structures. So instead, introduce a preprocessor symbol EFI_RT_VIRTUAL_LIMIT and define it to TASK_SIZE_64 on arm64 and TASK_SIZE on ARM, both of which are compile time constants. Also, change the 'headroom' variable to static const to force an error if this might change in the future. Tested-by: Mark Rutland Tested-by: James Morse Tested-by: Catalin Marinas Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-arm-ker...@lists.infradead.org Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170417093201.10181-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 11 +-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 1e45ec5..8181ac1 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -32,6 +32,12 @@ #define EFI_RT_VIRTUAL_BASESZ_512M #define EFI_RT_VIRTUAL_SIZESZ_512M +#ifdef CONFIG_ARM64 +# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_64 +#else +# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE +#endif + static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, @@ -236,8 +242,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, * shift of 21 bit positions into account when scaling * the headroom value using a 32-bit random value. */ - u64 headroom = TASK_SIZE - EFI_RT_VIRTUAL_BASE - - EFI_RT_VIRTUAL_SIZE; + static const u64 headroom = EFI_RT_VIRTUAL_LIMIT - + EFI_RT_VIRTUAL_BASE - + EFI_RT_VIRTUAL_SIZE; u32 rnd; status = efi_get_random_bytes(sys_table, sizeof(rnd),
[tip:efi/core] efi/capsule-loader: Use a cached copy of the capsule header
Commit-ID: 82c3768b8d68c40ecde92338899c838b7c674ffb Gitweb: http://git.kernel.org/tip/82c3768b8d68c40ecde92338899c838b7c674ffb Author: Ard BiesheuvelAuthorDate: Fri, 2 Jun 2017 13:52:00 + Committer: Ingo Molnar CommitDate: Mon, 5 Jun 2017 17:50:40 +0200 efi/capsule-loader: Use a cached copy of the capsule header Instead of kmapping the capsule data twice, copy the capsule header into the capsule info struct we keep locally. This is an improvement by itself, but will also enable handling of non-standard header formats more easily. Signed-off-by: Ard Biesheuvel Reviewed-by: Matt Fleming Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170602135207.21708-7-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/capsule-loader.c | 41 +++ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 37d3f6e..5b012a4 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -21,13 +21,13 @@ #define NO_FURTHER_WRITE_ACTION -1 struct capsule_info { - boolheader_obtained; - int reset_type; - longindex; - size_t count; - size_t total_size; - struct page **pages; - size_t page_bytes_remain; + efi_capsule_header_theader; + int reset_type; + longindex; + size_t count; + size_t total_size; + struct page **pages; + size_t page_bytes_remain; }; /** @@ -56,7 +56,6 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) static int efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff, size_t hdr_bytes) { - efi_capsule_header_t *cap_hdr; size_t pages_needed; int ret; void *temp_page; @@ -66,8 +65,9 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, return 0; /* Reset back to the correct offset of header */ - cap_hdr = kbuff - cap_info->count; - pages_needed = ALIGN(cap_hdr->imagesize, PAGE_SIZE) >> PAGE_SHIFT; + kbuff -= cap_info->count; + memcpy(_info->header, kbuff, sizeof(cap_info->header)); + pages_needed = ALIGN(cap_info->header.imagesize, PAGE_SIZE) / PAGE_SIZE; if (pages_needed == 0) { pr_err("invalid capsule size"); @@ -75,15 +75,16 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, } /* Check if the capsule binary supported */ - ret = efi_capsule_supported(cap_hdr->guid, cap_hdr->flags, - cap_hdr->imagesize, + ret = efi_capsule_supported(cap_info->header.guid, + cap_info->header.flags, + cap_info->header.imagesize, _info->reset_type); if (ret) { pr_err("capsule not supported\n"); return ret; } - cap_info->total_size = cap_hdr->imagesize; + cap_info->total_size = cap_info->header.imagesize; temp_page = krealloc(cap_info->pages, pages_needed * sizeof(void *), GFP_KERNEL | __GFP_ZERO); @@ -91,7 +92,6 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, return -ENOMEM; cap_info->pages = temp_page; - cap_info->header_obtained = true; return 0; } @@ -104,15 +104,8 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) { int ret; - void *cap_hdr_temp; - cap_hdr_temp = vmap(cap_info->pages, cap_info->index, - VM_MAP, PAGE_KERNEL); - if (!cap_hdr_temp) - return -ENOMEM; - - ret = efi_capsule_update(cap_hdr_temp, cap_info->pages); - vunmap(cap_hdr_temp); + ret = efi_capsule_update(_info->header, cap_info->pages); if (ret) { pr_err("capsule update failed\n"); return ret; @@ -192,7 +185,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, cap_info->page_bytes_remain -= write_byte; /* Setup capsule binary info structure */ - if (!cap_info->header_obtained) { + if (cap_info->header.headersize == 0) { ret = efi_capsule_setup_info(cap_info, kbuff,
[tip:efi/core] efi/capsule-loader: Use page addresses rather than struct page pointers
Commit-ID: 2a457fb31df62c6b482f78e4f74aaed99271f44d Gitweb: http://git.kernel.org/tip/2a457fb31df62c6b482f78e4f74aaed99271f44d Author: Ard BiesheuvelAuthorDate: Fri, 2 Jun 2017 13:52:03 + Committer: Ingo Molnar CommitDate: Mon, 5 Jun 2017 17:50:41 +0200 efi/capsule-loader: Use page addresses rather than struct page pointers To give some leeway to code that handles non-standard capsule headers, let's keep an array of page addresses rather than struct page pointers. This gives special implementations of efi_capsule_setup_info() the opportunity to mangle the payload a bit before it is presented to the firmware, without putting any knowledge of the nature of such quirks into the generic code. Tested-by: Bryan O'Donoghue Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170602135207.21708-10-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/capsule-loader.c | 12 drivers/firmware/efi/capsule.c| 7 --- include/linux/efi.h | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index cbc35269..ec8ac5c 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -20,6 +20,10 @@ #define NO_FURTHER_WRITE_ACTION -1 +#ifndef phys_to_page +#define phys_to_page(x)pfn_to_page((x) >> PAGE_SHIFT) +#endif + /** * efi_free_all_buff_pages - free all previous allocated buffer pages * @cap_info: pointer to current instance of capsule_info structure @@ -31,7 +35,7 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) { while (cap_info->index > 0) - __free_page(cap_info->pages[--cap_info->index]); + __free_page(phys_to_page(cap_info->pages[--cap_info->index])); cap_info->index = NO_FURTHER_WRITE_ACTION; } @@ -161,12 +165,12 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff, goto failed; } - cap_info->pages[cap_info->index++] = page; + cap_info->pages[cap_info->index++] = page_to_phys(page); cap_info->page_bytes_remain = PAGE_SIZE; + } else { + page = phys_to_page(cap_info->pages[cap_info->index - 1]); } - page = cap_info->pages[cap_info->index - 1]; - kbuff = kmap(page); kbuff += PAGE_SIZE - cap_info->page_bytes_remain; diff --git a/drivers/firmware/efi/capsule.c b/drivers/firmware/efi/capsule.c index e603ccf..901b930 100644 --- a/drivers/firmware/efi/capsule.c +++ b/drivers/firmware/efi/capsule.c @@ -214,7 +214,7 @@ efi_capsule_update_locked(efi_capsule_header_t *capsule, * * Return 0 on success, a converted EFI status code on failure. */ -int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages) +int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages) { u32 imagesize = capsule->imagesize; efi_guid_t guid = capsule->guid; @@ -249,10 +249,11 @@ int efi_capsule_update(efi_capsule_header_t *capsule, struct page **pages) sglist = kmap(sg_pages[i]); for (j = 0; j < SGLIST_PER_PAGE && count > 0; j++) { - u64 sz = min_t(u64, imagesize, PAGE_SIZE); + u64 sz = min_t(u64, imagesize, + PAGE_SIZE - (u64)*pages % PAGE_SIZE); sglist[j].length = sz; - sglist[j].data = page_to_phys(*pages++); + sglist[j].data = *pages++; imagesize -= sz; count--; diff --git a/include/linux/efi.h b/include/linux/efi.h index a7379a2..8269bcb 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -143,7 +143,7 @@ struct capsule_info { longindex; size_t count; size_t total_size; - struct page **pages; + phys_addr_t *pages; size_t page_bytes_remain; }; @@ -1415,7 +1415,7 @@ extern int efi_capsule_supported(efi_guid_t guid, u32 flags, size_t size, int *reset); extern int efi_capsule_update(efi_capsule_header_t *capsule, - struct page **pages); + phys_addr_t *pages); #ifdef CONFIG_EFI_RUNTIME_MAP int efi_runtime_map_init(struct kobject *);
[tip:efi/core] efi/capsule-loader: Redirect calls to efi_capsule_setup_info() via weak alias
Commit-ID: 3fabd628d5ea24b02ddb1230ffca1df0f779f84e Gitweb: http://git.kernel.org/tip/3fabd628d5ea24b02ddb1230ffca1df0f779f84e Author: Ard BiesheuvelAuthorDate: Fri, 2 Jun 2017 13:52:02 + Committer: Ingo Molnar CommitDate: Mon, 5 Jun 2017 17:50:41 +0200 efi/capsule-loader: Redirect calls to efi_capsule_setup_info() via weak alias To allow platform specific code to hook into the capsule loading routines, indirect calls to efi_capsule_setup_info() via a weak alias of __efi_capsule_setup_info(), allowing platforms to redefine the former but still use the latter. Tested-by: Bryan O'Donoghue Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170602135207.21708-9-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/capsule-loader.c | 56 +-- include/linux/efi.h | 12 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index 2357bcd..cbc35269 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -20,16 +20,6 @@ #define NO_FURTHER_WRITE_ACTION -1 -struct capsule_info { - efi_capsule_header_theader; - int reset_type; - longindex; - size_t count; - size_t total_size; - struct page **pages; - size_t page_bytes_remain; -}; - /** * efi_free_all_buff_pages - free all previous allocated buffer pages * @cap_info: pointer to current instance of capsule_info structure @@ -46,28 +36,13 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) cap_info->index = NO_FURTHER_WRITE_ACTION; } -/** - * efi_capsule_setup_info - obtain the efi capsule header in the binary and - * setup capsule_info structure - * @cap_info: pointer to current instance of capsule_info structure - * @kbuff: a mapped first page buffer pointer - * @hdr_bytes: the total received number of bytes for efi header - **/ -static int efi_capsule_setup_info(struct capsule_info *cap_info, - void *kbuff, size_t hdr_bytes) +int __efi_capsule_setup_info(struct capsule_info *cap_info) { size_t pages_needed; int ret; void *temp_page; - /* Only process data block that is larger than efi header size */ - if (hdr_bytes < sizeof(efi_capsule_header_t)) - return 0; - - /* Reset back to the correct offset of header */ - kbuff -= cap_info->count; - memcpy(_info->header, kbuff, sizeof(cap_info->header)); - pages_needed = ALIGN(cap_info->header.imagesize, PAGE_SIZE) / PAGE_SIZE; + pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) / PAGE_SIZE; if (pages_needed == 0) { pr_err("invalid capsule size"); @@ -84,7 +59,6 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, return ret; } - cap_info->total_size = cap_info->header.imagesize; temp_page = krealloc(cap_info->pages, pages_needed * sizeof(void *), GFP_KERNEL | __GFP_ZERO); @@ -97,6 +71,30 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info, } /** + * efi_capsule_setup_info - obtain the efi capsule header in the binary and + * setup capsule_info structure + * @cap_info: pointer to current instance of capsule_info structure + * @kbuff: a mapped first page buffer pointer + * @hdr_bytes: the total received number of bytes for efi header + * + * Platforms with non-standard capsule update mechanisms can override + * this __weak function so they can perform any required capsule + * image munging. See quark_quirk_function() for an example. + **/ +int __weak efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff, + size_t hdr_bytes) +{ + /* Only process data block that is larger than efi header size */ + if (hdr_bytes < sizeof(efi_capsule_header_t)) + return 0; + + memcpy(_info->header, kbuff, sizeof(cap_info->header)); + cap_info->total_size = cap_info->header.imagesize; + + return __efi_capsule_setup_info(cap_info); +} + +/** * efi_capsule_submit_update - invoke the efi_capsule_update API once binary *upload done * @cap_info: pointer to current instance of capsule_info structure @@ -182,7 +180,7 @@ static ssize_t efi_capsule_write(struct file
[tip:efi/core] efi/arm: Enable DMI/SMBIOS
Commit-ID: bb817bef3b1989a9cdb40362cfb8d2aa224ac1bc Gitweb: http://git.kernel.org/tip/bb817bef3b1989a9cdb40362cfb8d2aa224ac1bc Author: Ard BiesheuvelAuthorDate: Fri, 2 Jun 2017 13:52:07 + Committer: Ingo Molnar CommitDate: Mon, 5 Jun 2017 17:50:44 +0200 efi/arm: Enable DMI/SMBIOS Wire up the existing arm64 support for SMBIOS tables (aka DMI) for ARM as well, by moving the arm64 init code to drivers/firmware/efi/arm-runtime.c (which is shared between ARM and arm64), and adding a asm/dmi.h header to ARM that defines the mapping routines for the firmware tables. This allows userspace to access these tables to discover system information exposed by the firmware. It also sets the hardware name used in crash dumps, e.g.: Unable to handle kernel NULL pointer dereference at virtual address pgd = ed3c [] *pgd=bf1f3835 Internal error: Oops: 817 [#1] SMP THUMB2 Modules linked in: CPU: 0 PID: 759 Comm: bash Not tainted 4.10.0-09601-g0e8f38792120-dirty #112 Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 ^^^ NOTE: This does *NOT* enable or encourage the use of DMI quirks, i.e., the the practice of identifying the platform via DMI to decide whether certain workarounds for buggy hardware and/or firmware need to be enabled. This would require the DMI subsystem to be enabled much earlier than we do on ARM, which is non-trivial. Signed-off-by: Ard Biesheuvel Acked-by: Russell King Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170602135207.21708-14-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/Kconfig | 17 + arch/arm/include/asm/dmi.h | 19 +++ arch/arm64/kernel/efi.c| 15 --- drivers/firmware/efi/arm-runtime.c | 16 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4c1a35f..dabcaeb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2061,6 +2061,23 @@ config EFI is only useful for kernels that may run on systems that have UEFI firmware. +config DMI + bool "Enable support for SMBIOS (DMI) tables" + depends on EFI + default y + help + This enables SMBIOS/DMI feature for systems. + + This option is only useful on systems that have UEFI firmware. + However, even with this option, the resultant kernel should + continue to boot on existing non-UEFI platforms. + + NOTE: This does *NOT* enable or encourage the use of DMI quirks, + i.e., the the practice of identifying the platform via DMI to + decide whether certain workarounds for buggy hardware and/or + firmware need to be enabled. This would require the DMI subsystem + to be enabled much earlier than we do on ARM, which is non-trivial. + endmenu menu "CPU Power Management" diff --git a/arch/arm/include/asm/dmi.h b/arch/arm/include/asm/dmi.h new file mode 100644 index 000..df2d2ff --- /dev/null +++ b/arch/arm/include/asm/dmi.h @@ -0,0 +1,19 @@ +/* + * 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. + */ + +#ifndef __ASM_DMI_H +#define __ASM_DMI_H + +#include +#include + +#define dmi_early_remap(x, l) memremap(x, l, MEMREMAP_WB) +#define dmi_early_unmap(x, l) memunmap(x) +#define dmi_remap(x, l)memremap(x, l, MEMREMAP_WB) +#define dmi_unmap(x) memunmap(x) +#define dmi_alloc(l) kzalloc(l, GFP_KERNEL) + +#endif diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 5d17f37..82cd075 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -11,7 +11,6 @@ * */ -#include #include #include @@ -117,20 +116,6 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm, set_permissions, md); } -static int __init arm64_dmi_init(void) -{ - /* -* On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to -* be called early because dmi_id_init(), which is an arch_initcall -* itself, depends on dmi_scan_machine() having been called already. -*/ - dmi_scan_machine(); - if (dmi_available) - dmi_set_dump_stack_arch_desc(); - return 0; -} -core_initcall(arm64_dmi_init); - /* * UpdateCapsule() depends on the system being shutdown via * ResetSystem(). diff --git a/drivers/firmware/efi/arm-runtime.c
[tip:efi/core] efi/arm/arm64: Add missing assignment of efi.config_table
Commit-ID: 9a9de5c044be14c3337ef45174ac8baa568a0f93 Gitweb: http://git.kernel.org/tip/9a9de5c044be14c3337ef45174ac8baa568a0f93 Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:38 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:49 +0200 efi/arm/arm64: Add missing assignment of efi.config_table The ARM EFI init code never assigns the config_table member of the efi struct, which means the sysfs device node is missing, and other in-kernel users will not work correctly. So add the missing assignment. Note that, for now, the runtime and fw_vendor members are still omitted. This is deliberate: exposing physical addresses via sysfs nodes encourages behavior that we would like to avoid on ARM (given how it is more finicky about using correct memory attributes when mapping memory in userland that may be mapped by the kernel already as well). Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-6-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 0aa4ce7..80d1a88 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -145,6 +145,9 @@ static int __init uefi_init(void) sizeof(efi_config_table_t), arch_tables); + if (!retval) + efi.config_table = (unsigned long)efi.systab->tables; + early_memunmap(config_tables, table_size); out: early_memunmap(efi.systab, sizeof(efi_system_table_t));
[tip:efi/core] efi/libstub/arm64: Use hidden attribute for struct screen_info reference
Commit-ID: 760b61d76da6d6a99eb245ab61abf71ca5415cea Gitweb: http://git.kernel.org/tip/760b61d76da6d6a99eb245ab61abf71ca5415cea Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:35 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:49 +0200 efi/libstub/arm64: Use hidden attribute for struct screen_info reference To prevent the compiler from emitting absolute references to screen_info when building position independent code, redeclare the symbol with hidden visibility. Tested-by: Matthias Kaehlcke Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm64/include/asm/efi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 8f3043a..464ac85 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -81,6 +81,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, #define alloc_screen_info(x...)_info #define free_screen_info(x...) +/* redeclare as 'hidden' so the compiler will generate relative references */ +extern struct screen_info screen_info __attribute__((__visibility__("hidden"))); + static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) { }
[tip:efi/core] efi/libstub/arm64: Force 'hidden' visibility for section markers
Commit-ID: 0426a4e68f18d75515414361de9e3e1445d2644e Gitweb: http://git.kernel.org/tip/0426a4e68f18d75515414361de9e3e1445d2644e Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:36 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:49 +0200 efi/libstub/arm64: Force 'hidden' visibility for section markers To prevent the compiler from emitting absolute references to the section markers when running in PIC mode, override the visibility to 'hidden' for all contents of asm/sections.h Tested-by: Matthias Kaehlcke Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-4-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm64-stub.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index b4c2589..f7a6970 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -9,9 +9,17 @@ * published by the Free Software Foundation. * */ + +/* + * To prevent the compiler from emitting GOT-indirected (and thus absolute) + * references to the section markers, override their visibility as 'hidden' + */ +#pragma GCC visibility push(hidden) +#include +#pragma GCC visibility pop + #include #include -#include #include #include "efistub.h"
[tip:efi/core] efi/libstub/arm64: Set -fpie when building the EFI stub
Commit-ID: 91ee5b21ee026c49e4e7483de69b55b8b47042be Gitweb: http://git.kernel.org/tip/91ee5b21ee026c49e4e7483de69b55b8b47042be Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:37 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:49 +0200 efi/libstub/arm64: Set -fpie when building the EFI stub Clang may emit absolute symbol references when building in non-PIC mode, even when using the default 'small' code model, which is already mostly position independent to begin with, due to its use of adrp/add pairs that have a relative range of +/- 4 GB. The remedy is to pass the -fpie flag, which can be done safely now that the code has been updated to avoid GOT indirections (which may be emitted due to the compiler assuming that the PIC/PIE code may end up in a shared library that is subject to ELF symbol preemption) Passing -fpie when building code that needs to execute at an a priori unknown offset is arguably an improvement in any case, and given that the recent visibility changes allow the PIC build to pass with GCC as well, let's add -fpie for all arm64 builds rather than only for Clang. Tested-by: Matthias Kaehlcke Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-5-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 37e24f5..cf81e6c 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -10,7 +10,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -fPIC -fno-strict-aliasing -mno-red-zone \ -mno-mmx -mno-sse -cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) +cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ -fno-builtin -fpic -mno-single-pic-base
[tip:efi/core] arm/efi: Replace open coded constants with symbolic ones
Commit-ID: 609eaf0748a5b9dccf3810a2b822a0559f33c0b2 Gitweb: http://git.kernel.org/tip/609eaf0748a5b9dccf3810a2b822a0559f33c0b2 Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:43 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:50 +0200 arm/efi: Replace open coded constants with symbolic ones Replace the various open coded constants in the EFI PE/COFF header with definitions from pe.h, or expressions based on local symbols. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-11-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/boot/compressed/efi-header.S | 128 ++ 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S index 309d619..542e1ad 100644 --- a/arch/arm/boot/compressed/efi-header.S +++ b/arch/arm/boot/compressed/efi-header.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Linaro Ltd + * Copyright (C) 2013-2017 Linaro Ltd * Authors: Roy Franz * Ard Biesheuvel * @@ -8,6 +8,9 @@ * published by the Free Software Foundation. */ +#include +#include + .macro __nop #ifdef CONFIG_EFI_STUB @ This is almost but not quite a NOP, since it does clobber the @@ -15,7 +18,7 @@ @ PE/COFF expects the magic string "MZ" at offset 0, while the @ ARM/Linux boot protocol expects an executable instruction @ there. - .inst 'M' | ('Z' << 8) | (0x1310 << 16) @ tstne r0, #0x4d000 + .inst MZ_MAGIC | (0x1310 << 16) @ tstne r0, #0x4d000 #else AR_CLASS( mov r0, r0 ) M_CLASS( nop.w ) @@ -34,78 +37,81 @@ @ The only 2 fields of the MSDOS header that are used are this @ PE/COFF offset, and the "MZ" bytes at offset 0x0. @ - .long pe_header - start @ Offset to the PE header. + .long pe_header - start @ Offset to the PE header. pe_header: - .ascii "PE\0\0" + .long PE_MAGIC coff_header: - .short 0x01c2 @ ARM or Thumb - .short 1 @ nr_sections - .long 0 @ TimeDateStamp - .long 0 @ PointerToSymbolTable - .long 0 @ NumberOfSymbols - .short section_table - optional_header - @ SizeOfOptionalHeader - .short 0x306 @ Characteristics. - @ IMAGE_FILE_32BIT_MACHINE | - @ IMAGE_FILE_DEBUG_STRIPPED | - @ IMAGE_FILE_EXECUTABLE_IMAGE | - @ IMAGE_FILE_LINE_NUMS_STRIPPED + .short IMAGE_FILE_MACHINE_THUMB@ Machine + .short section_count @ NumberOfSections + .long 0 @ TimeDateStamp + .long 0 @ PointerToSymbolTable + .long 0 @ NumberOfSymbols + .short section_table - optional_header @ SizeOfOptionalHeader + .short IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_DEBUG_STRIPPED | \ + IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED @ Characteristics optional_header: - .short 0x10b @ PE32 format - .byte 0x02@ MajorLinkerVersion - .byte 0x14@ MinorLinkerVersion - .long _end - __efi_start @ SizeOfCode - .long 0 @ SizeOfInitializedData - .long 0 @ SizeOfUninitializedData - .long efi_stub_entry - start @ AddressOfEntryPoint - .long start_offset@ BaseOfCode - .long 0 @ data + .short PE_OPT_MAGIC_PE32 @ PE32 format + .byte 0x02@ MajorLinkerVersion + .byte 0x14@ MinorLinkerVersion + .long _end - __efi_start @ SizeOfCode +
[tip:efi/core] arm/efi: Remove forbidden values from the PE/COFF header
Commit-ID: 4415f9f4a6e5c6a4228098fc8289f21f3dda515c Gitweb: http://git.kernel.org/tip/4415f9f4a6e5c6a4228098fc8289f21f3dda515c Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:41 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:50 +0200 arm/efi: Remove forbidden values from the PE/COFF header Bring the PE/COFF header in line with the PE/COFF spec, by setting NumberOfSymbols to 0, and removing the section alignment flags. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-9-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/boot/compressed/efi-header.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S index a17ca8d..4169b90 100644 --- a/arch/arm/boot/compressed/efi-header.S +++ b/arch/arm/boot/compressed/efi-header.S @@ -44,7 +44,7 @@ coff_header: .short 2 @ nr_sections .long 0 @ TimeDateStamp .long 0 @ PointerToSymbolTable - .long 1 @ NumberOfSymbols + .long 0 @ NumberOfSymbols .short section_table - optional_header @ SizeOfOptionalHeader .short 0x306 @ Characteristics. @@ -110,7 +110,7 @@ section_table: .long 0 @ PointerToLineNumbers .short 0 @ NumberOfRelocations .short 0 @ NumberOfLineNumbers - .long 0x42100040 @ Characteristics + .long 0x4240 @ Characteristics .ascii ".text\0\0\0" .long _end - __efi_start @ VirtualSize @@ -121,7 +121,7 @@ section_table: .long 0 @ PointerToLineNumbers .short 0 @ NumberOfRelocations .short 0 @ NumberOfLineNumbers - .long 0xe0500020 @ Characteristics + .long 0xe020 @ Characteristics .align 9 __efi_start:
[tip:efi/core] drivers/fbdev/efifb: Allow BAR to be moved instead of claiming it
Commit-ID: dcf8f5ce31656534efada252f6a563c09b295983 Gitweb: http://git.kernel.org/tip/dcf8f5ce31656534efada252f6a563c09b295983 Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:40 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:50 +0200 drivers/fbdev/efifb: Allow BAR to be moved instead of claiming it On UEFI systems, the firmware may expose a Graphics Output Protocol (GOP) instance to which the efifb driver attempts to attach in order to provide a minimal, unaccelerated framebuffer. The GOP protocol itself is not very sophisticated, and only describes the offset and size of the framebuffer in memory, and the pixel format. If the GOP framebuffer is provided by a PCI device, it will have been configured and enabled by the UEFI firmware, and the GOP protocol will simply point into a live BAR region. However, the GOP protocol itself does not describe this relation, and so we have to take care not to reconfigure the BAR without taking efifb's dependency on it into account. Commit: 55d728a40d36 ("efi/fb: Avoid reconfiguration of BAR that covers the framebuffer") attempted to do so by claiming the BAR resource early on, which prevents the PCI resource allocation routines from changing it. However, it turns out that this only works if the PCI device is not behind any bridges, since the bridge resources need to be claimed first. So instead, allow the BAR to be moved, but make the efifb driver deal with that gracefully. So record the resource that covers the BAR early on, and if it turns out to have moved by the time we probe the efifb driver, update the framebuffer address accordingly. While this is less likely to occur on x86, given that the firmware's PCI resource allocation is more likely to be preserved, this is a worthwhile sanity check to have in place, and so let's remove the preprocessor conditional that makes it !X86 only. Signed-off-by: Ard Biesheuvel Reviewed-by: Peter Jones Acked-by: Bartlomiej Zolnierkiewicz Acked-by: Bjorn Helgaas Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-8-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/video/fbdev/efifb.c | 31 ++- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 1e784ad..3a01064 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -149,6 +149,10 @@ ATTRIBUTE_GROUPS(efifb); static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */ +static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */ +static struct resource *bar_resource; +static u64 bar_offset; + static int efifb_probe(struct platform_device *dev) { struct fb_info *info; @@ -203,6 +207,13 @@ static int efifb_probe(struct platform_device *dev) efifb_fix.smem_start |= ext_lfb_base; } + if (bar_resource && + bar_resource->start + bar_offset != efifb_fix.smem_start) { + dev_info(_pci_dev->dev, +"BAR has moved, updating efifb address\n"); + efifb_fix.smem_start = bar_resource->start + bar_offset; + } + efifb_defined.bits_per_pixel = screen_info.lfb_depth; efifb_defined.xres = screen_info.lfb_width; efifb_defined.yres = screen_info.lfb_height; @@ -370,15 +381,13 @@ static struct platform_driver efifb_driver = { builtin_platform_driver(efifb_driver); -#if defined(CONFIG_PCI) && !defined(CONFIG_X86) - -static bool pci_bar_found; /* did we find a BAR matching the efifb base? */ +#if defined(CONFIG_PCI) -static void claim_efifb_bar(struct pci_dev *dev, int idx) +static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset) { u16 word; - pci_bar_found = true; + efifb_pci_dev = dev; pci_read_config_word(dev, PCI_COMMAND, ); if (!(word & PCI_COMMAND_MEMORY)) { @@ -389,12 +398,8 @@ static void claim_efifb_bar(struct pci_dev *dev, int idx) return; } - if (pci_claim_resource(dev, idx)) { - pci_dev_disabled = true; - dev_err(>dev, - "BAR %d: failed to claim resource for efifb!\n", idx); - return; - } + bar_resource = >resource[idx]; + bar_offset = offset; dev_info(>dev, "BAR %d: assigned to efifb\n", idx); } @@ -405,7 +410,7 @@ static void efifb_fixup_resources(struct pci_dev *dev) u64 size = screen_info.lfb_size; int i; - if (pci_bar_found ||
[tip:efi/core] arm/efi: Remove pointless dummy .reloc section
Commit-ID: 574cea724cd81f4063491ed1c0534d81a094a913 Gitweb: http://git.kernel.org/tip/574cea724cd81f4063491ed1c0534d81a094a913 Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:42 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:50 +0200 arm/efi: Remove pointless dummy .reloc section The kernel's EFI PE/COFF header contains a dummy .reloc section, and an explanatory comment that claims that this is required for the EFI application loader to accept the Image as a relocatable image (i.e., one that can be loaded at any offset and fixed up in place) This was inherited from the x86 implementation, which has elaborate host tooling to mangle the PE/COFF header post-link time, and which populates the .reloc section with a single dummy base relocation. On ARM, no such tooling exists, and the .reloc section remains empty, and is never even exposed via the BaseRelocationTable directory entry, which is where the PE/COFF loader looks for it. The PE/COFF spec is unclear about relocatable images that do not require any fixups, but the EDK2 implementation, which is the de facto reference for PE/COFF in the UEFI space, clearly does not care, and explicitly mentions (in a comment) that relocatable images with no base relocations are perfectly fine, as long as they don't have the RELOCS_STRIPPED attribute set (which is not the case for our PE/COFF image) So simply remove the .reloc section altogether. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-10-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/boot/compressed/efi-header.S | 18 +- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S index 4169b90..309d619 100644 --- a/arch/arm/boot/compressed/efi-header.S +++ b/arch/arm/boot/compressed/efi-header.S @@ -41,7 +41,7 @@ pe_header: coff_header: .short 0x01c2 @ ARM or Thumb - .short 2 @ nr_sections + .short 1 @ nr_sections .long 0 @ TimeDateStamp .long 0 @ PointerToSymbolTable .long 0 @ NumberOfSymbols @@ -96,22 +96,6 @@ extra_header_fields: .quad 0 @ BaseRelocationTable section_table: - @ - @ The EFI application loader requires a relocation section - @ because EFI applications must be relocatable. This is a - @ dummy section as far as we are concerned. - @ - .ascii ".reloc\0\0" - .long 0 @ VirtualSize - .long 0 @ VirtualAddress - .long 0 @ SizeOfRawData - .long 0 @ PointerToRawData - .long 0 @ PointerToRelocations - .long 0 @ PointerToLineNumbers - .short 0 @ NumberOfRelocations - .short 0 @ NumberOfLineNumbers - .long 0x4240 @ Characteristics - .ascii ".text\0\0\0" .long _end - __efi_start @ VirtualSize .long __efi_start @ VirtualAddress
[tip:efi/core] efi/arm: Don't mark ACPI reclaim memory as MEMBLOCK_NOMAP
Commit-ID: f56ab9a5b73ca2aee777ccdf2d355ae2dd31db5a Gitweb: http://git.kernel.org/tip/f56ab9a5b73ca2aee777ccdf2d355ae2dd31db5a Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:34 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:49 +0200 efi/arm: Don't mark ACPI reclaim memory as MEMBLOCK_NOMAP On ARM, regions of memory that are described by UEFI as having special significance to the firmware itself are omitted from the linear mapping. This is necessary since we cannot guarantee that alternate mappings of the same physical region will use attributes that are compatible with the ones we use for the linear mapping, and aliases with mismatched attributes are prohibited by the architecture. The above does not apply to ACPI reclaim regions: such regions have no special significance to the firmware, and it is up to the OS to decide whether or not to preserve them after it has consumed their contents, and for how long, after which time the OS can use the memory in any way it likes. In the Linux case, such regions are preserved indefinitely, and are simply treated the same way as other 'reserved' memory types. Punching holes into the linear mapping causes page table fragmentation, which increases TLB pressure, and so we should avoid doing so if we can. So add a special case for regions of type EFI_ACPI_RECLAIM_MEMORY, and memblock_reserve() them instead of marking them MEMBLOCK_NOMAP. Signed-off-by: Ard Biesheuvel Acked-by: Mark Rutland Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/arm-init.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 1027d7b4..0aa4ce7 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -159,6 +159,7 @@ static __init int is_usable_memory(efi_memory_desc_t *md) switch (md->type) { case EFI_LOADER_CODE: case EFI_LOADER_DATA: + case EFI_ACPI_RECLAIM_MEMORY: case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: @@ -211,6 +212,10 @@ static __init void reserve_regions(void) if (!is_usable_memory(md)) memblock_mark_nomap(paddr, size); + + /* keep ACPI reclaim memory intact for kexec etc. */ + if (md->type == EFI_ACPI_RECLAIM_MEMORY) + memblock_reserve(paddr, size); } } }
[tip:efi/core] arm/efi: Split zImage code and data into separate PE/COFF sections
Commit-ID: e4bae4d0b5f368dda5bbf1374dca74c1b542d841 Gitweb: http://git.kernel.org/tip/e4bae4d0b5f368dda5bbf1374dca74c1b542d841 Author: Ard BiesheuvelAuthorDate: Fri, 18 Aug 2017 20:49:44 +0100 Committer: Ingo Molnar CommitDate: Mon, 21 Aug 2017 09:43:51 +0200 arm/efi: Split zImage code and data into separate PE/COFF sections To prevent unintended modifications to the kernel text (malicious or otherwise) while running the EFI stub, describe the kernel image as two separate sections: a .text section with read-execute permissions, covering .text, .rodata, .piggytext and the GOT sections (which the stub does not care about anyway), and a .data section with read-write permissions, covering .data and .bss. This relies on the firmware to actually take the section permission flags into account, but this is something that is currently being implemented in EDK2, which means we will likely start seeing it in the wild between one and two years from now. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Russell King Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170818194947.19347-12-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm/boot/compressed/efi-header.S | 32 +++- arch/arm/boot/compressed/vmlinux.lds.S | 30 +++--- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S index 542e1ad..c94a88a 100644 --- a/arch/arm/boot/compressed/efi-header.S +++ b/arch/arm/boot/compressed/efi-header.S @@ -54,20 +54,22 @@ coff_header: IMAGE_FILE_EXECUTABLE_IMAGE | \ IMAGE_FILE_LINE_NUMS_STRIPPED @ Characteristics +#define __pecoff_code_size (__pecoff_data_start - __efi_start) + optional_header: .short PE_OPT_MAGIC_PE32 @ PE32 format .byte 0x02@ MajorLinkerVersion .byte 0x14@ MinorLinkerVersion - .long _end - __efi_start @ SizeOfCode - .long 0 @ SizeOfInitializedData + .long __pecoff_code_size @ SizeOfCode + .long __pecoff_data_size @ SizeOfInitializedData .long 0 @ SizeOfUninitializedData .long efi_stub_entry - start @ AddressOfEntryPoint .long start_offset@ BaseOfCode - .long 0 @ BaseOfData + .long __pecoff_data_start - start @ BaseOfData extra_header_fields: .long 0 @ ImageBase - .long SZ_512 @ SectionAlignment + .long SZ_4K @ SectionAlignment .long SZ_512 @ FileAlignment .short 0 @ MajorOsVersion .short 0 @ MinorOsVersion @@ -77,7 +79,7 @@ extra_header_fields: .short 0 @ MinorSubsystemVersion .long 0 @ Win32VersionValue - .long _end - start@ SizeOfImage + .long __pecoff_end - start@ SizeOfImage .long start_offset@ SizeOfHeaders .long 0 @ CheckSum .short IMAGE_SUBSYSTEM_EFI_APPLICATION @ Subsystem @@ -98,9 +100,9 @@ extra_header_fields: section_table: .ascii ".text\0\0\0" - .long _end - __efi_start @ VirtualSize + .long __pecoff_code_size @ VirtualSize .long __efi_start @ VirtualAddress - .long _edata - __efi_start@ SizeOfRawData + .long __pecoff_code_size @ SizeOfRawData .long __efi_start @ PointerToRawData .long 0 @ PointerToRelocations .long 0 @ PointerToLineNumbers @@ -108,12 +110,24 @@ section_table: .short 0 @ NumberOfLineNumbers .long IMAGE_SCN_CNT_CODE | \ IMAGE_SCN_MEM_READ | \ - IMAGE_SCN_MEM_WRITE | \
[tip:efi/core] efi/random: Increase size of firmware supplied randomness
Commit-ID: c2ceb5fd4e921506e86208b82fca716a2c3aad59 Gitweb: http://git.kernel.org/tip/c2ceb5fd4e921506e86208b82fca716a2c3aad59 Author: Ard BiesheuvelAuthorDate: Fri, 25 Aug 2017 16:50:16 +0100 Committer: Ingo Molnar CommitDate: Sat, 26 Aug 2017 09:20:33 +0200 efi/random: Increase size of firmware supplied randomness The crng code requires at least 64 bytes (2 * CHACHA20_BLOCK_SIZE) to complete the fast boot-time init, so provide that many bytes when invoking UEFI protocols to seed the entropy pool. Also, add a notice so we can tell from the boot log when the seeding actually took place. Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20170825155019.6740-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/efi.c| 3 ++- drivers/firmware/efi/libstub/random.c | 10 -- include/linux/efi.h | 2 ++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a32e146..c8a27a2 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -541,6 +541,7 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, if (seed != NULL) { add_device_randomness(seed->bits, seed->size); early_memunmap(seed, sizeof(*seed) + size); + pr_notice("seeding entropy pool\n"); } else { pr_err("Could not map UEFI random seed!\n"); } @@ -900,7 +901,7 @@ static int update_efi_random_seed(struct notifier_block *nb, seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB); if (seed != NULL) { - size = min(seed->size, 32U); + size = min(seed->size, EFI_RANDOM_SEED_SIZE); memunmap(seed); } else { pr_err("Could not map UEFI random seed!\n"); diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 7e72954..e0e603a 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -145,8 +145,6 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, return status; } -#define RANDOM_SEED_SIZE 32 - efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) { efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; @@ -162,25 +160,25 @@ efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg) return status; status = efi_call_early(allocate_pool, EFI_RUNTIME_SERVICES_DATA, - sizeof(*seed) + RANDOM_SEED_SIZE, + sizeof(*seed) + EFI_RANDOM_SEED_SIZE, (void **)); if (status != EFI_SUCCESS) return status; - status = rng->get_rng(rng, _algo_raw, RANDOM_SEED_SIZE, + status = rng->get_rng(rng, _algo_raw, EFI_RANDOM_SEED_SIZE, seed->bits); if (status == EFI_UNSUPPORTED) /* * Use whatever algorithm we have available if the raw algorithm * is not implemented. */ - status = rng->get_rng(rng, NULL, RANDOM_SEED_SIZE, + status = rng->get_rng(rng, NULL, EFI_RANDOM_SEED_SIZE, seed->bits); if (status != EFI_SUCCESS) goto err_freepool; - seed->size = RANDOM_SEED_SIZE; + seed->size = EFI_RANDOM_SEED_SIZE; status = efi_call_early(install_configuration_table, _table_guid, seed); if (status != EFI_SUCCESS) diff --git a/include/linux/efi.h b/include/linux/efi.h index c241acc..33d41df 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1571,6 +1571,8 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table, void *priv, efi_exit_boot_map_processing priv_func); +#define EFI_RANDOM_SEED_SIZE 64U + struct linux_efi_random_seed { u32 size; u8 bits[];
[tip:efi/urgent] efi/libstub/arm: Don't randomize runtime regions when CONFIG_HIBERNATION=y
Commit-ID: 38fb6652229c2149e8694d57db442878fdf8a1bd Gitweb: https://git.kernel.org/tip/38fb6652229c2149e8694d57db442878fdf8a1bd Author: Ard BiesheuvelAuthorDate: Wed, 25 Oct 2017 11:04:48 +0100 Committer: Ingo Molnar CommitDate: Wed, 25 Oct 2017 12:10:59 +0200 efi/libstub/arm: Don't randomize runtime regions when CONFIG_HIBERNATION=y Commit: e69176d68d26 ("ef/libstub/arm/arm64: Randomize the base of the UEFI rt services region") implemented randomization of the virtual mapping that the OS chooses for the UEFI runtime services. This was motivated by the fact that UEFI usually does not bother to specify any permission restrictions for those regions, making them prime real estate for exploitation now that the OS is getting more and more careful not to leave any R+W+X mapped regions lying around. However, this randomization breaks assumptions in the resume from hibernation code, which expects all memory regions populated by UEFI to remain in the same place, including their virtual mapping into the OS memory space. While this assumption may not be entirely reasonable in the first place, breaking it deliberately does not make a lot of sense either. So let's refrain from this randomization pass if CONFIG_HIBERNATION=y. Signed-off-by: Ard Biesheuvel Cc: James Morse Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20171025100448.26056-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/libstub/arm-stub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 1cb2d1c..a94601d 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -238,7 +238,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_random_get_seed(sys_table); - if (!nokaslr()) { + /* hibernation expects the runtime regions to stay in the same place */ + if (!IS_ENABLED(CONFIG_HIBERNATION) && !nokaslr()) { /* * Randomize the base of the UEFI runtime services region. * Preserve the 2 MB alignment of the region by taking a
[tip:efi/core] efi/x86: Fold __setup_efi_pci32() and __setup_efi_pci64() into one function
Commit-ID: 2c3625cb9fa2c477d5877a1819e29d6a902e5fef Gitweb: https://git.kernel.org/tip/2c3625cb9fa2c477d5877a1819e29d6a902e5fef Author: Ard BiesheuvelAuthorDate: Fri, 4 May 2018 08:00:00 +0200 Committer: Ingo Molnar CommitDate: Mon, 14 May 2018 08:57:49 +0200 efi/x86: Fold __setup_efi_pci32() and __setup_efi_pci64() into one function As suggested by Lukas, use his efi_call_proto() and efi_table_attr() macros to merge __setup_efi_pci32() and __setup_efi_pci64() into a single function, removing the need to duplicate changes made in subsequent patches across both. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Lukas Wunner Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180504060003.19618-15-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 107 +-- 1 file changed, 25 insertions(+), 82 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 3994f48c4043..dadf32312082 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -109,23 +109,27 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) } static efi_status_t -__setup_efi_pci32(efi_pci_io_protocol_32_t *pci, struct pci_setup_rom **__rom) +__setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) { struct pci_setup_rom *rom = NULL; efi_status_t status; unsigned long size; - uint64_t attributes; + uint64_t attributes, romsize; + void *romimage; - status = efi_early->call(pci->attributes, pci, -EfiPciIoAttributeOperationGet, 0, 0, -); + status = efi_call_proto(efi_pci_io_protocol, attributes, pci, + EfiPciIoAttributeOperationGet, 0, 0, + ); if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol, +romimage, pci); + romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci); + if (!romimage || !romsize) return EFI_INVALID_PARAMETER; - size = pci->romsize + sizeof(*rom); + size = romsize + sizeof(*rom); status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, ); if (status != EFI_SUCCESS) { @@ -141,30 +145,32 @@ __setup_efi_pci32(efi_pci_io_protocol_32_t *pci, struct pci_setup_rom **__rom) rom->pcilen = pci->romsize; *__rom = rom; - status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, -PCI_VENDOR_ID, 1, &(rom->vendor)); + status = efi_call_proto(efi_pci_io_protocol, pci.read, pci, + EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, + >vendor); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to read rom->vendor\n"); goto free_struct; } - status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, -PCI_DEVICE_ID, 1, &(rom->devid)); + status = efi_call_proto(efi_pci_io_protocol, pci.read, pci, + EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, + >devid); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to read rom->devid\n"); goto free_struct; } - status = efi_early->call(pci->get_location, pci, &(rom->segment), -&(rom->bus), &(rom->device), &(rom->function)); + status = efi_call_proto(efi_pci_io_protocol, get_location, pci, + >segment, >bus, >device, + >function); if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, - pci->romsize); + memcpy(rom->romdata, romimage, romsize); return status; free_struct: @@ -176,7 +182,7 @@ static void setup_efi_pci32(struct boot_params *params, void **pci_handle, unsigned long size) { - efi_pci_io_protocol_32_t *pci = NULL; + efi_pci_io_protocol_t *pci = NULL; efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; u32 *handles = (u32 *)(unsigned long)pci_handle; efi_status_t status; @@ -203,7 +209,7 @@ setup_efi_pci32(struct boot_params *params, void
[tip:efi/core] efi: Align efi_pci_io_protocol typedefs to type naming convention
Commit-ID: cb0ba793525788e40e7a9ee82de8f3b017ca4459 Gitweb: https://git.kernel.org/tip/cb0ba793525788e40e7a9ee82de8f3b017ca4459 Author: Ard BiesheuvelAuthorDate: Fri, 4 May 2018 07:59:59 +0200 Committer: Ingo Molnar CommitDate: Mon, 14 May 2018 08:57:48 +0200 efi: Align efi_pci_io_protocol typedefs to type naming convention In order to use the helper macros that perform type mangling with the EFI PCI I/O protocol struct typedefs, align their Linux typenames with the convention we use for definitionns that originate in the UEFI spec, and add the trailing _t to each. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180504060003.19618-14-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 8 include/linux/efi.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 09f36c0d9d4f..3994f48c4043 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -109,7 +109,7 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) } static efi_status_t -__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) +__setup_efi_pci32(efi_pci_io_protocol_32_t *pci, struct pci_setup_rom **__rom) { struct pci_setup_rom *rom = NULL; efi_status_t status; @@ -176,7 +176,7 @@ static void setup_efi_pci32(struct boot_params *params, void **pci_handle, unsigned long size) { - efi_pci_io_protocol_32 *pci = NULL; + efi_pci_io_protocol_32_t *pci = NULL; efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; u32 *handles = (u32 *)(unsigned long)pci_handle; efi_status_t status; @@ -218,7 +218,7 @@ setup_efi_pci32(struct boot_params *params, void **pci_handle, } static efi_status_t -__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) +__setup_efi_pci64(efi_pci_io_protocol_64_t *pci, struct pci_setup_rom **__rom) { struct pci_setup_rom *rom; efi_status_t status; @@ -284,7 +284,7 @@ static void setup_efi_pci64(struct boot_params *params, void **pci_handle, unsigned long size) { - efi_pci_io_protocol_64 *pci = NULL; + efi_pci_io_protocol_64_t *pci = NULL; efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; u64 *handles = (u64 *)(unsigned long)pci_handle; efi_status_t status; diff --git a/include/linux/efi.h b/include/linux/efi.h index 3016d8c456bc..56add823f190 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -397,7 +397,7 @@ typedef struct { u32 set_bar_attributes; u64 romsize; u32 romimage; -} efi_pci_io_protocol_32; +} efi_pci_io_protocol_32_t; typedef struct { u64 poll_mem; @@ -417,7 +417,7 @@ typedef struct { u64 set_bar_attributes; u64 romsize; u64 romimage; -} efi_pci_io_protocol_64; +} efi_pci_io_protocol_64_t; typedef struct { void *poll_mem; @@ -437,7 +437,7 @@ typedef struct { void *set_bar_attributes; uint64_t romsize; void *romimage; -} efi_pci_io_protocol; +} efi_pci_io_protocol_t; #define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 #define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
[tip:efi/core] efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32' definition for mixed mode
Commit-ID: 0b3225ab9407f557a8e20f23f37aa7236c10a9b1 Gitweb: https://git.kernel.org/tip/0b3225ab9407f557a8e20f23f37aa7236c10a9b1 Author: Ard BiesheuvelAuthorDate: Fri, 4 May 2018 07:59:58 +0200 Committer: Ingo Molnar CommitDate: Mon, 14 May 2018 08:56:29 +0200 efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32' definition for mixed mode Mixed mode allows a kernel built for x86_64 to interact with 32-bit EFI firmware, but requires us to define all struct definitions carefully when it comes to pointer sizes. 'struct efi_pci_io_protocol_32' currently uses a 'void *' for the 'romimage' field, which will be interpreted as a 64-bit field on such kernels, potentially resulting in bogus memory references and subsequent crashes. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180504060003.19618-13-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 6 -- include/linux/efi.h | 8 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 47d3efff6805..09f36c0d9d4f 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -163,7 +163,8 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: @@ -269,7 +270,8 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) goto free_struct; - memcpy(rom->romdata, pci->romimage, pci->romsize); + memcpy(rom->romdata, (void *)(unsigned long)pci->romimage, + pci->romsize); return status; free_struct: diff --git a/include/linux/efi.h b/include/linux/efi.h index f1b7d68ac460..3016d8c456bc 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -395,8 +395,8 @@ typedef struct { u32 attributes; u32 get_bar_attributes; u32 set_bar_attributes; - uint64_t romsize; - void *romimage; + u64 romsize; + u32 romimage; } efi_pci_io_protocol_32; typedef struct { @@ -415,8 +415,8 @@ typedef struct { u64 attributes; u64 get_bar_attributes; u64 set_bar_attributes; - uint64_t romsize; - void *romimage; + u64 romsize; + u64 romimage; } efi_pci_io_protocol_64; typedef struct {
[tip:efi/core] arm64/efi: Ignore EFI_MEMORY_XP attribute if RP and/or WP are set
Commit-ID: 1e9de1d2207d67b97bb0b62e38454b663d6542fa Gitweb: https://git.kernel.org/tip/1e9de1d2207d67b97bb0b62e38454b663d6542fa Author: Ard BiesheuvelAuthorDate: Tue, 2 Jan 2018 18:10:39 + Committer: Ingo Molnar CommitDate: Wed, 3 Jan 2018 14:03:48 +0100 arm64/efi: Ignore EFI_MEMORY_XP attribute if RP and/or WP are set The UEFI memory map is a bit vague about how to interpret the EFI_MEMORY_XP attribute when it is combined with EFI_MEMORY_RP and/or EFI_MEMORY_WP, which have retroactively been redefined as cacheability attributes rather than permission attributes. So let's ignore EFI_MEMORY_XP if _RP and/or _WP are also set. In this case, it is likely that they are being used to describe the capability of the region (i.e., whether it has the controls to reconfigure it as non-executable) rather than the nature of the contents of the region (i.e., whether it contains data that we will never attempt to execute) Reported-by: Stephen Boyd Tested-by: Stephen Boyd Signed-off-by: Ard Biesheuvel Cc: Arvind Yadav Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tyler Baicar Cc: Vasyl Gomonovych Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180102181042.19074-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/arm64/kernel/efi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 82cd075..f85ac58 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -48,7 +48,9 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) return pgprot_val(PAGE_KERNEL_ROX); /* RW- */ - if (attr & EFI_MEMORY_XP || type != EFI_RUNTIME_SERVICES_CODE) + if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) == +EFI_MEMORY_XP) || + type != EFI_RUNTIME_SERVICES_CODE) return pgprot_val(PAGE_KERNEL); /* RWX */
[tip:efi/core] efi/capsule-loader: Reinstate virtual capsule mapping
Commit-ID: f24c4d478013d82bd1b943df566fff3561d52864 Gitweb: https://git.kernel.org/tip/f24c4d478013d82bd1b943df566fff3561d52864 Author: Ard BiesheuvelAuthorDate: Tue, 2 Jan 2018 17:21:10 + Committer: Ingo Molnar CommitDate: Wed, 3 Jan 2018 13:54:31 +0100 efi/capsule-loader: Reinstate virtual capsule mapping Commit: 82c3768b8d68 ("efi/capsule-loader: Use a cached copy of the capsule header") ... refactored the capsule loading code that maps the capsule header, to avoid having to map it several times. However, as it turns out, the vmap() call we ended up removing did not just map the header, but the entire capsule image, and dropping this virtual mapping breaks capsules that are processed by the firmware immediately (i.e., without a reboot). Unfortunately, that change was part of a larger refactor that allowed a quirk to be implemented for Quark, which has a non-standard memory layout for capsules, and we have slightly painted ourselves into a corner by allowing quirk code to mangle the capsule header and memory layout. So we need to fix this without breaking Quark. Fortunately, Quark does not appear to care about the virtual mapping, and so we can simply do a partial revert of commit: 2a457fb31df6 ("efi/capsule-loader: Use page addresses rather than struct page pointers") ... and create a vmap() mapping of the entire capsule (including header) based on the reinstated struct page array, unless running on Quark, in which case we pass the capsule header copy as before. Reported-by: Ge Song Tested-by: Bryan O'Donoghue Tested-by: Ge Song Signed-off-by: Ard Biesheuvel Cc: Cc: Dave Young Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Fixes: 82c3768b8d68 ("efi/capsule-loader: Use a cached copy of the capsule header") Link: http://lkml.kernel.org/r/20180102172110.17018-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/quirks.c| 13 +- drivers/firmware/efi/capsule-loader.c | 45 --- include/linux/efi.h | 4 +++- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 8a99a2e..5b513cc 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -592,7 +592,18 @@ static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff, /* * Update the first page pointer to skip over the CSH header. */ - cap_info->pages[0] += csh->headersize; + cap_info->phys[0] += csh->headersize; + + /* +* cap_info->capsule should point at a virtual mapping of the entire +* capsule, starting at the capsule header. Our image has the Quark +* security header prepended, so we cannot rely on the default vmap() +* mapping created by the generic capsule code. +* Given that the Quark firmware does not appear to care about the +* virtual mapping, let's just point cap_info->capsule at our copy +* of the capsule header. +*/ + cap_info->capsule = _info->header; return 1; } diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c index ec8ac5c..055e2e8 100644 --- a/drivers/firmware/efi/capsule-loader.c +++ b/drivers/firmware/efi/capsule-loader.c @@ -20,10 +20,6 @@ #define NO_FURTHER_WRITE_ACTION -1 -#ifndef phys_to_page -#define phys_to_page(x)pfn_to_page((x) >> PAGE_SHIFT) -#endif - /** * efi_free_all_buff_pages - free all previous allocated buffer pages * @cap_info: pointer to current instance of capsule_info structure @@ -35,7 +31,7 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info) { while (cap_info->index > 0) - __free_page(phys_to_page(cap_info->pages[--cap_info->index])); + __free_page(cap_info->pages[--cap_info->index]); cap_info->index = NO_FURTHER_WRITE_ACTION; } @@ -71,6 +67,14 @@ int __efi_capsule_setup_info(struct capsule_info *cap_info) cap_info->pages = temp_page; + temp_page = krealloc(cap_info->phys, +pages_needed * sizeof(phys_addr_t *), +GFP_KERNEL | __GFP_ZERO); + if (!temp_page) + return -ENOMEM; + + cap_info->phys = temp_page; + return 0; } @@ -105,9 +109,24 @@ int __weak efi_capsule_setup_info(struct capsule_info *cap_info, void *kbuff, **/ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info) { + bool do_vunmap = false;
[tip:efi/core] efi/libstub/arm: Add opt-in Kconfig option for the DTB loader
Commit-ID: 3d7ee348aa4127a7893c11261da9b76371a970e6 Gitweb: https://git.kernel.org/tip/3d7ee348aa4127a7893c11261da9b76371a970e6 Author: Ard Biesheuvel AuthorDate: Wed, 11 Jul 2018 11:40:38 +0200 Committer: Ingo Molnar CommitDate: Mon, 16 Jul 2018 00:43:12 +0200 efi/libstub/arm: Add opt-in Kconfig option for the DTB loader There are various ways a platform can provide a device tree binary to the kernel, with different levels of sophistication: - ideally, the UEFI firmware, which is tightly coupled with the platform, provides a device tree image directly as a UEFI configuration table, and typically permits the contents to be manipulated either via menu options or via UEFI environment variables that specify a replacement image, - GRUB for ARM has a 'devicetree' directive which allows a device tree image to be loaded from any location accessible to GRUB, and supersede the one provided by the firmware, - the EFI stub implements a dtb= command line option that allows a device tree image to be loaded from a file residing in the same file system as the one the kernel image was loaded from. The dtb= command line option was never intended to be more than a development feature, to allow the other options to be implemented in parallel. So let's make it an opt-in feature that is disabled by default, but can be re-enabled at will. Note that we already disable the dtb= command line option when we detect that we are running with UEFI Secure Boot enabled. Signed-off-by: Ard Biesheuvel Reviewed-by: Alexander Graf Acked-by: Leif Lindholm Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180711094040.12506-7-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/Kconfig| 12 drivers/firmware/efi/libstub/arm-stub.c | 7 --- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 781a4a337557..d8e159feb573 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -87,6 +87,18 @@ config EFI_RUNTIME_WRAPPERS config EFI_ARMSTUB bool +config EFI_ARMSTUB_DTB_LOADER + bool "Enable the DTB loader" + depends on EFI_ARMSTUB + help + Select this config option to add support for the dtb= command + line parameter, allowing a device tree blob to be loaded into + memory from the EFI System Partition by the stub. + + The device tree is typically provided by the platform or by + the bootloader, so this option is mostly for development + purposes only. + config EFI_BOOTLOADER_CONTROL tristate "EFI Bootloader Control" depends on EFI_VARS diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 01a9d78ee415..c98b1856fc3d 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -202,9 +202,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, * 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure * boot is enabled if we can't determine its state. */ - if (secure_boot != efi_secureboot_mode_disabled && - strstr(cmdline_ptr, "dtb=")) { - pr_efi(sys_table, "Ignoring DTB from command line.\n"); + if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) || +secure_boot != efi_secureboot_mode_disabled) { + if (strstr(cmdline_ptr, "dtb=")) + pr_efi(sys_table, "Ignoring DTB from command line.\n"); } else { status = handle_cmdline_files(sys_table, image, cmdline_ptr, "dtb=",
[tip:efi/core] efi: Drop type and attribute checks in efi_mem_desc_lookup()
Commit-ID: 7e1550b8f2081cccdfa9f1cf1e54cbc4d720af7f Gitweb: https://git.kernel.org/tip/7e1550b8f2081cccdfa9f1cf1e54cbc4d720af7f Author: Ard Biesheuvel AuthorDate: Wed, 11 Jul 2018 11:40:39 +0200 Committer: Ingo Molnar CommitDate: Mon, 16 Jul 2018 00:43:12 +0200 efi: Drop type and attribute checks in efi_mem_desc_lookup() The current implementation of efi_mem_desc_lookup() includes the following check on the memory descriptor it returns: if (!(md->attribute & EFI_MEMORY_RUNTIME) && md->type != EFI_BOOT_SERVICES_DATA && md->type != EFI_RUNTIME_SERVICES_DATA) { continue; } This means that only EfiBootServicesData or EfiRuntimeServicesData regions are considered, or any other region type provided that it has the EFI_MEMORY_RUNTIME attribute set. Given what the name of the function implies, and the fact that any physical address can be described in the UEFI memory map only a single time, it does not make sense to impose this condition in the body of the loop, but instead, should be imposed by the caller depending on the value that is returned to it. Two such callers exist at the moment: - The BGRT code when running on x86, via efi_mem_reserve() and efi_arch_mem_reserve(). In this case, the region is already known to be EfiBootServicesData, and so the check is redundant. - The ESRT handling code which introduced this function, which calls it both directly from efi_esrt_init() and again via efi_mem_reserve() and efi_arch_mem_reserve() [on x86]. So let's move this check into the callers instead. This preserves the current behavior both for BGRT and ESRT handling, and allows the lookup routine to be reused by other [upcoming] users that don't have this limitation. In the ESRT case, keep the entire condition, so that platforms that deviate from the UEFI spec and use something other than EfiBootServicesData for the ESRT table will keep working as before. For x86's efi_arch_mem_reserve() implementation, limit the type to EfiBootServicesData, since it is the only type the reservation code expects to operate on in the first place. While we're at it, drop the __init annotation so that drivers can use it as well. Tested-by: Laszlo Ersek Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180711094040.12506-8-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/quirks.c | 3 ++- drivers/firmware/efi/efi.c | 8 +--- drivers/firmware/efi/esrt.c| 5 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 6af39dc40325..844d31cb8a0c 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -248,7 +248,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) int num_entries; void *new; - if (efi_mem_desc_lookup(addr, )) { + if (efi_mem_desc_lookup(addr, ) || + md.type != EFI_BOOT_SERVICES_DATA) { pr_err("Failed to lookup EFI memory descriptor for %pa\n", ); return; } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1379a375dfa8..d8a33a781a57 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -402,7 +402,7 @@ subsys_initcall(efisubsys_init); * and if so, populate the supplied memory descriptor with the appropriate * data. */ -int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) +int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) { efi_memory_desc_t *md; @@ -420,12 +420,6 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) u64 size; u64 end; - if (!(md->attribute & EFI_MEMORY_RUNTIME) && - md->type != EFI_BOOT_SERVICES_DATA && - md->type != EFI_RUNTIME_SERVICES_DATA) { - continue; - } - size = md->num_pages << EFI_PAGE_SHIFT; end = md->phys_addr + size; if (phys_addr >= md->phys_addr && phys_addr < end) { diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 1ab80e06e7c5..375a77c1c6e5 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -250,7 +250,10 @@ void __init efi_esrt_init(void) return; rc = efi_mem_desc_lookup(efi.esrt, ); - if (rc < 0) { + if (rc < 0 || + (!(md.attribute & EFI_MEMORY_RUNTIME) && +md.type != EFI_BOOT_SERVICES_DATA && +md.type != EFI_RUNTIME_SERVICES_DATA)) { pr_warn("ESRT header is not in the memory map.\n"); return; }
[tip:efi/core] fbdev/efifb: Honour UEFI memory map attributes when mapping the FB
Commit-ID: 38ac0287b7f4f3922e25fd8f81db67f2c13d16bb Gitweb: https://git.kernel.org/tip/38ac0287b7f4f3922e25fd8f81db67f2c13d16bb Author: Ard Biesheuvel AuthorDate: Wed, 11 Jul 2018 11:40:40 +0200 Committer: Ingo Molnar CommitDate: Mon, 16 Jul 2018 00:43:12 +0200 fbdev/efifb: Honour UEFI memory map attributes when mapping the FB If the framebuffer address provided by the Graphics Output Protocol (GOP) is covered by the UEFI memory map, it will tell us which memory attributes are permitted when mapping this region. In some cases, (KVM guest on ARM), violating this will result in loss of coherency, which means that updates sent to the framebuffer by the guest will not be observeable by the host, and the emulated display simply does not work. So if the memory map contains such a description, take the attributes field into account, and add support for creating WT or WB mappings of the framebuffer region. Tested-by: Laszlo Ersek Signed-off-by: Ard Biesheuvel Acked-by: Bartlomiej Zolnierkiewicz Cc: Linus Torvalds Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180711094040.12506-9-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/video/fbdev/efifb.c | 51 - 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 46a4484e3da7..c6f78d27947b 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -20,7 +20,7 @@ #include /* For DRM_MODE_PANEL_ORIENTATION_* */ static bool request_mem_succeeded = false; -static bool nowc = false; +static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; static struct fb_var_screeninfo efifb_defined = { .activate = FB_ACTIVATE_NOW, @@ -68,8 +68,12 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, static void efifb_destroy(struct fb_info *info) { - if (info->screen_base) - iounmap(info->screen_base); + if (info->screen_base) { + if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) + iounmap(info->screen_base); + else + memunmap(info->screen_base); + } if (request_mem_succeeded) release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); @@ -104,7 +108,7 @@ static int efifb_setup(char *options) else if (!strncmp(this_opt, "width:", 6)) screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); else if (!strcmp(this_opt, "nowc")) - nowc = true; + mem_flags &= ~EFI_MEMORY_WC; } } @@ -164,6 +168,7 @@ static int efifb_probe(struct platform_device *dev) unsigned int size_remap; unsigned int size_total; char *option = NULL; + efi_memory_desc_t md; if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; @@ -272,12 +277,35 @@ static int efifb_probe(struct platform_device *dev) info->apertures->ranges[0].base = efifb_fix.smem_start; info->apertures->ranges[0].size = size_remap; - if (nowc) - info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); - else - info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); + if (!efi_mem_desc_lookup(efifb_fix.smem_start, )) { + if ((efifb_fix.smem_start + efifb_fix.smem_len) > + (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) { + pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n", + efifb_fix.smem_start); + err = -EIO; + goto err_release_fb; + } + /* +* If the UEFI memory map covers the efifb region, we may only +* remap it using the attributes the memory map prescribes. +*/ + mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB; + mem_flags &= md.attribute; + } + if (mem_flags & EFI_MEMORY_WC) + info->screen_base = ioremap_wc(efifb_fix.smem_start, + efifb_fix.smem_len); + else if (mem_flags & EFI_MEMORY_UC) + info->screen_base = ioremap(efifb_fix.smem_start, + efifb_fix.smem_len); + else if (mem_flags & EFI_MEMORY_WT) + info->screen_base = memremap(efifb_fix.smem_start, +efifb_fix.smem_len, MEMREMAP_WT); + else if (mem_flags & EFI_MEMORY_WB) + info->screen_base =
[tip:efi/core] efi/x86: Replace references to efi_early->is64 with efi_is_64bit()
Commit-ID: aab9593c0cb4454f9d261a8c87a3361f3186c4ec Gitweb: https://git.kernel.org/tip/aab9593c0cb4454f9d261a8c87a3361f3186c4ec Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:24 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:43 +0200 efi/x86: Replace references to efi_early->is64 with efi_is_64bit() There are a couple of places in the x86 EFI stub code where we select between 32-bit and 64-bit versions of the support routines based on the value of efi_early->is64. Referencing that field directly is a bad idea, since it prevents the compiler from inferring that this field can never be true on a 32-bit build, and can only become false on a 64-bit build if support for mixed mode is compiled in. This results in dead code to be retained in the uncompressed part of the kernel image, which is wasteful. So switch to the efi_is_64bit() helper, which will resolve to a constant boolean unless building for 64-bit with mixed mode support. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-8-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 16 ++-- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 915c64edbe8e..1458b1700fc7 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -404,7 +404,7 @@ struct boot_params *make_boot_params(struct efi_config *c) if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) return NULL; - if (efi_early->is64) + if (efi_is_64bit()) setup_boot_services64(efi_early); else setup_boot_services32(efi_early); @@ -639,7 +639,6 @@ struct exit_boot_struct { struct efi_info *efi; struct setup_data *e820ext; __u32 e820ext_size; - boolis64; }; static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, @@ -666,7 +665,8 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, first = false; } - signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE; + signature = efi_is_64bit() ? EFI64_LOADER_SIGNATURE + : EFI32_LOADER_SIGNATURE; memcpy(>efi->efi_loader_signature, signature, sizeof(__u32)); p->efi->efi_systab = (unsigned long)sys_table_arg; @@ -683,8 +683,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, return EFI_SUCCESS; } -static efi_status_t exit_boot(struct boot_params *boot_params, - void *handle, bool is64) +static efi_status_t exit_boot(struct boot_params *boot_params, void *handle) { unsigned long map_sz, key, desc_size, buff_size; efi_memory_desc_t *mem_map; @@ -705,7 +704,6 @@ static efi_status_t exit_boot(struct boot_params *boot_params, priv.efi= _params->efi_info; priv.e820ext= NULL; priv.e820ext_size = 0; - priv.is64 = is64; /* Might as well exit boot services now */ status = efi_exit_boot_services(sys_table, handle, , , @@ -740,13 +738,11 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) struct desc_struct *desc; void *handle; efi_system_table_t *_table; - bool is64; efi_early = c; _table = (efi_system_table_t *)(unsigned long)efi_early->table; handle = (void *)(unsigned long)efi_early->image_handle; - is64 = efi_early->is64; sys_table = _table; @@ -754,7 +750,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) goto fail; - if (is64) + if (efi_is_64bit()) setup_boot_services64(efi_early); else setup_boot_services32(efi_early); @@ -810,7 +806,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) hdr->code32_start = bzimage_addr; } - status = exit_boot(boot_params, handle, is64); + status = exit_boot(boot_params, handle); if (status != EFI_SUCCESS) { efi_printk(sys_table, "exit_boot() failed!\n"); goto fail;
[tip:efi/core] efi/x86: Merge the setup_efi_pci32() and setup_efi_pci64() routines
Commit-ID: 75c5a713ab4b774c7d990ec748dddba714034436 Gitweb: https://git.kernel.org/tip/75c5a713ab4b774c7d990ec748dddba714034436 Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:19 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:42 +0200 efi/x86: Merge the setup_efi_pci32() and setup_efi_pci64() routines After merging the 32-bit and 64-bit versions of the code that invokes the PCI I/O protocol methods to preserve PCI ROM images in commit: 2c3625cb9fa2 ("efi/x86: Fold __setup_efi_pci32() and __setup_efi_pci64() ...") there are still separate code paths for 32-bit and 64-bit, where the only difference is the size of a EFI_HANDLE. So let's parameterize a single implementation for that difference only, and get rid of the two copies of the code. While at it, rename __setup_efi_pci() to preserve_pci_rom_image() to better reflect its purpose. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-3-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 123 ++- 1 file changed, 32 insertions(+), 91 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 9f6813493945..c72550783c16 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -111,7 +111,7 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) } static efi_status_t -__setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) +preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) { struct pci_setup_rom *rom = NULL; efi_status_t status; @@ -181,92 +181,6 @@ free_struct: return status; } -static void -setup_efi_pci32(struct boot_params *params, void **pci_handle, unsigned long size) -{ - efi_pci_io_protocol_t *pci = NULL; - efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; - u32 *handles = (u32 *)(unsigned long)pci_handle; - efi_status_t status; - unsigned long nr_pci; - struct setup_data *data; - int i; - - data = (struct setup_data *)(unsigned long)params->hdr.setup_data; - - while (data && data->next) - data = (struct setup_data *)(unsigned long)data->next; - - nr_pci = size / sizeof(u32); - for (i = 0; i < nr_pci; i++) { - struct pci_setup_rom *rom = NULL; - u32 h = handles[i]; - - status = efi_call_early(handle_protocol, h, - _proto, (void **)); - - if (status != EFI_SUCCESS) - continue; - - if (!pci) - continue; - - status = __setup_efi_pci(pci, ); - if (status != EFI_SUCCESS) - continue; - - if (data) - data->next = (unsigned long)rom; - else - params->hdr.setup_data = (unsigned long)rom; - - data = (struct setup_data *)rom; - } -} - -static void -setup_efi_pci64(struct boot_params *params, void **pci_handle, unsigned long size) -{ - efi_pci_io_protocol_t *pci = NULL; - efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; - u64 *handles = (u64 *)(unsigned long)pci_handle; - efi_status_t status; - unsigned long nr_pci; - struct setup_data *data; - int i; - - data = (struct setup_data *)(unsigned long)params->hdr.setup_data; - - while (data && data->next) - data = (struct setup_data *)(unsigned long)data->next; - - nr_pci = size / sizeof(u64); - for (i = 0; i < nr_pci; i++) { - struct pci_setup_rom *rom = NULL; - u64 h = handles[i]; - - status = efi_call_early(handle_protocol, h, - _proto, (void **)); - - if (status != EFI_SUCCESS) - continue; - - if (!pci) - continue; - - status = __setup_efi_pci(pci, ); - if (status != EFI_SUCCESS) - continue; - - if (data) - data->next = (unsigned long)rom; - else - params->hdr.setup_data = (unsigned long)rom; - - data = (struct setup_data *)rom; - } -} - /* * There's no way to return an informative status from this function, * because any analysis (and printing of error messages) needs to be @@ -282,6 +196,9 @@ static void setup_efi_pci(struct boot_params *params) void **pci_handle = NULL; efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; unsigned long size = 0; + unsigned long nr_pci; +
[tip:efi/core] efi/x86: Prevent reentrant firmware calls in mixed mode
Commit-ID: 83a0a2ea0b991927e42984be220329e776ce7137 Gitweb: https://git.kernel.org/tip/83a0a2ea0b991927e42984be220329e776ce7137 Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:18 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:42 +0200 efi/x86: Prevent reentrant firmware calls in mixed mode The UEFI spec does not permit runtime services to be called reentrantly, and so it is up to the OS to provide proper locking around such calls. For the native case, this was fixed a long time ago, but for the mixed mode case, no locking is done whatsoever. Note that the calls are made with preemption and interrupts disabled, so only SMP configurations are affected by this issue. So add a spinlock and grab it when invoking a UEFI runtime service in mixed mode. We will also need to provide non-blocking versions of SetVariable() and QueryVariableInfo(), so add those as well. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/platform/efi/efi_64.c | 101 +++-- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 77873ce700ae..448267f1c073 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -636,6 +636,8 @@ void efi_switch_mm(struct mm_struct *mm) #ifdef CONFIG_EFI_MIXED extern efi_status_t efi64_thunk(u32, ...); +static DEFINE_SPINLOCK(efi_runtime_lock); + #define runtime_service32(func) \ ({ \ u32 table = (u32)(unsigned long)efi.systab; \ @@ -657,17 +659,14 @@ extern efi_status_t efi64_thunk(u32, ...); #define efi_thunk(f, ...) \ ({ \ efi_status_t __s; \ - unsigned long __flags; \ u32 __func; \ \ - local_irq_save(__flags);\ arch_efi_call_virt_setup(); \ \ __func = runtime_service32(f); \ __s = efi64_thunk(__func, __VA_ARGS__); \ \ arch_efi_call_virt_teardown(); \ - local_irq_restore(__flags); \ \ __s;\ }) @@ -702,14 +701,17 @@ static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc) { efi_status_t status; u32 phys_tm, phys_tc; + unsigned long flags; spin_lock(_lock); + spin_lock_irqsave(_runtime_lock, flags); phys_tm = virt_to_phys_or_null(tm); phys_tc = virt_to_phys_or_null(tc); status = efi_thunk(get_time, phys_tm, phys_tc); + spin_unlock_irqrestore(_runtime_lock, flags); spin_unlock(_lock); return status; @@ -719,13 +721,16 @@ static efi_status_t efi_thunk_set_time(efi_time_t *tm) { efi_status_t status; u32 phys_tm; + unsigned long flags; spin_lock(_lock); + spin_lock_irqsave(_runtime_lock, flags); phys_tm = virt_to_phys_or_null(tm); status = efi_thunk(set_time, phys_tm); + spin_unlock_irqrestore(_runtime_lock, flags); spin_unlock(_lock); return status; @@ -737,8 +742,10 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, { efi_status_t status; u32 phys_enabled, phys_pending, phys_tm; + unsigned long flags; spin_lock(_lock); + spin_lock_irqsave(_runtime_lock, flags); phys_enabled = virt_to_phys_or_null(enabled); phys_pending = virt_to_phys_or_null(pending); @@ -747,6 +754,7 @@ efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, status = efi_thunk(get_wakeup_time, phys_enabled, phys_pending, phys_tm); + spin_unlock_irqrestore(_runtime_lock, flags); spin_unlock(_lock); return status; @@ -757,13 +765,16 @@ efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) { efi_status_t status; u32 phys_tm; +
[tip:efi/core] efi/x86: Merge 32-bit and 64-bit UGA draw protocol setup routines
Commit-ID: 290084c2fa13e9aaa7f856ed1ab30760327dd9f8 Gitweb: https://git.kernel.org/tip/290084c2fa13e9aaa7f856ed1ab30760327dd9f8 Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:21 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:43 +0200 efi/x86: Merge 32-bit and 64-bit UGA draw protocol setup routines The two versions of setup_uga##() are mostly identical, with the exception of the size of EFI_HANDLE. So let's merge the two, and pull the implementation into the calling function setup_uga(). Note that the 32-bit version was only mixed-mode safe by accident: it only calls the get_mode() method of the UGA draw protocol, which happens to be the first member, and so truncating the 64-bit void* at offset 0 to 32 bits happens to produce the correct value. But let's not rely on that, and use the proper API instead. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-5-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 111 +-- 1 file changed, 26 insertions(+), 85 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 011d5c289449..ac8e442db71f 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -318,81 +318,54 @@ static void setup_quirks(struct boot_params *boot_params) } } +/* + * See if we have Universal Graphics Adapter (UGA) protocol + */ static efi_status_t -setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) +setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size) { + efi_status_t status; + u32 width, height; + void **uga_handle = NULL; efi_uga_draw_protocol_t *uga = NULL, *first_uga; - efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; unsigned long nr_ugas; - u32 *handles = (u32 *)uga_handle; - efi_status_t status = EFI_INVALID_PARAMETER; int i; - first_uga = NULL; - nr_ugas = size / sizeof(u32); - for (i = 0; i < nr_ugas; i++) { - efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; - u32 w, h, depth, refresh; - void *pciio; - u32 handle = handles[i]; - - status = efi_call_early(handle_protocol, handle, - _proto, (void **)); - if (status != EFI_SUCCESS) - continue; - - efi_call_early(handle_protocol, handle, _proto, ); - - status = efi_early->call((unsigned long)uga->get_mode, uga, -, , , ); - if (status == EFI_SUCCESS && (!first_uga || pciio)) { - *width = w; - *height = h; - - /* -* Once we've found a UGA supporting PCIIO, -* don't bother looking any further. -*/ - if (pciio) - break; - - first_uga = uga; - } - } + status = efi_call_early(allocate_pool, EFI_LOADER_DATA, + size, (void **)_handle); + if (status != EFI_SUCCESS) + return status; - return status; -} + status = efi_call_early(locate_handle, + EFI_LOCATE_BY_PROTOCOL, + uga_proto, NULL, , uga_handle); + if (status != EFI_SUCCESS) + goto free_handle; -static efi_status_t -setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height) -{ - efi_uga_draw_protocol_t *uga = NULL, *first_uga; - efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; - unsigned long nr_ugas; - u64 *handles = (u64 *)uga_handle; - efi_status_t status = EFI_INVALID_PARAMETER; - int i; + height = 0; + width = 0; first_uga = NULL; - nr_ugas = size / sizeof(u64); + nr_ugas = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32)); for (i = 0; i < nr_ugas; i++) { efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; u32 w, h, depth, refresh; void *pciio; - u64 handle = handles[i]; + unsigned long handle = efi_is_64bit() ? ((u64 *)uga_handle)[i] + : ((u32 *)uga_handle)[i]; status = efi_call_early(handle_protocol, handle, - _proto, (void **)); + uga_proto, (void **)); if (status != EFI_SUCCESS) continue;
[tip:efi/core] efi/x86: Add missing NULL initialization in UGA draw protocol discovery
Commit-ID: 093174f52553532b9eb0e63cbbb254f6990d46d5 Gitweb: https://git.kernel.org/tip/093174f52553532b9eb0e63cbbb254f6990d46d5 Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:22 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:43 +0200 efi/x86: Add missing NULL initialization in UGA draw protocol discovery The UGA draw protocol discovery routine looks for a EFI handle that has both the UGA draw protocol and the PCI I/O protocol installed. It checks for the latter by calling handle_protocol() and pass it a PCI I/O protocol pointer variable by reference, but fails to initialize it to NULL, which means the non-NULL check later on in the code could produce false positives, given that the return code of the handle_protocol() call is ignored entirely. So add the missing initialization. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-6-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index ac8e442db71f..92b573fd239c 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -359,6 +359,7 @@ setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size) if (status != EFI_SUCCESS) continue; + pciio = NULL; efi_call_early(handle_protocol, handle, _proto, ); status = efi_call_proto(efi_uga_draw_protocol, get_mode, uga,
[tip:efi/core] efi/x86: Align efi_uga_draw_protocol typedef names to convention
Commit-ID: 0b767b16d7b634dd62667f224425cef3c78e031c Gitweb: https://git.kernel.org/tip/0b767b16d7b634dd62667f224425cef3c78e031c Author: Ard Biesheuvel AuthorDate: Fri, 20 Jul 2018 10:47:20 +0900 Committer: Ingo Molnar CommitDate: Sun, 22 Jul 2018 14:13:42 +0200 efi/x86: Align efi_uga_draw_protocol typedef names to convention The linux-efi subsystem uses typedefs with the _t suffix to declare data structures that originate in the UEFI spec. Our type mangling for mixed mode depends on this convention, so rename the UGA drawing protocols to allow efi_call_proto() to be used with them in a subsequent patch. Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Linus Torvalds Cc: Lukas Wunner Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180720014726.24031-4-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 4 ++-- arch/x86/boot/compressed/eboot.h | 12 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index c72550783c16..011d5c289449 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -321,7 +321,7 @@ static void setup_quirks(struct boot_params *boot_params) static efi_status_t setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) { - struct efi_uga_draw_protocol *uga = NULL, *first_uga; + efi_uga_draw_protocol_t *uga = NULL, *first_uga; efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; unsigned long nr_ugas; u32 *handles = (u32 *)uga_handle; @@ -366,7 +366,7 @@ setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) static efi_status_t setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height) { - struct efi_uga_draw_protocol *uga = NULL, *first_uga; + efi_uga_draw_protocol_t *uga = NULL, *first_uga; efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; unsigned long nr_ugas; u64 *handles = (u64 *)uga_handle; diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h index e799dc5c6448..8297387c4676 100644 --- a/arch/x86/boot/compressed/eboot.h +++ b/arch/x86/boot/compressed/eboot.h @@ -12,22 +12,22 @@ #define DESC_TYPE_CODE_DATA(1 << 0) -struct efi_uga_draw_protocol_32 { +typedef struct { u32 get_mode; u32 set_mode; u32 blt; -}; +} efi_uga_draw_protocol_32_t; -struct efi_uga_draw_protocol_64 { +typedef struct { u64 get_mode; u64 set_mode; u64 blt; -}; +} efi_uga_draw_protocol_64_t; -struct efi_uga_draw_protocol { +typedef struct { void *get_mode; void *set_mode; void *blt; -}; +} efi_uga_draw_protocol_t; #endif /* BOOT_COMPRESSED_EBOOT_H */
[tip:efi/urgent] efi/x86: Fix mixed mode reboot loop by removing pointless call to PciIo->Attributes()
Commit-ID: e296701800f30d260a66f8aa1971b5b1bc3d2f81 Gitweb: https://git.kernel.org/tip/e296701800f30d260a66f8aa1971b5b1bc3d2f81 Author: Ard Biesheuvel AuthorDate: Wed, 11 Jul 2018 11:02:35 +0200 Committer: Ingo Molnar CommitDate: Wed, 11 Jul 2018 13:15:21 +0200 efi/x86: Fix mixed mode reboot loop by removing pointless call to PciIo->Attributes() Hans de Goede reported that his mixed EFI mode Bay Trail tablet would not boot at all any more, but enter a reboot loop without any logs printed by the kernel. Unbreak 64-bit Linux/x86 on 32-bit UEFI: When it was first introduced, the EFI stub code that copies the contents of PCI option ROMs originally only intended to do so if the EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM attribute was *not* set. The reason was that the UEFI spec permits PCI option ROM images to be provided by the platform directly, rather than via the ROM BAR, and in this case, the OS can only access them at runtime if they are preserved at boot time by copying them from the areas described by PciIo->RomImage and PciIo->RomSize. However, it implemented this check erroneously, as can be seen in commit: dd5fc854de5fd ("EFI: Stash ROMs if they're not in the PCI BAR") which introduced: if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) continue; and given that the numeric value of EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM is 0x4000, this condition never becomes true, and so the option ROMs were copied unconditionally. This was spotted and 'fixed' by commit: 886d751a2ea99a160 ("x86, efi: correct precedence of operators in setup_efi_pci") but inadvertently inverted the logic at the same time, defeating the purpose of the code, since it now only preserves option ROM images that can be read from the ROM BAR as well. Unsurprisingly, this broke some systems, and so the check was removed entirely in the following commit: 739701888f5d ("x86, efi: remove attribute check from setup_efi_pci") It is debatable whether this check should have been included in the first place, since the option ROM image provided to the UEFI driver by the firmware may be different from the one that is actually present in the card's flash ROM, and so whatever PciIo->RomImage points at should be preferred regardless of whether the attribute is set. As this was the only use of the attributes field, we can remove the call to PciIo->Attributes() entirely, which is especially nice because its prototype involves uint64_t type by-value arguments which the EFI mixed mode has trouble dealing with. Any mixed mode system with PCI is likely to be affected. Tested-by: Wilfried Klaebe Tested-by: Hans de Goede Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180711090235.9327-2-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 12 +++- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index e57665b4ba1c..e98522ea6f09 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -114,18 +114,12 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) struct pci_setup_rom *rom = NULL; efi_status_t status; unsigned long size; - uint64_t attributes, romsize; + uint64_t romsize; void *romimage; - status = efi_call_proto(efi_pci_io_protocol, attributes, pci, - EfiPciIoAttributeOperationGet, 0ULL, - ); - if (status != EFI_SUCCESS) - return status; - /* -* Some firmware images contain EFI function pointers at the place where the -* romimage and romsize fields are supposed to be. Typically the EFI +* Some firmware images contain EFI function pointers at the place where +* the romimage and romsize fields are supposed to be. Typically the EFI * code is mapped at high addresses, translating to an unrealistically * large romsize. The UEFI spec limits the size of option ROMs to 16 * MiB so we reject any ROMs over 16 MiB in size to catch this.
[tip:efi/core] efi/esrt: Fix handling of early ESRT table mapping
Commit-ID: 136d5d57e35cc6985c57d23d0c823133e3508bed Gitweb: https://git.kernel.org/tip/136d5d57e35cc6985c57d23d0c823133e3508bed Author: Ard BiesheuvelAuthorDate: Mon, 12 Mar 2018 08:44:59 + Committer: Ingo Molnar CommitDate: Mon, 12 Mar 2018 10:05:01 +0100 efi/esrt: Fix handling of early ESRT table mapping As reported by Tyler, efi_esrt_init() will return without releasing the ESRT table header mapping if it encounters a table with an unexpected version. Replacing the 'return' with 'goto err_memunmap' would fix this particular occurrence, but, as it turns out, the code is rather peculiar to begin with: - it never uses the header mapping after memcpy()'ing out its contents, - it maps and unmaps the entire table without ever looking at the contents. So let's refactor this code to unmap the table header right after the memcpy() so we can get rid of the error handling path altogether, and drop the second mapping entirely. Reported-by: Tyler Baicar Signed-off-by: Ard Biesheuvel Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Jones Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180312084500.10764-5-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- drivers/firmware/efi/esrt.c | 17 - 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index c47e0c6ec00f..1ab80e06e7c5 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -279,6 +279,7 @@ void __init efi_esrt_init(void) } memcpy(, va, sizeof(tmpesrt)); + early_memunmap(va, size); if (tmpesrt.fw_resource_version == 1) { entry_size = sizeof (*v1_entries); @@ -291,7 +292,7 @@ void __init efi_esrt_init(void) if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) { pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n", max - size, entry_size); - goto err_memunmap; + return; } /* @@ -304,7 +305,7 @@ void __init efi_esrt_init(void) if (tmpesrt.fw_resource_count > 128) { pr_err("ESRT says fw_resource_count has very large value %d.\n", tmpesrt.fw_resource_count); - goto err_memunmap; + return; } /* @@ -315,18 +316,10 @@ void __init efi_esrt_init(void) if (max < size + entries_size) { pr_err("ESRT does not fit on single memory map entry (size: %zu max: %zu)\n", size, max); - goto err_memunmap; + return; } - /* remap it with our (plausible) new pages */ - early_memunmap(va, size); size += entries_size; - va = early_memremap(efi.esrt, size); - if (!va) { - pr_err("early_memremap(%p, %zu) failed.\n", (void *)efi.esrt, - size); - return; - } esrt_data = (phys_addr_t)efi.esrt; esrt_data_size = size; @@ -336,8 +329,6 @@ void __init efi_esrt_init(void) efi_mem_reserve(esrt_data, esrt_data_size); pr_debug("esrt-init: loaded.\n"); -err_memunmap: - early_memunmap(va, size); } static int __init register_entries(void)
[tip:efi/core] efi: Use string literals for efi_char16_t variable initializers
Commit-ID: 36b649760e94968e0495b73284aaf07eed0a328f Gitweb: https://git.kernel.org/tip/36b649760e94968e0495b73284aaf07eed0a328f Author: Ard BiesheuvelAuthorDate: Mon, 12 Mar 2018 08:45:00 + Committer: Ingo Molnar CommitDate: Mon, 12 Mar 2018 10:05:02 +0100 efi: Use string literals for efi_char16_t variable initializers Now that we unambiguously build the entire kernel with -fshort-wchar, it is no longer necessary to open code efi_char16_t[] initializers as arrays of characters, and we can move to the L"xxx" notation instead. Signed-off-by: Ard Biesheuvel Cc: Arnd Bergmann Cc: Linus Torvalds Cc: Lukas Wunner Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-...@vger.kernel.org Link: http://lkml.kernel.org/r/20180312084500.10764-6-ard.biesheu...@linaro.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/eboot.c | 3 ++- arch/x86/platform/efi/quirks.c| 8 +--- drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/secureboot.c | 12 +++- drivers/firmware/efi/libstub/tpm.c| 7 ++- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index f2251c1c9853..47d3efff6805 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -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) { - static 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); diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 1ef11c26f79b..36c1f8b9f7e0 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -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; @@ -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, _DUMMY_GUID, + efi.set_variable((efi_char16_t *)efi_dummy_name, +_DUMMY_GUID, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, @@ -182,7 +183,8 @@ efi_status_t efi_query_variable_store(u32 attributes, unsigned long size, if (!dummy) return EFI_OUT_OF_RESOURCES; - status = efi.set_variable(efi_dummy_name, _DUMMY_GUID, + status = efi.set_variable((efi_char16_t *)efi_dummy_name, + _DUMMY_GUID, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 7b3ba40f0745..a34e9290a699 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -9,7 +9,7 @@ cflags-$(CONFIG_X86_32) := -march=i386 cflags-$(CONFIG_X86_64):= -mcmodel=small cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -fPIC -fno-strict-aliasing -mno-red-zone \ - -mno-mmx -mno-sse + -mno-mmx -mno-sse -fshort-wchar cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 959777ec8a77..8f07eb414c00 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -16,18 +16,12 @@ /* BIOS variables */ static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID; -static const efi_char16_t efi_SecureBoot_name[] = { - 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 -}; -static const efi_char16_t efi_SetupMode_name[] = { - 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 -}; +static const efi_char16_t efi_SecureBoot_name[] = L"SecureBoot"; +static const efi_char16_t efi_SetupMode_name[] = L"SetupMode"; /* SHIM variables */ static