Commit f958efe9 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Ingo Molnar

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: default avatarArd 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.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 1786e830
...@@ -52,7 +52,7 @@ void efi_virtmap_unload(void); ...@@ -52,7 +52,7 @@ void efi_virtmap_unload(void);
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__) #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (false) #define efi_is_native() (true)
#define efi_table_attr(table, attr, instance) \ #define efi_table_attr(table, attr, instance) \
((table##_t *)instance)->attr ((table##_t *)instance)->attr
......
...@@ -95,7 +95,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, ...@@ -95,7 +95,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
#define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__) #define efi_call_runtime(f, ...) sys_table_arg->runtime->f(__VA_ARGS__)
#define efi_is_64bit() (true) #define efi_is_native() (true)
#define efi_table_attr(table, attr, instance) \ #define efi_table_attr(table, attr, instance) \
((table##_t *)instance)->attr ((table##_t *)instance)->attr
......
...@@ -63,8 +63,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) ...@@ -63,8 +63,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
* large romsize. The UEFI spec limits the size of option ROMs to 16 * large romsize. The UEFI spec limits the size of option ROMs to 16
* MiB so we reject any ROMs over 16 MiB in size to catch this. * MiB so we reject any ROMs over 16 MiB in size to catch this.
*/ */
romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol, romimage = efi_table_attr(efi_pci_io_protocol, romimage, pci);
romimage, pci);
romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci); romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);
if (!romimage || !romsize || romsize > SZ_16M) if (!romimage || !romsize || romsize > SZ_16M)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
......
...@@ -222,21 +222,42 @@ static inline bool efi_is_64bit(void) ...@@ -222,21 +222,42 @@ static inline bool efi_is_64bit(void)
return __efi_early()->is64; return __efi_early()->is64;
} }
#define efi_table_attr(table, attr, instance) \ static inline bool efi_is_native(void)
(efi_is_64bit() ? \ {
((table##_64_t *)(unsigned long)instance)->attr : \ if (!IS_ENABLED(CONFIG_X86_64))
((table##_32_t *)(unsigned long)instance)->attr) 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, ...) \ #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__) instance, ##__VA_ARGS__)
#define efi_call_early(f, ...) \ #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__) __efi_early()->boot_services), __VA_ARGS__)
#define efi_call_runtime(f, ...) \ #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__) __efi_early()->runtime_services), __VA_ARGS__)
extern bool efi_reboot_required(void); extern bool efi_reboot_required(void);
......
...@@ -431,9 +431,7 @@ static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, ...@@ -431,9 +431,7 @@ static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
efi_file_handle_t *fh; efi_file_handle_t *fh;
efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
efi_status_t status; efi_status_t status;
void *handle = (void *)(unsigned long)efi_table_attr(efi_loaded_image, void *handle = efi_table_attr(efi_loaded_image, device_handle, image);
device_handle,
image);
status = efi_call_early(handle_protocol, handle, status = efi_call_early(handle_protocol, handle,
&fs_proto, (void **)&io); &fs_proto, (void **)&io);
...@@ -942,33 +940,20 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table_arg, ...@@ -942,33 +940,20 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table_arg,
return status; return status;
} }
#define GET_EFI_CONFIG_TABLE(bits) \
static void *get_efi_config_table##bits(efi_system_table_t *_sys_table, \
efi_guid_t guid) \
{ \
efi_system_table_##bits##_t *sys_table; \
efi_config_table_##bits##_t *tables; \
int i; \
\
sys_table = (typeof(sys_table))_sys_table; \
tables = (typeof(tables))(unsigned long)sys_table->tables; \
\
for (i = 0; i < sys_table->nr_tables; i++) { \
if (efi_guidcmp(tables[i].guid, guid) != 0) \
continue; \
\
return (void *)(unsigned long)tables[i].table; \
} \
\
return NULL; \
}
GET_EFI_CONFIG_TABLE(32)
GET_EFI_CONFIG_TABLE(64)
void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)
{ {
if (efi_is_64bit()) unsigned long tables = efi_table_attr(efi_system_table, tables, sys_table);
return get_efi_config_table64(sys_table, guid); int nr_tables = efi_table_attr(efi_system_table, nr_tables, sys_table);
else int i;
return get_efi_config_table32(sys_table, guid);
for (i = 0; i < nr_tables; i++) {
efi_config_table_t *t = (void *)tables;
if (efi_guidcmp(t->guid, guid) == 0)
return efi_table_attr(efi_config_table, table, t);
tables += efi_is_native() ? sizeof(efi_config_table_t)
: sizeof(efi_config_table_32_t);
}
return NULL;
} }
...@@ -49,11 +49,11 @@ typedef u64 efi_physical_addr_t; ...@@ -49,11 +49,11 @@ typedef u64 efi_physical_addr_t;
typedef void *efi_handle_t; typedef void *efi_handle_t;
#define efi_get_handle_at(array, idx) \ #define efi_get_handle_at(array, idx) \
(efi_is_64bit() ? (efi_handle_t)(unsigned long)((u64 *)(array))[idx] \ (efi_is_native() ? (array)[idx] \
: (efi_handle_t)(unsigned long)((u32 *)(array))[idx]) : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
#define efi_get_handle_num(size) \ #define efi_get_handle_num(size) \
((size) / (efi_is_64bit() ? sizeof(u64) : sizeof(u32))) ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
#define for_each_efi_handle(handle, array, size, i) \ #define for_each_efi_handle(handle, array, size, i) \
for (i = 0; \ for (i = 0; \
...@@ -805,7 +805,7 @@ typedef struct { ...@@ -805,7 +805,7 @@ typedef struct {
typedef union { typedef union {
struct { struct {
efi_guid_t guid; efi_guid_t guid;
unsigned long table; void *table;
}; };
efi_config_table_32_t mixed_mode; efi_config_table_32_t mixed_mode;
} efi_config_table_t; } efi_config_table_t;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment