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>
This commit is contained in:
Ard Biesheuvel 2019-12-24 16:10:09 +01:00 committed by Ingo Molnar
parent 1786e83011
commit f958efe975
6 changed files with 49 additions and 44 deletions

View file

@ -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);