* [PATCH 0/7] efi: more fixes and general cleanups for v5.6
@ 2019-12-28 15:21 Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 1/7] efi/libstub: fix boot argument handling in mixed mode entry code Ard Biesheuvel
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
In addition to two other series that are in flight, regarding the EFI
runtime call assembly wrappers [0], and the use of restricted memory
permissions for mapping EFI runtime service memory regions [1], here's
another batch of fixes and cleanups for the early EFI code.
Patches #1 .. #3 are fixes for the code that is currently queued in
tip/efi/core.
Patch #4 fixes an ancient issue in the EFI boot code where it doesn't
map the memory containing the EFI vendor name string correctly.
Patch #5 redefines the macro __efiapi to __attribute__((regparm(0)))
on 32-bit x86 so we no longer have to cast every function pointer
that requires that annotation.
Patch #6 refactors efi_runtime_init() so we no longer have two mostly
identical copies of the same code for 32-bit and 64-bit.
Patch #7 cleans up efi_systab_init() and also gets rid of the 'efi_phys'
data structure that exists for no good reason.
Branch can be found here:
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-more-cleanup-for-v5.6
[0] https://lore.kernel.org/linux-efi/20191226151407.29716-1-ardb@kernel.org/
[1] https://lore.kernel.org/linux-efi/20191227163418.16139-1-ardb@kernel.org/
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Hans de Goede <hdegoede@redhat.com>
Ard Biesheuvel (7):
efi/libstub: fix boot argument handling in mixed mode entry code
efi/libstub: use correct system table pointer in mixed mode efi_free()
efi/x86: re-disable RT services for 32-bit kernels running on 64-bit
EFI
efi/x86: map the entire EFI vendor string before copying it
efi/x86: avoid redundant cast of EFI firmware service pointer
efi/x86: merge two near identical versions of efi_runtime_init()
efi/x86: clean up efi_systab_init() routine for legibility
arch/x86/boot/compressed/eboot.c | 3 +-
arch/x86/boot/compressed/head_64.S | 17 +-
arch/x86/include/asm/efi.h | 25 +-
arch/x86/platform/efi/efi.c | 262 +++++++++-----------
arch/x86/platform/efi/efi_64.c | 5 +
include/linux/efi.h | 23 +-
6 files changed, 135 insertions(+), 200 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/7] efi/libstub: fix boot argument handling in mixed mode entry code
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 2/7] efi/libstub: use correct system table pointer in mixed mode efi_free() Ard Biesheuvel
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
The mixed mode refactor actually broke mixed mode by failing to
pass the bootparam structure to startup_32(). This went unnoticed
because it apparently has a high tolerance for being passed random
junk, and still boots fine in some cases. So let's fix this by
populating %esi as required when entering via efi32_stub_entry,
and while at it, preserve the arguments themselves instead of their
address in memory (via the stack pointer) since that memory could
be clobbered before we get to it.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/compressed/head_64.S | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index a6f3ee9ca61d..44a6bb6964b5 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -208,13 +208,12 @@ SYM_FUNC_START(startup_32)
pushl $__KERNEL_CS
leal startup_64(%ebp), %eax
#ifdef CONFIG_EFI_MIXED
- movl efi32_boot_args(%ebp), %ebx
- cmp $0, %ebx
+ movl efi32_boot_args(%ebp), %edi
+ cmp $0, %edi
jz 1f
leal handover_entry(%ebp), %eax
- movl 0(%ebx), %edi
- movl 4(%ebx), %esi
- movl 8(%ebx), %edx
+ movl %esi, %edx
+ movl efi32_boot_args+4(%ebp), %esi
movl $0x0, %ecx
1:
#endif
@@ -232,12 +231,16 @@ SYM_FUNC_END(startup_32)
.org 0x190
SYM_FUNC_START(efi32_stub_entry)
add $0x4, %esp /* Discard return address */
+ popl %ecx
+ popl %edx
+ popl %esi
call 1f
1: pop %ebp
subl $1b, %ebp
- movl %esp, efi32_boot_args(%ebp)
+ movl %ecx, efi32_boot_args(%ebp)
+ movl %edx, efi32_boot_args+4(%ebp)
sgdtl efi32_boot_gdt(%ebp)
/* Disable paging */
@@ -628,7 +631,7 @@ SYM_DATA_START_LOCAL(gdt)
SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
#ifdef CONFIG_EFI_MIXED
-SYM_DATA_LOCAL(efi32_boot_args, .long 0)
+SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0)
#endif
/*
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/7] efi/libstub: use correct system table pointer in mixed mode efi_free()
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 1/7] efi/libstub: fix boot argument handling in mixed mode entry code Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 3/7] efi/x86: re-disable RT services for 32-bit kernels running on 64-bit EFI Ard Biesheuvel
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
There is a special implementation for mixed mode of the efi_free()
function, to work around the incompatibility of the mixed mode
plumbing with the prototype of the EFI FreePages boot service,
which takes a 64-bit physical address as its first argument.
Calling FreePages in mixed mode involves passing the mixed mode
address of the FreePages code from the mixed mode version of the
EFI system table, and the current code dereferences the ordinary
system table instead, producing the wrong results. So fix this by
using the efi_table_attr() macro.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/compressed/eboot.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index da04948d75ed..98477f3529f6 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -901,7 +901,8 @@ void efi_free(unsigned long size, unsigned long addr)
if (efi_is_native())
efi_free_native(size, addr);
else
- efi64_thunk(efi_system_table()->boottime->mixed_mode.free_pages,
+ efi64_thunk(efi_table_attr(efi_system_table(),
+ boottime)->mixed_mode.free_pages,
addr, 0, DIV_ROUND_UP(size, EFI_PAGE_SIZE));
}
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/7] efi/x86: re-disable RT services for 32-bit kernels running on 64-bit EFI
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 1/7] efi/libstub: fix boot argument handling in mixed mode entry code Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 2/7] efi/libstub: use correct system table pointer in mixed mode efi_free() Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 4/7] efi/x86: map the entire EFI vendor string before copying it Ard Biesheuvel
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
Commit a8147dba75b1 ("efi/x86: Rename efi_is_native() to efi_is_mixed()")
renamed and refactored efi_is_native() into efi_is_mixed(), but failed
to take into account that these are not diametrical opposites.
Mixed mode is a construct that permits 64-bit kernels to boot on 32-bit
firmware, but there is another non-native combination which is supported,
i.e., 32-bit kernels booting on 64-bit firmware, but only for boot and not
for runtime services.
Due to this oversight, efi_runtime_supported() now incorrectly returns
true for such configurations, resulting in crashes at boot. So fix this
by making efi_runtime_supported() aware of this.
As a side effect, some efi_thunk_xxx() stubs have become obsolete, so
remove them as well.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/include/asm/efi.h | 17 +++--------------
1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 2d1378f19b74..9f4281aae779 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -163,6 +163,9 @@ static inline bool efi_is_mixed(void)
static inline bool efi_runtime_supported(void)
{
+ if (IS_ENABLED(CONFIG_X86_32))
+ return !efi_enabled(EFI_64BIT);
+
if (!efi_is_mixed())
return true;
@@ -176,7 +179,6 @@ 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(
void *phys_set_virtual_address_map,
@@ -184,19 +186,6 @@ extern efi_status_t efi_thunk_set_virtual_address_map(
unsigned long descriptor_size,
u32 descriptor_version,
efi_memory_desc_t *virtual_map);
-#else
-static inline void efi_thunk_runtime_setup(void) {}
-static inline efi_status_t efi_thunk_set_virtual_address_map(
- void *phys_set_virtual_address_map,
- unsigned long memory_map_size,
- unsigned long descriptor_size,
- u32 descriptor_version,
- efi_memory_desc_t *virtual_map)
-{
- return EFI_SUCCESS;
-}
-#endif /* CONFIG_EFI_MIXED */
-
/* arch specific definitions used by the stub code */
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/7] efi/x86: map the entire EFI vendor string before copying it
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
` (2 preceding siblings ...)
2019-12-28 15:21 ` [PATCH 3/7] efi/x86: re-disable RT services for 32-bit kernels running on 64-bit EFI Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 5/7] efi/x86: avoid redundant cast of EFI firmware service pointer Ard Biesheuvel
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
Fix a couple of issues with the way we map and copy the vendor string:
- we map only 2 bytes, which usually works since you get at least a
page, but if the vendor string happens to cross a page boundary,
a crash will result
- only call early_memunmap() if early_memremap() succeeded, or we will
call it with a NULL address which it doesn't like,
- while at it, switch to early_memremap_ro(), and array indexing rather
than pointer dereferencing to read the CHAR16 characters.
Fixes: 5b83683f32b1 ("x86: EFI runtime service support")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/platform/efi/efi.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d96953d9d4e7..3ce32c31bb61 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -541,7 +541,6 @@ void __init efi_init(void)
efi_char16_t *c16;
char vendor[100] = "unknown";
int i = 0;
- void *tmp;
#ifdef CONFIG_X86_32
if (boot_params.efi_info.efi_systab_hi ||
@@ -566,14 +565,16 @@ void __init efi_init(void)
/*
* Show what we know for posterity
*/
- c16 = tmp = early_memremap(efi.systab->fw_vendor, 2);
+ c16 = early_memremap_ro(efi.systab->fw_vendor,
+ sizeof(vendor) * sizeof(efi_char16_t));
if (c16) {
- for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
- vendor[i] = *c16++;
+ for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+ vendor[i] = c16[i];
vendor[i] = '\0';
- } else
+ early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
+ } else {
pr_err("Could not map the firmware vendor!\n");
- early_memunmap(tmp, 2);
+ }
pr_info("EFI v%u.%.02u by %s\n",
efi.systab->hdr.revision >> 16,
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/7] efi/x86: avoid redundant cast of EFI firmware service pointer
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
` (3 preceding siblings ...)
2019-12-28 15:21 ` [PATCH 4/7] efi/x86: map the entire EFI vendor string before copying it Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 6/7] efi/x86: merge two near identical versions of efi_runtime_init() Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 7/7] efi/x86: clean up efi_systab_init() routine for legibility Ard Biesheuvel
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
All EFI firmware call prototypes have been annotated as __efiapi,
permitting us to attach attributes regarding the calling convention
by overriding __efiapi to an architecture specific value.
On 32-bit x86, EFI firmware calls use the plain calling convention
where all arguments are passed via the stack, and cleaned up by the
caller. Let's add this to the __efiapi definition so we no longer
need to cast the function pointers before invoking them.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/include/asm/efi.h | 8 +-------
include/linux/efi.h | 4 +++-
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 9f4281aae779..9d25fc2ddc50 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -51,13 +51,7 @@ extern asmlinkage unsigned long efi_call_phys(void *, ...);
})
-/*
- * Wrap all the virtual calls in a way that forces the parameters on the stack.
- */
-#define arch_efi_call_virt(p, f, args...) \
-({ \
- ((efi_##f##_t __attribute__((regparm(0)))*) p->f)(args); \
-})
+#define arch_efi_call_virt(p, f, args...) p->f(args)
#define efi_ioremap(addr, size, type, attr) ioremap_cache(addr, size)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 726673e98990..952c1659dfd9 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -48,8 +48,10 @@ typedef u16 efi_char16_t; /* UNICODE character */
typedef u64 efi_physical_addr_t;
typedef void *efi_handle_t;
-#ifdef CONFIG_X86_64
+#if defined(CONFIG_X86_64)
#define __efiapi __attribute__((ms_abi))
+#elif defined(CONFIG_X86_32)
+#define __efiapi __attribute__((regparm(0)))
#else
#define __efiapi
#endif
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/7] efi/x86: merge two near identical versions of efi_runtime_init()
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
` (4 preceding siblings ...)
2019-12-28 15:21 ` [PATCH 5/7] efi/x86: avoid redundant cast of EFI firmware service pointer Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 7/7] efi/x86: clean up efi_systab_init() routine for legibility Ard Biesheuvel
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
The routines efi_runtime_init32() and efi_runtime_init64() are
almost indistinguishable, and the only relevant difference is
the offset in the runtime struct from where to obtain the address
of the SetVirtualAddressMap() routine. Let's collapse them into
one, and get rid of some unnecessary casts by switching to a
native vs mixed distinction instead, reusing the helper from the
EFI stub.
While at it, move the variable where we keep the physical address
of the SetVirtualAddressMap() EFI runtime service out of struct efi,
where it doesn't belong given that we only call it once (if ever)
during early boot.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/platform/efi/efi.c | 83 ++++++--------------
arch/x86/platform/efi/efi_64.c | 5 ++
include/linux/efi.h | 19 -----
3 files changed, 27 insertions(+), 80 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 3ce32c31bb61..aa6d9438fa89 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -56,6 +56,7 @@
static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata;
+static efi_set_virtual_address_map_t __efiapi *set_virtual_address_map __initdata;
static efi_config_table_type_t arch_tables[] __initdata = {
#ifdef CONFIG_X86_UV
@@ -113,7 +114,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
/* Disable interrupts around EFI calls: */
local_irq_save(flags);
- status = efi_call_phys(efi_phys.set_virtual_address_map,
+ status = efi_call_phys(set_virtual_address_map,
memory_map_size, descriptor_size,
descriptor_version, virtual_map);
local_irq_restore(flags);
@@ -455,57 +456,9 @@ static int __init efi_systab_init(void *phys)
return 0;
}
-static int __init efi_runtime_init32(void)
-{
- efi_runtime_services_32_t *runtime;
-
- runtime = early_memremap((unsigned long)efi.systab->runtime,
- sizeof(efi_runtime_services_32_t));
- if (!runtime) {
- pr_err("Could not map the runtime service table!\n");
- return -ENOMEM;
- }
-
- /*
- * We will only need *early* access to the SetVirtualAddressMap
- * EFI runtime service. All other runtime services will be called
- * via the virtual mapping.
- */
- efi_phys.set_virtual_address_map =
- (efi_set_virtual_address_map_t *)
- (unsigned long)runtime->set_virtual_address_map;
- early_memunmap(runtime, sizeof(efi_runtime_services_32_t));
-
- return 0;
-}
-
-static int __init efi_runtime_init64(void)
-{
- efi_runtime_services_64_t *runtime;
-
- runtime = early_memremap((unsigned long)efi.systab->runtime,
- sizeof(efi_runtime_services_64_t));
- if (!runtime) {
- pr_err("Could not map the runtime service table!\n");
- return -ENOMEM;
- }
-
- /*
- * We will only need *early* access to the SetVirtualAddressMap
- * EFI runtime service. All other runtime services will be called
- * via the virtual mapping.
- */
- efi_phys.set_virtual_address_map =
- (efi_set_virtual_address_map_t *)
- (unsigned long)runtime->set_virtual_address_map;
- early_memunmap(runtime, sizeof(efi_runtime_services_64_t));
-
- return 0;
-}
-
static int __init efi_runtime_init(void)
{
- int rv;
+ efi_runtime_services_t *runtime;
/*
* Check out the runtime services table. We need to map
@@ -522,13 +475,25 @@ static int __init efi_runtime_init(void)
*/
if (!efi_enabled(EFI_PARAVIRT)) {
- if (efi_enabled(EFI_64BIT))
- rv = efi_runtime_init64();
- else
- rv = efi_runtime_init32();
+ int size = !efi_is_mixed() ? sizeof(efi_runtime_services_t)
+ : sizeof(efi_runtime_services_32_t);
+
+ runtime = early_memremap_ro((unsigned long)efi.systab->runtime,
+ size);
+ if (!runtime) {
+ pr_err("Could not map the runtime service table!\n");
+ return -ENOMEM;
+ }
- if (rv)
- return rv;
+ /*
+ * We will only need *early* access to the SetVirtualAddressMap
+ * EFI runtime service. All other runtime services will be
+ * called via the virtual mapping.
+ */
+ set_virtual_address_map = efi_table_attr(runtime,
+ set_virtual_address_map);
+
+ early_memunmap(runtime, size);
}
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
@@ -960,8 +925,6 @@ static void __init kexec_enter_virtual_mode(void)
efi_native_runtime_setup();
- efi.set_virtual_address_map = NULL;
-
if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
runtime_code_page_mkexec();
#endif
@@ -1049,7 +1012,7 @@ static void __init __efi_enter_virtual_mode(void)
(efi_memory_desc_t *)pa);
} else {
status = efi_thunk_set_virtual_address_map(
- efi_phys.set_virtual_address_map,
+ set_virtual_address_map,
efi.memmap.desc_size * count,
efi.memmap.desc_size,
efi.memmap.desc_version,
@@ -1077,8 +1040,6 @@ static void __init __efi_enter_virtual_mode(void)
else
efi_thunk_runtime_setup();
- efi.set_virtual_address_map = NULL;
-
/*
* Apply more restrictive page table mapping attributes now that
* SVAM() has been called and the firmware has performed all
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 03c2ed3c645c..8c4f90eb909e 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -57,6 +57,11 @@ static u64 efi_va = EFI_VA_START;
struct efi_scratch efi_scratch;
+__pure bool efi_is_64bit(void)
+{
+ return efi_enabled(EFI_64BIT);
+}
+
static void __init early_code_mapping_set_exec(int executable)
{
efi_memory_desc_t *md;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 952c1659dfd9..ee68ea6f85ff 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -539,24 +539,6 @@ typedef struct {
u32 query_variable_info;
} efi_runtime_services_32_t;
-typedef struct {
- efi_table_hdr_t hdr;
- u64 get_time;
- u64 set_time;
- u64 get_wakeup_time;
- u64 set_wakeup_time;
- u64 set_virtual_address_map;
- u64 convert_pointer;
- u64 get_variable;
- u64 get_next_variable;
- u64 set_variable;
- u64 get_next_high_mono_count;
- u64 reset_system;
- u64 update_capsule;
- u64 query_capsule_caps;
- u64 query_variable_info;
-} efi_runtime_services_64_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,
@@ -946,7 +928,6 @@ extern struct efi {
efi_query_capsule_caps_t *query_capsule_caps;
efi_get_next_high_mono_count_t *get_next_high_mono_count;
efi_reset_system_t *reset_system;
- efi_set_virtual_address_map_t *set_virtual_address_map;
struct efi_memory_map memmap;
unsigned long flags;
} efi;
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 7/7] efi/x86: clean up efi_systab_init() routine for legibility
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
` (5 preceding siblings ...)
2019-12-28 15:21 ` [PATCH 6/7] efi/x86: merge two near identical versions of efi_runtime_init() Ard Biesheuvel
@ 2019-12-28 15:21 ` Ard Biesheuvel
6 siblings, 0 replies; 8+ messages in thread
From: Ard Biesheuvel @ 2019-12-28 15:21 UTC (permalink / raw)
To: linux-efi; +Cc: Ard Biesheuvel, Ingo Molnar, Arvind Sankar, Hans de Goede
Clean up the efi_systab_init() routine which maps the EFI system
table and copies the relevant pieces of data out of it.
The current routine is very difficult to read, so let's clean that
up. Also, switch to a R/O mapping of the system table since that is
all we need.
Finally, use a plain u64 variable to record the physical address of
the system table instead of pointlessly stashing it in a struct efi
that is never used for anything else.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/platform/efi/efi.c | 166 ++++++++++----------
1 file changed, 82 insertions(+), 84 deletions(-)
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index aa6d9438fa89..b905f867b811 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -54,7 +54,7 @@
#include <asm/x86_init.h>
#include <asm/uv/uv.h>
-static struct efi efi_phys __initdata;
+static u64 efi_systab_phys __initdata;
static efi_system_table_t efi_systab __initdata;
static efi_set_virtual_address_map_t __efiapi *set_virtual_address_map __initdata;
@@ -354,89 +354,90 @@ void __init efi_print_memmap(void)
}
}
-static int __init efi_systab_init(void *phys)
+static int __init efi_systab_init(u64 phys)
{
+ int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
+ : sizeof(efi_system_table_32_t);
+ bool over4g = false;
+ void *p;
+
+ p = early_memremap_ro(phys, size);
+ if (p == NULL) {
+ pr_err("Couldn't map the system table!\n");
+ return -ENOMEM;
+ }
+
if (efi_enabled(EFI_64BIT)) {
- efi_system_table_64_t *systab64;
- struct efi_setup_data *data = NULL;
- u64 tmp = 0;
+ const efi_system_table_64_t *systab64 = p;
+
+ efi_systab.hdr = systab64->hdr;
+ efi_systab.fw_vendor = systab64->fw_vendor;
+ efi_systab.fw_revision = systab64->fw_revision;
+ efi_systab.con_in_handle = systab64->con_in_handle;
+ efi_systab.con_in = systab64->con_in;
+ efi_systab.con_out_handle = systab64->con_out_handle;
+ efi_systab.con_out = (void *)(unsigned long)systab64->con_out;
+ efi_systab.stderr_handle = systab64->stderr_handle;
+ efi_systab.stderr = systab64->stderr;
+ efi_systab.runtime = (void *)(unsigned long)systab64->runtime;
+ efi_systab.boottime = (void *)(unsigned long)systab64->boottime;
+ efi_systab.nr_tables = systab64->nr_tables;
+ efi_systab.tables = systab64->tables;
+
+ over4g = systab64->con_in_handle > U32_MAX ||
+ systab64->con_in > U32_MAX ||
+ systab64->con_out_handle > U32_MAX ||
+ systab64->con_out > U32_MAX ||
+ systab64->stderr_handle > U32_MAX ||
+ systab64->stderr > U32_MAX ||
+ systab64->boottime > U32_MAX;
if (efi_setup) {
- data = early_memremap(efi_setup, sizeof(*data));
- if (!data)
+ struct efi_setup_data *data;
+
+ data = early_memremap_ro(efi_setup, sizeof(*data));
+ if (!data) {
+ early_memunmap(p, size);
return -ENOMEM;
- }
- systab64 = early_memremap((unsigned long)phys,
- sizeof(*systab64));
- if (systab64 == NULL) {
- pr_err("Couldn't map the system table!\n");
- if (data)
- early_memunmap(data, sizeof(*data));
- return -ENOMEM;
- }
+ }
+
+ efi_systab.fw_vendor = (unsigned long)data->fw_vendor;
+ efi_systab.runtime = (void *)(unsigned long)data->runtime;
+ efi_systab.tables = (unsigned long)data->tables;
+
+ over4g |= data->fw_vendor > U32_MAX ||
+ data->runtime > U32_MAX ||
+ data->tables > U32_MAX;
- efi_systab.hdr = systab64->hdr;
- efi_systab.fw_vendor = data ? (unsigned long)data->fw_vendor :
- systab64->fw_vendor;
- tmp |= data ? data->fw_vendor : systab64->fw_vendor;
- efi_systab.fw_revision = systab64->fw_revision;
- efi_systab.con_in_handle = systab64->con_in_handle;
- tmp |= systab64->con_in_handle;
- efi_systab.con_in = systab64->con_in;
- tmp |= systab64->con_in;
- efi_systab.con_out_handle = systab64->con_out_handle;
- tmp |= systab64->con_out_handle;
- efi_systab.con_out = (void *)(unsigned long)systab64->con_out;
- tmp |= systab64->con_out;
- efi_systab.stderr_handle = systab64->stderr_handle;
- tmp |= systab64->stderr_handle;
- efi_systab.stderr = systab64->stderr;
- tmp |= systab64->stderr;
- efi_systab.runtime = data ?
- (void *)(unsigned long)data->runtime :
- (void *)(unsigned long)systab64->runtime;
- tmp |= data ? data->runtime : systab64->runtime;
- efi_systab.boottime = (void *)(unsigned long)systab64->boottime;
- tmp |= systab64->boottime;
- efi_systab.nr_tables = systab64->nr_tables;
- efi_systab.tables = data ? (unsigned long)data->tables :
- systab64->tables;
- tmp |= data ? data->tables : systab64->tables;
-
- early_memunmap(systab64, sizeof(*systab64));
- if (data)
early_memunmap(data, sizeof(*data));
-#ifdef CONFIG_X86_32
- if (tmp >> 32) {
- pr_err("EFI data located above 4GB, disabling EFI.\n");
- return -EINVAL;
+ } else {
+ over4g |= systab64->fw_vendor > U32_MAX ||
+ systab64->runtime > U32_MAX ||
+ systab64->tables > U32_MAX;
}
-#endif
} else {
- efi_system_table_32_t *systab32;
+ const efi_system_table_32_t *systab32 = p;
+
+ efi_systab.hdr = systab32->hdr;
+ efi_systab.fw_vendor = systab32->fw_vendor;
+ efi_systab.fw_revision = systab32->fw_revision;
+ efi_systab.con_in_handle = systab32->con_in_handle;
+ efi_systab.con_in = systab32->con_in;
+ efi_systab.con_out_handle = systab32->con_out_handle;
+ efi_systab.con_out = (void *)(unsigned long)systab32->con_out;
+ efi_systab.stderr_handle = systab32->stderr_handle;
+ efi_systab.stderr = systab32->stderr;
+ efi_systab.runtime = (void *)(unsigned long)systab32->runtime;
+ efi_systab.boottime = (void *)(unsigned long)systab32->boottime;
+ efi_systab.nr_tables = systab32->nr_tables;
+ efi_systab.tables = systab32->tables;
+ }
- systab32 = early_memremap((unsigned long)phys,
- sizeof(*systab32));
- if (systab32 == NULL) {
- pr_err("Couldn't map the system table!\n");
- return -ENOMEM;
- }
+ early_memunmap(p, size);
- efi_systab.hdr = systab32->hdr;
- efi_systab.fw_vendor = systab32->fw_vendor;
- efi_systab.fw_revision = systab32->fw_revision;
- efi_systab.con_in_handle = systab32->con_in_handle;
- efi_systab.con_in = systab32->con_in;
- efi_systab.con_out_handle = systab32->con_out_handle;
- efi_systab.con_out = (void *)(unsigned long)systab32->con_out;
- efi_systab.stderr_handle = systab32->stderr_handle;
- efi_systab.stderr = systab32->stderr;
- efi_systab.runtime = (void *)(unsigned long)systab32->runtime;
- efi_systab.boottime = (void *)(unsigned long)systab32->boottime;
- efi_systab.nr_tables = systab32->nr_tables;
- efi_systab.tables = systab32->tables;
-
- early_memunmap(systab32, sizeof(*systab32));
+ if (IS_ENABLED(CONFIG_X86_32) && over4g) {
+ pr_err("EFI data located above 4GB, disabling EFI.\n");
+ return -EINVAL;
}
efi.systab = &efi_systab;
@@ -507,20 +508,17 @@ void __init efi_init(void)
char vendor[100] = "unknown";
int i = 0;
-#ifdef CONFIG_X86_32
- if (boot_params.efi_info.efi_systab_hi ||
- boot_params.efi_info.efi_memmap_hi) {
+ if (IS_ENABLED(CONFIG_X86_32) &&
+ (boot_params.efi_info.efi_systab_hi ||
+ boot_params.efi_info.efi_memmap_hi)) {
pr_info("Table located above 4GB, disabling EFI.\n");
return;
}
- efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
-#else
- efi_phys.systab = (efi_system_table_t *)
- (boot_params.efi_info.efi_systab |
- ((__u64)boot_params.efi_info.efi_systab_hi<<32));
-#endif
- if (efi_systab_init(efi_phys.systab))
+ efi_systab_phys = boot_params.efi_info.efi_systab |
+ ((__u64)boot_params.efi_info.efi_systab_hi << 32);
+
+ if (efi_systab_init(efi_systab_phys))
return;
efi.config_table = (unsigned long)efi.systab->tables;
@@ -673,7 +671,7 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md)
size = md->num_pages << EFI_PAGE_SHIFT;
end = md->phys_addr + size;
- systab = (u64)(unsigned long)efi_phys.systab;
+ systab = efi_systab_phys;
if (md->phys_addr <= systab && systab < end) {
systab += md->virt_addr - md->phys_addr;
efi.systab = (efi_system_table_t *)(unsigned long)systab;
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2019-12-28 15:22 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-12-28 15:21 [PATCH 0/7] efi: more fixes and general cleanups for v5.6 Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 1/7] efi/libstub: fix boot argument handling in mixed mode entry code Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 2/7] efi/libstub: use correct system table pointer in mixed mode efi_free() Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 3/7] efi/x86: re-disable RT services for 32-bit kernels running on 64-bit EFI Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 4/7] efi/x86: map the entire EFI vendor string before copying it Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 5/7] efi/x86: avoid redundant cast of EFI firmware service pointer Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 6/7] efi/x86: merge two near identical versions of efi_runtime_init() Ard Biesheuvel
2019-12-28 15:21 ` [PATCH 7/7] efi/x86: clean up efi_systab_init() routine for legibility Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).