efi: libstub: Permit mixed mode return types other than efi_status_t

Rework the EFI stub macro wrappers around protocol method calls and
other indirect calls in order to allow return types other than
efi_status_t. This means the widening should be conditional on whether
or not the return type is efi_status_t, and should be omitted otherwise.

Also, switch to _Generic() to implement the type based compile time
conditionals, which is more concise, and distinguishes between
efi_status_t and u64 properly.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2022-09-26 21:14:23 +02:00
parent 7091298554
commit a61962d8e7
3 changed files with 41 additions and 44 deletions

View File

@ -93,12 +93,6 @@ SYM_FUNC_START(__efi64_thunk)
movl %ebx, %fs
movl %ebx, %gs
/*
* Convert 32-bit status code into 64-bit.
*/
roll $1, %eax
rorq $1, %rax
pop %rbx
pop %rbp
RET

View File

@ -178,7 +178,7 @@ struct efi_setup_data {
extern u64 efi_setup;
#ifdef CONFIG_EFI
extern efi_status_t __efi64_thunk(u32, ...);
extern u64 __efi64_thunk(u32, ...);
#define efi64_thunk(...) ({ \
u64 __pad[3]; /* must have space for 3 args on the stack */ \
@ -228,16 +228,15 @@ static inline bool efi_is_native(void)
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(inst, attr) \
(efi_is_native() \
? inst->attr \
: (__typeof__(inst->attr)) \
efi_mixed_mode_cast(inst->mixed_mode.attr))
(efi_is_native() ? (inst)->attr \
: efi_mixed_table_attr((inst), attr))
#define efi_mixed_table_attr(inst, attr) \
(__typeof__(inst->attr)) \
_Generic(inst->mixed_mode.attr, \
u32: (unsigned long)(inst->mixed_mode.attr), \
default: (inst->mixed_mode.attr))
/*
* The following macros allow translating arguments if necessary from native to
@ -344,31 +343,27 @@ static inline u32 efi64_convert_status(efi_status_t status)
#define __efi_eat(...)
#define __efi_eval(...) __VA_ARGS__
/* The three macros below handle dispatching via the thunk if needed */
static inline efi_status_t __efi64_widen_efi_status(u64 status)
{
/* use rotate to move the value of bit #31 into position #63 */
return ror64(rol32(status, 1), 1);
}
#define efi_call_proto(inst, func, ...) \
(efi_is_native() \
? inst->func(inst, ##__VA_ARGS__) \
: __efi64_thunk_map(inst, func, inst, ##__VA_ARGS__))
/* The macro below handles dispatching via the thunk if needed */
#define efi_bs_call(func, ...) \
(efi_is_native() \
? efi_system_table->boottime->func(__VA_ARGS__) \
: __efi64_thunk_map(efi_table_attr(efi_system_table, \
boottime), \
func, __VA_ARGS__))
#define efi_fn_call(inst, func, ...) \
(efi_is_native() ? (inst)->func(__VA_ARGS__) \
: efi_mixed_call((inst), func, ##__VA_ARGS__))
#define efi_rt_call(func, ...) \
(efi_is_native() \
? efi_system_table->runtime->func(__VA_ARGS__) \
: __efi64_thunk_map(efi_table_attr(efi_system_table, \
runtime), \
func, __VA_ARGS__))
#define efi_dxe_call(func, ...) \
(efi_is_native() \
? efi_dxe_table->func(__VA_ARGS__) \
: __efi64_thunk_map(efi_dxe_table, func, __VA_ARGS__))
#define efi_mixed_call(inst, func, ...) \
_Generic(inst->func(__VA_ARGS__), \
efi_status_t: \
__efi64_widen_efi_status( \
__efi64_thunk_map(inst, func, ##__VA_ARGS__)), \
u64: ({ BUILD_BUG(); ULONG_MAX; }), \
default: \
(__typeof__(inst->func(__VA_ARGS__))) \
__efi64_thunk_map(inst, func, ##__VA_ARGS__))
#else /* CONFIG_EFI_MIXED */

View File

@ -44,15 +44,23 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
#ifndef ARCH_HAS_EFISTUB_WRAPPERS
#define efi_is_native() (true)
#define efi_bs_call(func, ...) efi_system_table->boottime->func(__VA_ARGS__)
#define efi_rt_call(func, ...) efi_system_table->runtime->func(__VA_ARGS__)
#define efi_dxe_call(func, ...) efi_dxe_table->func(__VA_ARGS__)
#define efi_table_attr(inst, attr) (inst->attr)
#define efi_call_proto(inst, func, ...) inst->func(inst, ##__VA_ARGS__)
#define efi_is_native() (true)
#define efi_table_attr(inst, attr) (inst)->attr
#define efi_fn_call(inst, func, ...) (inst)->func(__VA_ARGS__)
#endif
#define efi_call_proto(inst, func, ...) ({ \
__typeof__(inst) __inst = (inst); \
efi_fn_call(__inst, func, __inst, ##__VA_ARGS__); \
})
#define efi_bs_call(func, ...) \
efi_fn_call(efi_table_attr(efi_system_table, boottime), func, ##__VA_ARGS__)
#define efi_rt_call(func, ...) \
efi_fn_call(efi_table_attr(efi_system_table, runtime), func, ##__VA_ARGS__)
#define efi_dxe_call(func, ...) \
efi_fn_call(efi_dxe_table, func, ##__VA_ARGS__)
#define efi_info(fmt, ...) \
efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
#define efi_warn(fmt, ...) \