aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2019-12-24 16:10:09 +0100
committerIngo Molnar <mingo@kernel.org>2019-12-25 10:49:17 +0100
commitf958efe97596837f9504fc38d75ef8e284bc0ebd (patch)
tree40b5cc3b945654f16c17248eadc724eee0194cf4 /arch/x86
parentefi/libstub: Extend native protocol definitions with mixed_mode aliases (diff)
downloadlinux-dev-f958efe97596837f9504fc38d75ef8e284bc0ebd.tar.xz
linux-dev-f958efe97596837f9504fc38d75ef8e284bc0ebd.zip
efi/libstub: Distinguish between native/mixed not 32/64 bit
Currently, we support mixed mode by casting all boot time firmware calls to 64-bit explicitly on native 64-bit systems, and to 32-bit on 32-bit systems or 64-bit systems running with 32-bit firmware. Due to this explicit awareness of the bitness in the code, we do a lot of casting even on generic code that is shared with other architectures, where mixed mode does not even exist. This casting leads to loss of coverage of type checking by the compiler, which we should try to avoid. So instead of distinguishing between 32-bit vs 64-bit, distinguish between native vs mixed, and limit all the nasty casting and pointer mangling to the code that actually deals with mixed mode. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Cc: Arvind Sankar <nivedita@alum.mit.edu> Cc: Borislav Petkov <bp@alien8.de> Cc: James Morse <james.morse@arm.com> Cc: Matt Fleming <matt@codeblueprint.co.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191224151025.32482-10-ardb@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/boot/compressed/eboot.c3
-rw-r--r--arch/x86/include/asm/efi.h35
2 files changed, 29 insertions, 9 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 959bcdd8c1fe..990b93379965 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -63,8 +63,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
* 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.
*/
- romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol,
- romimage, pci);
+ romimage = efi_table_attr(efi_pci_io_protocol, romimage, pci);
romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);
if (!romimage || !romsize || romsize > SZ_16M)
return EFI_INVALID_PARAMETER;
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 6094e7f49a99..c27323cb49e5 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -222,21 +222,42 @@ static inline bool efi_is_64bit(void)
return __efi_early()->is64;
}
-#define efi_table_attr(table, attr, instance) \
- (efi_is_64bit() ? \
- ((table##_64_t *)(unsigned long)instance)->attr : \
- ((table##_32_t *)(unsigned long)instance)->attr)
+static inline bool efi_is_native(void)
+{
+ if (!IS_ENABLED(CONFIG_X86_64))
+ return true;
+ return efi_is_64bit();
+}
+
+#define efi_mixed_mode_cast(attr) \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(u32, __typeof__(attr)), \
+ (unsigned long)(attr), (attr))
+
+#define efi_table_attr(table, attr, instance) ({ \
+ __typeof__(((table##_t *)0)->attr) __ret; \
+ if (efi_is_native()) { \
+ __ret = ((table##_t *)(unsigned long)instance)->attr; \
+ } else { \
+ __ret = (__typeof__(__ret))efi_mixed_mode_cast( \
+ ((table##_t *)(unsigned long)instance)->mixed_mode.attr);\
+ } \
+ __ret; \
+})
#define efi_call_proto(protocol, f, instance, ...) \
- __efi_early()->call(efi_table_attr(protocol, f, instance), \
+ __efi_early()->call((unsigned long) \
+ efi_table_attr(protocol, f, instance), \
instance, ##__VA_ARGS__)
#define efi_call_early(f, ...) \
- __efi_early()->call(efi_table_attr(efi_boot_services, f, \
+ __efi_early()->call((unsigned long) \
+ efi_table_attr(efi_boot_services, f, \
__efi_early()->boot_services), __VA_ARGS__)
#define efi_call_runtime(f, ...) \
- __efi_early()->call(efi_table_attr(efi_runtime_services, f, \
+ __efi_early()->call((unsigned long) \
+ efi_table_attr(efi_runtime_services, f, \
__efi_early()->runtime_services), __VA_ARGS__)
extern bool efi_reboot_required(void);