efi: libstub: Permit mixed mode return types other than efi_status_t
authorArd Biesheuvel <ardb@kernel.org>
Mon, 26 Sep 2022 19:14:23 +0000 (21:14 +0200)
committerArd Biesheuvel <ardb@kernel.org>
Fri, 18 Nov 2022 08:14:08 +0000 (09:14 +0100)
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>
arch/x86/boot/compressed/efi_thunk_64.S
arch/x86/include/asm/efi.h
drivers/firmware/efi/libstub/efistub.h

index 67e7edc..0c988f2 100644 (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
index 233ae69..f76f15f 100644 (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 */
-
-#define efi_call_proto(inst, func, ...)                                        \
-       (efi_is_native()                                                \
-               ? inst->func(inst, ##__VA_ARGS__)                       \
-               : __efi64_thunk_map(inst, func, inst, ##__VA_ARGS__))
-
-#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_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__))
+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);
+}
+
+/* The macro below handles dispatching via the thunk if needed */
+
+#define efi_fn_call(inst, func, ...)                                   \
+       (efi_is_native() ? (inst)->func(__VA_ARGS__)                    \
+                        : efi_mixed_call((inst), 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 */
 
index 1fde9cb..8bb11fb 100644 (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, ...) \