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
52 52
53#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)53#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
54#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)54#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
55#define efi_is_64bit() (false)55#define efi_is_native() (true)
56 56
57#define efi_table_attr(table, attr, instance) \57#define efi_table_attr(table, attr, instance) \
58 ((table##_t *)instance)->attr58 ((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
95 95
96#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)96#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
97#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)97#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
98#define efi_is_64bit() (true)98#define efi_is_native() (true)
99 99
100#define efi_table_attr(table, attr, instance) \100#define efi_table_attr(table, attr, instance) \
101 ((table##_t *)instance)->attr101 ((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
63 * large romsize. The UEFI spec limits the size of option ROMs to 1663 * large romsize. The UEFI spec limits the size of option ROMs to 16
64 * MiB so we reject any ROMs over 16 MiB in size to catch this.64 * MiB so we reject any ROMs over 16 MiB in size to catch this.
65 */65 */
66 romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol,66 romimage = efi_table_attr(efi_pci_io_protocol, romimage, pci);
67 romimage, pci);
68 romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);67 romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);
69 if (!romimage || !romsize || romsize > SZ_16M)68 if (!romimage || !romsize || romsize > SZ_16M)
70 return EFI_INVALID_PARAMETER;69 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
222 return __efi_early()->is64;222 return __efi_early()->is64;
223}223}
224 224
225#define efi_table_attr(table, attr, instance) \225static inline bool efi_is_native(void)
226 (efi_is_64bit() ? \226{
227 ((table##_64_t *)(unsigned long)instance)->attr : \227 if (!IS_ENABLED(CONFIG_X86_64))
228 ((table##_32_t *)(unsigned long)instance)->attr)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})
229 247
230#define efi_call_proto(protocol, f, instance, ...) \248#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), \
232 instance, ##__VA_ARGS__)251 instance, ##__VA_ARGS__)
233 252
234#define efi_call_early(f, ...) \253#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, \
236 __efi_early()->boot_services), __VA_ARGS__)256 __efi_early()->boot_services), __VA_ARGS__)
237 257
238#define efi_call_runtime(f, ...) \258#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, \
240 __efi_early()->runtime_services), __VA_ARGS__)261 __efi_early()->runtime_services), __VA_ARGS__)
241 262
242extern bool efi_reboot_required(void);263extern 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
431 efi_file_handle_t *fh;431 efi_file_handle_t *fh;
432 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;432 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
433 efi_status_t status;433 efi_status_t status;
434 void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image,434 void *handle = efi_table_attr(efi_loaded_image, device_handle, image);
435 device_handle,
436 image);
437 435
438 status = efi_call_early(handle_protocol, handle,436 status = efi_call_early(handle_protocol, handle,
439 &fs_proto, (void **)&io);437 &fs_proto, (void **)&io);
@@ -942,33 +940,20 @@ fail: · 502 unmodified lines
942 return status;940 return status;
943}941}
944 942
945#define GET_EFI_CONFIG_TABLE(bits) \
946static 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}
965GET_EFI_CONFIG_TABLE(32)
966GET_EFI_CONFIG_TABLE(64)
967
968void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)943void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
969{944{
970 if (efi_is_64bit())945 unsigned long tables = efi_table_attr(efi_system_table, tables, sys_table);
971 return get_efi_config_table64(sys_table, guid);946 int nr_tables = efi_table_attr(efi_system_table, nr_tables, sys_table);
972 else947 int i;
973 return get_efi_config_table32(sys_table, guid);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;
974}959}
include/linux/efi.h+3−3
@@ -49,11 +49,11 @@ typedef u64 efi_physical_addr_t; · 48 unmodified lines
49typedef void *efi_handle_t;49typedef void *efi_handle_t;
50 50
51#define efi_get_handle_at(array, idx) \51#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] \
53 : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])53 : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
54 54
55#define efi_get_handle_num(size) \55#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)))
57 57
58#define for_each_efi_handle(handle, array, size, i) \58#define for_each_efi_handle(handle, array, size, i) \
59 for (i = 0; \59 for (i = 0; \
@@ -805,7 +805,7 @@ typedef struct { · 745 unmodified lines
805typedef union {805typedef union {
806 struct {806 struct {
807 efi_guid_t guid;807 efi_guid_t guid;
808 unsigned long table;808 void *table;
809 };809 };
810 efi_config_table_32_t mixed_mode;810 efi_config_table_32_t mixed_mode;
811} efi_config_table_t;811} efi_config_table_t;