History

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.

Ard Biesheuvel committed 6 years ago

Commit f958efe1 parent 1786e836 files · +49 −44Browse files

Unified · Split

6 files
  1. arch/arm/include/asm/efi.h +1 −1
  2. arch/arm64/include/asm/efi.h +1 −1
  3. arch/x86/boot/compressed/eboot.c +1 −2
  4. arch/x86/include/asm/efi.h +28 −7
  5. drivers/firmware/efi/libstub/efi-stub-helper.c +15 −30
  6. include/linux/efi.h +3 −3
arch/arm/include/asm/efi.h+1−1
@@ -52,7 +52,7 @@ void efi_virtmap_unload(void); · 51 unmodified lines
5252
5353 #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
5454 #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
55−#define efi_is_64bit() (false)
55+#define efi_is_native() (true)
5656
5757 #define efi_table_attr(table, attr, instance) \
5858 ((table##_t *)instance)->attr
arch/arm64/include/asm/efi.h+1−1
@@ -95,7 +95,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, · 94 unmodified lines
9595
9696 #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
9797 #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
98−#define efi_is_64bit() (true)
98+#define efi_is_native() (true)
9999
100100 #define efi_table_attr(table, attr, instance) \
101101 ((table##_t *)instance)->attr
arch/x86/boot/compressed/eboot.c+1−2
@@ -63,8 +63,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) · 62 unmodified lines
6363 * large romsize. The UEFI spec limits the size of option ROMs to 16
6464 * MiB so we reject any ROMs over 16 MiB in size to catch this.
6565 */
66− romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol,
67− romimage, pci);
66+ romimage = efi_table_attr(efi_pci_io_protocol, romimage, pci);
6867 romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);
6968 if (!romimage || !romsize || romsize > SZ_16M)
7069 return EFI_INVALID_PARAMETER;
arch/x86/include/asm/efi.h+28−7
@@ -222,21 +222,42 @@ static inline bool efi_is_64bit(void) · 221 unmodified lines
222222 return __efi_early()->is64;
223223 }
224224
225−#define efi_table_attr(table, attr, instance) \
226− (efi_is_64bit() ? \
227− ((table##_64_t *)(unsigned long)instance)->attr : \
228− ((table##_32_t *)(unsigned long)instance)->attr)
225+static inline bool efi_is_native(void)
226+{
227+ if (!IS_ENABLED(CONFIG_X86_64))
228+ return true;
229+ return efi_is_64bit();
230+}
231+
232+#define efi_mixed_mode_cast(attr) \
233+ __builtin_choose_expr( \
234+ __builtin_types_compatible_p(u32, __typeof__(attr)), \
235+ (unsigned long)(attr), (attr))
236+
237+#define efi_table_attr(table, attr, instance) ({ \
238+ __typeof__(((table##_t *)0)->attr) __ret; \
239+ if (efi_is_native()) { \
240+ __ret = ((table##_t *)(unsigned long)instance)->attr; \
241+ } else { \
242+ __ret = (__typeof__(__ret))efi_mixed_mode_cast( \
243+ ((table##_t *)(unsigned long)instance)->mixed_mode.attr);\
244+ } \
245+ __ret; \
246+})
229247
230248 #define efi_call_proto(protocol, f, instance, ...) \
231− __efi_early()->call(efi_table_attr(protocol, f, instance), \
249+ __efi_early()->call((unsigned long) \
250+ efi_table_attr(protocol, f, instance), \
232251 instance, ##__VA_ARGS__)
233252
234253 #define efi_call_early(f, ...) \
235− __efi_early()->call(efi_table_attr(efi_boot_services, f, \
254+ __efi_early()->call((unsigned long) \
255+ efi_table_attr(efi_boot_services, f, \
236256 __efi_early()->boot_services), __VA_ARGS__)
237257
238258 #define efi_call_runtime(f, ...) \
239− __efi_early()->call(efi_table_attr(efi_runtime_services, f, \
259+ __efi_early()->call((unsigned long) \
260+ efi_table_attr(efi_runtime_services, f, \
240261 __efi_early()->runtime_services), __VA_ARGS__)
241262
242263 extern bool efi_reboot_required(void);
drivers/firmware/efi/libstub/efi-stub-helper.c+15−30
@@ -431,9 +431,7 @@ static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, · 430 unmodified lines
431431 efi_file_handle_t *fh;
432432 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
433433 efi_status_t status;
434− void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image,
435− device_handle,
436− image);
434+ void *handle = efi_table_attr(efi_loaded_image, device_handle, image);
437435
438436 status = efi_call_early(handle_protocol, handle,
439437 &fs_proto, (void **)&io);
@@ -942,33 +940,20 @@ fail: · 502 unmodified lines
942940 return status;
943941 }
944942
945−#define GET_EFI_CONFIG_TABLE(bits) \
946−static void *get_efi_config_table##bits(efi_system_table_t *_sys_table, \
947− efi_guid_t guid) \
948−{ \
949− efi_system_table_##bits##_t *sys_table; \
950− efi_config_table_##bits##_t *tables; \
951− int i; \
952− \
953− sys_table = (typeof(sys_table))_sys_table; \
954− tables = (typeof(tables))(unsigned long)sys_table->tables; \
955− \
956− for (i = 0; i < sys_table->nr_tables; i++) { \
957− if (efi_guidcmp(tables[i].guid, guid) != 0) \
958− continue; \
959− \
960− return (void *)(unsigned long)tables[i].table; \
961− } \
962− \
963− return NULL; \
964−}
965−GET_EFI_CONFIG_TABLE(32)
966−GET_EFI_CONFIG_TABLE(64)
967−
968943 void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
969944 {
970− if (efi_is_64bit())
971− return get_efi_config_table64(sys_table, guid);
972− else
973− return get_efi_config_table32(sys_table, guid);
945+ unsigned long tables = efi_table_attr(efi_system_table, tables, sys_table);
946+ int nr_tables = efi_table_attr(efi_system_table, nr_tables, sys_table);
947+ int i;
948+
949+ for (i = 0; i < nr_tables; i++) {
950+ efi_config_table_t *t = (void *)tables;
951+
952+ if (efi_guidcmp(t->guid, guid) == 0)
953+ return efi_table_attr(efi_config_table, table, t);
954+
955+ tables += efi_is_native() ? sizeof(efi_config_table_t)
956+ : sizeof(efi_config_table_32_t);
957+ }
958+ return NULL;
974959 }
include/linux/efi.h+3−3
@@ -49,11 +49,11 @@ typedef u64 efi_physical_addr_t; · 48 unmodified lines
4949 typedef void *efi_handle_t;
5050
5151 #define efi_get_handle_at(array, idx) \
52− (efi_is_64bit() ? (efi_handle_t)(unsigned long)((u64 *)(array))[idx] \
52+ (efi_is_native() ? (array)[idx] \
5353 : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
5454
5555 #define efi_get_handle_num(size) \
56− ((size) / (efi_is_64bit() ? sizeof(u64) : sizeof(u32)))
56+ ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
5757
5858 #define for_each_efi_handle(handle, array, size, i) \
5959 for (i = 0; \
@@ -805,7 +805,7 @@ typedef struct { · 745 unmodified lines
805805 typedef union {
806806 struct {
807807 efi_guid_t guid;
808− unsigned long table;
808+ void *table;
809809 };
810810 efi_config_table_32_t mixed_mode;
811811 } efi_config_table_t;