efi/x86: confine type unsafe casting to mixed mode
Subsystems (4)
Ard Biesheuvel
maintainercover efi/x86: confine type unsafe casting to mixed mode
Currently, we support mixed mode (64-bit Linux running on 32-bit firmware) by explicitly reasoning about pointer sizes for every call into the
firmware: on x86, there are 32-bit and 64-bit versions of each protocol interface, and each call gets routed via one of the two, depending on the native size of the firmware.
There is a lot of casting and pointer mangling involved in this, and as a result, we end up with much less coverage in terms of type checking by the compiler, due to the indirection via an anonymous, variadic thunking routine.
This peculiarity of x86 is also leaking into generic EFI code, which is shared with ia64, arm64, ARM and likely RiscV in the future. So let's try to clean this up a bit.
The approach taken by this series is to replace the 32/64 bit distinction with a distinction between native calls and mixed mode calls, where the former can be either 32 or 64 bit [depending on the platform] and use the ordinary native protocol definitions, while mixed mode calls retain the existing casting/thunking approach based on the 32-bit protocol definitions.
Given that GCC now supports emitting function calls using the MS calling convention, we can get rid of all the wrapping and casting, and emit the indirect calls directly.
Code can be found here
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-x86-cleanup
Ard Biesheuvel (10):
efi/libstub: remove unused __efi_call_early() macro efi/x86: rename efi_is_native() to efi_is_mixed() efi/libstub: use a helper to iterate over a EFI handle array efi/libstub: add missing apple_properties_protocol_t definition efi/libstub: distinguish between native/mixed not 32/64 bit efi/libstub/x86: use mixed mode helpers to populate efi_config efi/libstub: drop explicit 64-bit protocol definitions efi/libstub: use stricter typing for firmware function pointers efi/libstub: annotate firmware routines as __efiapi efi/libstub/x86: avoid thunking for native firmware calls
arch/arm/include/asm/efi.h | 3 +- arch/arm64/include/asm/efi.h | 3 +- arch/x86/Kconfig | 1 + arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/eboot.c | 51 ++-- arch/x86/boot/compressed/eboot.h | 11 +- arch/x86/boot/compressed/efi_stub_32.S | 87 ------ arch/x86/boot/compressed/efi_stub_64.S | 5 - arch/x86/boot/compressed/head_32.S | 8 +- arch/x86/boot/compressed/head_64.S | 12 - arch/x86/include/asm/efi.h | 64 ++-- arch/x86/platform/efi/efi.c | 12 +- arch/x86/platform/efi/efi_64.c | 6 +- arch/x86/platform/efi/quirks.c | 2 +- .../firmware/efi/libstub/efi-stub-helper.c | 46 ++- drivers/firmware/efi/libstub/gop.c | 9 +- drivers/firmware/efi/libstub/pci.c | 9 +- drivers/firmware/efi/libstub/random.c | 13 +- drivers/firmware/efi/libstub/tpm.c | 4 +- include/linux/efi.h | 278 ++++++------------ 20 files changed, 195 insertions(+), 431 deletions(-) delete mode 100644 arch/x86/boot/compressed/efi_stub_32.S delete mode 100644 arch/x86/boot/compressed/efi_stub_64.S
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 1/10 efi/libstub: remove unused __efi_call_early() macro
The macro __efi_call_early() is defined by various architectures but never used. Let's get rid of it.
--- arch/arm/include/asm/efi.h | 1 - arch/arm64/include/asm/efi.h | 1 - arch/x86/include/asm/efi.h | 3 --- 3 files changed, 5 deletions(-)
arch/arm/include/asm/efi.h +0 -1
@@ -51,7 +51,6 @@ void efi_virtmap_unload(void);/* arch specific definitions used by the stub code */ #define efi_call_early (f, ...) sys_table_arg->boottime->f(__VA_ARGS__) -#define __efi_call_early (f, ...) f(__VA_ARGS__)#define efi_call_runtime (f, ...) sys_table_arg->runtime->f(__VA_ARGS__)#define efi_is_64bit () (false)
arch/arm64/include/asm/efi.h +0 -1
@@ -94,7 +94,6 @@ 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, ...) f(__VA_ARGS__)#define efi_call_runtime (f, ...) sys_table_arg->runtime->f(__VA_ARGS__)#define efi_is_64bit () (true)
arch/x86/include/asm/efi.h +0 -3
@@ -233,9 +233,6 @@ static inline bool efi_is_64bit(void)__efi_early ()->call (efi_table_attr (efi_boot_services, f, \ __efi_early()->boot_services), __VA_ARGS__) -#define __efi_call_early (f, ...) \ - __efi_early()->call((unsigned long)f, __VA_ARGS__); -#define efi_call_runtime (f, ...) \ __efi_early()->call(efi_table_attr(efi_runtime_services, f, \ __efi_early()->runtime_services), __VA_ARGS__)
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 2/10 efi/x86: rename efi_is_native() to efi_is_mixed()
In reply to Ard BiesheuvelThe ARM architecture does not permit combining 32-bit and 64-bit code at the same privilege level, and so EFI mixed mode is strictly a x86 concept.
In preparation of turning the 32/64 bit distinction in shared stub code to a native vs mixed one, refactor x86's current use of the helper function efi_is_native() into efi_is_mixed().
--- arch/x86/include/asm/efi.h | 10 ++++++---- arch/x86/platform/efi/efi.c | 8 ++++---- arch/x86/platform/efi/efi_64.c | 4 ++-- arch/x86/platform/efi/quirks.c | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-)
arch/x86/include/asm/efi.h +6 -4
@@ -153,17 +153,19 @@ extern u64 efi_setup;#ifdef CONFIG_EFI -static inline bool efi_is_native (void ) +static inline bool efi_is_mixed (void ) { -return IS_ENABLED (CONFIG_X86_64 ) ==efi_enabled (EFI_64BIT ); +if (!IS_ENABLED (CONFIG_EFI_MIXED )) +return false; +return IS_ENABLED (CONFIG_X86_64 ) && !efi_enabled (EFI_64BIT ); }static inline bool efi_runtime_supported (void ) { -if (efi_is_native ()) +if (!efi_is_mixed ())return true; -if (IS_ENABLED (CONFIG_EFI_MIXED ) && !efi_enabled (EFI_OLD_MEMMAP )) +if (!efi_enabled (EFI_OLD_MEMMAP ))return true;return false;
arch/x86/platform/efi/efi.c +4 -4
@@ -848,7 +848,7 @@ static bool should_map_region(efi_memory_desc_t *md)* Map all of RAM so that we can access arguments in the 1:1 * mapping when making EFI runtime calls. */ -if (IS_ENABLED (CONFIG_EFI_MIXED ) && !efi_is_native ()) { +if (efi_is_mixed ()) {if (md->type ==EFI_CONVENTIONAL_MEMORY || md->type ==EFI_LOADER_DATA || md->type ==EFI_LOADER_CODE )
@@ -923,7 +923,7 @@ static void __init kexec_enter_virtual_mode(void)* kexec kernel because in the initial boot something else might * have been mapped at these virtual addresses. */ -if (!efi_is_native () ||efi_enabled (EFI_OLD_MEMMAP )) { +if (efi_is_mixed () ||efi_enabled (EFI_OLD_MEMMAP )) {efi_memmap_unmap ();clear_bit (EFI_RUNTIME_SERVICES , &efi.flags);return ;
@@ -1060,7 +1060,7 @@ static void __init __efi_enter_virtual_mode(void)efi_sync_low_kernel_mappings (); -if (efi_is_native ()) { +if (!efi_is_mixed ()) { status = phys_efi_set_virtual_address_map( efi.memmap.desc_size * count, efi.memmap.desc_size,
@@ -1091,7 +1091,7 @@ static void __init __efi_enter_virtual_mode(void)*/ efi.runtime_version = efi_systab.hdr.revision; -if (efi_is_native ()) +if (!efi_is_mixed ())efi_native_runtime_setup ();else efi_thunk_runtime_setup ();
arch/x86/platform/efi/efi_64.c +2 -2
@@ -388,7 +388,7 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)* text and allocate a new stack because we can't rely on the * stack pointer being < 4GB. */ -if (!IS_ENABLED (CONFIG_EFI_MIXED ) ||efi_is_native ()) +if (!efi_is_mixed ())return 0 ; page =alloc_page (GFP_KERNEL |__GFP_DMA32);
@@ -449,7 +449,7 @@ void __init efi_map_region(efi_memory_desc_t *md)* booting in EFI mixed mode, because even though we may be * running a 64-bit kernel, the firmware may only be 32-bit. */ -if (!efi_is_native () &&IS_ENABLED (CONFIG_EFI_MIXED )) { +if (efi_is_mixed ()) { md->virt_addr = md->phys_addr;return ; }
arch/x86/platform/efi/quirks.c +1 -1
@@ -397,7 +397,7 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)* EFI runtime calls, hence don't unmap EFI boot services code/data * regions. */ -if (!efi_is_native ()) +if (efi_is_mixed ())return ;if (kernel_unmap_pages_in_pgd (pgd, pa, md->num_pages))
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 3/10 efi/libstub: use a helper to iterate over a EFI handle array
In reply to Ard BiesheuvelIterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native efi_handle_t type is 64-bit.
So introduce a helper, and replace the various occurrences of this pattern.
--- arch/x86/boot/compressed/eboot.c | 14 +++++--------- drivers/firmware/efi/libstub/gop.c | 9 ++------- drivers/firmware/efi/libstub/pci.c | 9 +++------ include/linux/efi.h | 10 ++++++++++ 4 files changed, 20 insertions(+), 22 deletions(-)
arch/x86/boot/compressed/eboot.c +5 -9
@@ -135,6 +135,7 @@ static void setup_efi_pci(struct boot_params *params)unsigned long size =0 ;unsigned long nr_pci;struct setup_data *data; +efi_handle_t h;int i;efi_pci_disable_bridge_busmaster (sys_table);
@@ -166,14 +167,11 @@ static void setup_efi_pci(struct boot_params *params)while (data && data->next) data = (struct setup_data *)(unsigned long )data->next; - nr_pci = size / (efi_is_64bit () ?sizeof (u64) :sizeof (u32)); -for (i =0 ; i < nr_pci; i++) { +for_each_efi_handle (h, pci_handle, size, i) {efi_pci_io_protocol_t *pci =NULL ;struct pci_setup_rom *rom; - status =efi_call_early (handle_protocol, -efi_is_64bit () ? ((u64 *)pci_handle)[i] - : ((u32 *)pci_handle)[i], + status =efi_call_early (handle_protocol, h, &pci_proto, (void **)&pci);if (status !=EFI_SUCCESS || !pci)continue ;
@@ -268,6 +266,7 @@ setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)void **uga_handle =NULL ;efi_uga_draw_protocol_t *uga =NULL , *first_uga;unsigned long nr_ugas; +efi_handle_t handle;int i; status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
@@ -285,13 +284,10 @@ setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size) width =0 ; first_uga =NULL ; - nr_ugas = size / (efi_is_64bit () ?sizeof (u64) :sizeof (u32)); -for (i =0 ; i < nr_ugas; i++) { +for_each_efi_handle (handle, uga_handle, size, i) {efi_guid_t pciio_proto =EFI_PCI_IO_PROTOCOL_GUID ;u32 w, h, depth, refresh;void *pciio; -unsigned long handle =efi_is_64bit () ? ((u64 *)uga_handle)[i] - : ((u32 *)uga_handle)[i]; status =efi_call_early (handle_protocol, handle, uga_proto, (void **)&uga);
drivers/firmware/efi/libstub/gop.c +2 -7
@@ -91,7 +91,6 @@ setup_gop(efi_system_table_t *sys_table_arg, struct screen_info *si, efi_guid_t *proto, unsigned long size, void **handles) { efi_graphics_output_protocol_t *gop, *first_gop; -unsigned long nr_gops;u16 width, height;u32 pixels_per_scan_line;u32 ext_lfb_base;
@@ -99,22 +98,18 @@ setup_gop(efi_system_table_t *sys_table_arg, struct screen_info *si,efi_pixel_bitmask_t pixel_info;int pixel_format;efi_status_t status; +efi_handle_t h;int i; -bool is64 =efi_is_64bit (); first_gop =NULL ; gop =NULL ; - nr_gops = size / (is64 ?sizeof (u64) :sizeof (u32)); -for (i =0 ; i < nr_gops; i++) { +for_each_efi_handle (h, handles, size, i) {efi_graphics_output_protocol_mode_t *mode;efi_graphics_output_mode_info_t *info =NULL ;efi_guid_t conout_proto =EFI_CONSOLE_OUT_DEVICE_GUID ;bool conout_found = false;void *dummy =NULL ; -efi_handle_t h = (efi_handle_t )(unsigned long ) - (is64 ? ((u64 *)handles)[i] - : ((u32 *)handles)[i]);efi_physical_addr_t current_fb_base; status = efi_call_early(handle_protocol, h,
drivers/firmware/efi/libstub/pci.c +3 -6
@@ -19,8 +19,8 @@ void efi_pci_disable_bridge_busmaster(efi_system_table_t *sys_table_arg)void **pci_handle =NULL ;efi_guid_t pci_proto =EFI_PCI_IO_PROTOCOL_GUID ;unsigned long size =0 ; -unsigned long nr_pci;u16 class, command; +efi_handle_t handle;int i;if (!nobusmaster ())
@@ -49,13 +49,10 @@ void efi_pci_disable_bridge_busmaster(efi_system_table_t *sys_table_arg)if (status !=EFI_SUCCESS ) goto free_handle; - nr_pci = size / (efi_is_64bit () ?sizeof (u64) :sizeof (u32)); -for (i =0 ; i < nr_pci; i++) { +for_each_efi_handle (handle, pci_handle, size, i) {efi_pci_io_protocol_t *pci =NULL ; -unsigned long handle =efi_is_64bit () ? ((u64 *)pci_handle)[i] - : ((u32 *)pci_handle)[i]; - status =efi_call_early (handle_protocol, (efi_handle_t )handle, + status =efi_call_early (handle_protocol, handle, &pci_proto, (void **)&pci);if (status !=EFI_SUCCESS || !pci)continue ;
include/linux/efi.h +10 -0
@@ -48,6 +48,16 @@ typedef u16 efi_char16_t; /* UNICODE character */typedef u64 efi_physical_addr_t ;typedef void *efi_handle_t ; +#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment
Signature · 1 line
2.17.1
Re: [PATCH 03/10] efi/libstub: use a helper to iterate over a EFI handle array
Quoted 26 lines · Ard Biesheuvel
Iterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native
efi_handle_ttype is 64-bit.So introduce a helper, and replace the various occurrences of this pattern.
Signed-off-by Ard Biesheuvel <[email protected]>---
include/linux/efi.h +10
-0+#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment Signature · 1 line
2.17.1
This would access one past the array, no? Eg if the array has one handle, i is incremented to 2 the first time the condition is checked, then the loop increment will access array[2] before the condition is checked again. There seem to be at least a couple of other for_each macros that might have similar issues.
How about the below instead?
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ (i < (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32))) && \ ((handle = efi_is_64bit() \ ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i]), 1);\ i++)
Re: [PATCH 03/10] efi/libstub: use a helper to iterate over a EFI handle array
Quoted 26 lines · Arvind Sankar
Quoted 24 lines · Ard Biesheuvel
Iterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native
efi_handle_ttype is 64-bit.So introduce a helper, and replace the various occurrences of this pattern.
Signed-off-by Ard Biesheuvel <[email protected]>---
include/linux/efi.h +10
-1+#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment --
Quoted 9 lines
Quoted 2 lines
2.17.1
This would access one past the array, no? Eg if the array has one handle, i is incremented to 2 the first time the condition is checked, then the loop increment will access array[2] before the condition is checked again. There seem to be at least a couple of other
for_eachmacros that might have similar issues.
Indeed.
Quoted 11 lines
How about the below instead?
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ (i < (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32))) && \ ((handle = efi_is_64bit() \ ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i]), 1);\ i++)
Yeah, that looks correct to me, but perhaps we can come up with something slightly more readable? :-)
(Not saying my code was better in that respect)
Re: [PATCH 03/10] efi/libstub: use a helper to iterate over a EFI handle array
Quoted 52 lines · Ard Biesheuvel
Quoted 26 lines · Arvind Sankar
Quoted 24 lines · Ard Biesheuvel
Iterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native
efi_handle_ttype is 64-bit.So introduce a helper, and replace the various occurrences of this pattern.
Signed-off-by Ard Biesheuvel <[email protected]>---
include/linux/efi.h +10
-1+#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment -- Quoted 9 lines
Quoted 2 lines
2.17.1
This would access one past the array, no? Eg if the array has one handle, i is incremented to 2 the first time the condition is checked, then the loop increment will access array[2] before the condition is checked again. There seem to be at least a couple of other
for_eachmacros that might have similar issues.Indeed.
Quoted 11 lines
How about the below instead?
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ (i < (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32))) && \ ((handle = efi_is_64bit() \ ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i]), 1);\ i++)
Quoted 3 lines
Yeah, that looks correct to me, but perhaps we can come up with something slightly more readable? :-)
(Not saying my code was better in that respect)
How about
#define efi_get_handle_at(array, idx) \
(efi_is_64bit() ? (efi_handle_t)(unsigned long)((u64 *)(array))[idx] \
: (efi_handle_t)(unsigned long)((u32 *)(array))[i])#define efi_get_handle_num(size) \
((size) / (efi_is_64bit() ? sizeof(u64) : sizeof(u32)))#define for_each_efi_handle(handle, array, size, i) \
for (i = 0; \
i < efi_get_handle_num(size) && \
((handle = efi_get_handle_at((array), i)) || true); \
i++)Re: [PATCH 03/10] efi/libstub: use a helper to iterate over a EFI handle array
Quoted 64 lines · Ard Biesheuvel
Quoted 52 lines · Ard Biesheuvel
Quoted 26 lines · Arvind Sankar
Quoted 24 lines · Ard Biesheuvel
Iterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native
efi_handle_ttype is 64-bit.So introduce a helper, and replace the various occurrences of this pattern.
Signed-off-by Ard Biesheuvel <[email protected]>---
include/linux/efi.h +10
-1+#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment -- Quoted 9 lines
Quoted 2 lines
2.17.1
This would access one past the array, no? Eg if the array has one handle, i is incremented to 2 the first time the condition is checked, then the loop increment will access array[2] before the condition is checked again. There seem to be at least a couple of other
for_eachmacros that might have similar issues.Indeed.
Quoted 11 lines
How about the below instead?
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ (i < (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32))) && \ ((handle = efi_is_64bit() \ ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i]), 1);\ i++)Quoted 3 lines
Yeah, that looks correct to me, but perhaps we can come up with something slightly more readable? :-)
(Not saying my code was better in that respect)How about
#define efi_get_handle_at(array, idx) \ (efi_is_64bit() ? (efi_handle_t)(unsigned long)((u64 *)(array))[idx] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i])
Quoted 8 lines
#define efi_get_handle_num(size) \ ((size) / (efi_is_64bit() ? sizeof(u64) : sizeof(u32)))#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ i < efi_get_handle_num(size) && \ ((handle = efi_get_handle_at((array), i)) || true); \ i++)
Heh, I came up with almost the same thing, but yours is slightly better, You have a typo in efi_get_handle_at (i instead of idx in the second line).
Re: [PATCH 03/10] efi/libstub: use a helper to iterate over a EFI handle array
In reply to Ard BiesheuvelQuoted 51 lines · Ard Biesheuvel
Quoted 26 lines · Arvind Sankar
Quoted 24 lines · Ard Biesheuvel
Iterating over a EFI handle array is a bit finicky, since we have to take mixed mode into account, where handles are only 32-bit while the native
efi_handle_ttype is 64-bit.So introduce a helper, and replace the various occurrences of this pattern.
Signed-off-by Ard Biesheuvel <[email protected]>---
include/linux/efi.h +10
-1+#define for_each_efi_handle (handle, array, size, i) \ + for (i = 1, handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ + i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + : sizeof(u32)); \ + handle = efi_is_64bit() \ + ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + : (efi_handle_t)(unsigned long)((u32 *)(array))[i]) +/* * The UEFI spec and EDK2 reference implementation both define EFI_GUID as * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment -- Quoted 9 lines
Quoted 2 lines
2.17.1
This would access one past the array, no? Eg if the array has one handle, i is incremented to 2 the first time the condition is checked, then the loop increment will access array[2] before the condition is checked again. There seem to be at least a couple of other
for_eachmacros that might have similar issues.Indeed.
Quoted 11 lines
How about the below instead?
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; \ (i < (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32))) && \ ((handle = efi_is_64bit() \ ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i]), 1);\ i++)
Quoted 3 lines
Yeah, that looks correct to me, but perhaps we can come up with something slightly more readable? :-)
(Not saying my code was better in that respect)
:) The idiom of the && with , operator is copied from for_each_bvec in bvec.h.
Perhaps more readable with helper macros:
#define __efi_handle_size (efi_is_64bit() ? sizeof(efi_handle_t) \ : sizeof(u32)) #define __efi_handle_elem(array, i) \ (efi_is_64bit() ? ((efi_handle_t *)(array))[i] \ : (efi_handle_t)(uintptr_t)((u32 *)(array))[i])
#define for_each_efi_handle(handle, array, size, i) \ for (i = 0; i < (size) / __efi_handle_size && \ (handle = __efi_handle_elem(array, i), 1); i++)
Ard Biesheuvel
maintainerPATCH 4/10 efi/libstub: add missing apple_properties_protocol_t definition
In reply to Ard BiesheuvelAs apple_properties_protocol_t is only used on x86, we never bothered to define the native apple_properties_protocol_t struct, but only added the explicit 32-bit and 64-bit ones. We'll need the native one for the next patch so let's add it, based on the prototypes that can be found in commit 58c5475aba67706b31d9237808d5d3d54074e5ea.
--- include/linux/efi.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
include/linux/efi.h +16 -0
@@ -518,6 +518,22 @@ typedef struct {u64 get_all; } apple_properties_protocol_64_t; +struct efi_dev_path ; + +typedef struct apple_properties_protocol { +unsigned long version; +efi_status_t (*get)(struct apple_properties_protocol *, +struct efi_dev_path *,efi_char16_t *, +void *,u32 *); +efi_status_t (*set)(struct apple_properties_protocol *, +struct efi_dev_path *,efi_char16_t *, +void *,u32 ); +efi_status_t (*del)(struct apple_properties_protocol *, +struct efi_dev_path *,efi_char16_t *); +efi_status_t (*get_all)(struct apple_properties_protocol *, +void *buffer,u32 *); +}apple_properties_protocol_t ; + typedef struct { u32 get_capability; u32 get_event_log;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 5/10 efi/libstub: distinguish between native/mixed not 32/64 bit
In reply to Ard BiesheuvelCurrently, 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.
--- arch/arm/include/asm/efi.h | 2 +- arch/arm64/include/asm/efi.h | 2 +- arch/x86/include/asm/efi.h | 31 +++++++++++---- drivers/firmware/efi/libstub/efi-stub-helper.c | 41 +++++++------------- include/linux/efi.h | 10 ++--- 5 files changed, 44 insertions(+), 42 deletions(-)
arch/arm/include/asm/efi.h +1 -1
@@ -52,7 +52,7 @@ void efi_virtmap_unload(void);#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_is_64bit () (false) +#define efi_is_native () (true)#define efi_table_attr (table, attr, instance) \ ((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,#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_is_64bit () (true) +#define efi_is_native () (true)#define efi_table_attr (table, attr, instance) \ ((table##_t *)instance)->attr
arch/x86/include/asm/efi.h +24 -7
@@ -222,21 +222,38 @@ static inline bool efi_is_64bit(void)return __efi_early ()->is64; } -#define efi_table_attr (table, attr, instance) \ - (efi_is_64bit() ? \ - ((table##_64_t *)(unsigned long)instance)->attr : \ - ((table##_32_t *)(unsigned long)instance)->attr) +static inline bool efi_is_native (void ) +{ +if (!IS_ENABLED (CONFIG_X86_64 )) +return true; +return efi_is_64bit (); +} + +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})#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__)#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__)#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__)extern bool efi_reboot_required (void );
drivers/firmware/efi/libstub/efi-stub-helper.c +14 -27
47 lines not on this page · raw message
include/linux/efi.h +4 -6
@@ -49,13 +49,11 @@ typedef u64 efi_physical_addr_t;typedef void *efi_handle_t ;#define for_each_efi_handle (handle, array, size, i) \ - for (i = 1, handle = efi_is_64bit() \ - ? (efi_handle_t)(unsigned long)((u64 *)(array))[0] \ + for (i = 1, handle = efi_is_native() ? (array)[0] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[0]; \ - i++ <= (size) / (efi_is_64bit() ? sizeof(efi_handle_t) \ + i++ <= (size) / (efi_is_native() ? sizeof(efi_handle_t) \ : sizeof(u32)); \ - handle = efi_is_64bit() \ - ? (efi_handle_t)(unsigned long)((u64 *)(array))[i] \ + handle = efi_is_native() ? (array)[i] \ : (efi_handle_t)(unsigned long)((u32 *)(array))[i])/*
@@ -753,7 +751,7 @@ typedef struct {typedef struct {efi_guid_t guid; -unsigned long table; +void *table; }efi_config_table_t ; typedef struct {
Signature · 1 line
2.17.1
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 12 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +12
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})
The casting of `at' is appropriate if the attr is a pointer type which needs to be zero-extended to 64-bit, but for other fields it is unnecessary at best and possibly dangerous. There are probably no instances currently where it is called for a non-pointer field, but is it possible to detect if the type is pointer and avoid the cast if not?
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 11 lines · Arvind Sankar
Quoted 10 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +10
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \
Quoted 8 lines
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 2 lines
arch/x86/include/asm/efi.h +2
-0+ __ret; \ +})The casting of `at' is appropriate if the attr is a pointer type which needs to be zero-extended to 64-bit, but for other fields it is unnecessary at best and possibly dangerous. There are probably no instances currently where it is called for a non-pointer field, but is it possible to detect if the type is pointer and avoid the cast if not?
To clarify, I mean the casting via `unsigned long' -- casting to type of __ret should be ok. We could also use uintptr_t for cleanliness when the cast is required?
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 22 lines · Arvind Sankar
Quoted 11 lines · Arvind Sankar
Quoted 10 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +10
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \Quoted 8 lines
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 2 lines
arch/x86/include/asm/efi.h +2
-0+ __ret; \ +})The casting of `at' is appropriate if the attr is a pointer type which needs to be zero-extended to 64-bit, but for other fields it is unnecessary at best and possibly dangerous. There are probably no instances currently where it is called for a non-pointer field, but is it possible to detect if the type is pointer and avoid the cast if not?
Quoted 3 lines
To clarify, I mean the casting via `unsigned long' -- casting to type of
__retshould be ok. We could also useuintptr_tfor cleanliness when the cast is required?
Could you give an example of how it could break?
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 23 lines · Ard Biesheuvel
Quoted 22 lines · Arvind Sankar
Quoted 19 lines · Arvind Sankar
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 12 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +12
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})The casting of `at' is appropriate if the attr is a pointer type which needs to be zero-extended to 64-bit, but for other fields it is unnecessary at best and possibly dangerous. There are probably no instances currently where it is called for a non-pointer field, but is it possible to detect if the type is pointer and avoid the cast if not?
Quoted 5 lines
Quoted 3 lines
To clarify, I mean the casting via `unsigned long' -- casting to type of
__retshould be ok. We could also useuintptr_tfor cleanliness when the cast is required?Could you give an example of how it could break?
eg, if the field is actually a structure. Nobody seems to do this currently, but say for
efi_table_attr(efi_boot_services, hdr, instance)
you shouldn't cast hdr to unsigned long.
There's also the case of nested 32/64-bit structures that breaks, but that might be too hard to try to handle:
efi_table_attr(efi_pci_io_protocol, io, instance)
where io is a structure of two pointers which would need to be individually casted. It's properly accessible as io.read/io.write though.
In general though, everything is either a pointer or a u64, so if it's too messy to detect pointer type, the cast is still probably safe in practice.
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 29 lines · Arvind Sankar
Quoted 27 lines · Ard Biesheuvel
Quoted 25 lines · Arvind Sankar
Quoted 11 lines · Arvind Sankar
Quoted 10 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +10
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \ + } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \Quoted 8 lines
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 2 lines
arch/x86/include/asm/efi.h +2
-0+ __ret; \ +})The casting of `at' is appropriate if the attr is a pointer type which needs to be zero-extended to 64-bit, but for other fields it is unnecessary at best and possibly dangerous. There are probably no instances currently where it is called for a non-pointer field, but is it possible to detect if the type is pointer and avoid the cast if not?
To clarify, I mean the casting via `unsigned long' -- casting to type of
__retshould be ok. We could also useuintptr_tfor cleanliness when the cast is required?
Quoted 7 lines
Quoted 1 line
Could you give an example of how it could break?
eg, if the field is actually a structure. Nobody seems to do this currently, but say for
efi_table_attr(efi_boot_services, hdr, instance)
you shouldn't cast hdr to unsigned long.
Yes. the efi_guid_t in efi_config_table_t is another example - I had to work around that in get_efi_config_table().
Quoted 7 lines
There's also the case of nested 32/64-bit structures that breaks, but that might be too hard to try to handle:
efi_table_attr(efi_pci_io_protocol, io, instance)
where io is a structure of two pointers which would need to be individually casted. It's properly accessible as io.read/io.write though.
Yes. We already have calls to pci.read that use this.
Quoted 3 lines
In general though, everything is either a pointer or a u64, so if it's too messy to detect pointer type, the cast is still probably safe in practice.
Yes. I'm open to suggestions on how to improve this, but mixed mode is somewhat of a maintenance burden, so if new future functionality needs to leave mixed mode behind, I'm not too bothered.
Thanks,
Ard.
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 20 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 4 lines · Ard Biesheuvel
Quoted 3 lines · Arvind Sankar
Quoted 1 line · Arvind Sankar
On Sat, Dec 14, 2019 at 06:57:30PM +0100, Ard Biesheuvel wrote:
Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
arch/x86/include/asm/efi.h +5
-0+ +#define efi_table_attr (table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
arch/x86/include/asm/efi.h static inline bool efi_is_64bit(void) · line 242
Quoted 7 lines
arch/x86/include/asm/efi.h +7
-0+ }else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__ (__ret ))(unsigned long )at; \ + } \ + __ret; \ +})
Quoted 4 lines
Yes. I'm open to suggestions on how to improve this, but mixed mode is somewhat of a maintenance burden, so if new future functionality needs to leave mixed mode behind, I'm not too bothered.
Maybe just do
if (sizeof(at) < sizeof(__ret)) __ret = (__typeof__(__ret))(uintptr_t)at; else __ret = (__typeof__(__ret))at;
That should cover most of the cases.
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 27 lines · Arvind Sankar
Quoted 20 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 4 lines · Ard Biesheuvel
Quoted 3 lines · Arvind Sankar
Quoted 1 line · Arvind Sankar
On Sat, Dec 14, 2019 at 06:57:30PM +0100, Ard Biesheuvel wrote:
Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +5
-0+ +#define efi_table_attr(table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})Quoted 4 lines
Yes. I'm open to suggestions on how to improve this, but mixed mode is somewhat of a maintenance burden, so if new future functionality needs to leave mixed mode behind, I'm not too bothered.
Quoted 6 lines
Maybe just do
if (sizeof(at) < sizeof(__ret)) __ret = (__typeof__(__ret))(uintptr_t)at; else __ret = (__typeof__(__ret))at;That should cover most of the cases.
But the compiler will still be unhappy about the else clause if __ret is a pointer type, since we'll be casting an u32 to a pointer,
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 11 lines · Ard Biesheuvel
Quoted 7 lines · Arvind Sankar
Maybe just do
if (sizeof(at) < sizeof(__ret)) __ret = (__typeof__(__ret))(uintptr_t)at; else __ret = (__typeof__(__ret))at;That should cover most of the cases.
But the compiler will still be unhappy about the else clause if
__retis a pointer type, since we'll be casting an u32 to a pointer,
Ugh, yeah it complains even though it can tell at compile time that that branch isn't taken.
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
In reply to Ard BiesheuvelQuoted 36 lines · Ard Biesheuvel
Quoted 27 lines · Arvind Sankar
Quoted 20 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 4 lines · Ard Biesheuvel
Quoted 3 lines · Arvind Sankar
Quoted 1 line · Arvind Sankar
On Sat, Dec 14, 2019 at 06:57:30PM +0100, Ard Biesheuvel wrote:
Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +5
-0+ +#define efi_table_attr(table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})Quoted 4 lines
Yes. I'm open to suggestions on how to improve this, but mixed mode is somewhat of a maintenance burden, so if new future functionality needs to leave mixed mode behind, I'm not too bothered.
Quoted 6 lines
Maybe just do
if (sizeof(at) < sizeof(__ret)) __ret = (__typeof__(__ret))(uintptr_t)at; else __ret = (__typeof__(__ret))at;That should cover most of the cases.
Quoted 2 lines
But the compiler will still be unhappy about the else clause if
__retis a pointer type, since we'll be casting an u32 to a pointer,
I think the answer is to have efi_table_ptr() for pointers and efi_table_attr() for other types.
Re: [PATCH 05/10] efi/libstub: distinguish between native/mixed not 32/64 bit
Quoted 37 lines · Ard Biesheuvel
Quoted 36 lines · Ard Biesheuvel
Quoted 33 lines · Arvind Sankar
Quoted 20 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 4 lines · Ard Biesheuvel
Quoted 3 lines · Arvind Sankar
Quoted 1 line · Arvind Sankar
On Sat, Dec 14, 2019 at 06:57:30PM +0100, Ard Biesheuvel wrote:
Quoted 13 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +5
-0+ +#define efi_table_attr(table, attr, instance) ({ \ + __typeof__(((table##_t *)0)->attr) __ret; \ + if (efi_is_native()) { \ + __ret = ((table##_t *)instance)->attr; \Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Review
Quoted 7 lines
(quoted diff) +7
-0+ } else { \ + __typeof__(((table##_32_t *)0)->attr) at; \ + at = (((table##_32_t *)(unsigned long)instance)->attr); \ + __ret = (__typeof__(__ret))(unsigned long)at; \ + } \ + __ret; \ +})Quoted 4 lines
Yes. I'm open to suggestions on how to improve this, but mixed mode is somewhat of a maintenance burden, so if new future functionality needs to leave mixed mode behind, I'm not too bothered.
Maybe just do
if (sizeof(at) < sizeof(__ret)) __ret = (__typeof__(__ret))(uintptr_t)at; else __ret = (__typeof__(__ret))at;That should cover most of the cases.
Quoted 5 lines
Quoted 2 lines
But the compiler will still be unhappy about the else clause if
__retis a pointer type, since we'll be casting an u32 to a pointer,I think the answer is to have
efi_table_ptr()for pointers andefi_table_attr()for other types.
Using __builtin_choose_expr avoids the warning:
__ret = (__typeof__(__ret)) __builtin_choose_expr(sizeof(at) < sizeof(ret), (uintptr_t)at, at);
But having different efi_table_ macros sounds cleaner.
Ard Biesheuvel
maintainerPATCH 6/10 efi/libstub/x86: use mixed mode helpers to populate efi_config
In reply to Ard BiesheuvelThe efi_config struct returned by __efi_early() contains a couple of pointers that are obtained from the EFI system table, which could be 32-bit on a 64-bit system. For this reason, there are two versions of the setup_boot_services() routine, one for 32-bit and one for 64-bit.
We have helpers now that hide all this nastiness, so let's use those instead.
--- arch/x86/boot/compressed/eboot.c | 27 +++++--------------- arch/x86/boot/compressed/head_32.S | 6 ++--- arch/x86/include/asm/efi.h | 6 ++--- arch/x86/platform/efi/efi.c | 4 +-- include/linux/efi.h | 6 ++--- 5 files changed, 18 insertions(+), 31 deletions(-)
arch/x86/boot/compressed/eboot.c +7 -20
@@ -27,19 +27,12 @@ __pure const struct efi_config *__efi_early(void)return efi_early; } -#define BOOT_SERVICES (bits) \ -static void setup_boot_services##bits(struct efi_config *c) \ -{ \ - efi_system_table_##bits##_t *table; \ - \ - table = (typeof(table))sys_table; \ - \ - c->runtime_services = table->runtime; \ - c->boot_services = table->boottime; \ - c->text_output = table->con_out; \ +static void setup_boot_services (struct efi_config *c) +{ + c->runtime_services =efi_table_attr (efi_system_table, runtime, sys_table); + c->boot_services =efi_table_attr (efi_system_table, boottime, sys_table); + c->text_output =efi_table_attr (efi_system_table, con_out, sys_table); } -BOOT_SERVICES (32 ); -BOOT_SERVICES (64 );void efi_char16_printk (efi_system_table_t *table,efi_char16_t *str) {
@@ -399,10 +392,7 @@ struct boot_params *make_boot_params(struct efi_config *c)if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE )return NULL ; -if (efi_is_64bit ()) -setup_boot_services64 (efi_early); -else -setup_boot_services32 (efi_early); +setup_boot_services (efi_early); status =efi_call_early (handle_protocol, handle, &proto, (void *)&image);
@@ -761,10 +751,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE ) goto fail; -if (efi_is_64bit ()) -setup_boot_services64 (efi_early); -else -setup_boot_services32 (efi_early); +setup_boot_services (efi_early);/* * make_boot_params() may have been called before efi_main(), in which
arch/x86/boot/compressed/head_32.S +3 -3
@@ -163,7 +163,7 @@ SYM_FUNC_START(efi_pe_entry) /* Relocate efi_config->call() */ leal efi32_config(%esi), %eax - add %esi, 40(%eax) + add %esi, 28(%eax) pushl %eax call make_boot_params
@@ -190,7 +190,7 @@ SYM_FUNC_START(efi32_stub_entry) /* Relocate efi_config->call() */ leal efi32_config(%esi), %eax - add %esi, 40(%eax) + add %esi, 28(%eax) pushl %eax 2: call efi_main
@@ -265,7 +265,7 @@ SYM_FUNC_END(.Lrelocated) #ifdef CONFIG_EFI_STUB .data efi32_config: - .fill 5,8,0 + .fill 7,4,0 .long efi_call_phys .long 0 .byte 0
arch/x86/include/asm/efi.h +3 -3
@@ -202,9 +202,9 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(struct efi_config {u64 image_handle;u64 table; -u64 runtime_services; -u64 boot_services; -u64 text_output; +efi_runtime_services_t *runtime_services; +efi_boot_services_t *boot_services; +efi_simple_text_output_protocol_t *text_output;efi_status_t (*call)(unsigned long , ...);bool is64; } __packed;
arch/x86/platform/efi/efi.c +2 -2
@@ -388,7 +388,7 @@ static int __init efi_systab_init(void *phys) tmp |= systab64->con_in; efi_systab.con_out_handle = systab64->con_out_handle; tmp |= systab64->con_out_handle; - efi_systab.con_out = systab64->con_out; + efi_systab.con_out = (void *)(unsigned long )systab64->con_out; tmp |= systab64->con_out; efi_systab.stderr_handle = systab64->stderr_handle; tmp |= systab64->stderr_handle;
@@ -430,7 +430,7 @@ static int __init efi_systab_init(void *phys) efi_systab.con_in_handle = systab32->con_in_handle; efi_systab.con_in = systab32->con_in; efi_systab.con_out_handle = systab32->con_out_handle; - efi_systab.con_out = systab32->con_out; + efi_systab.con_out = (void *)(unsigned long )systab32->con_out; efi_systab.stderr_handle = systab32->stderr_handle; efi_systab.stderr = systab32->stderr; efi_systab.runtime = (void *)(unsigned long )systab32->runtime;
include/linux/efi.h +3 -3
@@ -810,7 +810,7 @@ typedef struct {unsigned long con_in_handle;unsigned long con_in;unsigned long con_out_handle; -unsigned long con_out; +struct efi_simple_text_output_protocol *con_out;unsigned long stderr_handle;unsigned long stderr;efi_runtime_services_t *runtime;
@@ -1445,11 +1445,11 @@ typedef struct {u64 test_string; } efi_simple_text_output_protocol_64_t; -struct efi_simple_text_output_protocol { +typedef struct efi_simple_text_output_protocol {void *reset;efi_status_t (*output_string)(void *,void *);void *test_string; -}; +}efi_simple_text_output_protocol_t ;#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR 0#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR 1
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 7/10 efi/libstub: drop explicit 64-bit protocol definitions
In reply to Ard BiesheuvelMixed mode involves casting 64-bit native calls to 32-bit EFI calls, which requires explicit 32-bit protocol definitions. Native calls are always done using the protocol definitions that use native types, and so the explicit 64-bit ones are redundant. Remove them.
--- arch/x86/boot/compressed/eboot.h | 6 - drivers/firmware/efi/libstub/random.c | 5 - include/linux/efi.h | 142 -------------------- 3 files changed, 153 deletions(-)
arch/x86/boot/compressed/eboot.h +0 -6
@@ -18,12 +18,6 @@ typedef struct {u32 blt; } efi_uga_draw_protocol_32_t; -typedef struct { -u64 get_mode; -u64 set_mode; -u64 blt; -}efi_uga_draw_protocol_64_t ; - typedef struct { void *get_mode; void *set_mode;
drivers/firmware/efi/libstub/random.c +0 -5
@@ -16,11 +16,6 @@ typedef struct {u32 get_rng; } efi_rng_protocol_32_t; -typedef struct { -u64 get_info; -u64 get_rng; -}efi_rng_protocol_64_t ; -struct efi_rng_protocol {efi_status_t (*get_info)(struct efi_rng_protocol *,unsigned long *,efi_guid_t *);
include/linux/efi.h +0 -142
202 lines not on this page · raw message
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 8/10 efi/libstub: use stricter typing for firmware function pointers
In reply to Ard BiesheuvelWe will soon remove another level of pointer casting, so let's make sure all type handling involving firmware calls at boot time is correct.
--- arch/x86/boot/compressed/eboot.c | 10 ++++++---- arch/x86/boot/compressed/eboot.h | 5 +++-- drivers/firmware/efi/libstub/efi-stub-helper.c | 5 +++-- drivers/firmware/efi/libstub/tpm.c | 4 ++-- include/linux/efi.h | 6 +++++- 5 files changed, 19 insertions(+), 11 deletions(-)
arch/x86/boot/compressed/eboot.c +6 -4
@@ -64,7 +64,8 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) size = romsize +sizeof (*rom); - status =efi_call_early (allocate_pool,EFI_LOADER_DATA , size, &rom); + status =efi_call_early (allocate_pool,EFI_LOADER_DATA , size, + (void **)&rom);if (status !=EFI_SUCCESS ) {efi_printk (sys_table,"Failed to allocate memory for 'rom'\n" );return status;
@@ -191,9 +192,9 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)struct setup_data *data, *new;efi_status_t status;u32 size =0 ; -void *p; +apple_properties_protocol_t *p; - status =efi_call_early (locate_protocol, &guid,NULL , &p); + status =efi_call_early (locate_protocol, &guid,NULL , (void **)&p);if (status !=EFI_SUCCESS )return ;
@@ -208,7 +209,8 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params) do { status = efi_call_early(allocate_pool, EFI_LOADER_DATA, - size + sizeof(struct setup_data), &new); + size + sizeof(struct setup_data), + (void **)&new); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to allocate memory for 'properties'\n"); return;
arch/x86/boot/compressed/eboot.h +3 -2
@@ -18,8 +18,9 @@ typedef struct {u32 blt; } efi_uga_draw_protocol_32_t; -typedef struct { -void *get_mode; +typedef struct efi_uga_draw_protocol { +efi_status_t (*get_mode)(struct efi_uga_draw_protocol *, +u32 *,u32 *,u32 *,u32 *);void *set_mode;void *blt; }efi_uga_draw_protocol_t ;
drivers/firmware/efi/libstub/efi-stub-helper.c +3 -2
@@ -423,12 +423,13 @@ static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,return status; } -static efi_status_t efi_file_read (void *handle,unsigned long *size,void *addr) +static efi_status_t efi_file_read (efi_file_handle_t *handle, +unsigned long *size,void *addr) {return efi_call_proto (efi_file_handle, read, handle, size, addr); } -static efi_status_t efi_file_close (void *handle) +static efi_status_t efi_file_close (efi_file_handle_t *handle) {return efi_call_proto (efi_file_handle, close, handle); }
drivers/firmware/efi/libstub/tpm.c +2 -2
@@ -59,11 +59,11 @@ void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)size_t log_size, last_entry_size;efi_bool_t truncated;int version =EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ; -void *tcg2_protocol =NULL ; +efi_tcg2_protocol_t *tcg2_protocol =NULL ;int final_events_size =0 ; status =efi_call_early (locate_protocol, &tcg2_guid,NULL , - &tcg2_protocol); + (void **)&tcg2_protocol);if (status !=EFI_SUCCESS )return ;
include/linux/efi.h +5 -1
@@ -399,7 +399,11 @@ struct efi_pci_io_protocol {void *allocate_buffer;void *free_buffer;void *flush; -void *get_location; +efi_status_t (*get_location)(struct efi_pci_io_protocol *, +unsigned long *segment_nr, +unsigned long *bus_nr, +unsigned long *device_nr, +unsigned long *function_nr);void *attributes;void *get_bar_attributes;void *set_bar_attributes;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH 9/10 efi/libstub: annotate firmware routines as __efiapi
In reply to Ard BiesheuvelAnnotate all the firmware routines (boot services, runtime services and protocol methods) called in the boot context as __efiapi, and make it expand to __attribute__((ms_abi)) on 64-bit x86. This allows us to use the compiler to generate the calls into firmware that use the MS calling convention instead of the SysV one.
--- arch/x86/Kconfig | 1 + arch/x86/boot/compressed/eboot.h | 4 +- drivers/firmware/efi/libstub/random.c | 8 +- include/linux/efi.h | 130 +++++++++++--------- 4 files changed, 79 insertions(+), 64 deletions(-)
arch/x86/Kconfig +1 -0
@@ -1993,6 +1993,7 @@ config EFI config EFI_STUB bool "EFI stub support" depends on EFI && !X86_USE_3DNOW + depends on $(cc-option,-mabi=ms) select RELOCATABLE ---help--- This kernel feature allows a bzImage to be loaded directly
arch/x86/boot/compressed/eboot.h +2 -2
@@ -19,8 +19,8 @@ typedef struct { } efi_uga_draw_protocol_32_t;typedef struct efi_uga_draw_protocol { -efi_status_t (*get_mode)(struct efi_uga_draw_protocol *, -u32 *,u32 *,u32 *,u32 *); + efi_status_t (__efiapi *get_mode)(struct efi_uga_draw_protocol *, + u32*, u32*, u32*, u32*);void *set_mode;void *blt; }efi_uga_draw_protocol_t ;
drivers/firmware/efi/libstub/random.c +4 -4
@@ -17,10 +17,10 @@ typedef struct { } efi_rng_protocol_32_t;struct efi_rng_protocol { -efi_status_t (*get_info)(struct efi_rng_protocol *, -unsigned long *,efi_guid_t *); -efi_status_t (*get_rng)(struct efi_rng_protocol *, -efi_guid_t *,unsigned long ,u8 *out); + efi_status_t (__efiapi *get_info)(struct efi_rng_protocol *, + unsigned long *, efi_guid_t *); + efi_status_t (__efiapi *get_rng)(struct efi_rng_protocol *, + efi_guid_t *, unsigned long, u8 *out); }; efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,
include/linux/efi.h +72 -58
225 lines not on this page · raw message
Signature · 1 line
2.17.1
Re: [PATCH 09/10] efi/libstub: annotate firmware routines as __efiapi
Quoted 66 lines · Ard Biesheuvel
Annotate all the firmware routines (boot services, runtime services and protocol methods) called in the boot context as
__efiapi, and make it expand to __attribute__((ms_abi)) on 64-bit x86. This allows us to use the compiler to generate the calls into firmware that use the MS calling convention instead of the SysV one.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/x86/Kconfig | 1 + arch/x86/boot/compressed/eboot.h | 4 +- drivers/firmware/efi/libstub/random.c | 8 +- include/linux/efi.h | 130 +++++++++++--------- 4 files changed, 79 insertions(+), 64 deletions(-)arch/x86/Kconfig +1
-0@@ -1993,6 +1993,7 @@ config EFI config EFI_STUB bool "EFI stub support" depends on EFI && !X86_USE_3DNOW + depends on $(cc-option,-mabi=ms) select RELOCATABLE ---help--- This kernel feature allows a bzImage to be loaded directlyarch/x86/boot/compressed/eboot.h +2
-2@@ -19,8 +19,8 @@ typedef struct { } efi_uga_draw_protocol_32_t;typedef struct efi_uga_draw_protocol { -efi_status_t (*get_mode)(struct efi_uga_draw_protocol *, -u32 *,u32 *,u32 *,u32 *); + efi_status_t (__efiapi *get_mode)(struct efi_uga_draw_protocol *, + u32*, u32*, u32*, u32*);void *set_mode;void *blt; }efi_uga_draw_protocol_t ;drivers/firmware/efi/libstub/random.c +4
-4@@ -17,10 +17,10 @@ typedef struct { } efi_rng_protocol_32_t;struct efi_rng_protocol { -efi_status_t (*get_info)(struct efi_rng_protocol *, -unsigned long *,efi_guid_t *); -efi_status_t (*get_rng)(struct efi_rng_protocol *, -efi_guid_t *,unsigned long ,u8 *out); + efi_status_t (__efiapi *get_info)(struct efi_rng_protocol *, + unsigned long *, efi_guid_t *); + efi_status_t (__efiapi *get_rng)(struct efi_rng_protocol *, + efi_guid_t *, unsigned long, u8 *out); }; efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,include/linux/efi.h +0
-0
include/linux/efi.h typedef u16 efi_char16_t; /* UNICODE character */ · line 54
Quoted 7 lines
include/linux/efi.h +4
-0@@ -48,6 +48,12 @@ typedef u16 efi_char16_t; /* UNICODE character */typedef u64 efi_physical_addr_t ;typedef void *efi_handle_t ; +#ifdef CONFIG_X86_64 +#define __efiapi __attribute__((ms_abi)) +#else +#define __efiapi
I think it would be better to explicitly use the regparm(0) attribute for 32-bit, even though that is currently the default.
--
Brian Gerst
Ard Biesheuvel
maintainerPATCH 10/10 efi/libstub/x86: avoid thunking for native firmware calls
In reply to Ard BiesheuvelWe use special wrapper routines to invoke firmware services in the native case as well as the mixed mode case. For mixed mode, the need is obvious, but for the native cases, we can simply rely on the compiler to generate the indirect call, given that GCC now has support for the MS calling convention (and has had it for quite some time now). Note that on i386, the decompressor and the EFI stub are not built with -mregparm=3 like the rest of the i386 kernel, so we can safely allow the compiler to emit the indirect calls here as well.
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
--- arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/efi_stub_32.S | 87 -------------------- arch/x86/boot/compressed/efi_stub_64.S | 5 -- arch/x86/boot/compressed/head_32.S | 6 -- arch/x86/boot/compressed/head_64.S | 12 --- arch/x86/include/asm/efi.h | 22 +++-- arch/x86/platform/efi/efi_64.c | 2 - 7 files changed, 15 insertions(+), 121 deletions(-)
arch/x86/boot/compressed/Makefile +1 -1
@@ -89,7 +89,7 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone -vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \ +vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o \ $(objtree)/drivers/firmware/efi/libstub/lib.a vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
arch/x86/boot/compressed/efi_stub_32.S deleted +0 -87
87 lines not on this page · raw message
arch/x86/boot/compressed/efi_stub_64.S deleted +0 -5
@@ -1,5 +0,0 @@ -#include <asm/segment.h> -#include <asm/msr.h> -#include <asm/processor-flags.h> - -#include "../../platform/efi/efi_stub_64.S"
arch/x86/boot/compressed/head_32.S +0 -6
@@ -161,9 +161,7 @@ SYM_FUNC_START(efi_pe_entry) popl %ecx movl %ecx, efi32_config+8(%esi) /* EFI System table pointer */ - /* Relocate efi_config->call() */ leal efi32_config(%esi), %eax - add %esi, 28(%eax) pushl %eax call make_boot_params
@@ -188,9 +186,7 @@ SYM_FUNC_START(efi32_stub_entry) movl %ecx, efi32_config(%esi) /* Handle */ movl %edx, efi32_config+8(%esi) /* EFI System table pointer */ - /* Relocate efi_config->call() */ leal efi32_config(%esi), %eax - add %esi, 28(%eax) pushl %eax 2: call efi_main
@@ -266,8 +262,6 @@ SYM_FUNC_END(.Lrelocated) .data efi32_config: .fill 7,4,0 - .long efi_call_phys - .long 0 .byte 0 #endif
arch/x86/boot/compressed/head_64.S +0 -12
@@ -458,11 +458,6 @@ SYM_FUNC_START(efi_pe_entry) 1: popq %rbp subq $1b, %rbp - /* - * Relocate efi_config->call(). - */ - addq %rbp, efi64_config+40(%rip) - movq %rax, %rdi call make_boot_params cmpq $0,%rax
@@ -477,11 +472,6 @@ handover_entry: 1: popq %rbp subq $1b, %rbp - /* - * Relocate efi_config->call(). - */ - movq efi_config(%rip), %rax - addq %rbp, 40(%rax) 2: movq efi_config(%rip), %rdi call efi_main
@@ -683,14 +673,12 @@ SYM_DATA_LOCAL(efi_config, .quad 0) #ifdef CONFIG_EFI_MIXED SYM_DATA_START(efi32_config) .fill 5,8,0 - .quad efi64_thunk .byte 0 SYM_DATA_END(efi32_config) #endif SYM_DATA_START(efi64_config) .fill 5,8,0 - .quad efi_call .byte 1 SYM_DATA_END(efi64_config) #endif /* CONFIG_EFI_STUB */
arch/x86/include/asm/efi.h +14 -8
@@ -152,6 +152,7 @@ struct efi_setup_data {extern u64 efi_setup;#ifdef CONFIG_EFI +extern efi_status_t efi64_thunk (u32 , ...);static inline bool efi_is_mixed (void ) {
@@ -205,7 +206,6 @@ struct efi_config {efi_runtime_services_t *runtime_services;efi_boot_services_t *boot_services;efi_simple_text_output_protocol_t *text_output; -efi_status_t (*call)(unsigned long , ...);bool is64; } __packed;
@@ -232,7 +232,7 @@ static inline bool efi_is_native(void)#define efi_table_attr (table, attr, instance) ({ \ __typeof__(((table##_t *)0)->attr) __ret; \ if (efi_is_native()) { \ - __ret = ((table##_t *)instance)->attr; \ + __ret = instance->attr; \ } else { \ __typeof__(((table##_32_t *)0)->attr) at; \ at = (((table##_32_t *)(unsigned long)instance)->attr); \
@@ -242,19 +242,25 @@ static inline bool efi_is_native(void) })#define efi_call_proto (protocol, f, instance, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? instance->f(instance, ##__VA_ARGS__) \ + : efi64_thunk((unsigned long) \ efi_table_attr(protocol, f, instance), \ - instance, ##__VA_ARGS__) + instance, ##__VA_ARGS__)#define efi_call_early (f, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? __efi_early()->boot_services->f(__VA_ARGS__) \ + : efi64_thunk((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, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? __efi_early()->runtime_services->f(__VA_ARGS__) \ + : efi64_thunk((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_is_table_address (unsigned long phys_addr);
arch/x86/platform/efi/efi_64.c +0 -2
@@ -635,8 +635,6 @@ void efi_switch_mm(struct mm_struct *mm) }#ifdef CONFIG_EFI_MIXED -extern efi_status_t efi64_thunk (u32 , ...); -static DEFINE_SPINLOCK (efi_runtime_lock);#define runtime_service32 (func) \
Signature · 1 line
2.17.1
Re: [PATCH 10/10] efi/libstub/x86: avoid thunking for native firmware calls
arch/x86/include/asm/efi.h static inline bool efi_is_native(void) · line 238
Quoted 10 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +1
-1@@ -232,7 +232,7 @@ static inline bool efi_is_native(void)#define efi_table_attr (table, attr, instance) ({ \ __typeof__(((table##_t *)0)->attr) __ret; \ if (efi_is_native()) { \ - __ret = ((table##_t *)instance)->attr; \ + __ret = instance->attr; \ } else { \ __typeof__(((table##_32_t *)0)->attr) at; \ at = (((table##_32_t *)(unsigned long)instance)->attr); \
Is there a reason we didn't remove this cast for native-mode earlier in the series?
Quoted 22 lines
arch/x86/include/asm/efi.h +8
-4@@ -242,19 +242,25 @@ static inline bool efi_is_native(void) })#define efi_call_proto (protocol, f, instance, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? instance->f(instance, ##__VA_ARGS__) \ + : efi64_thunk((unsigned long) \ efi_table_attr(protocol, f, instance), \ - instance, ##__VA_ARGS__) + instance, ##__VA_ARGS__)#define efi_call_early (f, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? __efi_early()->boot_services->f(__VA_ARGS__) \ + : efi64_thunk((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, ...) \
arch/x86/include/asm/efi.h static inline bool efi_is_native(void) · line 266
Quoted 10 lines
arch/x86/include/asm/efi.h +4
-2-__efi_early ()->call ((unsigned long ) \ +efi_is_native () \ + ?__efi_early ()->runtime_services->f (__VA_ARGS__) \ + :efi64_thunk ((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_is_table_address (unsigned long phys_addr);
For the efi_call macros, their definition should be enclosed in parentheses now that it's a ternary operator.
Re: [PATCH 10/10] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 16 lines · Arvind Sankar
arch/x86/include/asm/efi.h static inline bool efi_is_native(void) · line 238
Quoted 10 lines · Ard Biesheuvel
arch/x86/include/asm/efi.h +1
-1@@ -232,7 +232,7 @@ static inline bool efi_is_native(void)#define efi_table_attr (table, attr, instance) ({ \ __typeof__(((table##_t *)0)->attr) __ret; \ if (efi_is_native()) { \ - __ret = ((table##_t *)instance)->attr; \ + __ret = instance->attr; \ } else { \ __typeof__(((table##_32_t *)0)->attr) at; \ at = (((table##_32_t *)(unsigned long)instance)->attr); \Is there a reason we didn't remove this cast for native-mode earlier in the series?
Yes. In patch 9/10, I fix a couple of occurrences where the protocol pointer is a void*, so without the cast, things break.
Quoted 30 lines
Quoted 30 lines
arch/x86/include/asm/efi.h +12
-6@@ -242,19 +242,25 @@ static inline bool efi_is_native(void) })#define efi_call_proto (protocol, f, instance, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? instance->f(instance, ##__VA_ARGS__) \ + : efi64_thunk((unsigned long) \ efi_table_attr(protocol, f, instance), \ - instance, ##__VA_ARGS__) + instance, ##__VA_ARGS__)#define efi_call_early (f, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? __efi_early()->boot_services->f(__VA_ARGS__) \ + : efi64_thunk((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, ...) \ - __efi_early()->call((unsigned long) \ + efi_is_native() \ + ? __efi_early()->runtime_services->f(__VA_ARGS__) \ + : efi64_thunk((unsigned long) \ efi_table_attr(efi_runtime_services, f, \ - __efi_early()->runtime_services), __VA_ARGS__) + __efi_early()->runtime_services), __VA_ARGS__)
Quoted 5 lines
arch/x86/include/asm/efi.h static inline bool efi_is_native(void) · line 266
Quoted 2 lines
arch/x86/include/asm/efi.h +0
-0extern bool efi_reboot_required (void );extern bool efi_is_table_address (unsigned long phys_addr);For the
efi_callmacros, their definition should be enclosed in parentheses now that it's a ternary operator.
Ack